diff --git a/.gitignore b/.gitignore index 602476d2..846aaca3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,12 @@ +.idea .DS_Store -depthmapX-build \ No newline at end of file +depthmapX-build +build +RegressionTest/rundir +__pycache__ +depthmapX.pro.user +*_BACKUP_* +*_BASE_* +*_LOCAL_* +*_REMOTE_* + diff --git a/.travis.yml b/.travis.yml index cdde9e1e..87e884df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,18 +1,18 @@ sudo: required -dist: trusty +dist: xenial +language: c++ +services: + - docker -before_install: - - sudo add-apt-repository --yes ppa:beineri/opt-qt571-trusty - - sudo add-apt-repository --yes ppa:fkrull/deadsnakes - - sudo apt-get update -qq +notifications: + slack: depthmapx:B3CKNlNDLrNz1vSOU5yoQQqA + webhooks: + urls: + - "https://scalar.vector.im/api/neb/services/hooks/dHJhdmlzLWNpLyU0MG9yYW5nZS12ZXJ0ZXglM0FtYXRyaXgub3JnLyUyMUVZQUZRaEVrV3lDZm1hcm9QaCUzQW1hdHJpeC5vcmc" + on_success: always # always|never|change + on_failure: always + on_start: never -install: - - sudo apt-get -y install qt573d qt57tools libgl1-mesa-dev libglu1-mesa-dev python3.5 script: - - source /opt/qt57/bin/qt57-env.sh - - mkdir build && cd build - - /opt/qt57/bin/qmake ../depthmapX.pro - - make - - ./cliTest/cliTest && ./GuiUnitTest/GuiUnitTest - - cd ../RegressionTest && python3.5 test_main.py && python3.5 RegressionTestRunner.py + - docker run --security-opt seccomp:unconfined --user $UID -v $PWD:/mnt/code blackseamonster/depthmapx-buildenv:0.3 bash -c ci/build.sh diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..dd75dc6e --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,50 @@ +project(depthmapX) +cmake_minimum_required(VERSION 3.13.0) +set(CMAKE_CXX_STANDARD 11) + +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR + "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set(warnings "-Wall -Wextra") +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + set(warnings "/W4 /EHsc") + execute_process(COMMAND make_version_header.bat WORKING_DIRECTORY depthmapX) +endif() + +# policy for target sources - we don't expect any old CMakes +cmake_policy(SET CMP0076 NEW) + +include_directories(".") + +# Get the current working branch +execute_process( + COMMAND git rev-parse --abbrev-ref HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE APP_BRANCH + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +# Get the latest abbreviated commit hash of the working branch +execute_process( + COMMAND git log -1 --format=%h + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE APP_COMMIT + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +# generate version_defs.h +include_directories(${CMAKE_BINARY_DIR}) +configure_file("${CMAKE_SOURCE_DIR}/version_defs.h.in" "${CMAKE_BINARY_DIR}/version_defs.h" @ONLY) + +string(TIMESTAMP APP_DATE %Y-%m-%d) + +add_subdirectory(genlib) +add_subdirectory(genlibTest) +add_subdirectory(salalib) +add_subdirectory(mgraph440) +add_subdirectory(mgraph440Test) +add_subdirectory(salaTest) +add_subdirectory(depthmapXcli) +add_subdirectory(cliTest) +add_subdirectory(depthmapXTest) +add_subdirectory(depthmapX) +add_subdirectory(GuiUnitTest) diff --git a/GuiApp/GuiApp.pro b/GuiApp/GuiApp.pro deleted file mode 100644 index 1ac283f4..00000000 --- a/GuiApp/GuiApp.pro +++ /dev/null @@ -1,24 +0,0 @@ -include(../defaults.pri) - -QT += core gui opengl widgets -DEFINES += _DEPTHMAP -TEMPLATE = app -TARGET =depthmapX - -SOURCES = main.cpp - - -win32:Release:LIBS += -L../depthmapX/release -L../genlib/release -L../salalib/release -win32:Debug:LIBS += -L../depthmapX/debug -L../genlib/debug -L../salalib/debug -!win32:LIBS += -L../depthmapX -L../genlib -L../salalib - -LIBS += -ldepthmapX -lsalalib -lgenlib - -!win32:!macx:LIBS += -L/usr/lib/i386-linux-gnu/ - -!win32:!macx:LIBS += -lGL -lGLU - - -win32:LIBS += -lOpenGl32 -lglu32 -lgdi32 - - diff --git a/GuiApp/main.cpp b/GuiApp/main.cpp deleted file mode 100644 index 591f1ff4..00000000 --- a/GuiApp/main.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2011-2012, Tasos Varoudis -// Copyright (C) 2017 Christian Sailer - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - - -#include -#include -#include -#include -#include -#include - -#include "mainwindowfactory.h" -#include "version.h" - -#ifdef _WIN32 -#include -#endif - -//////// dX Simple // -// Search for #ifndef _COMPILE_dX_SIMPLE_VERSION in order to force "simple dX" compile - - -int main(int argc, char *argv[]) -{ - Q_INIT_RESOURCE(resource); - - QApplication app(argc, argv); - - LicenseAgreementHolder dummy; - dummy.get().setModal(true); - dummy.get().setWindowTitle(TITLE_BASE); - dummy.get().exec(); - if ( dummy.get().result() == dummy.get().Rejected ) return 0; - - QSplashScreen *splash = 0; - int screenId = QApplication::desktop()->screenNumber(); - splash = new QSplashScreen(QPixmap(QLatin1String("images/splash.png"))); - if (QApplication::desktop()->isVirtualDesktop()) - { - QRect srect(0, 0, splash->width(), splash->height()); - splash->move(QApplication::desktop()->availableGeometry(screenId).center() - srect.center() ); - } - //splash->show(); - - MainWindowHolder mainWindow; - mainWindow.get().show(); - - //splash->finish(&mainWin); - return app.exec(); -} diff --git a/GuiUnitTest/CMakeLists.txt b/GuiUnitTest/CMakeLists.txt new file mode 100644 index 00000000..7dcc3406 --- /dev/null +++ b/GuiUnitTest/CMakeLists.txt @@ -0,0 +1,22 @@ +set(GuiUnitTest GuiUnitTest) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +# Find the QtWidgets library +find_package(Qt5 COMPONENTS Core Widgets Gui OpenGL REQUIRED) +# Instruct CMake to run moc automatically when needed +set(CMAKE_AUTOMOC ON) + +set(guiUnitTest_SRCS + main.cpp + testviewhelpers.cpp + testsettings.cpp + ../depthmapX/settingsimpl.cpp + ../depthmapX/views/viewhelpers.cpp) + +include_directories("../ThirdParty/Catch" "../ThirdParty/FakeIt" "../depthmapX") + +set(LINK_LIBS salalib genlib mgraph440 Qt5::Core) + +add_executable(${GuiUnitTest} ${guiUnitTest_SRCS}) +target_link_libraries(${GuiUnitTest} ${LINK_LIBS}) + diff --git a/GuiUnitTest/GuiUnitTest.pro b/GuiUnitTest/GuiUnitTest.pro deleted file mode 100644 index da3d6986..00000000 --- a/GuiUnitTest/GuiUnitTest.pro +++ /dev/null @@ -1,33 +0,0 @@ -include(../defaults.pri) -QT += core -QT -= gui - -CONFIG += c++11 - -TARGET = GuiUnitTest -CONFIG += console -CONFIG -= app_bundle -INCLUDEPATH += ../ThirdParty/Catch - -TEMPLATE = app - -SOURCES += main.cpp \ - testviewhelpers.cpp - -win32:Release:LIBS += -L../depthmapX/release -win32:Debug:LIBS += -L../depthmapX/debug -!win32:LIBS += -L../depthmapX - -LIBS += -ldepthmapX - - -# The following define makes your compiler emit warnings if you use -# any feature of Qt which as been marked deprecated (the exact warnings -# depend on your compiler). Please consult the documentation of the -# deprecated API in order to know how to port your code away from it. -DEFINES += QT_DEPRECATED_WARNINGS - -# You can also make your code fail to compile if you use deprecated APIs. -# In order to do so, uncomment the following line. -# You can also select to disable deprecated APIs only up to a certain version of Qt. -#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 diff --git a/GuiUnitTest/testsettings.cpp b/GuiUnitTest/testsettings.cpp new file mode 100644 index 00000000..5cfdcce0 --- /dev/null +++ b/GuiUnitTest/testsettings.cpp @@ -0,0 +1,57 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include <../cliTest/selfcleaningfile.h> +#include <../depthmapX/settingsimpl.h> + + +class TestSettingsFactory : public QSettingsFactory +{ +public: + TestSettingsFactory(const QString &filename) : mFilename(filename) + {} + virtual std::unique_ptr getSettings() const + { + return std::unique_ptr(new QSettings(mFilename, QSettings::IniFormat)); + } +private: + QString mFilename; +}; + +TEST_CASE("Test simple settings") +{ + SelfCleaningFile scf("./test.ini"); + SettingsImpl settings(new TestSettingsFactory(scf.Filename().c_str())); + + REQUIRE(settings.readSetting("test1", "bar").toString().toStdString() == "bar"); + settings.writeSetting("test1", "foo"); + REQUIRE(settings.readSetting("test1", "bar").toString().toStdString() == "foo"); +} + + +TEST_CASE("Test settings transaction") +{ + SelfCleaningFile scf("./test.ini"); + SettingsImpl settings(new TestSettingsFactory(scf.Filename().c_str())); + + REQUIRE(settings.readSetting("test1", "bar").toString() == "bar"); + { + auto transaction = settings.getTransaction(); + transaction->writeSetting("test1", "foo"); + } + REQUIRE(settings.readSetting("test1", "bar").toString() == "foo"); + +} diff --git a/GuiUnitTest/testviewhelpers.cpp b/GuiUnitTest/testviewhelpers.cpp index 414674c3..224226d6 100644 --- a/GuiUnitTest/testviewhelpers.cpp +++ b/GuiUnitTest/testviewhelpers.cpp @@ -13,7 +13,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "viewhelpers.h" +#include "depthmapX/views/viewhelpers.h" #include "catch.hpp" #include #include @@ -22,12 +22,12 @@ TEST_CASE("Calculating the new center", "[calculateCenter]"){ auto point = QPoint(100, 100); auto oldCenter = QPoint(200,200); - auto newCenter = QPoint(150,150); + auto newCenter = Point2f(150,150); REQUIRE(ViewHelpers::calculateCenter(point, oldCenter, 0.5) == newCenter); - newCenter.rx() = 300; - newCenter.ry() = 300; + newCenter.x = 300; + newCenter.y = 300; REQUIRE(ViewHelpers::calculateCenter(point, oldCenter, 2.0) == newCenter); @@ -38,9 +38,9 @@ TEST_CASE("Date string format", "[getCurrentDate]"){ const tm* ltime = localtime(&now); std::stringstream sstream; sstream << ltime->tm_year + 1900 << "/" << - setfill('0') << setw(2) << ltime->tm_mon + 1 << "/" << - setfill('0') << setw(2) << ltime->tm_mday << std::flush; + std::setfill('0') << std::setw(2) << ltime->tm_mon + 1 << "/" << + std::setfill('0') << std::setw(2) << ltime->tm_mday << std::flush; - REQUIRE(ViewHelpers::getCurrentDate() == pstring(sstream.str().c_str())); + REQUIRE(ViewHelpers::getCurrentDate() == sstream.str().c_str()); } diff --git a/README.md b/README.md new file mode 100644 index 00000000..aed5c3e4 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +## depthmapX - multi-platform spatial network analyses software + + +This is the home for the development of depthmapX. + + +Latest releases can be found at the [releases page](https://github.com/SpaceGroupUCL/depthmapX/releases) + + +For any issues/bugs/crashes please create [a new issue](https://github.com/SpaceGroupUCL/depthmapX/issues/new) + + +For more information please check the [documentation](./docs/index.md) and the [wiki](https://github.com/SpaceGroupUCL/depthmapX/wiki) + +[About depthmapX](./docs/about.md) + + +## + +depthmapX is licensed under the [GPLv3](http://www.gnu.org/licenses/gpl-3.0.html) licence. + +depthmapX uses [Qt5](http://www.qt.io) as UI toolkit and build system, [Catch](https://github.com/philsquared/catch) as unit testing framework and [FakeIt](https://github.com/eranpeer/FakeIt) for test mocks. + +Please join the depthmapX mail distribution list at www.jiscmail.ac.uk/lists/DEPTHMAP.html for updates. + +The developers and users of depthmapX can also be found on matrix/riot for more direct and extended discussions in the following channels: +- [depthmapX-users](https://riot.im/app/#/room/#depthmapX-users:matrix.org) - for general discussion, and questions about using depthmapX +- [depthmapX-devel](https://riot.im/app/#/room/#depthmapX-devel:matrix.org) - for development discussion diff --git a/RegressionTest/BaselineBinaries/Darwin/depthmapXcli b/RegressionTest/BaselineBinaries/Darwin/depthmapXcli new file mode 100755 index 00000000..644a8d4f Binary files /dev/null and b/RegressionTest/BaselineBinaries/Darwin/depthmapXcli differ diff --git a/RegressionTest/BaselineBinaries/Linux/depthmapXcli b/RegressionTest/BaselineBinaries/Linux/depthmapXcli index 0273940d..eb2155da 100755 Binary files a/RegressionTest/BaselineBinaries/Linux/depthmapXcli and b/RegressionTest/BaselineBinaries/Linux/depthmapXcli differ diff --git a/RegressionTest/BaselineBinaries/Windows/depthmapXcli.exe b/RegressionTest/BaselineBinaries/Windows/depthmapXcli.exe index 03a63c33..fd384046 100644 Binary files a/RegressionTest/BaselineBinaries/Windows/depthmapXcli.exe and b/RegressionTest/BaselineBinaries/Windows/depthmapXcli.exe differ diff --git a/RegressionTest/RegressionTestRunner.py b/RegressionTest/RegressionTestRunner.py old mode 100644 new mode 100755 index dac68c18..6e8219b0 --- a/RegressionTest/RegressionTestRunner.py +++ b/RegressionTest/RegressionTestRunner.py @@ -1,7 +1,9 @@ import runhelpers import config import depthmaprunner +import performancerunner import os +import sys defaultConfigFile = "regressionconfig.json" @@ -17,12 +19,17 @@ def __init__(self, configfile, runfunc): def run(self): if not os.path.exists(self.config.rundir): os.makedirs(self.config.rundir) - runner = depthmaprunner.DepthmapRegressionRunner( self.runfunc, self.baseBinary, self.testBinary, self.config.rundir ) + if self.config.performanceRegression.enabled: + print("Performance regression runs enabled") + runner = performancerunner.PerformanceRunner(self.runfunc, self.baseBinary, self.testBinary, self.config.rundir,self.config.performanceRegression ) + else: + print("Default regression runs - no performance") + runner = depthmaprunner.DepthmapRegressionRunner( self.runfunc, self.baseBinary, self.testBinary, self.config.rundir ) good = True for name, case in self.config.testcases.items(): print("Running test case " + name) - success, output = runner.runTestCase(name, case.cmd.infile, case.cmd.outfile, case.cmd.mode, case.cmd.simpleMode, case.cmd.modeLines) + success, output = runner.runTestCase(name, case) if not success: good = False print ("Failed:\n" + output) @@ -31,7 +38,13 @@ def run(self): return good if __name__ == "__main__": - r = RegressionTestRunner(defaultConfigFile, runhelpers.runExecutable) + print("Starting up RegressionTestRunner") + configFile = defaultConfigFile + if len(sys.argv) == 2: + configFile = sys.argv[1] + print("Config file in use is: " + configFile) + r = RegressionTestRunner(configFile, runhelpers.runExecutable) + print("Setup complete, starting run") if not r.run(): exit(-1) diff --git a/RegressionTest/cmdlinewrapper.py b/RegressionTest/cmdlinewrapper.py index 19fe943e..b661388b 100644 --- a/RegressionTest/cmdlinewrapper.py +++ b/RegressionTest/cmdlinewrapper.py @@ -9,7 +9,8 @@ def __init__(self): self.outfile = None self.simpleMode = False self.mode = None - self.modeLines = [] + self.extraArgs = {} + self.timingFile = None def toCmdArray(self): @@ -22,26 +23,19 @@ def toCmdArray(self): args = ["-f", self.infile, "-o", self.outfile, "-m", self.mode] if self.simpleMode: args.append("-s") + + if self.timingFile: + args.extend(["-t", self.timingFile]) - for modeLine in self.modeLines: - args.extend(modeLine.toCmdArray()) + for key, value in self.extraArgs.items(): + if isinstance(value, list): + for v in value: + args.append(key) + args.append(v) + else: + args.append(key) + if value: + args.append(value) return args -class VisibilityCmd(): - visibilityMode = None - globalMeasures = False - localMeasures = False - radius = None - - def toCmdArray(self): - if self.visibilityMode == None: - raise CommandLineError("visibility mode must be defined") - args = ["-vm", self.visibilityMode ] - if self.globalMeasures: - args.append("-vg") - if self.localMeasures: - args.append("-vl") - if not self.radius == None: - args.extend(["-vr", self.radius]) - return args diff --git a/RegressionTest/config.py b/RegressionTest/config.py index 081761f4..2940dab3 100644 --- a/RegressionTest/config.py +++ b/RegressionTest/config.py @@ -1,44 +1,25 @@ import json import os.path import cmdlinewrapper +from performanceregressionconfig import PerformanceRegressionConfig + class ConfigError(Exception): def __init__(self, message): self.message = message -def buildSubCmd( subType, subConfig ): - if subType == "Visibility": - scmd = cmdlinewrapper.VisibilityCmd() - scmd.visibilityMode = subConfig["visibilityMode"] - if "globalMeasures" in subConfig: - scmd.globalMeasures = True - if "localMeasures" in subConfig: - scmd.localMeasures = True - if "radius" in subConfig: - scmd.radius = subConfig["radius"] - return scmd; - else: - raise ConfigError("Unknown sub commandline config " + subType) - -def buildCmd(testcase): - cmd = cmdlinewrapper.DepthmapCmd() - cmd.infile = testcase["infile"] - cmd.outfile = testcase["outfile"] - cmd.mode = testcase["mode"] - if "simple" in testcase and not testcase["simple"] == "false": - cmd.simpleMode = True - if "subcmds" in testcase: - for (key, value) in testcase["subcmds"].items(): - cmd.modeLines.append(buildSubCmd(key, value)) - return cmd - -class TestCase(): - def __init__(self, cmd): - self.cmd = cmd - -def buildTestcase(testcase, rundir, configdir): - return TestCase(buildCmd(testcase)) - +def buildCmd(testcaseSet): + cmds = []; + for testcase in testcaseSet: + cmd = cmdlinewrapper.DepthmapCmd() + cmd.infile = testcase["infile"] + cmd.outfile = testcase["outfile"] + cmd.mode = testcase["mode"] + if "simple" in testcase and not testcase["simple"] == "false": + cmd.simpleMode = True + cmd.extraArgs = testcase.get("extraArgs", {}) + cmds.append(cmd) + return cmds class RegressionConfig(): def __init__(self, filename): @@ -48,8 +29,9 @@ def __init__(self, filename): self.rundir = config["rundir"] self.basebinlocation = config["basebinlocation"] self.testbinlocation = config["testbinlocation"] + self.performanceRegression = PerformanceRegressionConfig(config.get("performance", None)) self.testcases = {} for (name, tc) in config["testcases"].items(): - self.testcases[name] = buildTestcase(tc, self.rundir, configdir) + self.testcases[name] = buildCmd(tc) diff --git a/RegressionTest/depthmaprunner.py b/RegressionTest/depthmaprunner.py index 00618ef8..166ba1f7 100644 --- a/RegressionTest/depthmaprunner.py +++ b/RegressionTest/depthmaprunner.py @@ -3,6 +3,9 @@ import difflib import pprint +import runhelpers + + class DepthmapRunner(): def __init__(self, runFunc, binary ): self.__runFunc = runFunc @@ -27,29 +30,36 @@ def __init__(self, runFunc, baseBinary, testBinary, workingDir): self.__testRunner = DepthmapRunner(runFunc, testBinary) self.__workingDir = workingDir - def runTestCase(self, name, infile, outfile, mode, simpleMode = False, subcmds = []): - cmd = cmdlinewrapper.DepthmapCmd() - cmd.infile = infile - cmd.outfile = outfile - cmd.mode = mode - cmd.simpleMode = simpleMode - cmd.modeLines = subcmds + def makeBaseDir(self, name): + return os.path.join(self.__workingDir, name + "_base") + + def makeTestDir(self, name): + return os.path.join(self.__workingDir, name + "_test") + + def runTestCase(self, name, cmds): + runhelpers.prepareDirectory(self.makeBaseDir(name)) + runhelpers.prepareDirectory(self.makeTestDir(name)) + return self.runTestCaseImpl(name, cmds) + + def runTestCaseImpl(self, name, cmds): + baseDir = self.makeBaseDir(name) + for step,cmd in enumerate(cmds): + (baseSuccess, baseOut) = self.__baseRunner.runDepthmap(cmd, baseDir) + if not baseSuccess: + print("Baseline run failed at step " + str(step) + " with arguments " + pprint.pformat(cmd.toCmdArray())) + print(baseOut) + return (False, "Baseline run failed at step: " + str(step)) - baseDir = os.path.join(self.__workingDir, name + "_base") - (baseSuccess, baseOut) = self.__baseRunner.runDepthmap(cmd, baseDir) - if not baseSuccess: - print("Baseline run failed with arguments " + pprint.pformat(cmd.toCmdArray())) - print(baseOut) - return (False, "Baseline run failed") - testDir = os.path.join(self.__workingDir, name + "_test") - (testSuccess, testOut) = self.__testRunner.runDepthmap(cmd, testDir) - if not testSuccess: - print("Test run failed with arguments " + pprint.pformat(cmd.toCmdArray())) - print(testOut) - return (False, "Test run failed") + testDir = self.makeTestDir(name) + for step,cmd in enumerate(cmds): + (testSuccess, testOut) = self.__testRunner.runDepthmap(cmd, testDir) + if not testSuccess: + print("Test run failed at step " + str(step) + " with arguments " + pprint.pformat(cmd.toCmdArray())) + print(testOut) + return (False, "Test run failed at step: " + str(step)) - baseFile = os.path.join(baseDir, outfile) - testFile = os.path.join(testDir, outfile) + baseFile = os.path.join(baseDir, cmds[-1].outfile) + testFile = os.path.join(testDir, cmds[-1].outfile) if not os.path.exists(baseFile): message = "Baseline output {0} does not exist".format(baseFile) print (message) diff --git a/RegressionTest/performance_regression.json b/RegressionTest/performance_regression.json new file mode 100644 index 00000000..5bacea67 --- /dev/null +++ b/RegressionTest/performance_regression.json @@ -0,0 +1,184 @@ +{ + "rundir": "rundir", + "basebinlocation": "../../BaselineBinaries", + "testbinlocation": "../../../build", + "performance":{}, + "testcases": { + "vis_prep_dense_pointmap":[{ + "infile": "../../../testdata/rect1x1.graph", + "outfile": "out.graph", + "mode": "VISPREP", + "extraArgs": { + "-pg": "0.02", + "-pp": "0.5,0.5" + } + }], + "visibility_local": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "visibility", + "-vl": "" + } + }], + "vga_isovist": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "isovist" + } + }], + "vga_angular": [{ + "infile": "../../../testdata/turns_connected.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "angular" + } + }], + "vga_metric": [{ + "infile": "../../../testdata/turns_connected.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "metric", + "-vr": "n" + } + }], + "vga_thru_vision": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "thruvision" + } + }], + "isovist_args": [{ + "infile": "../../../testdata/gallery_empty.graph", + "outfile": "out.graph", + "mode": "ISOVIST", + "extraArgs": + { + "-ii": ["1.77,6.6,90,30", "3.1,5.6,270,90" ] + } + }], + "visibility_global_n": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "visibility", + "-vg": "1", + "-vr": "n" + } + }], + "axial_makelines": [{ + "infile": "../../../testdata/gallery_empty.graph", + "outfile": "out.graph", + "mode": "AXIAL", + "extraArgs":{ + "-xl": "3,5", + "-xf": "" + } + }], + "axial_rn": [{ + "infile": "../../../testdata/barnsbury_extended2_axial.graph", + "outfile": "out.graph", + "mode": "AXIAL", + "extraArgs": { + "-xa": "n" + } + }], + "axial_rn_choice": [{ + "infile": "../../../testdata/barnsbury_extended2_axial.graph", + "outfile": "out.graph", + "mode": "AXIAL", + "extraArgs": { + "-xa": "n", + "-xac": "" + } + }], + "axial_rn_local": [{ + "infile": "../../../testdata/barnsbury_extended2_axial.graph", + "outfile": "out.graph", + "mode": "AXIAL", + "extraArgs": { + "-xa": "n", + "-xal": "" + } + }], + "segment_tulip_1024_rn_steps": [{ + "infile": "../../../testdata/barnsbury_extended1_segment.graph", + "outfile": "out.graph", + "mode": "SEGMENT", + "extraArgs": { + "-st": "tulip", + "-stb": "1024", + "-sr": "n", + "-srt": "steps" + } + }], + "segment_tulip_1024_rn_steps_choice": [{ + "infile": "../../../testdata/barnsbury_extended1_segment.graph", + "outfile": "out.graph", + "mode": "SEGMENT", + "extraArgs": { + "-st": "tulip", + "-stb": "1024", + "-sr": "n", + "-srt": "steps", + "-sic": "" + } + }], + "segment_tulip_1024_rn_steps_weighted": [{ + "infile": "../../../testdata/barnsbury_extended1_segment.graph", + "outfile": "out.graph", + "mode": "SEGMENT", + "extraArgs": { + "-st": "tulip", + "-stb": "1024", + "-sr": "n", + "-srt": "steps", + "-swa": "Segment Length" + } + }], + "segment_topological_rn": [{ + "infile": "../../../testdata/barnsbury_extended1_segment.graph", + "outfile": "out.graph", + "mode": "SEGMENT", + "extraArgs": { + "-st": "topological", + "-sr": "n" + } + }], + "segment_metric_rn": [{ + "infile": "../../../testdata/barnsbury_extended1_segment.graph", + "outfile": "out.graph", + "mode": "SEGMENT", + "extraArgs": { + "-st": "metric", + "-sr": "n" + } + }], + "convert_drawing_axial":[{ + "infile": "../../../testdata/barnsbury_extended2_drawing.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "axial", + "-con": "Axial Map Test" + } + }], + "convert_axial_segment":[{ + "infile": "../../../testdata/barnsbury_extended2_axial.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "segment", + "-con": "Segment Map Test" + } + }] + } +} diff --git a/RegressionTest/performanceregressionconfig.py b/RegressionTest/performanceregressionconfig.py new file mode 100644 index 00000000..ee501bf6 --- /dev/null +++ b/RegressionTest/performanceregressionconfig.py @@ -0,0 +1,24 @@ + + +class PerformanceRegressionConfig: + """ Encapsulate performance regression config + This takes an optional performance regression config. All Elements + in the performance regression config are optional. If it is None + completly, performance regresssion will be disabled + "peformanceRegression": + { + enabled = 1, <- enabling performance regression - only required if nothing else is set, the existence of a non null config will turn on performance regression + runsPerInstance = 3, <- how many runs of each run def to run and average over + relativeThresholdInPercent = 1.5, <- how many percent can the new version be slower without failing + absoluteThresholdInSeconds = 2.3, <- how many seconds the new version can be slower without failing + of the two above, breaching the lower one will lead to failure. + } + """ + def __init__(self, perfConfig): + if None == perfConfig or ("enabled" in perfConfig and perfConfig["enabled"] not in ["True", "true", "1", "yes"]): + self.enabled = False + return + self.enabled = True; + self.runsPerInstance = int(perfConfig.get("runsPerInstance", 3)) + self.relativeThresholdInPercent = float(perfConfig.get("relativeThresholdInPercent", 1)) + self.absoluteThresholdInSeconds = float(perfConfig.get("absoluteThresholdInSeconds",1)) diff --git a/RegressionTest/performancerunner.py b/RegressionTest/performancerunner.py new file mode 100644 index 00000000..beb9473d --- /dev/null +++ b/RegressionTest/performancerunner.py @@ -0,0 +1,109 @@ +from statistics import mean +from collections import OrderedDict + +import depthmaprunner +import os +import csv + +import runhelpers +from performanceregressionconfig import PerformanceRegressionConfig + +def checkPerformance(baseFile, testFile, relativeThreshold, absoluteThreshold): + """ + Check the performance of 2 depthmap runs against each other + This function expects the timing from a base and test run and parses them + as CSV. For now, it expects the entries to be the same. It will return an + error message if + * one or both of the files are missing + * the number of lines or the labels don't match + * the test run is more than 5 seconds or 5% slower than the baseline + (whatever is greater) + """ + if not os.path.exists(baseFile): + return "Base performance timing file {0} is missing".format(baseFile) + if not os.path.exists(testFile): + return "Test performance timing file {0} is missing".format(testFile) + with open(baseFile) as baseHandle, open(testFile) as testHandle: + baseReader = csv.DictReader(baseHandle) + testReader = csv.DictReader(testHandle) + + baseDone = False + testDone = False + + while True: + try: + baseLine = next(baseReader) + except StopIteration: + baseDone = True + + try: + testLine = next(testReader) + except StopIteration: + testDone = True + + if baseDone and testDone: + return "" + if baseDone and not testDone: + return "baseline performance file {0} has fewer lines than the test one {1}".format(baseFile, testFile) + if testDone and not baseDone: + return "baseline performance file {0} has more lines than the test one {1}".format(baseFile, testFile) + + if not baseLine["action"] == testLine["action"]: + return "performance line mismatch: base '{0}', test '{1}'".format(baseLine["action"], testLine["action"]) + + baseTime = float(baseLine["average"]) + testTime = float(testLine["average"]) + + allowance = max(absoluteThreshold, baseTime * relativeThreshold / 100 ) + if testTime > baseTime + allowance: + return "Performance regression: {0} took {1}s instead of {2}s".format(baseLine["action"], testLine["average"], baseLine["average"]) + +def aggregatePerformanceStats(dir, numRuns, numCmds, filenameTemplate ): + data = OrderedDict() + totalValues = [] + for i in range(numRuns): + for j in range(numCmds): + with open(os.path.join(dir, filenameTemplate.format(i, j)), "r") as f: + reader = csv.DictReader(f) + total = 0 + for line in reader: + if not line["action"] in data: + data[line["action"]] = [] + data[line["action"]].append(float(line["duration"])) + total = total + float(line["duration"]) + totalValues.append(total) + data["total"] = totalValues + + outputFile =os.path.join(dir, filenameTemplate.format("", "all")) + with open(outputFile, "w+") as f: + writer = csv.DictWriter(f, ["action", "min", "max", "average"]) + writer.writeheader() + for key, val in data.items(): + rowDict = {"action": key, "min": min(val), "max": max(val), "average": mean(val)} + writer.writerow(rowDict) + return outputFile + +class PerformanceRunner(depthmaprunner.DepthmapRegressionRunner): + def __init__(self, runFunc, baseBinary, testBinary, workingDir, perfConfig): + depthmaprunner.DepthmapRegressionRunner.__init__(self,runFunc,baseBinary,testBinary,workingDir) + self.perfConfig = perfConfig + + def runTestCase(self, name, cmds): + runhelpers.prepareDirectory(self.makeBaseDir(name)) + runhelpers.prepareDirectory(self.makeTestDir(name)) + + nameTemplate = "timings_{0}_{1}.csv" + for i in range(self.perfConfig.runsPerInstance): + print ("Running test case {0}, run {1} of {2}".format(name, i, self.perfConfig.runsPerInstance)) + for j in range(len(cmds)): + cmds[j].timingFile = nameTemplate.format(i,j) + result, message = self.runTestCaseImpl(name, cmds) + if not result: + return (False, "Run {0} failed with message: {1}".format(i, message)) + + testFile = aggregatePerformanceStats(self.makeTestDir(name),self.perfConfig.runsPerInstance, len(cmds), nameTemplate) + baseFile = aggregatePerformanceStats(self.makeBaseDir(name),self.perfConfig.runsPerInstance, len(cmds), nameTemplate) + message = checkPerformance(testFile, baseFile, self.perfConfig.relativeThresholdInPercent, self.perfConfig.absoluteThresholdInSeconds) + if message: + return (False, message) + return (True, "") \ No newline at end of file diff --git a/RegressionTest/regressionconfig.json b/RegressionTest/regressionconfig.json index 5e0925fa..021bbc86 100644 --- a/RegressionTest/regressionconfig.json +++ b/RegressionTest/regressionconfig.json @@ -3,16 +3,908 @@ "basebinlocation": "../../BaselineBinaries", "testbinlocation": "../../../build", "testcases": { - "visibility_local": { + "links_pointmap_manual": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "LINK", + "extraArgs": { + "-lnk": ["1.32,7.24,4.88,5.24","1.16,5.28,3.28,7.12"] + } + }], + "links_pointmap_file": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "LINK", + "extraArgs": { + "-lf": "../../../testdata/gallery_connected_merge_links.txt" + } + }], + "unlinks_shapegraph_coords": [{ + "infile": "../../../testdata/barnsbury_axial.graph", + "outfile": "out.graph", + "mode": "LINK", + "extraArgs": { + "-lmt": "shapegraphs", + "-lm": "unlink", + "-lt": "coords", + "-lnk": "530797,184255" + } + }], + "unlinks_shapegraph_refs": [{ + "infile": "../../../testdata/barnsbury_axial.graph", + "outfile": "out.graph", + "mode": "LINK", + "extraArgs": { + "-lmt": "shapegraphs", + "-lm": "unlink", + "-lt": "refs", + "-lnk": "18,24" + } + }], + "links_shapegraph_coords": [{ + "infile": "../../../testdata/barnsbury_axial.graph", + "outfile": "out.graph", + "mode": "LINK", + "extraArgs": { + "-lmt": "shapegraphs", + "-lm": "link", + "-lt": "coords", + "-lnk": "530684,184098,531388,184353" + } + }], + "links_shapegraph_refs": [{ + "infile": "../../../testdata/barnsbury_axial.graph", + "outfile": "out.graph", + "mode": "LINK", + "extraArgs": { + "-lmt": "shapegraphs", + "-lm": "link", + "-lt": "refs", + "-lnk": "1,41" + } + }], + "links_shapegraph_refs_non_cont_keys": [{ + "infile": "../../../testdata/axmap_noncont_keys.graph", + "outfile": "out.graph", + "mode": "LINK", + "extraArgs": { + "-lmt": "shapegraphs", + "-lm": "link", + "-lt": "refs", + "-lnk": "17,11" + } + }], + "visibility_local": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "visibility", + "-vl": "" + } + }], + "visibility_local_only_map": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "visibility", + "-vl": "" + } + },{ + "infile": "out.graph", + "outfile": "out.csv", + "mode": "EXPORT", + "extraArgs": { + "-em": "pointmap-data-csv" + } + }], + "visibility_global_with_multiple_pointmaps": [{ + "infile": "../../../testdata/gallery_two_pointmaps.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "visibility", + "-vg": "", + "-vr": "3" + } + }], + "visibility_global_3": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "visibility", + "-vg": "", + "-vr": "3" + } + }], + "visibility_global_3_only_map": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "visibility", + "-vg": "", + "-vr": "3" + } + },{ + "infile": "out.graph", + "outfile": "out.csv", + "mode": "EXPORT", + "extraArgs": { + "-em": "pointmap-data-csv" + } + }], + "pointmap_export_links": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.csv", + "mode": "EXPORT", + "extraArgs": { + "-em": "pointmap-links-csv" + } + }], + "axial_export_map_csv": [{ + "infile": "../../../testdata/barnsbury_axial.graph", + "outfile": "out.csv", + "mode": "EXPORT", + "extraArgs": { + "-em": "shapegraph-map-csv" + } + }], + "axial_export_map_mif_given_mif": [{ + "infile": "../../../testdata/barnsbury_axial.graph", + "outfile": "out.mif", + "mode": "EXPORT", + "extraArgs": { + "-em": "shapegraph-map-mif" + } + }], + "axial_export_map_mif_given_mid": [{ + "infile": "../../../testdata/barnsbury_axial.graph", + "outfile": "out.mid", + "mode": "EXPORT", + "extraArgs": { + "-em": "shapegraph-map-mif" + } + }], + "visibility_global_n": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "visibility", + "-vg": "", + "-vr": "n" + } + }], + "visibility_global_n_only_map": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "visibility", + "-vg": "", + "-vr": "n" + } + },{ + "infile": "out.graph", + "outfile": "out.csv", + "mode": "EXPORT", + "extraArgs": { + "-em": "pointmap-data-csv" + } + }], + "vga_isovist": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "isovist" + } + }], + "vga_isovist_only_map": [{ "infile": "../../../testdata/gallery_connected.graph", "outfile": "out.graph", "mode": "VGA", - "subcmds": { - "Visibility": { - "visibilityMode": "visibility", - "localMeasures": "1" - } + "extraArgs": { + "-vm": "isovist" + } + },{ + "infile": "out.graph", + "outfile": "out.csv", + "mode": "EXPORT", + "extraArgs": { + "-em": "pointmap-data-csv" + } + }], + "vga_angular": [{ + "infile": "../../../testdata/turns_connected.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "angular" + } + }], + "vga_angular_only_map": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "angular" + } + },{ + "infile": "out.graph", + "outfile": "out.csv", + "mode": "EXPORT", + "extraArgs": { + "-em": "pointmap-data-csv" + } + }], + "vga_metric": [{ + "infile": "../../../testdata/turns_connected.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "metric", + "-vr": "n" + } + }], + "vga_metric_only_map": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "metric", + "-vr": "n" + } + },{ + "infile": "out.graph", + "outfile": "out.csv", + "mode": "EXPORT", + "extraArgs": { + "-em": "pointmap-data-csv" + } + }], + "vga_thru_vision": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "thruvision" + } + }], + "vga_thru_vision_only_map": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "VGA", + "extraArgs": { + "-vm": "thruvision" + } + },{ + "infile": "out.graph", + "outfile": "out.csv", + "mode": "EXPORT", + "extraArgs": { + "-em": "pointmap-data-csv" + } + }], + "vga_visual_step_depth": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "STEPDEPTH", + "extraArgs":{ + "-sdp": "3,5", + "-sdt": "visual" + } + }], + "vga_metric_step_depth": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "STEPDEPTH", + "extraArgs":{ + "-sdp": "3,5", + "-sdt": "metric" + } + }], + "vga_angular_step_depth": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "STEPDEPTH", + "extraArgs":{ + "-sdp": "3,5", + "-sdt": "angular" + } + }], + "isovist_args": [{ + "infile": "../../../testdata/gallery_empty.graph", + "outfile": "out.graph", + "mode": "ISOVIST", + "extraArgs": + { + "-ii": ["1.77,6.6,90,30", "3.1,5.6,270,90" ] + } + }], + "isovist_file": [{ + "infile": "../../../testdata/gallery_empty.graph", + "outfile": "out.graph", + "mode": "ISOVIST", + "extraArgs": + { + "-if": "../../../testdata/isovists.csv" + } + }], + "axial_makelines": [{ + "infile": "../../../testdata/gallery_empty.graph", + "outfile": "out.graph", + "mode": "AXIAL", + "extraArgs":{ + "-xl": "3,5", + "-xf": "" + } + }], + "axial_rn": [{ + "infile": "../../../testdata/simple_axlines.graph", + "outfile": "out.graph", + "mode": "AXIAL", + "extraArgs": { + "-xa": "n" + } + }], + "axial_r3": [{ + "infile": "../../../testdata/simple_axlines.graph", + "outfile": "out.graph", + "mode": "AXIAL", + "extraArgs": { + "-xa": "3" + } + }], + "axial_rn_rra": [{ + "infile": "../../../testdata/simple_axlines.graph", + "outfile": "out.graph", + "mode": "AXIAL", + "extraArgs": { + "-xa": "n", + "-xar": "" + } + }], + "axial_rn_choice": [{ + "infile": "../../../testdata/simple_axlines.graph", + "outfile": "out.graph", + "mode": "AXIAL", + "extraArgs": { + "-xa": "n", + "-xac": "" + } + }], + "axial_rn_local": [{ + "infile": "../../../testdata/simple_axlines.graph", + "outfile": "out.graph", + "mode": "AXIAL", + "extraArgs": { + "-xa": "n", + "-xal": "" + } + }], + "axial_rn_noncont_keys": [{ + "infile": "../../../testdata/axmap_noncont_keys.graph", + "outfile": "out.graph", + "mode": "AXIAL", + "extraArgs": { + "-xa": "n" + } + }], + "axial_r3_noncont_keys": [{ + "infile": "../../../testdata/axmap_noncont_keys.graph", + "outfile": "out.graph", + "mode": "AXIAL", + "extraArgs": { + "-xa": "3" + } + }], + "axial_rn_rra_noncont_keys": [{ + "infile": "../../../testdata/axmap_noncont_keys.graph", + "outfile": "out.graph", + "mode": "AXIAL", + "extraArgs": { + "-xa": "n", + "-xar": "" + } + }], + "axial_rn_choice_noncont_keys": [{ + "infile": "../../../testdata/axmap_noncont_keys.graph", + "outfile": "out.graph", + "mode": "AXIAL", + "extraArgs": { + "-xa": "n", + "-xac": "" + } + }], + "axial_rn_local_noncont_keys": [{ + "infile": "../../../testdata/axmap_noncont_keys.graph", + "outfile": "out.graph", + "mode": "AXIAL", + "extraArgs": { + "-xa": "n", + "-xal": "" + } + }], + "segment_tulip_1024_rn_steps": [{ + "infile": "../../../testdata/barnsbury_segment.graph", + "outfile": "out.graph", + "mode": "SEGMENT", + "extraArgs": { + "-st": "tulip", + "-stb": "1024", + "-sr": "n", + "-srt": "steps" + } + }], + "segment_tulip_1024_rn_steps_choice": [{ + "infile": "../../../testdata/barnsbury_segment.graph", + "outfile": "out.graph", + "mode": "SEGMENT", + "extraArgs": { + "-st": "tulip", + "-stb": "1024", + "-sr": "n", + "-srt": "steps", + "-sic": "" + } + }], + "segment_tulip_1024_rn_steps_weighted": [{ + "infile": "../../../testdata/barnsbury_segment.graph", + "outfile": "out.graph", + "mode": "SEGMENT", + "extraArgs": { + "-st": "tulip", + "-stb": "1024", + "-sr": "n", + "-srt": "steps", + "-swa": "Segment Length" + } + }], + "segment_tulip_512_rn_steps": [{ + "infile": "../../../testdata/barnsbury_segment.graph", + "outfile": "out.graph", + "mode": "SEGMENT", + "extraArgs": { + "-st": "tulip", + "-stb": "512", + "-sr": "n", + "-srt": "steps" + } + }], + "segment_tulip_123_rn_steps": [{ + "infile": "../../../testdata/barnsbury_segment.graph", + "outfile": "out.graph", + "mode": "SEGMENT", + "extraArgs": { + "-st": "tulip", + "-stb": "123", + "-sr": "n", + "-srt": "steps" + } + }], + "segment_tulip_4_rn_steps": [{ + "infile": "../../../testdata/barnsbury_segment.graph", + "outfile": "out.graph", + "mode": "SEGMENT", + "extraArgs": { + "-st": "tulip", + "-stb": "4", + "-sr": "n", + "-srt": "steps" + } + }], + "segment_tulip_1024_r5_steps": [{ + "infile": "../../../testdata/barnsbury_segment.graph", + "outfile": "out.graph", + "mode": "SEGMENT", + "extraArgs": { + "-st": "tulip", + "-stb": "1024", + "-sr": "5", + "-srt": "steps" + } + }], + "segment_tulip_1024_rn_r5_steps": [{ + "infile": "../../../testdata/barnsbury_segment.graph", + "outfile": "out.graph", + "mode": "SEGMENT", + "extraArgs": { + "-st": "tulip", + "-stb": "1024", + "-sr": "5,n", + "-srt": "steps" + } + }], + "segment_tulip_1024_r500_metric": [{ + "infile": "../../../testdata/barnsbury_segment.graph", + "outfile": "out.graph", + "mode": "SEGMENT", + "extraArgs": { + "-st": "tulip", + "-stb": "1024", + "-sr": "500", + "-srt": "metric" + } + }], + "segment_tulip_1024_r180_angular": [{ + "infile": "../../../testdata/barnsbury_segment.graph", + "outfile": "out.graph", + "mode": "SEGMENT", + "extraArgs": { + "-st": "tulip", + "-stb": "1024", + "-sr": "500", + "-srt": "metric" + } + }], + "segment_angular_rn": [{ + "infile": "../../../testdata/barnsbury_segment.graph", + "outfile": "out.graph", + "mode": "SEGMENT", + "extraArgs": { + "-st": "angular", + "-sr": "n" + } + }], + "segment_topological_rn": [{ + "infile": "../../../testdata/barnsbury_segment.graph", + "outfile": "out.graph", + "mode": "SEGMENT", + "extraArgs": { + "-st": "topological", + "-sr": "n" + } + }], + "segment_metric_rn": [{ + "infile": "../../../testdata/barnsbury_segment.graph", + "outfile": "out.graph", + "mode": "SEGMENT", + "extraArgs": { + "-st": "metric", + "-sr": "n" + } + }], + "convert_drawing_axial":[{ + "infile": "../../../testdata/barnsbury_drawing.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "axial", + "-con": "Axial Map Test" + } + }], + "convert_drawing_segment":[{ + "infile": "../../../testdata/barnsbury_drawing.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "segment", + "-con": "Segment Map Test" + } + }], + "convert_drawing_segment_only_map":[{ + "infile": "../../../testdata/barnsbury_drawing.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "segment", + "-con": "Segment Map Test" + } + },{ + "infile": "out.graph", + "outfile": "out.csv", + "mode": "EXPORT", + "extraArgs": { + "-em": "shapegraph-map-csv" + } + }], + "convert_drawing_convex":[{ + "infile": "../../../testdata/polygons_drawing.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "convex", + "-con": "Convex Map Test" + } + }], + "convert_drawing_data_convex":[{ + "infile": "../../../testdata/polygons_drawing.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "data", + "-con": "Data Map Test" + } + },{ + "infile": "out.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "convex", + "-con": "Convex Map Test" + } + }], + "convert_drawing_data_drawing_polygons":[{ + "infile": "../../../testdata/polygons_drawing.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "data", + "-con": "Data Map Test" + } + },{ + "infile": "out.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "drawing", + "-con": "Drawing Map Test" + } + }], + "convert_drawing_data_drawing_lines":[{ + "infile": "../../../testdata/barnsbury_drawing.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "data", + "-con": "Data Map Test" + } + },{ + "infile": "out.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "drawing", + "-con": "Drawing Map Test" + } + }], + "convert_axial_data":[{ + "infile": "../../../testdata/barnsbury_axial.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "data", + "-con": "Data Map Test" + } + }], + "convert_axial_data_copy_attributes":[{ + "infile": "../../../testdata/barnsbury_axial.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "data", + "-con": "Data Map Test", + "-coc":"" + } + }], + "convert_axial_drawing":[{ + "infile": "../../../testdata/barnsbury_axial.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "drawing", + "-con": "Drawing Map Test" + } + }], + "convert_axial_segment":[{ + "infile": "../../../testdata/barnsbury_axial.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "segment", + "-con": "Segment Map Test" + } + }], + "convert_axial_segment_remove_input":[{ + "infile": "../../../testdata/barnsbury_axial.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "segment", + "-con": "Segment Map Test", + "-cir":"" + } + }], + "convert_axial_segment_trim_lines":[{ + "infile": "../../../testdata/barnsbury_axial.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "segment", + "-con": "Segment Map Test", + "-crsl":"40" + } + }], + "convert_axial_data_axial":[{ + "infile": "../../../testdata/barnsbury_axial.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "data", + "-con": "Data Map Test" + } + },{ + "infile": "out.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "axial", + "-con": "Axial Map Test" + } + }], + "convert_axial_data_axial_copy_attributes":[{ + "infile": "../../../testdata/barnsbury_axial.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "data", + "-con": "Data Map Test", + "-coc": "" + } + },{ + "infile": "out.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "axial", + "-con": "Axial Map Test", + "-coc": "" + } + }], + "convert_segment_data":[{ + "infile": "../../../testdata/barnsbury_segment.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "data", + "-con": "Data Map Test" + } + }], + "convert_segment_data_segment":[{ + "infile": "../../../testdata/barnsbury_segment.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "data", + "-con": "Data Map Test" + } + },{ + "infile": "out.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "axial", + "-con": "Segment Map Test" + } + }], + "convert_segment_data_segment_copy_attributes":[{ + "infile": "../../../testdata/barnsbury_segment.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "data", + "-con": "Data Map Test", + "-coc": "" + } + },{ + "infile": "out.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "axial", + "-con": "Segment Map Test", + "-coc": "" + } + }], + "convert_segment_drawing":[{ + "infile": "../../../testdata/barnsbury_segment.graph", + "outfile": "out.graph", + "mode": "MAPCONVERT", + "extraArgs": { + "-co": "drawing", + "-con": "Drawing Map Test" + } + }], + "pointmap_create_fill_make_one_operation": [{ + "infile": "../../../testdata/gallery_empty.graph", + "outfile": "out.graph", + "mode": "VISPREP", + "extraArgs": { + "-pg": "0.04", + "-pp": "1.32,7.24,4.88,5.24", + "-pm": "" + } + }], + "dense_pointmap_create_fill_make":[{ + "infile": "../../../testdata/rect1x1.graph", + "outfile": "out.graph", + "mode": "VISPREP", + "extraArgs": { + "-pg": "0.02", + "-pp": "0.5,0.5" + } + }], + "pointmap_create_fill_make_unmake": [{ + "infile": "../../../testdata/gallery_empty.graph", + "outfile": "out.graph", + "mode": "VISPREP", + "extraArgs": { + "-pg": "0.04" + } + },{ + "infile": "out.graph", + "outfile": "out.graph", + "mode": "VISPREP", + "extraArgs": { + "-pp": "1.32,7.24,4.88,5.24" + } + },{ + "infile": "out.graph", + "outfile": "out.graph", + "mode": "VISPREP", + "extraArgs": { + "-pm": "" + } + },{ + "infile": "out.graph", + "outfile": "out.graph", + "mode": "VISPREP", + "extraArgs": { + "-pu": "" + } + }], + "pointmap_create_fill_make_link_unmake": [{ + "infile": "../../../testdata/gallery_empty.graph", + "outfile": "out.graph", + "mode": "VISPREP", + "extraArgs": { + "-pg": "0.04", + "-pp": "1.32,7.24,4.88,5.24", + "-pm": "" + } + },{ + "infile": "out.graph", + "outfile": "out.graph", + "mode": "LINK", + "extraArgs": { + "-lnk": ["1.32,7.24,4.88,5.24","1.16,5.28,3.28,7.12"] + } + },{ + "infile": "out.graph", + "outfile": "out.graph", + "mode": "VISPREP", + "extraArgs": { + "-pu": "" + } + }], + "pointmap_create_fill_make_link_unmake_unlink": [{ + "infile": "../../../testdata/gallery_empty.graph", + "outfile": "out.graph", + "mode": "VISPREP", + "extraArgs": { + "-pg": "0.04", + "-pp": "1.32,7.24,4.88,5.24", + "-pm": "" + } + },{ + "infile": "out.graph", + "outfile": "out.graph", + "mode": "LINK", + "extraArgs": { + "-lnk": ["1.32,7.24,4.88,5.24","1.16,5.28,3.28,7.12"] + } + },{ + "infile": "out.graph", + "outfile": "out.graph", + "mode": "VISPREP", + "extraArgs": { + "-pu": "", + "-pl": "" } - } + }] } } diff --git a/RegressionTest/regressionconfig_agents.json b/RegressionTest/regressionconfig_agents.json new file mode 100644 index 00000000..6ede4043 --- /dev/null +++ b/RegressionTest/regressionconfig_agents.json @@ -0,0 +1,223 @@ +{ + "rundir": "rundir", + "basebinlocation": "../../BaselineBinaries", + "testbinlocation": "../../../build", + "testcases": { + "agents_defaults": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "AGENTS", + "extraArgs": { + "-am": "standard", + "-ats": "5000", + "-arr": "0.1", + "-afov": "15", + "-asteps": "3", + "-alife": "1000", + "-alocseed": "0" + } + }], + "agents_line_of_sight_length_look": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "AGENTS", + "extraArgs": { + "-am": "los-length", + "-ats": "5000", + "-arr": "0.1", + "-afov": "15", + "-asteps": "3", + "-alife": "1000", + "-alocseed": "0" + } + }], + "agents_line_of_sight_length_look_only_map": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.tsv", + "mode": "AGENTS", + "extraArgs": { + "-am": "los-length", + "-ats": "5000", + "-arr": "0.1", + "-afov": "15", + "-asteps": "3", + "-alife": "1000", + "-alocseed": "0", + "-ot": "gatecounts" + } + }], + "agents_occluded_length_look": [{ + "infile": "../../../testdata/gallery_connected_with_isovist.graph", + "outfile": "out.graph", + "mode": "AGENTS", + "extraArgs": { + "-am": "occ-length", + "-ats": "5000", + "-arr": "0.1", + "-afov": "15", + "-asteps": "3", + "-alife": "1000", + "-alocseed": "0" + } + }], + "agents_any_occlusion_look": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "AGENTS", + "extraArgs": { + "-am": "occ-any", + "-ats": "5000", + "-arr": "0.1", + "-afov": "15", + "-asteps": "3", + "-alife": "1000", + "-alocseed": "0" + } + }], + "agents_occlusion_group_bins_45_look": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "AGENTS", + "extraArgs": { + "-am": "occ-group-45", + "-ats": "5000", + "-arr": "0.1", + "-afov": "15", + "-asteps": "3", + "-alife": "1000", + "-alocseed": "0" + } + }], + "agents_occlusion_group_bins_60_look": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "AGENTS", + "extraArgs": { + "-am": "occ-group-60", + "-ats": "5000", + "-arr": "0.1", + "-afov": "15", + "-asteps": "3", + "-alife": "1000", + "-alocseed": "0" + } + }], + "agents_furthest_occlusion_per_bin_look": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "AGENTS", + "extraArgs": { + "-am": "occ-furthest", + "-ats": "5000", + "-arr": "0.1", + "-afov": "15", + "-asteps": "3", + "-alife": "1000", + "-alocseed": "0" + } + }], + "agents_per_bin_far_distance_look": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "AGENTS", + "extraArgs": { + "-am": "bin-far-dist", + "-ats": "5000", + "-arr": "0.1", + "-afov": "15", + "-asteps": "3", + "-alife": "1000", + "-alocseed": "0" + } + }], + "agents_per_bin_angle_look": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "AGENTS", + "extraArgs": { + "-am": "bin-angle", + "-ats": "5000", + "-arr": "0.1", + "-afov": "15", + "-asteps": "3", + "-alife": "1000", + "-alocseed": "0" + } + }], + "agents_per_bin_far_distance_and_angle_look": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "AGENTS", + "extraArgs": { + "-am": "bin-far-dist-angle", + "-ats": "5000", + "-arr": "0.1", + "-afov": "15", + "-asteps": "3", + "-alife": "1000", + "-alocseed": "0" + } + }], + "agents_per_bin_memory_look": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.graph", + "mode": "AGENTS", + "extraArgs": { + "-am": "bin-memory", + "-ats": "5000", + "-arr": "0.1", + "-afov": "15", + "-asteps": "3", + "-alife": "1000", + "-alocseed": "0" + } + }], + "agents_gatecounts": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.tsv", + "mode": "AGENTS", + "extraArgs": { + "-am": "standard", + "-ats": "5000", + "-arr": "0.1", + "-afov": "15", + "-asteps": "3", + "-alife": "1000", + "-alocseed": "5", + "-ot": "gatecounts" + } + }], + "agents_trails_all": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.cat", + "mode": "AGENTS", + "extraArgs": { + "-am": "standard", + "-ats": "5000", + "-arr": "0.1", + "-afov": "15", + "-asteps": "3", + "-alife": "1000", + "-alocseed": "0", + "-atrails": "0", + "-ot": "trails" + } + }], + "agents_trails_1": [{ + "infile": "../../../testdata/gallery_connected.graph", + "outfile": "out.cat", + "mode": "AGENTS", + "extraArgs": { + "-am": "standard", + "-ats": "5000", + "-arr": "0.1", + "-afov": "15", + "-asteps": "3", + "-alife": "1000", + "-alocseed": "0", + "-atrails": "1", + "-ot": "trails" + } + }] + } +} diff --git a/RegressionTest/runhelpers.py b/RegressionTest/runhelpers.py index bda2e2f7..a57167b0 100644 --- a/RegressionTest/runhelpers.py +++ b/RegressionTest/runhelpers.py @@ -26,7 +26,6 @@ def prepareDirectory(dirname): def runExecutable( workingDir, arguments ): """ Prepares a clean run directoy and runs the process in this """ - prepareDirectory(workingDir) with cd(workingDir): with open("out.txt", "w") as outfile: result = subprocess.run(arguments, stdout = outfile, stderr = subprocess.STDOUT ) diff --git a/RegressionTest/test/context.py b/RegressionTest/test/context.py new file mode 100644 index 00000000..41274fd8 --- /dev/null +++ b/RegressionTest/test/context.py @@ -0,0 +1,11 @@ +import os +import sys +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) + +import cmdlinewrapper +import config +import depthmaprunner +import RegressionTestRunner +import runhelpers +import performanceregressionconfig +import performancerunner \ No newline at end of file diff --git a/RegressionTest/disposablefile.py b/RegressionTest/test/disposablefile.py similarity index 100% rename from RegressionTest/disposablefile.py rename to RegressionTest/test/disposablefile.py diff --git a/RegressionTest/fail/test_fail.py b/RegressionTest/test/fail/test_fail.py similarity index 100% rename from RegressionTest/fail/test_fail.py rename to RegressionTest/test/fail/test_fail.py diff --git a/RegressionTest/pass/test_pass.py b/RegressionTest/test/pass/test_pass.py similarity index 100% rename from RegressionTest/pass/test_pass.py rename to RegressionTest/test/pass/test_pass.py diff --git a/RegressionTest/test_RegressionTestRunner.py b/RegressionTest/test/test_RegressionTestRunner.py similarity index 92% rename from RegressionTest/test_RegressionTestRunner.py rename to RegressionTest/test/test_RegressionTestRunner.py index d975d9bc..1b389450 100644 --- a/RegressionTest/test_RegressionTestRunner.py +++ b/RegressionTest/test/test_RegressionTestRunner.py @@ -14,6 +14,8 @@ def runfunc(self, workingdir, args): os.makedirs(workingdir) with open(os.path.join(workingdir, "outfile.graph"), "w") as f: f.write("123") + with open(os.path.join(workingdir, "runtimes.csv"), "w") as f: + f.write("action,duration\n") return (True, "") diff --git a/RegressionTest/test_cmdlinewrapper.py b/RegressionTest/test/test_cmdlinewrapper.py similarity index 63% rename from RegressionTest/test_cmdlinewrapper.py rename to RegressionTest/test/test_cmdlinewrapper.py index 4b98fb4a..cc856c4f 100644 --- a/RegressionTest/test_cmdlinewrapper.py +++ b/RegressionTest/test/test_cmdlinewrapper.py @@ -1,5 +1,7 @@ import unittest -import cmdlinewrapper + +import collections +from context import cmdlinewrapper class TestDepthmapCmd(unittest.TestCase): def test_correctBehaviour(self): @@ -26,33 +28,17 @@ def test_exceptions(self): cmd.toCmdArray() self.assertEqual(cm.exception.message, "mode must be defined") - def test_subcmd(self): + def test_extraArgs(self): cmd = cmdlinewrapper.DepthmapCmd() cmd.infile = "foo" cmd.outfile = "bar" cmd.mode = "visibility" + # use ordered dict here for testability + cmd.extraArgs = collections.OrderedDict([("-lnk", ["foo", "bar"]), ("-vm", "metric"), ("-vg", "" )]) - vis = cmdlinewrapper.VisibilityCmd() - vis.visibilityMode = "metric" - cmd.modeLines.append(vis) - - self.assertEqual(cmd.toCmdArray(), ["-f", "foo", "-o", "bar", "-m", "visibility", "-vm", "metric" ]) + self.assertEqual(cmd.toCmdArray(), ["-f", "foo", "-o", "bar", "-m", "visibility", "-lnk", "foo", "-lnk", "bar", "-vm", "metric", "-vg" ]) -class TestVisibiltyCmd(unittest.TestCase): - def test_correctBehaviour(self): - cmd = cmdlinewrapper.VisibilityCmd() - cmd.visibilityMode = "isovist" - self.assertEqual(cmd.toCmdArray(), ["-vm", "isovist"]) - cmd.radius = "5" - self.assertEqual(cmd.toCmdArray(), ["-vm", "isovist", "-vr", "5"]) - cmd.globalMeasures = True; - self.assertEqual(cmd.toCmdArray(), ["-vm", "isovist", "-vg", "-vr", "5"]) - cmd.localMeasures = True; - self.assertEqual(cmd.toCmdArray(), ["-vm", "isovist", "-vg", "-vl", "-vr", "5"]) - - - if __name__ == "__main__": unittest.main() diff --git a/RegressionTest/test/test_config.py b/RegressionTest/test/test_config.py new file mode 100644 index 00000000..c17c0b47 --- /dev/null +++ b/RegressionTest/test/test_config.py @@ -0,0 +1,50 @@ +import unittest +from context import config +from disposablefile import DisposableFile +import RegressionTestRunner +import os + +def writeConfig(filename, rundir): + with open(filename, "w") as f: + f.write('{ "rundir": "'+ rundir +'",\n') + f.write(' "basebinlocation": "../baselineBinaries",\n') + f.write(' "testbinlocation": "../..",\n') + f.write(' "testcases": {\n') + f.write(' "test1": [{\n') + f.write(' "infile": "infile.graph",\n') + f.write(' "outfile": "outfile.graph",\n') + f.write(' "mode": "VGA",\n') + f.write(' "extraArgs": {\n') + f.write(' "-vm": "metric",\n') + f.write(' "-vr": "7"}}]}}') + + + +class TestMethods(unittest.TestCase): + def test_buildCmd(self): + data = [{ "infile": "foo.graph", "outfile": "bar.graph", "mode": "VGA", "extraArgs": { "-vm": "visibility", "-vg": "", "-vr": "5"}}] + cmds = config.buildCmd( data ) + self.assertEqual(cmds[0].infile, "foo.graph") + self.assertEqual(cmds[0].outfile, "bar.graph") + self.assertEqual(cmds[0].mode, "VGA") + self.assertEqual(len(cmds[0].extraArgs),3) + + + def test_configClass(self): + with DisposableFile("test.config") as testfile: + writeConfig(testfile.filename(), "../foo/bar") + conf = config.RegressionConfig(testfile.filename()) + self.assertEqual(len(conf.testcases), 1) + self.assertEqual(conf.rundir, "../foo/bar") + self.assertTrue("test1" in conf.testcases) + + +class TestRealConfig(unittest.TestCase): + def test_realConfig(self): + configFile = os.path.join("..", RegressionTestRunner.defaultConfigFile) + self.assertNotEqual( configFile, "" ) + conf = config.RegressionConfig(configFile) + self.assertFalse(conf.performanceRegression.enabled) + +if __name__ == "__main__": + unittest.main() diff --git a/RegressionTest/test_depthmaprunner.py b/RegressionTest/test/test_depthmaprunner.py similarity index 75% rename from RegressionTest/test_depthmaprunner.py rename to RegressionTest/test/test_depthmaprunner.py index 2e63498d..5a501c91 100644 --- a/RegressionTest/test_depthmaprunner.py +++ b/RegressionTest/test/test_depthmaprunner.py @@ -1,4 +1,6 @@ -import depthmaprunner +from context import depthmaprunner + +import cmdlinewrapper from cmdlinewrapper import DepthmapCmd import unittest from disposablefile import DisposableFile, DisposableDirectory @@ -15,7 +17,7 @@ def test_binaryDiff(self): self.assertFalse(depthmaprunner.diffBinaryFiles(f1.filename(), f2.filename())) - + class DepthmapRunnerTest(unittest.TestCase): def runfunc(self, rundir, args): @@ -44,17 +46,27 @@ def getOutfile(self, args): break self.assertFalse( outputfile == None ) return outputfile - + + def getTimingsFile(self,args): + timingsFile = None + for i in range(0, len(args)): + if args[i] == "-t" and i < len(args): + timingsFile = args[i+1] + break + return timingsFile + def runfuncSucceedAlwaysSame(self, rundir, args): - os.makedirs(rundir) outpath = os.path.join(rundir, self.getOutfile(args)) with open (outpath, "w") as f: f.write("123") + timingsFile = self.getTimingsFile(args) + if timingsFile: + with open (os.path.join(rundir, timingsFile), "w") as f: + f.write('"action","duration"\n') return (True, "") def runfuncDifferentResults(self, rundir, args): - os.makedirs(rundir) outpath = os.path.join(rundir, self.getOutfile(args)) with open (outpath, "w") as f: f.write(self.__outContent) @@ -62,7 +74,6 @@ def runfuncDifferentResults(self, rundir, args): return (True, "") def runfuncWriteNoFile(self, rundir, args, dontWriteFor): - os.makedirs(rundir) if not args[0] == dontWriteFor: outpath = os.path.join(rundir, self.getOutfile(args)) with open (outpath, "w") as f: @@ -70,7 +81,6 @@ def runfuncWriteNoFile(self, rundir, args, dontWriteFor): return (True, "") def runfuncFail(self, rundir, args, failFor, shouldOtherRun): - os.makedirs(rundir) if args[0] == failFor: return (False, "Boom!") if shouldOtherRun: @@ -82,48 +92,55 @@ def runfuncFail(self, rundir, args, failFor, shouldOtherRun): self.assertFail("Should not have been called for " + args[0]) + def makeCommand(self, infile, outfile, mode): + cmd = cmdlinewrapper.DepthmapCmd() + cmd.infile = infile + cmd.outfile = outfile + cmd.mode = mode + return [cmd] + def testSuccessfullRun(self): with DisposableDirectory("testdir", True) as dir: runner = depthmaprunner.DepthmapRegressionRunner(lambda d, a: self.runfuncSucceedAlwaysSame(d,a), "basebin", "testbin", dir.name()) - (result, message) = runner.runTestCase("testname", "infile.graph", "outfile.graph", "visibility") + (result, message) = runner.runTestCase("testname", self.makeCommand("infile.graph", "outfile.graph", "visibility")) self.assertTrue(result) def testRunWithDiff(self): self.__outContent = "abc" with DisposableDirectory("testdir", True) as dir: runner = depthmaprunner.DepthmapRegressionRunner(lambda d, a: self.runfuncDifferentResults(d,a), "basebin", "testbin", dir.name()) - (result, message) = runner.runTestCase("testname", "infile.graph", "outfile.graph", "visibility") + (result, message) = runner.runTestCase("testname", self.makeCommand("infile.graph", "outfile.graph", "visibility")) self.assertFalse(result) self.assertEqual(message, "Test outputs differ") def testBaseRunOutputMissing(self): with DisposableDirectory("testdir", True) as dir: runner = depthmaprunner.DepthmapRegressionRunner(lambda d, a: self.runfuncWriteNoFile(d,a, "basebin"), "basebin", "testbin", dir.name()) - (result, message) = runner.runTestCase("testname", "infile.graph", "outfile.graph", "visibility") + (result, message) = runner.runTestCase("testname", self.makeCommand("infile.graph", "outfile.graph", "visibility")) self.assertFalse(result) self.assertEqual(message, "Baseline output {0} does not exist".format(os.path.join(dir.name(), "testname" + "_base", "outfile.graph"))) def testTestRunOutputMissing(self): with DisposableDirectory("testdir", True) as dir: runner = depthmaprunner.DepthmapRegressionRunner(lambda d, a: self.runfuncWriteNoFile(d,a, "testbin"), "basebin", "testbin", dir.name()) - (result, message) = runner.runTestCase("testname", "infile.graph", "outfile.graph", "visibility") + (result, message) = runner.runTestCase("testname", self.makeCommand("infile.graph", "outfile.graph", "visibility")) self.assertFalse(result) self.assertEqual(message, "Test output {0} does not exist".format(os.path.join(dir.name(), "testname" + "_test", "outfile.graph"))) def testBaseRunFail(self): with DisposableDirectory("testdir", True) as dir: runner = depthmaprunner.DepthmapRegressionRunner(lambda d, a: self.runfuncFail(d,a, "basebin", False), "basebin", "testbin", dir.name()) - (result, message) = runner.runTestCase("testname", "infile.graph", "outfile.graph", "visibility") + (result, message) = runner.runTestCase("testname", self.makeCommand("infile.graph", "outfile.graph", "visibility")) self.assertFalse(result) - self.assertEqual(message, "Baseline run failed") + self.assertEqual(message, "Baseline run failed at step: 0") def testTestRunFail(self): with DisposableDirectory("testdir", True) as dir: runner = depthmaprunner.DepthmapRegressionRunner(lambda d, a: self.runfuncFail(d,a, "testbin", True), "basebin", "testbin", dir.name()) - (result, message) = runner.runTestCase("testname", "infile.graph", "outfile.graph", "visibility") + (result, message) = runner.runTestCase("testname", self.makeCommand("infile.graph", "outfile.graph", "visibility")) self.assertFalse(result) - self.assertEqual(message, "Test run failed") + self.assertEqual(message, "Test run failed at step: 0") if __name__=="__main__": diff --git a/RegressionTest/test_disposablefile.py b/RegressionTest/test/test_disposablefile.py similarity index 100% rename from RegressionTest/test_disposablefile.py rename to RegressionTest/test/test_disposablefile.py diff --git a/RegressionTest/test_main.py b/RegressionTest/test/test_main.py similarity index 100% rename from RegressionTest/test_main.py rename to RegressionTest/test/test_main.py diff --git a/RegressionTest/test/test_performanceregressionconfig.py b/RegressionTest/test/test_performanceregressionconfig.py new file mode 100644 index 00000000..fa4d1268 --- /dev/null +++ b/RegressionTest/test/test_performanceregressionconfig.py @@ -0,0 +1,43 @@ +import unittest +from context import performanceregressionconfig +import disposablefile + + +class TestDisabledConfig(unittest.TestCase): + def test_missingConfig(self): + p = performanceregressionconfig.PerformanceRegressionConfig(None) + self.assertFalse(p.enabled) + + def test_disabledConfig(self): + p = performanceregressionconfig.PerformanceRegressionConfig({"enabled": "0"}) + self.assertFalse(p.enabled) + + p = performanceregressionconfig.PerformanceRegressionConfig({"enabled": "False"}) + self.assertFalse(p.enabled) + + p = performanceregressionconfig.PerformanceRegressionConfig({"enabled": "True"}) + self.assertTrue(p.enabled) + +class TestSuccessfulConfig(unittest.TestCase): + def test_defaultValues(self): + p = performanceregressionconfig.PerformanceRegressionConfig({}) + self.assertTrue(p.enabled) + self.assertEqual(p.runsPerInstance, 3) + self.assertEqual(p.relativeThresholdInPercent, 1) + self.assertEqual(p.absoluteThresholdInSeconds, 1) + + def test_overrideValues(self): + p = performanceregressionconfig.PerformanceRegressionConfig( + { "runsPerInstance": "5", + "relativeThresholdInPercent": 1.5, + "absoluteThresholdInSeconds": "4.1" + }) + self.assertTrue(p.enabled) + self.assertEqual(p.runsPerInstance, 5) + self.assertEqual(p.relativeThresholdInPercent, 1.5) + self.assertEqual(p.absoluteThresholdInSeconds, 4.1) + + + +if __name__ == "__main__": + unittest.main() diff --git a/RegressionTest/test/test_performancerunner.py b/RegressionTest/test/test_performancerunner.py new file mode 100644 index 00000000..b37495d7 --- /dev/null +++ b/RegressionTest/test/test_performancerunner.py @@ -0,0 +1,122 @@ +import csv + +import os +import unittest +from disposablefile import DisposableFile, DisposableDirectory +from context import performancerunner +from context import performanceregressionconfig + +import test_depthmaprunner + + +class PerformanceCheckTest(unittest.TestCase): + def test_filesMissing(self): + message = performancerunner.checkPerformance("f1.csv", "f2.csv", 1, 2) + self.assertEqual(message, "Base performance timing file f1.csv is missing") + + with DisposableFile("f1.csv") as f1: + with open(f1.filename(), "w") as f: + f.write("action,average\n") + message = performancerunner.checkPerformance("f1.csv", "f2.csv",1 ,2) + self.assertEqual(message, "Test performance timing file f2.csv is missing") + + with DisposableFile("f2.csv") as f2: + with open(f2.filename(), "w") as f: + f.write("action,average\n") + message = performancerunner.checkPerformance("f1.csv", "f2.csv", 1, 2) + self.assertEqual(message, "Base performance timing file f1.csv is missing") + + def test_fileLineNumberMismatch(self): + with DisposableFile("f1.csv") as f1, DisposableFile("f2.csv") as f2: + with open(f1.filename(), "w") as f: + f.write("action,average\nfoo,10\n") + with open(f2.filename(), "w") as f: + f.write("action,average\n") + message = performancerunner.checkPerformance("f1.csv", "f2.csv", 1, 2) + self.assertEqual(message, "baseline performance file f1.csv has more lines than the test one f2.csv") + + with DisposableFile("f1.csv") as f1, DisposableFile("f2.csv") as f2: + with open(f1.filename(), "w") as f: + f.write("action,average\nfoo,10\n") + with open(f2.filename(), "w") as f: + f.write("action,average\nfoo,10\nbar,20\n") + message = performancerunner.checkPerformance("f1.csv", "f2.csv", 1 , 2) + self.assertEqual(message, "baseline performance file f1.csv has fewer lines than the test one f2.csv") + + def test_fileLabelMismatch(self): + with DisposableFile("f1.csv") as f1, DisposableFile("f2.csv") as f2: + with open(f1.filename(), "w") as f: + f.write("action,average\nfoo,10\n") + with open(f2.filename(), "w") as f: + f.write("action,average\nbar,10\n") + message = performancerunner.checkPerformance("f1.csv", "f2.csv", 1, 2) + self.assertEqual(message, "performance line mismatch: base 'foo', test 'bar'") + + def test_successfulRunEmptyFile(self): + with DisposableFile("f1.csv") as f1, DisposableFile("f2.csv") as f2: + with open(f1.filename(), "w") as f: + f.write("action,average\n") + with open(f2.filename(), "w") as f: + f.write("action,average\n") + message = performancerunner.checkPerformance("f1.csv", "f2.csv", 1, 2) + self.assertEqual(message, "") + + def test_successfulRun(self): + with DisposableFile("f1.csv") as f1, DisposableFile("f2.csv") as f2: + with open(f1.filename(), "w") as f: + f.write("action,average\nfoo,10\nbar,21\nbaz,1000\nblub,10\n") + with open(f2.filename(), "w") as f: + f.write("action,average\nfoo,10.9\nbar,10\nbaz,1010\nblub,10\n") + message = performancerunner.checkPerformance("f1.csv", "f2.csv", 1, 2) + self.assertEqual(message, "") + + def test_performanceRegression(self): + with DisposableFile("f1.csv") as f1, DisposableFile("f2.csv") as f2: + with open(f1.filename(), "w") as f: + f.write("action,average\nfoo,10\n") + with open(f2.filename(), "w") as f: + f.write("action,average\nfoo,18\n") + message = performancerunner.checkPerformance("f1.csv", "f2.csv", 1, 2) + self.assertEqual(message, "Performance regression: foo took 18s instead of 10s") + +class test_PerformanceAggregation(unittest.TestCase): + def test_aggregation(self): + with DisposableDirectory("testdir") as d: + os.makedirs(d.name()) + nameTemplate = "test{0}{1}.csv" + with open(os.path.join(d.name(), nameTemplate.format(0,0)), "w") as f: + f.write("action,duration\nt1,3\nt2,2\n") + with open(os.path.join(d.name(), nameTemplate.format(1,0)), "w") as f: + f.write("action,duration\nt1,1.5\nt2,2.5\n") + with open(os.path.join(d.name(), nameTemplate.format(2,0)), "w") as f: + f.write("action,duration\nt1,2\nt2,1.5\n") + + resFile = performancerunner.aggregatePerformanceStats(d.name(), 3, 1, nameTemplate) + with open(resFile, "r") as f: + reader = csv.DictReader(f) + line = next(reader) + self.assertEqual(line["action"], "t1") + self.assertEqual(float(line["max"]), 3 ) + self.assertEqual(float(line["min"]), 1.5) + self.assertEqual(float(line["average"]), 6.5/3) + + line = next(reader) + self.assertEqual(line["action"], "t2") + self.assertEqual(float(line["max"]), 2.5 ) + self.assertEqual(float(line["min"]), 1.5) + self.assertEqual(float(line["average"]), 2) + + line = next(reader) + self.assertEqual(line["action"], "total") + self.assertEqual(float(line["max"]), 5 ) + self.assertEqual(float(line["min"]), 3.5) + self.assertEqual(float(line["average"]), 12.5/3) + +class test_PerformanceRunner(test_depthmaprunner.DepthmapRegressioRunnerTest): + def testSuccessfullRun(self): + with DisposableDirectory("testdir", True) as testDir, DisposableDirectory("basedir") as baseDir: + conf = performanceregressionconfig.PerformanceRegressionConfig({}) + runner = performancerunner.PerformanceRunner(lambda d, a: self.runfuncSucceedAlwaysSame(d,a), "basebin", "testbin", testDir.name(), conf) + (result, message) = runner.runTestCase("testname", self.makeCommand("infile.graph", "outfile.graph","visibility")) + self.assertTrue(result) + diff --git a/RegressionTest/test_runhelpers.py b/RegressionTest/test/test_runhelpers.py similarity index 95% rename from RegressionTest/test_runhelpers.py rename to RegressionTest/test/test_runhelpers.py index c3da70f4..1d116ce7 100644 --- a/RegressionTest/test_runhelpers.py +++ b/RegressionTest/test/test_runhelpers.py @@ -1,5 +1,5 @@ import unittest -import runhelpers +from context import runhelpers from disposablefile import DisposableDirectory import os import platform @@ -49,12 +49,14 @@ def test_runExecutable(self): def test_runExecutableFail(self): with DisposableDirectory("testdir") as d: + runhelpers.prepareDirectory(d.name()) retcode, output = runhelpers.runExecutable( d.name(), [sys.executable, "-c", "exit(-1)"]) self.assertFalse(retcode) self.assertEqual(output, "") def test_runExecutableException(self): with DisposableDirectory("testdir") as d: + runhelpers.prepareDirectory(d.name()) retcode, output = runhelpers.runExecutable( d.name(), [sys.executable, "-c", "raise Exception()"]) self.assertFalse(retcode) self.assertEqual(output, 'Traceback (most recent call last):\n File "", line 1, in \nException\n') diff --git a/RegressionTest/test_test_main.py b/RegressionTest/test/test_test_main.py similarity index 96% rename from RegressionTest/test_test_main.py rename to RegressionTest/test/test_test_main.py index b931a373..628d42a1 100644 --- a/RegressionTest/test_test_main.py +++ b/RegressionTest/test/test_test_main.py @@ -1,6 +1,6 @@ import unittest from disposablefile import DisposableDirectory -import runhelpers +from context import runhelpers import sys class TestUnitTestMain(unittest.TestCase): diff --git a/RegressionTest/test_config.py b/RegressionTest/test_config.py deleted file mode 100644 index b6a757ca..00000000 --- a/RegressionTest/test_config.py +++ /dev/null @@ -1,64 +0,0 @@ -import unittest -import config -from disposablefile import DisposableFile -import RegressionTestRunner - -def writeConfig(filename, rundir): - with open(filename, "w") as f: - f.write('{ "rundir": "'+ rundir +'",\n') - f.write(' "basebinlocation": "../baselineBinaries",\n') - f.write(' "testbinlocation": "../..",\n') - f.write(' "testcases": {\n') - f.write(' "test1": {\n') - f.write(' "infile": "infile.graph",\n') - f.write(' "outfile": "outfile.graph",\n') - f.write(' "mode": "VGA",\n') - f.write(' "subcmds": {\n') - f.write(' "Visibility": {\n') - f.write(' "visibilityMode": "metric",\n') - f.write(' "radius": "7"}}}}}') - - - -class TestMethods(unittest.TestCase): - def test_buildCmd(self): - data = { "infile": "foo.graph", "outfile": "bar.graph", "mode": "VGA", "subcmds": { "Visibility" : {"visibilityMode": "visibility", "globalMeasures": "1", "radius": "5"}}} - cmd = config.buildCmd( data ) - self.assertEqual(cmd.infile, "foo.graph") - self.assertEqual(cmd.outfile, "bar.graph") - self.assertEqual(cmd.mode, "VGA") - self.assertEqual(len(cmd.modeLines), 1) - - - def test_buildSubCmd(self): - data = { "visibilityMode": "visibility", "globalMeasures": "1", "radius": "5"} - cmd = config.buildSubCmd("Visibility", data) - self.assertEqual(cmd.visibilityMode, "visibility") - self.assertTrue(cmd.globalMeasures) - self.assertFalse(cmd.localMeasures) - self.assertEqual(cmd.radius, "5") - - - def test_buildSubCmdInvalid(self): - data = { "visibilityMode": "visibility", "globalMeasures": "1", "radius": "5"} - with self.assertRaises(config.ConfigError) as cm: - config.buildSubCmd("foobar", data) - self.assertEqual(cm.exception.message, "Unknown sub commandline config foobar") - - def test_configClass(self): - with DisposableFile("test.config") as testfile: - writeConfig(testfile.filename(), "../foo/bar") - conf = config.RegressionConfig(testfile.filename()) - self.assertEqual(len(conf.testcases), 1) - self.assertEqual(conf.rundir, "../foo/bar") - self.assertTrue("test1" in conf.testcases) - - -class TestRealConfig(unittest.TestCase): - def test_realConfig(self): - configFile = RegressionTestRunner.defaultConfigFile - self.assertNotEqual( configFile, "" ) - conf = config.RegressionConfig(configFile) - -if __name__ == "__main__": - unittest.main() diff --git a/ThirdParty/FakeIt/Catch/fakeit.hpp b/ThirdParty/FakeIt/Catch/fakeit.hpp new file mode 100644 index 00000000..81ad3c14 --- /dev/null +++ b/ThirdParty/FakeIt/Catch/fakeit.hpp @@ -0,0 +1,9300 @@ +#pragma once +/* + * FakeIt - A Simplified C++ Mocking Framework + * Copyright (c) Eran Pe'er 2013 + * Generated: 2017-05-07 09:27:02.651812 + * Distributed under the MIT License. Please refer to the LICENSE file at: + * https://github.com/eranpeer/FakeIt + */ + +#ifndef fakeit_h__ +#define fakeit_h__ + + + +#include +#include +#include +#include +#include +#if defined (__GNUG__) || _MSC_VER >= 1900 +#define THROWS noexcept(false) +#define NO_THROWS noexcept(true) +#elif defined (_MSC_VER) +#define THROWS throw(...) +#define NO_THROWS +#endif +#include +#include +#include +#include +#include +#include +#include + + +namespace fakeit { + + template + struct naked_type { + typedef typename std::remove_cv::type>::type type; + }; + + template< class T > struct tuple_arg { typedef T type; }; + template< class T > struct tuple_arg < T& > { typedef T& type; }; + template< class T > struct tuple_arg < T&& > { typedef T&& type; }; + + + + + template + using ArgumentsTuple = std::tuple < arglist... > ; + + template< class T > struct test_arg { typedef T& type; }; + template< class T > struct test_arg< T& > { typedef T& type; }; + template< class T > struct test_arg< T&& > { typedef T& type; }; + + template< class T > struct production_arg { typedef T& type; }; + template< class T > struct production_arg< T& > { typedef T& type; }; + template< class T > struct production_arg< T&& > { typedef T&& type; }; + + template + class is_ostreamable { + struct no {}; +#if defined(_MSC_VER) && _MSC_VER < 1900 + template + static decltype(operator<<(std::declval(), std::declval())) test(std::ostream &s, const T1 &t); +#else + template + static auto test(std::ostream &s, const T1 &t) -> decltype(s << t); +#endif + static no test(...); + public: + + static const bool value = + std::is_arithmetic::value || + std::is_pointer::value || + std::is_same())), std::ostream &>::value; + }; + + + template <> + class is_ostreamable { + public: + static const bool value = true; + }; + + template + class is_ostreamable& (*)(std::basic_ios&)> { + public: + static const bool value = true; + }; + + template + class is_ostreamable& (*)(std::basic_ostream&)> { + public: + static const bool value = true; + }; + + template + struct VTableMethodType { +#if defined (__GNUG__) + typedef R(*type)(void *, arglist...); +#elif defined (_MSC_VER) + typedef R(__thiscall *type)(void *, arglist...); +#endif + }; +} +#include +#include +#include +#include +#include +#include + +namespace fakeit { + + struct FakeitContext; + + template + struct MockObject { + virtual ~MockObject() THROWS { }; + + virtual C &get() = 0; + + virtual FakeitContext &getFakeIt() = 0; + }; + + struct MethodInfo { + + static unsigned int nextMethodOrdinal() { + static std::atomic_uint ordinal{0}; + return ++ordinal; + } + + MethodInfo(unsigned int anId, std::string aName) : + _id(anId), _name(aName) { } + + unsigned int id() const { + return _id; + } + + std::string name() const { + return _name; + } + + void setName(const std::string &value) { + _name = value; + } + + private: + unsigned int _id; + std::string _name; + }; + + struct UnknownMethod { + + static MethodInfo &instance() { + static MethodInfo instance(MethodInfo::nextMethodOrdinal(), "unknown"); + return instance; + } + + }; + +} +namespace fakeit { + class Destructible { + public: + virtual ~Destructible() {} + }; +} + +namespace fakeit { + + struct Invocation : Destructible { + + static unsigned int nextInvocationOrdinal() { + static std::atomic_uint invocationOrdinal{0}; + return ++invocationOrdinal; + } + + struct Matcher { + + virtual ~Matcher() THROWS { + } + + virtual bool matches(Invocation &invocation) = 0; + + virtual std::string format() const = 0; + }; + + Invocation(unsigned int ordinal, MethodInfo &method) : + _ordinal(ordinal), _method(method), _isVerified(false) { + } + + virtual ~Invocation() override = default; + + unsigned int getOrdinal() const { + return _ordinal; + } + + MethodInfo &getMethod() const { + return _method; + } + + void markAsVerified() { + _isVerified = true; + } + + bool isVerified() const { + return _isVerified; + } + + virtual std::string format() const = 0; + + private: + const unsigned int _ordinal; + MethodInfo &_method; + bool _isVerified; + }; + +} +#include +#include +#include +#include +#include + +namespace fakeit { + + template + struct Formatter; + + template <> + struct Formatter + { + static std::string format(bool const &val) + { + return val ? "true" : "false"; + } + }; + + template <> + struct Formatter + { + static std::string format(char const &val) + { + std::string s; + s += "'"; + s += val; + s += "'"; + return s; + } + }; + + template + struct Formatter::value>::type> { + static std::string format(C const &) + { + return "?"; + } + }; + + template + struct Formatter::value>::type> { + static std::string format(C const &val) + { + std::ostringstream os; + os << val; + return os.str(); + } + }; + + + template + using TypeFormatter = Formatter::type>; +} + +namespace fakeit { + + + template + struct TuplePrinter { + static void print(std::ostream &strm, const Tuple &t) { + TuplePrinter::print(strm, t); + strm << ", " << fakeit::TypeFormatter(t))>::format(std::get(t)); + } + }; + + template + struct TuplePrinter { + static void print(std::ostream &strm, const Tuple &t) { + strm << fakeit::TypeFormatter(t))>::format(std::get<0>(t)); + } + }; + + template + struct TuplePrinter { + static void print(std::ostream &, const Tuple &) { + } + }; + + template + void print(std::ostream &strm, const std::tuple &t) { + strm << "("; + TuplePrinter::print(strm, t); + strm << ")"; + } + + template + std::ostream &operator<<(std::ostream &strm, const std::tuple &t) { + print(strm, t); + return strm; + } + +} + + +namespace fakeit { + + template + struct ActualInvocation : public Invocation { + + struct Matcher : public virtual Destructible { + virtual bool matches(ActualInvocation &actualInvocation) = 0; + + virtual std::string format() const = 0; + }; + + ActualInvocation(unsigned int ordinal, MethodInfo &method, const typename fakeit::production_arg::type... args) : + Invocation(ordinal, method), _matcher{ nullptr } + , actualArguments{ std::forward(args)... } + { + } + + ArgumentsTuple & getActualArguments() { + return actualArguments; + } + + + void setActualMatcher(Matcher *matcher) { + this->_matcher = matcher; + } + + Matcher *getActualMatcher() { + return _matcher; + } + + virtual std::string format() const override { + std::ostringstream out; + out << getMethod().name(); + print(out, actualArguments); + return out.str(); + } + + private: + + Matcher *_matcher; + ArgumentsTuple actualArguments; + }; + + template + std::ostream &operator<<(std::ostream &strm, const ActualInvocation &ai) { + strm << ai.format(); + return strm; + } + +} + + + + + +#include + +namespace fakeit { + + struct ActualInvocationsContainer { + virtual void clear() = 0; + + virtual ~ActualInvocationsContainer() NO_THROWS { } + }; + + struct ActualInvocationsSource { + virtual void getActualInvocations(std::unordered_set &into) const = 0; + + virtual ~ActualInvocationsSource() NO_THROWS { } + }; + + struct InvocationsSourceProxy : public ActualInvocationsSource { + + InvocationsSourceProxy(ActualInvocationsSource *inner) : + _inner(inner) { + } + + void getActualInvocations(std::unordered_set &into) const override { + _inner->getActualInvocations(into); + } + + private: + std::shared_ptr _inner; + }; + + struct UnverifiedInvocationsSource : public ActualInvocationsSource { + + UnverifiedInvocationsSource(InvocationsSourceProxy decorated) : _decorated(decorated) { + } + + void getActualInvocations(std::unordered_set &into) const override { + std::unordered_set all; + _decorated.getActualInvocations(all); + for (fakeit::Invocation *i : all) { + if (!i->isVerified()) { + into.insert(i); + } + } + } + + private: + InvocationsSourceProxy _decorated; + }; + + struct AggregateInvocationsSource : public ActualInvocationsSource { + + AggregateInvocationsSource(std::vector &sources) : _sources(sources) { + } + + void getActualInvocations(std::unordered_set &into) const override { + std::unordered_set tmp; + for (ActualInvocationsSource *source : _sources) { + source->getActualInvocations(tmp); + } + filter(tmp, into); + } + + protected: + bool shouldInclude(fakeit::Invocation *) const { + return true; + } + + private: + std::vector _sources; + + void filter(std::unordered_set &source, std::unordered_set &target) const { + for (Invocation *i:source) { + if (shouldInclude(i)) { + target.insert(i); + } + } + } + }; +} + +namespace fakeit { + + class Sequence { + private: + + protected: + + Sequence() { + } + + virtual ~Sequence() THROWS { + } + + public: + + + virtual void getExpectedSequence(std::vector &into) const = 0; + + + virtual void getInvolvedMocks(std::vector &into) const = 0; + + virtual unsigned int size() const = 0; + + friend class VerifyFunctor; + }; + + class ConcatenatedSequence : public virtual Sequence { + private: + const Sequence &s1; + const Sequence &s2; + + protected: + ConcatenatedSequence(const Sequence &seq1, const Sequence &seq2) : + s1(seq1), s2(seq2) { + } + + public: + + virtual ~ConcatenatedSequence() { + } + + unsigned int size() const override { + return s1.size() + s2.size(); + } + + const Sequence &getLeft() const { + return s1; + } + + const Sequence &getRight() const { + return s2; + } + + void getExpectedSequence(std::vector &into) const override { + s1.getExpectedSequence(into); + s2.getExpectedSequence(into); + } + + virtual void getInvolvedMocks(std::vector &into) const override { + s1.getInvolvedMocks(into); + s2.getInvolvedMocks(into); + } + + friend inline ConcatenatedSequence operator+(const Sequence &s1, const Sequence &s2); + }; + + class RepeatedSequence : public virtual Sequence { + private: + const Sequence &_s; + const int times; + + protected: + RepeatedSequence(const Sequence &s, const int t) : + _s(s), times(t) { + } + + public: + + ~RepeatedSequence() { + } + + unsigned int size() const override { + return _s.size() * times; + } + + friend inline RepeatedSequence operator*(const Sequence &s, int times); + + friend inline RepeatedSequence operator*(int times, const Sequence &s); + + void getInvolvedMocks(std::vector &into) const override { + _s.getInvolvedMocks(into); + } + + void getExpectedSequence(std::vector &into) const override { + for (int i = 0; i < times; i++) + _s.getExpectedSequence(into); + } + + int getTimes() const { + return times; + } + + const Sequence &getSequence() const { + return _s; + } + }; + + inline ConcatenatedSequence operator+(const Sequence &s1, const Sequence &s2) { + return ConcatenatedSequence(s1, s2); + } + + inline RepeatedSequence operator*(const Sequence &s, int times) { + if (times <= 0) + throw std::invalid_argument("times"); + return RepeatedSequence(s, times); + } + + inline RepeatedSequence operator*(int times, const Sequence &s) { + if (times <= 0) + throw std::invalid_argument("times"); + return RepeatedSequence(s, times); + } + +} + +namespace fakeit { + + enum class VerificationType { + Exact, AtLeast, NoMoreInvocations + }; + + enum class UnexpectedType { + Unmocked, Unmatched + }; + + struct VerificationEvent { + + VerificationEvent(VerificationType aVerificationType) : + _verificationType(aVerificationType), _line(0) { + } + + virtual ~VerificationEvent() = default; + + VerificationType verificationType() const { + return _verificationType; + } + + void setFileInfo(const char * aFile, int aLine, const char * aCallingMethod) { + _file = aFile; + _callingMethod = aCallingMethod; + _line = aLine; + } + + const char * file() const { + return _file; + } + + int line() const { + return _line; + } + + const char * callingMethod() const { + return _callingMethod; + } + + private: + VerificationType _verificationType; + const char * _file; + int _line; + const char * _callingMethod; + }; + + struct NoMoreInvocationsVerificationEvent : public VerificationEvent { + + ~NoMoreInvocationsVerificationEvent() = default; + + NoMoreInvocationsVerificationEvent( + std::vector &allTheIvocations, + std::vector &anUnverifedIvocations) : + VerificationEvent(VerificationType::NoMoreInvocations), + _allIvocations(allTheIvocations), + _unverifedIvocations(anUnverifedIvocations) { + } + + const std::vector &allIvocations() const { + return _allIvocations; + } + + const std::vector &unverifedIvocations() const { + return _unverifedIvocations; + } + + private: + const std::vector _allIvocations; + const std::vector _unverifedIvocations; + }; + + struct SequenceVerificationEvent : public VerificationEvent { + + ~SequenceVerificationEvent() = default; + + SequenceVerificationEvent(VerificationType aVerificationType, + std::vector &anExpectedPattern, + std::vector &anActualSequence, + int anExpectedCount, + int anActualCount) : + VerificationEvent(aVerificationType), + _expectedPattern(anExpectedPattern), + _actualSequence(anActualSequence), + _expectedCount(anExpectedCount), + _actualCount(anActualCount) + { + } + + const std::vector &expectedPattern() const { + return _expectedPattern; + } + + const std::vector &actualSequence() const { + return _actualSequence; + } + + int expectedCount() const { + return _expectedCount; + } + + int actualCount() const { + return _actualCount; + } + + private: + const std::vector _expectedPattern; + const std::vector _actualSequence; + const int _expectedCount; + const int _actualCount; + }; + + struct UnexpectedMethodCallEvent { + UnexpectedMethodCallEvent(UnexpectedType unexpectedType, const Invocation &invocation) : + _unexpectedType(unexpectedType), _invocation(invocation) { + } + + const Invocation &getInvocation() const { + return _invocation; + } + + UnexpectedType getUnexpectedType() const { + return _unexpectedType; + } + + const UnexpectedType _unexpectedType; + const Invocation &_invocation; + }; + +} + +namespace fakeit { + + struct VerificationEventHandler { + virtual void handle(const SequenceVerificationEvent &e) = 0; + + virtual void handle(const NoMoreInvocationsVerificationEvent &e) = 0; + }; + + struct EventHandler : public VerificationEventHandler { + using VerificationEventHandler::handle; + + virtual void handle(const UnexpectedMethodCallEvent &e) = 0; + }; + +} +#include +#include + +namespace fakeit { + + struct UnexpectedMethodCallEvent; + struct SequenceVerificationEvent; + struct NoMoreInvocationsVerificationEvent; + + struct EventFormatter { + + virtual std::string format(const fakeit::UnexpectedMethodCallEvent &e) = 0; + + virtual std::string format(const fakeit::SequenceVerificationEvent &e) = 0; + + virtual std::string format(const fakeit::NoMoreInvocationsVerificationEvent &e) = 0; + + }; + +} + +namespace fakeit { + + struct FakeitContext : public EventHandler, protected EventFormatter { + + virtual ~FakeitContext() = default; + + void handle(const UnexpectedMethodCallEvent &e) override { + fireEvent(e); + auto &eh = getTestingFrameworkAdapter(); + eh.handle(e); + } + + void handle(const SequenceVerificationEvent &e) override { + fireEvent(e); + auto &eh = getTestingFrameworkAdapter(); + return eh.handle(e); + } + + void handle(const NoMoreInvocationsVerificationEvent &e) override { + fireEvent(e); + auto &eh = getTestingFrameworkAdapter(); + return eh.handle(e); + } + + std::string format(const UnexpectedMethodCallEvent &e) override { + auto &eventFormatter = getEventFormatter(); + return eventFormatter.format(e); + } + + std::string format(const SequenceVerificationEvent &e) override { + auto &eventFormatter = getEventFormatter(); + return eventFormatter.format(e); + } + + std::string format(const NoMoreInvocationsVerificationEvent &e) override { + auto &eventFormatter = getEventFormatter(); + return eventFormatter.format(e); + } + + void addEventHandler(EventHandler &eventListener) { + _eventListeners.push_back(&eventListener); + } + + void clearEventHandlers() { + _eventListeners.clear(); + } + + protected: + virtual EventHandler &getTestingFrameworkAdapter() = 0; + + virtual EventFormatter &getEventFormatter() = 0; + + private: + std::vector _eventListeners; + + void fireEvent(const NoMoreInvocationsVerificationEvent &evt) { + for (auto listener : _eventListeners) + listener->handle(evt); + } + + void fireEvent(const UnexpectedMethodCallEvent &evt) { + for (auto listener : _eventListeners) + listener->handle(evt); + } + + void fireEvent(const SequenceVerificationEvent &evt) { + for (auto listener : _eventListeners) + listener->handle(evt); + } + + }; + +} +#include +#include + +namespace fakeit { + + struct DefaultEventFormatter : public EventFormatter { + + virtual std::string format(const UnexpectedMethodCallEvent &e) override { + std::ostringstream out; + out << "Unexpected method invocation: "; + out << e.getInvocation().format() << std::endl; + if (UnexpectedType::Unmatched == e.getUnexpectedType()) { + out << " Could not find Any recorded behavior to support this method call."; + } else { + out << " An unmocked method was invoked. All used virtual methods must be stubbed!"; + } + return out.str(); + } + + + virtual std::string format(const SequenceVerificationEvent &e) override { + std::ostringstream out; + out << "Verification error" << std::endl; + + out << "Expected pattern: "; + const std::vector expectedPattern = e.expectedPattern(); + out << formatExpectedPattern(expectedPattern) << std::endl; + + out << "Expected matches: "; + formatExpectedCount(out, e.verificationType(), e.expectedCount()); + out << std::endl; + + out << "Actual matches : " << e.actualCount() << std::endl; + + auto actualSequence = e.actualSequence(); + out << "Actual sequence : total of " << actualSequence.size() << " actual invocations"; + if (actualSequence.size() == 0) { + out << "."; + } else { + out << ":" << std::endl; + } + formatInvocationList(out, actualSequence); + + return out.str(); + } + + virtual std::string format(const NoMoreInvocationsVerificationEvent &e) override { + std::ostringstream out; + out << "Verification error" << std::endl; + out << "Expected no more invocations!! But the following unverified invocations were found:" << std::endl; + formatInvocationList(out, e.unverifedIvocations()); + return out.str(); + } + + private: + + static std::string formatSequence(const Sequence &val) { + const ConcatenatedSequence *cs = dynamic_cast(&val); + if (cs) { + return format(*cs); + } + const RepeatedSequence *rs = dynamic_cast(&val); + if (rs) { + return format(*rs); + } + + + std::vector vec; + val.getExpectedSequence(vec); + return vec[0]->format(); + } + + static void formatExpectedCount(std::ostream &out, fakeit::VerificationType verificationType, + int expectedCount) { + if (verificationType == fakeit::VerificationType::Exact) + out << "exactly "; + + if (verificationType == fakeit::VerificationType::AtLeast) + out << "at least "; + + out << expectedCount; + } + + static void formatInvocationList(std::ostream &out, const std::vector &actualSequence) { + size_t max_size = actualSequence.size(); + if (max_size > 5) + max_size = 5; + + for (unsigned int i = 0; i < max_size; i++) { + out << " "; + auto invocation = actualSequence[i]; + out << invocation->format(); + if (i < max_size - 1) + out << std::endl; + } + + if (actualSequence.size() > max_size) + out << std::endl << " ..."; + } + + static std::string format(const ConcatenatedSequence &val) { + std::ostringstream out; + out << formatSequence(val.getLeft()) << " + " << formatSequence(val.getRight()); + return out.str(); + } + + static std::string format(const RepeatedSequence &val) { + std::ostringstream out; + const ConcatenatedSequence *cs = dynamic_cast(&val.getSequence()); + const RepeatedSequence *rs = dynamic_cast(&val.getSequence()); + if (rs || cs) + out << '('; + out << formatSequence(val.getSequence()); + if (rs || cs) + out << ')'; + + out << " * " << val.getTimes(); + return out.str(); + } + + static std::string formatExpectedPattern(const std::vector &expectedPattern) { + std::string expectedPatternStr; + for (unsigned int i = 0; i < expectedPattern.size(); i++) { + Sequence *s = expectedPattern[i]; + expectedPatternStr += formatSequence(*s); + if (i < expectedPattern.size() - 1) + expectedPatternStr += " ... "; + } + return expectedPatternStr; + } + }; +} +namespace fakeit { + + struct FakeitException { + std::exception err; + + virtual ~FakeitException() = default; + + virtual std::string what() const = 0; + + friend std::ostream &operator<<(std::ostream &os, const FakeitException &val) { + os << val.what(); + return os; + } + }; + + + + + struct UnexpectedMethodCallException : public FakeitException { + + UnexpectedMethodCallException(std::string format) : + _format(format) { + } + + virtual std::string what() const override { + return _format; + } + + private: + std::string _format; + }; + +} + +namespace fakeit { + + struct DefaultEventLogger : public fakeit::EventHandler { + + DefaultEventLogger(EventFormatter &formatter) : _formatter(formatter), _out(std::cout) { } + + virtual void handle(const UnexpectedMethodCallEvent &e) override { + _out << _formatter.format(e) << std::endl; + } + + virtual void handle(const SequenceVerificationEvent &e) override { + _out << _formatter.format(e) << std::endl; + } + + virtual void handle(const NoMoreInvocationsVerificationEvent &e) override { + _out << _formatter.format(e) << std::endl; + } + + private: + EventFormatter &_formatter; + std::ostream &_out; + }; + +} + +namespace fakeit { + + class AbstractFakeit : public FakeitContext { + public: + virtual ~AbstractFakeit() = default; + + protected: + + virtual fakeit::EventHandler &accessTestingFrameworkAdapter() = 0; + + virtual EventFormatter &accessEventFormatter() = 0; + }; + + class DefaultFakeit : public AbstractFakeit { + DefaultEventFormatter _formatter; + fakeit::EventFormatter *_customFormatter; + fakeit::EventHandler *_testingFrameworkAdapter; + + public: + + DefaultFakeit() : _formatter(), + _customFormatter(nullptr), + _testingFrameworkAdapter(nullptr) { + } + + virtual ~DefaultFakeit() = default; + + void setCustomEventFormatter(fakeit::EventFormatter &customEventFormatter) { + _customFormatter = &customEventFormatter; + } + + void resetCustomEventFormatter() { + _customFormatter = nullptr; + } + + void setTestingFrameworkAdapter(fakeit::EventHandler &testingFrameforkAdapter) { + _testingFrameworkAdapter = &testingFrameforkAdapter; + } + + void resetTestingFrameworkAdapter() { + _testingFrameworkAdapter = nullptr; + } + + protected: + + fakeit::EventHandler &getTestingFrameworkAdapter() override { + if (_testingFrameworkAdapter) + return *_testingFrameworkAdapter; + return accessTestingFrameworkAdapter(); + } + + EventFormatter &getEventFormatter() override { + if (_customFormatter) + return *_customFormatter; + return accessEventFormatter(); + } + + EventFormatter &accessEventFormatter() override { + return _formatter; + } + + }; +} + +namespace fakeit { + + struct VerificationException : public FakeitException { + virtual ~VerificationException() = default; + + void setFileInfo(const char *file, int line, const char *callingMethod) { + _file = file; + _callingMethod = callingMethod; + _line = line; + } + + const char *file() const { + return _file; + } + + int line() const { + return _line; + } + + const char *callingMethod() const { + return _callingMethod; + } + + private: + const char *_file; + int _line; + const char *_callingMethod; + }; + + struct NoMoreInvocationsVerificationException : public VerificationException { + + NoMoreInvocationsVerificationException(std::string format) : + _format(format) { + } + + virtual std::string what() const override { + return _format; + } + + private: + std::string _format; + }; + + struct SequenceVerificationException : public VerificationException { + SequenceVerificationException(const std::string &format) : + _format(format) + { + } + + virtual std::string what() const override { + return _format; + } + + private: + std::string _format; + }; + + class CatchAdapter : public EventHandler { + EventFormatter &_formatter; + + std::string formatLineNumber(std::string file, int num) { +#ifndef __GNUG__ + return file + std::string("(") + std::to_string(num) + std::string(")"); +#else + return file + std::string(":") + std::to_string(num); +#endif + } + + public: + + virtual ~CatchAdapter() = default; + + CatchAdapter(EventFormatter &formatter) + : _formatter(formatter) {} + + virtual void handle(const UnexpectedMethodCallEvent &evt) override { + std::string format = _formatter.format(evt); + Catch::ResultBuilder __catchResult("FAIL", ::Catch::SourceLineInfo(), + "", Catch::ResultDisposition::Normal); + __catchResult << format + ::Catch::StreamEndStop(); + __catchResult.captureResult(Catch::ResultWas::ExplicitFailure); + INTERNAL_CATCH_REACT(__catchResult) + throw Catch::TestFailureException(); + } + + virtual void handle(const SequenceVerificationEvent &evt) override { + std::string format(formatLineNumber(evt.file(), evt.line()) + ": " + _formatter.format(evt)); + Catch::ResultBuilder __catchResult("FAIL", ::Catch::SourceLineInfo(evt.file(), + static_cast( evt.line())), + "", Catch::ResultDisposition::Normal); + __catchResult << format + ::Catch::StreamEndStop(); + __catchResult.captureResult(Catch::ResultWas::ExplicitFailure); + INTERNAL_CATCH_REACT(__catchResult) + throw Catch::TestFailureException(); + } + + virtual void handle(const NoMoreInvocationsVerificationEvent &evt) override { + std::string format(formatLineNumber(evt.file(), evt.line()) + ": " + _formatter.format(evt)); + Catch::ResultBuilder __catchResult("FAIL", ::Catch::SourceLineInfo(evt.file(), + static_cast( evt.line())), + "", Catch::ResultDisposition::Normal); + __catchResult << format + ::Catch::StreamEndStop(); + __catchResult.captureResult(Catch::ResultWas::ExplicitFailure); + INTERNAL_CATCH_REACT(__catchResult) + throw Catch::TestFailureException(); + } + + }; + + + class CatchFakeit : public DefaultFakeit { + + + public: + + virtual ~CatchFakeit() = default; + + CatchFakeit() : _formatter(), _catchAdapter(_formatter) {} + + static CatchFakeit &getInstance() { + static CatchFakeit instance; + return instance; + } + + protected: + + fakeit::EventHandler &accessTestingFrameworkAdapter() override { + return _catchAdapter; + } + + EventFormatter &accessEventFormatter() override { + return _formatter; + } + + private: + + DefaultEventFormatter _formatter; + CatchAdapter _catchAdapter; + }; + +} + +static fakeit::DefaultFakeit& Fakeit = fakeit::CatchFakeit::getInstance(); + + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +namespace fakeit { + + struct VirtualOffsetSelector { + + unsigned int offset; + + virtual unsigned int offset0(int) { + return offset = 0; + } + + virtual unsigned int offset1(int) { + return offset = 1; + } + + virtual unsigned int offset2(int) { + return offset = 2; + } + + virtual unsigned int offset3(int) { + return offset = 3; + } + + virtual unsigned int offset4(int) { + return offset = 4; + } + + virtual unsigned int offset5(int) { + return offset = 5; + } + + virtual unsigned int offset6(int) { + return offset = 6; + } + + virtual unsigned int offset7(int) { + return offset = 7; + } + + virtual unsigned int offset8(int) { + return offset = 8; + } + + virtual unsigned int offset9(int) { + return offset = 9; + } + + virtual unsigned int offset10(int) { + return offset = 10; + } + + virtual unsigned int offset11(int) { + return offset = 11; + } + + virtual unsigned int offset12(int) { + return offset = 12; + } + + virtual unsigned int offset13(int) { + return offset = 13; + } + + virtual unsigned int offset14(int) { + return offset = 14; + } + + virtual unsigned int offset15(int) { + return offset = 15; + } + + virtual unsigned int offset16(int) { + return offset = 16; + } + + virtual unsigned int offset17(int) { + return offset = 17; + } + + virtual unsigned int offset18(int) { + return offset = 18; + } + + virtual unsigned int offset19(int) { + return offset = 19; + } + + virtual unsigned int offset20(int) { + return offset = 20; + } + + virtual unsigned int offset21(int) { + return offset = 21; + } + + virtual unsigned int offset22(int) { + return offset = 22; + } + + virtual unsigned int offset23(int) { + return offset = 23; + } + + virtual unsigned int offset24(int) { + return offset = 24; + } + + virtual unsigned int offset25(int) { + return offset = 25; + } + + virtual unsigned int offset26(int) { + return offset = 26; + } + + virtual unsigned int offset27(int) { + return offset = 27; + } + + virtual unsigned int offset28(int) { + return offset = 28; + } + + virtual unsigned int offset29(int) { + return offset = 29; + } + + virtual unsigned int offset30(int) { + return offset = 30; + } + + virtual unsigned int offset31(int) { + return offset = 31; + } + + virtual unsigned int offset32(int) { + return offset = 32; + } + + virtual unsigned int offset33(int) { + return offset = 33; + } + + virtual unsigned int offset34(int) { + return offset = 34; + } + + virtual unsigned int offset35(int) { + return offset = 35; + } + + virtual unsigned int offset36(int) { + return offset = 36; + } + + virtual unsigned int offset37(int) { + return offset = 37; + } + + virtual unsigned int offset38(int) { + return offset = 38; + } + + virtual unsigned int offset39(int) { + return offset = 39; + } + + virtual unsigned int offset40(int) { + return offset = 40; + } + + virtual unsigned int offset41(int) { + return offset = 41; + } + + virtual unsigned int offset42(int) { + return offset = 42; + } + + virtual unsigned int offset43(int) { + return offset = 43; + } + + virtual unsigned int offset44(int) { + return offset = 44; + } + + virtual unsigned int offset45(int) { + return offset = 45; + } + + virtual unsigned int offset46(int) { + return offset = 46; + } + + virtual unsigned int offset47(int) { + return offset = 47; + } + + virtual unsigned int offset48(int) { + return offset = 48; + } + + virtual unsigned int offset49(int) { + return offset = 49; + } + + virtual unsigned int offset50(int) { + return offset = 50; + } + + virtual unsigned int offset51(int) { + return offset = 51; + } + + virtual unsigned int offset52(int) { + return offset = 52; + } + + virtual unsigned int offset53(int) { + return offset = 53; + } + + virtual unsigned int offset54(int) { + return offset = 54; + } + + virtual unsigned int offset55(int) { + return offset = 55; + } + + virtual unsigned int offset56(int) { + return offset = 56; + } + + virtual unsigned int offset57(int) { + return offset = 57; + } + + virtual unsigned int offset58(int) { + return offset = 58; + } + + virtual unsigned int offset59(int) { + return offset = 59; + } + + virtual unsigned int offset60(int) { + return offset = 60; + } + + virtual unsigned int offset61(int) { + return offset = 61; + } + + virtual unsigned int offset62(int) { + return offset = 62; + } + + virtual unsigned int offset63(int) { + return offset = 63; + } + + virtual unsigned int offset64(int) { + return offset = 64; + } + + virtual unsigned int offset65(int) { + return offset = 65; + } + + virtual unsigned int offset66(int) { + return offset = 66; + } + + virtual unsigned int offset67(int) { + return offset = 67; + } + + virtual unsigned int offset68(int) { + return offset = 68; + } + + virtual unsigned int offset69(int) { + return offset = 69; + } + + virtual unsigned int offset70(int) { + return offset = 70; + } + + virtual unsigned int offset71(int) { + return offset = 71; + } + + virtual unsigned int offset72(int) { + return offset = 72; + } + + virtual unsigned int offset73(int) { + return offset = 73; + } + + virtual unsigned int offset74(int) { + return offset = 74; + } + + virtual unsigned int offset75(int) { + return offset = 75; + } + + virtual unsigned int offset76(int) { + return offset = 76; + } + + virtual unsigned int offset77(int) { + return offset = 77; + } + + virtual unsigned int offset78(int) { + return offset = 78; + } + + virtual unsigned int offset79(int) { + return offset = 79; + } + + virtual unsigned int offset80(int) { + return offset = 80; + } + + virtual unsigned int offset81(int) { + return offset = 81; + } + + virtual unsigned int offset82(int) { + return offset = 82; + } + + virtual unsigned int offset83(int) { + return offset = 83; + } + + virtual unsigned int offset84(int) { + return offset = 84; + } + + virtual unsigned int offset85(int) { + return offset = 85; + } + + virtual unsigned int offset86(int) { + return offset = 86; + } + + virtual unsigned int offset87(int) { + return offset = 87; + } + + virtual unsigned int offset88(int) { + return offset = 88; + } + + virtual unsigned int offset89(int) { + return offset = 89; + } + + virtual unsigned int offset90(int) { + return offset = 90; + } + + virtual unsigned int offset91(int) { + return offset = 91; + } + + virtual unsigned int offset92(int) { + return offset = 92; + } + + virtual unsigned int offset93(int) { + return offset = 93; + } + + virtual unsigned int offset94(int) { + return offset = 94; + } + + virtual unsigned int offset95(int) { + return offset = 95; + } + + virtual unsigned int offset96(int) { + return offset = 96; + } + + virtual unsigned int offset97(int) { + return offset = 97; + } + + virtual unsigned int offset98(int) { + return offset = 98; + } + + virtual unsigned int offset99(int) { + return offset = 99; + } + + virtual unsigned int offset100(int) { + return offset = 100; + } + + virtual unsigned int offset101(int) { + return offset = 101; + } + + virtual unsigned int offset102(int) { + return offset = 102; + } + + virtual unsigned int offset103(int) { + return offset = 103; + } + + virtual unsigned int offset104(int) { + return offset = 104; + } + + virtual unsigned int offset105(int) { + return offset = 105; + } + + virtual unsigned int offset106(int) { + return offset = 106; + } + + virtual unsigned int offset107(int) { + return offset = 107; + } + + virtual unsigned int offset108(int) { + return offset = 108; + } + + virtual unsigned int offset109(int) { + return offset = 109; + } + + virtual unsigned int offset110(int) { + return offset = 110; + } + + virtual unsigned int offset111(int) { + return offset = 111; + } + + virtual unsigned int offset112(int) { + return offset = 112; + } + + virtual unsigned int offset113(int) { + return offset = 113; + } + + virtual unsigned int offset114(int) { + return offset = 114; + } + + virtual unsigned int offset115(int) { + return offset = 115; + } + + virtual unsigned int offset116(int) { + return offset = 116; + } + + virtual unsigned int offset117(int) { + return offset = 117; + } + + virtual unsigned int offset118(int) { + return offset = 118; + } + + virtual unsigned int offset119(int) { + return offset = 119; + } + + virtual unsigned int offset120(int) { + return offset = 120; + } + + virtual unsigned int offset121(int) { + return offset = 121; + } + + virtual unsigned int offset122(int) { + return offset = 122; + } + + virtual unsigned int offset123(int) { + return offset = 123; + } + + virtual unsigned int offset124(int) { + return offset = 124; + } + + virtual unsigned int offset125(int) { + return offset = 125; + } + + virtual unsigned int offset126(int) { + return offset = 126; + } + + virtual unsigned int offset127(int) { + return offset = 127; + } + + virtual unsigned int offset128(int) { + return offset = 128; + } + + virtual unsigned int offset129(int) { + return offset = 129; + } + + virtual unsigned int offset130(int) { + return offset = 130; + } + + virtual unsigned int offset131(int) { + return offset = 131; + } + + virtual unsigned int offset132(int) { + return offset = 132; + } + + virtual unsigned int offset133(int) { + return offset = 133; + } + + virtual unsigned int offset134(int) { + return offset = 134; + } + + virtual unsigned int offset135(int) { + return offset = 135; + } + + virtual unsigned int offset136(int) { + return offset = 136; + } + + virtual unsigned int offset137(int) { + return offset = 137; + } + + virtual unsigned int offset138(int) { + return offset = 138; + } + + virtual unsigned int offset139(int) { + return offset = 139; + } + + virtual unsigned int offset140(int) { + return offset = 140; + } + + virtual unsigned int offset141(int) { + return offset = 141; + } + + virtual unsigned int offset142(int) { + return offset = 142; + } + + virtual unsigned int offset143(int) { + return offset = 143; + } + + virtual unsigned int offset144(int) { + return offset = 144; + } + + virtual unsigned int offset145(int) { + return offset = 145; + } + + virtual unsigned int offset146(int) { + return offset = 146; + } + + virtual unsigned int offset147(int) { + return offset = 147; + } + + virtual unsigned int offset148(int) { + return offset = 148; + } + + virtual unsigned int offset149(int) { + return offset = 149; + } + + virtual unsigned int offset150(int) { + return offset = 150; + } + + virtual unsigned int offset151(int) { + return offset = 151; + } + + virtual unsigned int offset152(int) { + return offset = 152; + } + + virtual unsigned int offset153(int) { + return offset = 153; + } + + virtual unsigned int offset154(int) { + return offset = 154; + } + + virtual unsigned int offset155(int) { + return offset = 155; + } + + virtual unsigned int offset156(int) { + return offset = 156; + } + + virtual unsigned int offset157(int) { + return offset = 157; + } + + virtual unsigned int offset158(int) { + return offset = 158; + } + + virtual unsigned int offset159(int) { + return offset = 159; + } + + virtual unsigned int offset160(int) { + return offset = 160; + } + + virtual unsigned int offset161(int) { + return offset = 161; + } + + virtual unsigned int offset162(int) { + return offset = 162; + } + + virtual unsigned int offset163(int) { + return offset = 163; + } + + virtual unsigned int offset164(int) { + return offset = 164; + } + + virtual unsigned int offset165(int) { + return offset = 165; + } + + virtual unsigned int offset166(int) { + return offset = 166; + } + + virtual unsigned int offset167(int) { + return offset = 167; + } + + virtual unsigned int offset168(int) { + return offset = 168; + } + + virtual unsigned int offset169(int) { + return offset = 169; + } + + virtual unsigned int offset170(int) { + return offset = 170; + } + + virtual unsigned int offset171(int) { + return offset = 171; + } + + virtual unsigned int offset172(int) { + return offset = 172; + } + + virtual unsigned int offset173(int) { + return offset = 173; + } + + virtual unsigned int offset174(int) { + return offset = 174; + } + + virtual unsigned int offset175(int) { + return offset = 175; + } + + virtual unsigned int offset176(int) { + return offset = 176; + } + + virtual unsigned int offset177(int) { + return offset = 177; + } + + virtual unsigned int offset178(int) { + return offset = 178; + } + + virtual unsigned int offset179(int) { + return offset = 179; + } + + virtual unsigned int offset180(int) { + return offset = 180; + } + + virtual unsigned int offset181(int) { + return offset = 181; + } + + virtual unsigned int offset182(int) { + return offset = 182; + } + + virtual unsigned int offset183(int) { + return offset = 183; + } + + virtual unsigned int offset184(int) { + return offset = 184; + } + + virtual unsigned int offset185(int) { + return offset = 185; + } + + virtual unsigned int offset186(int) { + return offset = 186; + } + + virtual unsigned int offset187(int) { + return offset = 187; + } + + virtual unsigned int offset188(int) { + return offset = 188; + } + + virtual unsigned int offset189(int) { + return offset = 189; + } + + virtual unsigned int offset190(int) { + return offset = 190; + } + + virtual unsigned int offset191(int) { + return offset = 191; + } + + virtual unsigned int offset192(int) { + return offset = 192; + } + + virtual unsigned int offset193(int) { + return offset = 193; + } + + virtual unsigned int offset194(int) { + return offset = 194; + } + + virtual unsigned int offset195(int) { + return offset = 195; + } + + virtual unsigned int offset196(int) { + return offset = 196; + } + + virtual unsigned int offset197(int) { + return offset = 197; + } + + virtual unsigned int offset198(int) { + return offset = 198; + } + + virtual unsigned int offset199(int) { + return offset = 199; + } + + + virtual unsigned int offset200(int) { + return offset = 200; + } + + virtual unsigned int offset201(int) { + return offset = 201; + } + + virtual unsigned int offset202(int) { + return offset = 202; + } + + virtual unsigned int offset203(int) { + return offset = 203; + } + + virtual unsigned int offset204(int) { + return offset = 204; + } + + virtual unsigned int offset205(int) { + return offset = 205; + } + + virtual unsigned int offset206(int) { + return offset = 206; + } + + virtual unsigned int offset207(int) { + return offset = 207; + } + + virtual unsigned int offset208(int) { + return offset = 208; + } + + virtual unsigned int offset209(int) { + return offset = 209; + } + + virtual unsigned int offset210(int) { + return offset = 210; + } + + virtual unsigned int offset211(int) { + return offset = 211; + } + + virtual unsigned int offset212(int) { + return offset = 212; + } + + virtual unsigned int offset213(int) { + return offset = 213; + } + + virtual unsigned int offset214(int) { + return offset = 214; + } + + virtual unsigned int offset215(int) { + return offset = 215; + } + + virtual unsigned int offset216(int) { + return offset = 216; + } + + virtual unsigned int offset217(int) { + return offset = 217; + } + + virtual unsigned int offset218(int) { + return offset = 218; + } + + virtual unsigned int offset219(int) { + return offset = 219; + } + + virtual unsigned int offset220(int) { + return offset = 220; + } + + virtual unsigned int offset221(int) { + return offset = 221; + } + + virtual unsigned int offset222(int) { + return offset = 222; + } + + virtual unsigned int offset223(int) { + return offset = 223; + } + + virtual unsigned int offset224(int) { + return offset = 224; + } + + virtual unsigned int offset225(int) { + return offset = 225; + } + + virtual unsigned int offset226(int) { + return offset = 226; + } + + virtual unsigned int offset227(int) { + return offset = 227; + } + + virtual unsigned int offset228(int) { + return offset = 228; + } + + virtual unsigned int offset229(int) { + return offset = 229; + } + + virtual unsigned int offset230(int) { + return offset = 230; + } + + virtual unsigned int offset231(int) { + return offset = 231; + } + + virtual unsigned int offset232(int) { + return offset = 232; + } + + virtual unsigned int offset233(int) { + return offset = 233; + } + + virtual unsigned int offset234(int) { + return offset = 234; + } + + virtual unsigned int offset235(int) { + return offset = 235; + } + + virtual unsigned int offset236(int) { + return offset = 236; + } + + virtual unsigned int offset237(int) { + return offset = 237; + } + + virtual unsigned int offset238(int) { + return offset = 238; + } + + virtual unsigned int offset239(int) { + return offset = 239; + } + + virtual unsigned int offset240(int) { + return offset = 240; + } + + virtual unsigned int offset241(int) { + return offset = 241; + } + + virtual unsigned int offset242(int) { + return offset = 242; + } + + virtual unsigned int offset243(int) { + return offset = 243; + } + + virtual unsigned int offset244(int) { + return offset = 244; + } + + virtual unsigned int offset245(int) { + return offset = 245; + } + + virtual unsigned int offset246(int) { + return offset = 246; + } + + virtual unsigned int offset247(int) { + return offset = 247; + } + + virtual unsigned int offset248(int) { + return offset = 248; + } + + virtual unsigned int offset249(int) { + return offset = 249; + } + + virtual unsigned int offset250(int) { + return offset = 250; + } + + virtual unsigned int offset251(int) { + return offset = 251; + } + + virtual unsigned int offset252(int) { + return offset = 252; + } + + virtual unsigned int offset253(int) { + return offset = 253; + } + + virtual unsigned int offset254(int) { + return offset = 254; + } + + virtual unsigned int offset255(int) { + return offset = 255; + } + + virtual unsigned int offset256(int) { + return offset = 256; + } + + virtual unsigned int offset257(int) { + return offset = 257; + } + + virtual unsigned int offset258(int) { + return offset = 258; + } + + virtual unsigned int offset259(int) { + return offset = 259; + } + + virtual unsigned int offset260(int) { + return offset = 260; + } + + virtual unsigned int offset261(int) { + return offset = 261; + } + + virtual unsigned int offset262(int) { + return offset = 262; + } + + virtual unsigned int offset263(int) { + return offset = 263; + } + + virtual unsigned int offset264(int) { + return offset = 264; + } + + virtual unsigned int offset265(int) { + return offset = 265; + } + + virtual unsigned int offset266(int) { + return offset = 266; + } + + virtual unsigned int offset267(int) { + return offset = 267; + } + + virtual unsigned int offset268(int) { + return offset = 268; + } + + virtual unsigned int offset269(int) { + return offset = 269; + } + + virtual unsigned int offset270(int) { + return offset = 270; + } + + virtual unsigned int offset271(int) { + return offset = 271; + } + + virtual unsigned int offset272(int) { + return offset = 272; + } + + virtual unsigned int offset273(int) { + return offset = 273; + } + + virtual unsigned int offset274(int) { + return offset = 274; + } + + virtual unsigned int offset275(int) { + return offset = 275; + } + + virtual unsigned int offset276(int) { + return offset = 276; + } + + virtual unsigned int offset277(int) { + return offset = 277; + } + + virtual unsigned int offset278(int) { + return offset = 278; + } + + virtual unsigned int offset279(int) { + return offset = 279; + } + + virtual unsigned int offset280(int) { + return offset = 280; + } + + virtual unsigned int offset281(int) { + return offset = 281; + } + + virtual unsigned int offset282(int) { + return offset = 282; + } + + virtual unsigned int offset283(int) { + return offset = 283; + } + + virtual unsigned int offset284(int) { + return offset = 284; + } + + virtual unsigned int offset285(int) { + return offset = 285; + } + + virtual unsigned int offset286(int) { + return offset = 286; + } + + virtual unsigned int offset287(int) { + return offset = 287; + } + + virtual unsigned int offset288(int) { + return offset = 288; + } + + virtual unsigned int offset289(int) { + return offset = 289; + } + + virtual unsigned int offset290(int) { + return offset = 290; + } + + virtual unsigned int offset291(int) { + return offset = 291; + } + + virtual unsigned int offset292(int) { + return offset = 292; + } + + virtual unsigned int offset293(int) { + return offset = 293; + } + + virtual unsigned int offset294(int) { + return offset = 294; + } + + virtual unsigned int offset295(int) { + return offset = 295; + } + + virtual unsigned int offset296(int) { + return offset = 296; + } + + virtual unsigned int offset297(int) { + return offset = 297; + } + + virtual unsigned int offset298(int) { + return offset = 298; + } + + virtual unsigned int offset299(int) { + return offset = 299; + } + + + virtual unsigned int offset300(int) { + return offset = 300; + } + + virtual unsigned int offset301(int) { + return offset = 301; + } + + virtual unsigned int offset302(int) { + return offset = 302; + } + + virtual unsigned int offset303(int) { + return offset = 303; + } + + virtual unsigned int offset304(int) { + return offset = 304; + } + + virtual unsigned int offset305(int) { + return offset = 305; + } + + virtual unsigned int offset306(int) { + return offset = 306; + } + + virtual unsigned int offset307(int) { + return offset = 307; + } + + virtual unsigned int offset308(int) { + return offset = 308; + } + + virtual unsigned int offset309(int) { + return offset = 309; + } + + virtual unsigned int offset310(int) { + return offset = 310; + } + + virtual unsigned int offset311(int) { + return offset = 311; + } + + virtual unsigned int offset312(int) { + return offset = 312; + } + + virtual unsigned int offset313(int) { + return offset = 313; + } + + virtual unsigned int offset314(int) { + return offset = 314; + } + + virtual unsigned int offset315(int) { + return offset = 315; + } + + virtual unsigned int offset316(int) { + return offset = 316; + } + + virtual unsigned int offset317(int) { + return offset = 317; + } + + virtual unsigned int offset318(int) { + return offset = 318; + } + + virtual unsigned int offset319(int) { + return offset = 319; + } + + virtual unsigned int offset320(int) { + return offset = 320; + } + + virtual unsigned int offset321(int) { + return offset = 321; + } + + virtual unsigned int offset322(int) { + return offset = 322; + } + + virtual unsigned int offset323(int) { + return offset = 323; + } + + virtual unsigned int offset324(int) { + return offset = 324; + } + + virtual unsigned int offset325(int) { + return offset = 325; + } + + virtual unsigned int offset326(int) { + return offset = 326; + } + + virtual unsigned int offset327(int) { + return offset = 327; + } + + virtual unsigned int offset328(int) { + return offset = 328; + } + + virtual unsigned int offset329(int) { + return offset = 329; + } + + virtual unsigned int offset330(int) { + return offset = 330; + } + + virtual unsigned int offset331(int) { + return offset = 331; + } + + virtual unsigned int offset332(int) { + return offset = 332; + } + + virtual unsigned int offset333(int) { + return offset = 333; + } + + virtual unsigned int offset334(int) { + return offset = 334; + } + + virtual unsigned int offset335(int) { + return offset = 335; + } + + virtual unsigned int offset336(int) { + return offset = 336; + } + + virtual unsigned int offset337(int) { + return offset = 337; + } + + virtual unsigned int offset338(int) { + return offset = 338; + } + + virtual unsigned int offset339(int) { + return offset = 339; + } + + virtual unsigned int offset340(int) { + return offset = 340; + } + + virtual unsigned int offset341(int) { + return offset = 341; + } + + virtual unsigned int offset342(int) { + return offset = 342; + } + + virtual unsigned int offset343(int) { + return offset = 343; + } + + virtual unsigned int offset344(int) { + return offset = 344; + } + + virtual unsigned int offset345(int) { + return offset = 345; + } + + virtual unsigned int offset346(int) { + return offset = 346; + } + + virtual unsigned int offset347(int) { + return offset = 347; + } + + virtual unsigned int offset348(int) { + return offset = 348; + } + + virtual unsigned int offset349(int) { + return offset = 349; + } + + virtual unsigned int offset350(int) { + return offset = 350; + } + + virtual unsigned int offset351(int) { + return offset = 351; + } + + virtual unsigned int offset352(int) { + return offset = 352; + } + + virtual unsigned int offset353(int) { + return offset = 353; + } + + virtual unsigned int offset354(int) { + return offset = 354; + } + + virtual unsigned int offset355(int) { + return offset = 355; + } + + virtual unsigned int offset356(int) { + return offset = 356; + } + + virtual unsigned int offset357(int) { + return offset = 357; + } + + virtual unsigned int offset358(int) { + return offset = 358; + } + + virtual unsigned int offset359(int) { + return offset = 359; + } + + virtual unsigned int offset360(int) { + return offset = 360; + } + + virtual unsigned int offset361(int) { + return offset = 361; + } + + virtual unsigned int offset362(int) { + return offset = 362; + } + + virtual unsigned int offset363(int) { + return offset = 363; + } + + virtual unsigned int offset364(int) { + return offset = 364; + } + + virtual unsigned int offset365(int) { + return offset = 365; + } + + virtual unsigned int offset366(int) { + return offset = 366; + } + + virtual unsigned int offset367(int) { + return offset = 367; + } + + virtual unsigned int offset368(int) { + return offset = 368; + } + + virtual unsigned int offset369(int) { + return offset = 369; + } + + virtual unsigned int offset370(int) { + return offset = 370; + } + + virtual unsigned int offset371(int) { + return offset = 371; + } + + virtual unsigned int offset372(int) { + return offset = 372; + } + + virtual unsigned int offset373(int) { + return offset = 373; + } + + virtual unsigned int offset374(int) { + return offset = 374; + } + + virtual unsigned int offset375(int) { + return offset = 375; + } + + virtual unsigned int offset376(int) { + return offset = 376; + } + + virtual unsigned int offset377(int) { + return offset = 377; + } + + virtual unsigned int offset378(int) { + return offset = 378; + } + + virtual unsigned int offset379(int) { + return offset = 379; + } + + virtual unsigned int offset380(int) { + return offset = 380; + } + + virtual unsigned int offset381(int) { + return offset = 381; + } + + virtual unsigned int offset382(int) { + return offset = 382; + } + + virtual unsigned int offset383(int) { + return offset = 383; + } + + virtual unsigned int offset384(int) { + return offset = 384; + } + + virtual unsigned int offset385(int) { + return offset = 385; + } + + virtual unsigned int offset386(int) { + return offset = 386; + } + + virtual unsigned int offset387(int) { + return offset = 387; + } + + virtual unsigned int offset388(int) { + return offset = 388; + } + + virtual unsigned int offset389(int) { + return offset = 389; + } + + virtual unsigned int offset390(int) { + return offset = 390; + } + + virtual unsigned int offset391(int) { + return offset = 391; + } + + virtual unsigned int offset392(int) { + return offset = 392; + } + + virtual unsigned int offset393(int) { + return offset = 393; + } + + virtual unsigned int offset394(int) { + return offset = 394; + } + + virtual unsigned int offset395(int) { + return offset = 395; + } + + virtual unsigned int offset396(int) { + return offset = 396; + } + + virtual unsigned int offset397(int) { + return offset = 397; + } + + virtual unsigned int offset398(int) { + return offset = 398; + } + + virtual unsigned int offset399(int) { + return offset = 399; + } + + + virtual unsigned int offset400(int) { + return offset = 400; + } + + virtual unsigned int offset401(int) { + return offset = 401; + } + + virtual unsigned int offset402(int) { + return offset = 402; + } + + virtual unsigned int offset403(int) { + return offset = 403; + } + + virtual unsigned int offset404(int) { + return offset = 404; + } + + virtual unsigned int offset405(int) { + return offset = 405; + } + + virtual unsigned int offset406(int) { + return offset = 406; + } + + virtual unsigned int offset407(int) { + return offset = 407; + } + + virtual unsigned int offset408(int) { + return offset = 408; + } + + virtual unsigned int offset409(int) { + return offset = 409; + } + + virtual unsigned int offset410(int) { + return offset = 410; + } + + virtual unsigned int offset411(int) { + return offset = 411; + } + + virtual unsigned int offset412(int) { + return offset = 412; + } + + virtual unsigned int offset413(int) { + return offset = 413; + } + + virtual unsigned int offset414(int) { + return offset = 414; + } + + virtual unsigned int offset415(int) { + return offset = 415; + } + + virtual unsigned int offset416(int) { + return offset = 416; + } + + virtual unsigned int offset417(int) { + return offset = 417; + } + + virtual unsigned int offset418(int) { + return offset = 418; + } + + virtual unsigned int offset419(int) { + return offset = 419; + } + + virtual unsigned int offset420(int) { + return offset = 420; + } + + virtual unsigned int offset421(int) { + return offset = 421; + } + + virtual unsigned int offset422(int) { + return offset = 422; + } + + virtual unsigned int offset423(int) { + return offset = 423; + } + + virtual unsigned int offset424(int) { + return offset = 424; + } + + virtual unsigned int offset425(int) { + return offset = 425; + } + + virtual unsigned int offset426(int) { + return offset = 426; + } + + virtual unsigned int offset427(int) { + return offset = 427; + } + + virtual unsigned int offset428(int) { + return offset = 428; + } + + virtual unsigned int offset429(int) { + return offset = 429; + } + + virtual unsigned int offset430(int) { + return offset = 430; + } + + virtual unsigned int offset431(int) { + return offset = 431; + } + + virtual unsigned int offset432(int) { + return offset = 432; + } + + virtual unsigned int offset433(int) { + return offset = 433; + } + + virtual unsigned int offset434(int) { + return offset = 434; + } + + virtual unsigned int offset435(int) { + return offset = 435; + } + + virtual unsigned int offset436(int) { + return offset = 436; + } + + virtual unsigned int offset437(int) { + return offset = 437; + } + + virtual unsigned int offset438(int) { + return offset = 438; + } + + virtual unsigned int offset439(int) { + return offset = 439; + } + + virtual unsigned int offset440(int) { + return offset = 440; + } + + virtual unsigned int offset441(int) { + return offset = 441; + } + + virtual unsigned int offset442(int) { + return offset = 442; + } + + virtual unsigned int offset443(int) { + return offset = 443; + } + + virtual unsigned int offset444(int) { + return offset = 444; + } + + virtual unsigned int offset445(int) { + return offset = 445; + } + + virtual unsigned int offset446(int) { + return offset = 446; + } + + virtual unsigned int offset447(int) { + return offset = 447; + } + + virtual unsigned int offset448(int) { + return offset = 448; + } + + virtual unsigned int offset449(int) { + return offset = 449; + } + + virtual unsigned int offset450(int) { + return offset = 450; + } + + virtual unsigned int offset451(int) { + return offset = 451; + } + + virtual unsigned int offset452(int) { + return offset = 452; + } + + virtual unsigned int offset453(int) { + return offset = 453; + } + + virtual unsigned int offset454(int) { + return offset = 454; + } + + virtual unsigned int offset455(int) { + return offset = 455; + } + + virtual unsigned int offset456(int) { + return offset = 456; + } + + virtual unsigned int offset457(int) { + return offset = 457; + } + + virtual unsigned int offset458(int) { + return offset = 458; + } + + virtual unsigned int offset459(int) { + return offset = 459; + } + + virtual unsigned int offset460(int) { + return offset = 460; + } + + virtual unsigned int offset461(int) { + return offset = 461; + } + + virtual unsigned int offset462(int) { + return offset = 462; + } + + virtual unsigned int offset463(int) { + return offset = 463; + } + + virtual unsigned int offset464(int) { + return offset = 464; + } + + virtual unsigned int offset465(int) { + return offset = 465; + } + + virtual unsigned int offset466(int) { + return offset = 466; + } + + virtual unsigned int offset467(int) { + return offset = 467; + } + + virtual unsigned int offset468(int) { + return offset = 468; + } + + virtual unsigned int offset469(int) { + return offset = 469; + } + + virtual unsigned int offset470(int) { + return offset = 470; + } + + virtual unsigned int offset471(int) { + return offset = 471; + } + + virtual unsigned int offset472(int) { + return offset = 472; + } + + virtual unsigned int offset473(int) { + return offset = 473; + } + + virtual unsigned int offset474(int) { + return offset = 474; + } + + virtual unsigned int offset475(int) { + return offset = 475; + } + + virtual unsigned int offset476(int) { + return offset = 476; + } + + virtual unsigned int offset477(int) { + return offset = 477; + } + + virtual unsigned int offset478(int) { + return offset = 478; + } + + virtual unsigned int offset479(int) { + return offset = 479; + } + + virtual unsigned int offset480(int) { + return offset = 480; + } + + virtual unsigned int offset481(int) { + return offset = 481; + } + + virtual unsigned int offset482(int) { + return offset = 482; + } + + virtual unsigned int offset483(int) { + return offset = 483; + } + + virtual unsigned int offset484(int) { + return offset = 484; + } + + virtual unsigned int offset485(int) { + return offset = 485; + } + + virtual unsigned int offset486(int) { + return offset = 486; + } + + virtual unsigned int offset487(int) { + return offset = 487; + } + + virtual unsigned int offset488(int) { + return offset = 488; + } + + virtual unsigned int offset489(int) { + return offset = 489; + } + + virtual unsigned int offset490(int) { + return offset = 490; + } + + virtual unsigned int offset491(int) { + return offset = 491; + } + + virtual unsigned int offset492(int) { + return offset = 492; + } + + virtual unsigned int offset493(int) { + return offset = 493; + } + + virtual unsigned int offset494(int) { + return offset = 494; + } + + virtual unsigned int offset495(int) { + return offset = 495; + } + + virtual unsigned int offset496(int) { + return offset = 496; + } + + virtual unsigned int offset497(int) { + return offset = 497; + } + + virtual unsigned int offset498(int) { + return offset = 498; + } + + virtual unsigned int offset499(int) { + return offset = 499; + } + + + virtual unsigned int offset500(int) { + return offset = 500; + } + + virtual unsigned int offset501(int) { + return offset = 501; + } + + virtual unsigned int offset502(int) { + return offset = 502; + } + + virtual unsigned int offset503(int) { + return offset = 503; + } + + virtual unsigned int offset504(int) { + return offset = 504; + } + + virtual unsigned int offset505(int) { + return offset = 505; + } + + virtual unsigned int offset506(int) { + return offset = 506; + } + + virtual unsigned int offset507(int) { + return offset = 507; + } + + virtual unsigned int offset508(int) { + return offset = 508; + } + + virtual unsigned int offset509(int) { + return offset = 509; + } + + virtual unsigned int offset510(int) { + return offset = 510; + } + + virtual unsigned int offset511(int) { + return offset = 511; + } + + virtual unsigned int offset512(int) { + return offset = 512; + } + + virtual unsigned int offset513(int) { + return offset = 513; + } + + virtual unsigned int offset514(int) { + return offset = 514; + } + + virtual unsigned int offset515(int) { + return offset = 515; + } + + virtual unsigned int offset516(int) { + return offset = 516; + } + + virtual unsigned int offset517(int) { + return offset = 517; + } + + virtual unsigned int offset518(int) { + return offset = 518; + } + + virtual unsigned int offset519(int) { + return offset = 519; + } + + virtual unsigned int offset520(int) { + return offset = 520; + } + + virtual unsigned int offset521(int) { + return offset = 521; + } + + virtual unsigned int offset522(int) { + return offset = 522; + } + + virtual unsigned int offset523(int) { + return offset = 523; + } + + virtual unsigned int offset524(int) { + return offset = 524; + } + + virtual unsigned int offset525(int) { + return offset = 525; + } + + virtual unsigned int offset526(int) { + return offset = 526; + } + + virtual unsigned int offset527(int) { + return offset = 527; + } + + virtual unsigned int offset528(int) { + return offset = 528; + } + + virtual unsigned int offset529(int) { + return offset = 529; + } + + virtual unsigned int offset530(int) { + return offset = 530; + } + + virtual unsigned int offset531(int) { + return offset = 531; + } + + virtual unsigned int offset532(int) { + return offset = 532; + } + + virtual unsigned int offset533(int) { + return offset = 533; + } + + virtual unsigned int offset534(int) { + return offset = 534; + } + + virtual unsigned int offset535(int) { + return offset = 535; + } + + virtual unsigned int offset536(int) { + return offset = 536; + } + + virtual unsigned int offset537(int) { + return offset = 537; + } + + virtual unsigned int offset538(int) { + return offset = 538; + } + + virtual unsigned int offset539(int) { + return offset = 539; + } + + virtual unsigned int offset540(int) { + return offset = 540; + } + + virtual unsigned int offset541(int) { + return offset = 541; + } + + virtual unsigned int offset542(int) { + return offset = 542; + } + + virtual unsigned int offset543(int) { + return offset = 543; + } + + virtual unsigned int offset544(int) { + return offset = 544; + } + + virtual unsigned int offset545(int) { + return offset = 545; + } + + virtual unsigned int offset546(int) { + return offset = 546; + } + + virtual unsigned int offset547(int) { + return offset = 547; + } + + virtual unsigned int offset548(int) { + return offset = 548; + } + + virtual unsigned int offset549(int) { + return offset = 549; + } + + virtual unsigned int offset550(int) { + return offset = 550; + } + + virtual unsigned int offset551(int) { + return offset = 551; + } + + virtual unsigned int offset552(int) { + return offset = 552; + } + + virtual unsigned int offset553(int) { + return offset = 553; + } + + virtual unsigned int offset554(int) { + return offset = 554; + } + + virtual unsigned int offset555(int) { + return offset = 555; + } + + virtual unsigned int offset556(int) { + return offset = 556; + } + + virtual unsigned int offset557(int) { + return offset = 557; + } + + virtual unsigned int offset558(int) { + return offset = 558; + } + + virtual unsigned int offset559(int) { + return offset = 559; + } + + virtual unsigned int offset560(int) { + return offset = 560; + } + + virtual unsigned int offset561(int) { + return offset = 561; + } + + virtual unsigned int offset562(int) { + return offset = 562; + } + + virtual unsigned int offset563(int) { + return offset = 563; + } + + virtual unsigned int offset564(int) { + return offset = 564; + } + + virtual unsigned int offset565(int) { + return offset = 565; + } + + virtual unsigned int offset566(int) { + return offset = 566; + } + + virtual unsigned int offset567(int) { + return offset = 567; + } + + virtual unsigned int offset568(int) { + return offset = 568; + } + + virtual unsigned int offset569(int) { + return offset = 569; + } + + virtual unsigned int offset570(int) { + return offset = 570; + } + + virtual unsigned int offset571(int) { + return offset = 571; + } + + virtual unsigned int offset572(int) { + return offset = 572; + } + + virtual unsigned int offset573(int) { + return offset = 573; + } + + virtual unsigned int offset574(int) { + return offset = 574; + } + + virtual unsigned int offset575(int) { + return offset = 575; + } + + virtual unsigned int offset576(int) { + return offset = 576; + } + + virtual unsigned int offset577(int) { + return offset = 577; + } + + virtual unsigned int offset578(int) { + return offset = 578; + } + + virtual unsigned int offset579(int) { + return offset = 579; + } + + virtual unsigned int offset580(int) { + return offset = 580; + } + + virtual unsigned int offset581(int) { + return offset = 581; + } + + virtual unsigned int offset582(int) { + return offset = 582; + } + + virtual unsigned int offset583(int) { + return offset = 583; + } + + virtual unsigned int offset584(int) { + return offset = 584; + } + + virtual unsigned int offset585(int) { + return offset = 585; + } + + virtual unsigned int offset586(int) { + return offset = 586; + } + + virtual unsigned int offset587(int) { + return offset = 587; + } + + virtual unsigned int offset588(int) { + return offset = 588; + } + + virtual unsigned int offset589(int) { + return offset = 589; + } + + virtual unsigned int offset590(int) { + return offset = 590; + } + + virtual unsigned int offset591(int) { + return offset = 591; + } + + virtual unsigned int offset592(int) { + return offset = 592; + } + + virtual unsigned int offset593(int) { + return offset = 593; + } + + virtual unsigned int offset594(int) { + return offset = 594; + } + + virtual unsigned int offset595(int) { + return offset = 595; + } + + virtual unsigned int offset596(int) { + return offset = 596; + } + + virtual unsigned int offset597(int) { + return offset = 597; + } + + virtual unsigned int offset598(int) { + return offset = 598; + } + + virtual unsigned int offset599(int) { + return offset = 599; + } + + + virtual unsigned int offset600(int) { + return offset = 600; + } + + virtual unsigned int offset601(int) { + return offset = 601; + } + + virtual unsigned int offset602(int) { + return offset = 602; + } + + virtual unsigned int offset603(int) { + return offset = 603; + } + + virtual unsigned int offset604(int) { + return offset = 604; + } + + virtual unsigned int offset605(int) { + return offset = 605; + } + + virtual unsigned int offset606(int) { + return offset = 606; + } + + virtual unsigned int offset607(int) { + return offset = 607; + } + + virtual unsigned int offset608(int) { + return offset = 608; + } + + virtual unsigned int offset609(int) { + return offset = 609; + } + + virtual unsigned int offset610(int) { + return offset = 610; + } + + virtual unsigned int offset611(int) { + return offset = 611; + } + + virtual unsigned int offset612(int) { + return offset = 612; + } + + virtual unsigned int offset613(int) { + return offset = 613; + } + + virtual unsigned int offset614(int) { + return offset = 614; + } + + virtual unsigned int offset615(int) { + return offset = 615; + } + + virtual unsigned int offset616(int) { + return offset = 616; + } + + virtual unsigned int offset617(int) { + return offset = 617; + } + + virtual unsigned int offset618(int) { + return offset = 618; + } + + virtual unsigned int offset619(int) { + return offset = 619; + } + + virtual unsigned int offset620(int) { + return offset = 620; + } + + virtual unsigned int offset621(int) { + return offset = 621; + } + + virtual unsigned int offset622(int) { + return offset = 622; + } + + virtual unsigned int offset623(int) { + return offset = 623; + } + + virtual unsigned int offset624(int) { + return offset = 624; + } + + virtual unsigned int offset625(int) { + return offset = 625; + } + + virtual unsigned int offset626(int) { + return offset = 626; + } + + virtual unsigned int offset627(int) { + return offset = 627; + } + + virtual unsigned int offset628(int) { + return offset = 628; + } + + virtual unsigned int offset629(int) { + return offset = 629; + } + + virtual unsigned int offset630(int) { + return offset = 630; + } + + virtual unsigned int offset631(int) { + return offset = 631; + } + + virtual unsigned int offset632(int) { + return offset = 632; + } + + virtual unsigned int offset633(int) { + return offset = 633; + } + + virtual unsigned int offset634(int) { + return offset = 634; + } + + virtual unsigned int offset635(int) { + return offset = 635; + } + + virtual unsigned int offset636(int) { + return offset = 636; + } + + virtual unsigned int offset637(int) { + return offset = 637; + } + + virtual unsigned int offset638(int) { + return offset = 638; + } + + virtual unsigned int offset639(int) { + return offset = 639; + } + + virtual unsigned int offset640(int) { + return offset = 640; + } + + virtual unsigned int offset641(int) { + return offset = 641; + } + + virtual unsigned int offset642(int) { + return offset = 642; + } + + virtual unsigned int offset643(int) { + return offset = 643; + } + + virtual unsigned int offset644(int) { + return offset = 644; + } + + virtual unsigned int offset645(int) { + return offset = 645; + } + + virtual unsigned int offset646(int) { + return offset = 646; + } + + virtual unsigned int offset647(int) { + return offset = 647; + } + + virtual unsigned int offset648(int) { + return offset = 648; + } + + virtual unsigned int offset649(int) { + return offset = 649; + } + + virtual unsigned int offset650(int) { + return offset = 650; + } + + virtual unsigned int offset651(int) { + return offset = 651; + } + + virtual unsigned int offset652(int) { + return offset = 652; + } + + virtual unsigned int offset653(int) { + return offset = 653; + } + + virtual unsigned int offset654(int) { + return offset = 654; + } + + virtual unsigned int offset655(int) { + return offset = 655; + } + + virtual unsigned int offset656(int) { + return offset = 656; + } + + virtual unsigned int offset657(int) { + return offset = 657; + } + + virtual unsigned int offset658(int) { + return offset = 658; + } + + virtual unsigned int offset659(int) { + return offset = 659; + } + + virtual unsigned int offset660(int) { + return offset = 660; + } + + virtual unsigned int offset661(int) { + return offset = 661; + } + + virtual unsigned int offset662(int) { + return offset = 662; + } + + virtual unsigned int offset663(int) { + return offset = 663; + } + + virtual unsigned int offset664(int) { + return offset = 664; + } + + virtual unsigned int offset665(int) { + return offset = 665; + } + + virtual unsigned int offset666(int) { + return offset = 666; + } + + virtual unsigned int offset667(int) { + return offset = 667; + } + + virtual unsigned int offset668(int) { + return offset = 668; + } + + virtual unsigned int offset669(int) { + return offset = 669; + } + + virtual unsigned int offset670(int) { + return offset = 670; + } + + virtual unsigned int offset671(int) { + return offset = 671; + } + + virtual unsigned int offset672(int) { + return offset = 672; + } + + virtual unsigned int offset673(int) { + return offset = 673; + } + + virtual unsigned int offset674(int) { + return offset = 674; + } + + virtual unsigned int offset675(int) { + return offset = 675; + } + + virtual unsigned int offset676(int) { + return offset = 676; + } + + virtual unsigned int offset677(int) { + return offset = 677; + } + + virtual unsigned int offset678(int) { + return offset = 678; + } + + virtual unsigned int offset679(int) { + return offset = 679; + } + + virtual unsigned int offset680(int) { + return offset = 680; + } + + virtual unsigned int offset681(int) { + return offset = 681; + } + + virtual unsigned int offset682(int) { + return offset = 682; + } + + virtual unsigned int offset683(int) { + return offset = 683; + } + + virtual unsigned int offset684(int) { + return offset = 684; + } + + virtual unsigned int offset685(int) { + return offset = 685; + } + + virtual unsigned int offset686(int) { + return offset = 686; + } + + virtual unsigned int offset687(int) { + return offset = 687; + } + + virtual unsigned int offset688(int) { + return offset = 688; + } + + virtual unsigned int offset689(int) { + return offset = 689; + } + + virtual unsigned int offset690(int) { + return offset = 690; + } + + virtual unsigned int offset691(int) { + return offset = 691; + } + + virtual unsigned int offset692(int) { + return offset = 692; + } + + virtual unsigned int offset693(int) { + return offset = 693; + } + + virtual unsigned int offset694(int) { + return offset = 694; + } + + virtual unsigned int offset695(int) { + return offset = 695; + } + + virtual unsigned int offset696(int) { + return offset = 696; + } + + virtual unsigned int offset697(int) { + return offset = 697; + } + + virtual unsigned int offset698(int) { + return offset = 698; + } + + virtual unsigned int offset699(int) { + return offset = 699; + } + + + virtual unsigned int offset700(int) { + return offset = 700; + } + + virtual unsigned int offset701(int) { + return offset = 701; + } + + virtual unsigned int offset702(int) { + return offset = 702; + } + + virtual unsigned int offset703(int) { + return offset = 703; + } + + virtual unsigned int offset704(int) { + return offset = 704; + } + + virtual unsigned int offset705(int) { + return offset = 705; + } + + virtual unsigned int offset706(int) { + return offset = 706; + } + + virtual unsigned int offset707(int) { + return offset = 707; + } + + virtual unsigned int offset708(int) { + return offset = 708; + } + + virtual unsigned int offset709(int) { + return offset = 709; + } + + virtual unsigned int offset710(int) { + return offset = 710; + } + + virtual unsigned int offset711(int) { + return offset = 711; + } + + virtual unsigned int offset712(int) { + return offset = 712; + } + + virtual unsigned int offset713(int) { + return offset = 713; + } + + virtual unsigned int offset714(int) { + return offset = 714; + } + + virtual unsigned int offset715(int) { + return offset = 715; + } + + virtual unsigned int offset716(int) { + return offset = 716; + } + + virtual unsigned int offset717(int) { + return offset = 717; + } + + virtual unsigned int offset718(int) { + return offset = 718; + } + + virtual unsigned int offset719(int) { + return offset = 719; + } + + virtual unsigned int offset720(int) { + return offset = 720; + } + + virtual unsigned int offset721(int) { + return offset = 721; + } + + virtual unsigned int offset722(int) { + return offset = 722; + } + + virtual unsigned int offset723(int) { + return offset = 723; + } + + virtual unsigned int offset724(int) { + return offset = 724; + } + + virtual unsigned int offset725(int) { + return offset = 725; + } + + virtual unsigned int offset726(int) { + return offset = 726; + } + + virtual unsigned int offset727(int) { + return offset = 727; + } + + virtual unsigned int offset728(int) { + return offset = 728; + } + + virtual unsigned int offset729(int) { + return offset = 729; + } + + virtual unsigned int offset730(int) { + return offset = 730; + } + + virtual unsigned int offset731(int) { + return offset = 731; + } + + virtual unsigned int offset732(int) { + return offset = 732; + } + + virtual unsigned int offset733(int) { + return offset = 733; + } + + virtual unsigned int offset734(int) { + return offset = 734; + } + + virtual unsigned int offset735(int) { + return offset = 735; + } + + virtual unsigned int offset736(int) { + return offset = 736; + } + + virtual unsigned int offset737(int) { + return offset = 737; + } + + virtual unsigned int offset738(int) { + return offset = 738; + } + + virtual unsigned int offset739(int) { + return offset = 739; + } + + virtual unsigned int offset740(int) { + return offset = 740; + } + + virtual unsigned int offset741(int) { + return offset = 741; + } + + virtual unsigned int offset742(int) { + return offset = 742; + } + + virtual unsigned int offset743(int) { + return offset = 743; + } + + virtual unsigned int offset744(int) { + return offset = 744; + } + + virtual unsigned int offset745(int) { + return offset = 745; + } + + virtual unsigned int offset746(int) { + return offset = 746; + } + + virtual unsigned int offset747(int) { + return offset = 747; + } + + virtual unsigned int offset748(int) { + return offset = 748; + } + + virtual unsigned int offset749(int) { + return offset = 749; + } + + virtual unsigned int offset750(int) { + return offset = 750; + } + + virtual unsigned int offset751(int) { + return offset = 751; + } + + virtual unsigned int offset752(int) { + return offset = 752; + } + + virtual unsigned int offset753(int) { + return offset = 753; + } + + virtual unsigned int offset754(int) { + return offset = 754; + } + + virtual unsigned int offset755(int) { + return offset = 755; + } + + virtual unsigned int offset756(int) { + return offset = 756; + } + + virtual unsigned int offset757(int) { + return offset = 757; + } + + virtual unsigned int offset758(int) { + return offset = 758; + } + + virtual unsigned int offset759(int) { + return offset = 759; + } + + virtual unsigned int offset760(int) { + return offset = 760; + } + + virtual unsigned int offset761(int) { + return offset = 761; + } + + virtual unsigned int offset762(int) { + return offset = 762; + } + + virtual unsigned int offset763(int) { + return offset = 763; + } + + virtual unsigned int offset764(int) { + return offset = 764; + } + + virtual unsigned int offset765(int) { + return offset = 765; + } + + virtual unsigned int offset766(int) { + return offset = 766; + } + + virtual unsigned int offset767(int) { + return offset = 767; + } + + virtual unsigned int offset768(int) { + return offset = 768; + } + + virtual unsigned int offset769(int) { + return offset = 769; + } + + virtual unsigned int offset770(int) { + return offset = 770; + } + + virtual unsigned int offset771(int) { + return offset = 771; + } + + virtual unsigned int offset772(int) { + return offset = 772; + } + + virtual unsigned int offset773(int) { + return offset = 773; + } + + virtual unsigned int offset774(int) { + return offset = 774; + } + + virtual unsigned int offset775(int) { + return offset = 775; + } + + virtual unsigned int offset776(int) { + return offset = 776; + } + + virtual unsigned int offset777(int) { + return offset = 777; + } + + virtual unsigned int offset778(int) { + return offset = 778; + } + + virtual unsigned int offset779(int) { + return offset = 779; + } + + virtual unsigned int offset780(int) { + return offset = 780; + } + + virtual unsigned int offset781(int) { + return offset = 781; + } + + virtual unsigned int offset782(int) { + return offset = 782; + } + + virtual unsigned int offset783(int) { + return offset = 783; + } + + virtual unsigned int offset784(int) { + return offset = 784; + } + + virtual unsigned int offset785(int) { + return offset = 785; + } + + virtual unsigned int offset786(int) { + return offset = 786; + } + + virtual unsigned int offset787(int) { + return offset = 787; + } + + virtual unsigned int offset788(int) { + return offset = 788; + } + + virtual unsigned int offset789(int) { + return offset = 789; + } + + virtual unsigned int offset790(int) { + return offset = 790; + } + + virtual unsigned int offset791(int) { + return offset = 791; + } + + virtual unsigned int offset792(int) { + return offset = 792; + } + + virtual unsigned int offset793(int) { + return offset = 793; + } + + virtual unsigned int offset794(int) { + return offset = 794; + } + + virtual unsigned int offset795(int) { + return offset = 795; + } + + virtual unsigned int offset796(int) { + return offset = 796; + } + + virtual unsigned int offset797(int) { + return offset = 797; + } + + virtual unsigned int offset798(int) { + return offset = 798; + } + + virtual unsigned int offset799(int) { + return offset = 799; + } + + + virtual unsigned int offset800(int) { + return offset = 800; + } + + virtual unsigned int offset801(int) { + return offset = 801; + } + + virtual unsigned int offset802(int) { + return offset = 802; + } + + virtual unsigned int offset803(int) { + return offset = 803; + } + + virtual unsigned int offset804(int) { + return offset = 804; + } + + virtual unsigned int offset805(int) { + return offset = 805; + } + + virtual unsigned int offset806(int) { + return offset = 806; + } + + virtual unsigned int offset807(int) { + return offset = 807; + } + + virtual unsigned int offset808(int) { + return offset = 808; + } + + virtual unsigned int offset809(int) { + return offset = 809; + } + + virtual unsigned int offset810(int) { + return offset = 810; + } + + virtual unsigned int offset811(int) { + return offset = 811; + } + + virtual unsigned int offset812(int) { + return offset = 812; + } + + virtual unsigned int offset813(int) { + return offset = 813; + } + + virtual unsigned int offset814(int) { + return offset = 814; + } + + virtual unsigned int offset815(int) { + return offset = 815; + } + + virtual unsigned int offset816(int) { + return offset = 816; + } + + virtual unsigned int offset817(int) { + return offset = 817; + } + + virtual unsigned int offset818(int) { + return offset = 818; + } + + virtual unsigned int offset819(int) { + return offset = 819; + } + + virtual unsigned int offset820(int) { + return offset = 820; + } + + virtual unsigned int offset821(int) { + return offset = 821; + } + + virtual unsigned int offset822(int) { + return offset = 822; + } + + virtual unsigned int offset823(int) { + return offset = 823; + } + + virtual unsigned int offset824(int) { + return offset = 824; + } + + virtual unsigned int offset825(int) { + return offset = 825; + } + + virtual unsigned int offset826(int) { + return offset = 826; + } + + virtual unsigned int offset827(int) { + return offset = 827; + } + + virtual unsigned int offset828(int) { + return offset = 828; + } + + virtual unsigned int offset829(int) { + return offset = 829; + } + + virtual unsigned int offset830(int) { + return offset = 830; + } + + virtual unsigned int offset831(int) { + return offset = 831; + } + + virtual unsigned int offset832(int) { + return offset = 832; + } + + virtual unsigned int offset833(int) { + return offset = 833; + } + + virtual unsigned int offset834(int) { + return offset = 834; + } + + virtual unsigned int offset835(int) { + return offset = 835; + } + + virtual unsigned int offset836(int) { + return offset = 836; + } + + virtual unsigned int offset837(int) { + return offset = 837; + } + + virtual unsigned int offset838(int) { + return offset = 838; + } + + virtual unsigned int offset839(int) { + return offset = 839; + } + + virtual unsigned int offset840(int) { + return offset = 840; + } + + virtual unsigned int offset841(int) { + return offset = 841; + } + + virtual unsigned int offset842(int) { + return offset = 842; + } + + virtual unsigned int offset843(int) { + return offset = 843; + } + + virtual unsigned int offset844(int) { + return offset = 844; + } + + virtual unsigned int offset845(int) { + return offset = 845; + } + + virtual unsigned int offset846(int) { + return offset = 846; + } + + virtual unsigned int offset847(int) { + return offset = 847; + } + + virtual unsigned int offset848(int) { + return offset = 848; + } + + virtual unsigned int offset849(int) { + return offset = 849; + } + + virtual unsigned int offset850(int) { + return offset = 850; + } + + virtual unsigned int offset851(int) { + return offset = 851; + } + + virtual unsigned int offset852(int) { + return offset = 852; + } + + virtual unsigned int offset853(int) { + return offset = 853; + } + + virtual unsigned int offset854(int) { + return offset = 854; + } + + virtual unsigned int offset855(int) { + return offset = 855; + } + + virtual unsigned int offset856(int) { + return offset = 856; + } + + virtual unsigned int offset857(int) { + return offset = 857; + } + + virtual unsigned int offset858(int) { + return offset = 858; + } + + virtual unsigned int offset859(int) { + return offset = 859; + } + + virtual unsigned int offset860(int) { + return offset = 860; + } + + virtual unsigned int offset861(int) { + return offset = 861; + } + + virtual unsigned int offset862(int) { + return offset = 862; + } + + virtual unsigned int offset863(int) { + return offset = 863; + } + + virtual unsigned int offset864(int) { + return offset = 864; + } + + virtual unsigned int offset865(int) { + return offset = 865; + } + + virtual unsigned int offset866(int) { + return offset = 866; + } + + virtual unsigned int offset867(int) { + return offset = 867; + } + + virtual unsigned int offset868(int) { + return offset = 868; + } + + virtual unsigned int offset869(int) { + return offset = 869; + } + + virtual unsigned int offset870(int) { + return offset = 870; + } + + virtual unsigned int offset871(int) { + return offset = 871; + } + + virtual unsigned int offset872(int) { + return offset = 872; + } + + virtual unsigned int offset873(int) { + return offset = 873; + } + + virtual unsigned int offset874(int) { + return offset = 874; + } + + virtual unsigned int offset875(int) { + return offset = 875; + } + + virtual unsigned int offset876(int) { + return offset = 876; + } + + virtual unsigned int offset877(int) { + return offset = 877; + } + + virtual unsigned int offset878(int) { + return offset = 878; + } + + virtual unsigned int offset879(int) { + return offset = 879; + } + + virtual unsigned int offset880(int) { + return offset = 880; + } + + virtual unsigned int offset881(int) { + return offset = 881; + } + + virtual unsigned int offset882(int) { + return offset = 882; + } + + virtual unsigned int offset883(int) { + return offset = 883; + } + + virtual unsigned int offset884(int) { + return offset = 884; + } + + virtual unsigned int offset885(int) { + return offset = 885; + } + + virtual unsigned int offset886(int) { + return offset = 886; + } + + virtual unsigned int offset887(int) { + return offset = 887; + } + + virtual unsigned int offset888(int) { + return offset = 888; + } + + virtual unsigned int offset889(int) { + return offset = 889; + } + + virtual unsigned int offset890(int) { + return offset = 890; + } + + virtual unsigned int offset891(int) { + return offset = 891; + } + + virtual unsigned int offset892(int) { + return offset = 892; + } + + virtual unsigned int offset893(int) { + return offset = 893; + } + + virtual unsigned int offset894(int) { + return offset = 894; + } + + virtual unsigned int offset895(int) { + return offset = 895; + } + + virtual unsigned int offset896(int) { + return offset = 896; + } + + virtual unsigned int offset897(int) { + return offset = 897; + } + + virtual unsigned int offset898(int) { + return offset = 898; + } + + virtual unsigned int offset899(int) { + return offset = 899; + } + + + virtual unsigned int offset900(int) { + return offset = 900; + } + + virtual unsigned int offset901(int) { + return offset = 901; + } + + virtual unsigned int offset902(int) { + return offset = 902; + } + + virtual unsigned int offset903(int) { + return offset = 903; + } + + virtual unsigned int offset904(int) { + return offset = 904; + } + + virtual unsigned int offset905(int) { + return offset = 905; + } + + virtual unsigned int offset906(int) { + return offset = 906; + } + + virtual unsigned int offset907(int) { + return offset = 907; + } + + virtual unsigned int offset908(int) { + return offset = 908; + } + + virtual unsigned int offset909(int) { + return offset = 909; + } + + virtual unsigned int offset910(int) { + return offset = 910; + } + + virtual unsigned int offset911(int) { + return offset = 911; + } + + virtual unsigned int offset912(int) { + return offset = 912; + } + + virtual unsigned int offset913(int) { + return offset = 913; + } + + virtual unsigned int offset914(int) { + return offset = 914; + } + + virtual unsigned int offset915(int) { + return offset = 915; + } + + virtual unsigned int offset916(int) { + return offset = 916; + } + + virtual unsigned int offset917(int) { + return offset = 917; + } + + virtual unsigned int offset918(int) { + return offset = 918; + } + + virtual unsigned int offset919(int) { + return offset = 919; + } + + virtual unsigned int offset920(int) { + return offset = 920; + } + + virtual unsigned int offset921(int) { + return offset = 921; + } + + virtual unsigned int offset922(int) { + return offset = 922; + } + + virtual unsigned int offset923(int) { + return offset = 923; + } + + virtual unsigned int offset924(int) { + return offset = 924; + } + + virtual unsigned int offset925(int) { + return offset = 925; + } + + virtual unsigned int offset926(int) { + return offset = 926; + } + + virtual unsigned int offset927(int) { + return offset = 927; + } + + virtual unsigned int offset928(int) { + return offset = 928; + } + + virtual unsigned int offset929(int) { + return offset = 929; + } + + virtual unsigned int offset930(int) { + return offset = 930; + } + + virtual unsigned int offset931(int) { + return offset = 931; + } + + virtual unsigned int offset932(int) { + return offset = 932; + } + + virtual unsigned int offset933(int) { + return offset = 933; + } + + virtual unsigned int offset934(int) { + return offset = 934; + } + + virtual unsigned int offset935(int) { + return offset = 935; + } + + virtual unsigned int offset936(int) { + return offset = 936; + } + + virtual unsigned int offset937(int) { + return offset = 937; + } + + virtual unsigned int offset938(int) { + return offset = 938; + } + + virtual unsigned int offset939(int) { + return offset = 939; + } + + virtual unsigned int offset940(int) { + return offset = 940; + } + + virtual unsigned int offset941(int) { + return offset = 941; + } + + virtual unsigned int offset942(int) { + return offset = 942; + } + + virtual unsigned int offset943(int) { + return offset = 943; + } + + virtual unsigned int offset944(int) { + return offset = 944; + } + + virtual unsigned int offset945(int) { + return offset = 945; + } + + virtual unsigned int offset946(int) { + return offset = 946; + } + + virtual unsigned int offset947(int) { + return offset = 947; + } + + virtual unsigned int offset948(int) { + return offset = 948; + } + + virtual unsigned int offset949(int) { + return offset = 949; + } + + virtual unsigned int offset950(int) { + return offset = 950; + } + + virtual unsigned int offset951(int) { + return offset = 951; + } + + virtual unsigned int offset952(int) { + return offset = 952; + } + + virtual unsigned int offset953(int) { + return offset = 953; + } + + virtual unsigned int offset954(int) { + return offset = 954; + } + + virtual unsigned int offset955(int) { + return offset = 955; + } + + virtual unsigned int offset956(int) { + return offset = 956; + } + + virtual unsigned int offset957(int) { + return offset = 957; + } + + virtual unsigned int offset958(int) { + return offset = 958; + } + + virtual unsigned int offset959(int) { + return offset = 959; + } + + virtual unsigned int offset960(int) { + return offset = 960; + } + + virtual unsigned int offset961(int) { + return offset = 961; + } + + virtual unsigned int offset962(int) { + return offset = 962; + } + + virtual unsigned int offset963(int) { + return offset = 963; + } + + virtual unsigned int offset964(int) { + return offset = 964; + } + + virtual unsigned int offset965(int) { + return offset = 965; + } + + virtual unsigned int offset966(int) { + return offset = 966; + } + + virtual unsigned int offset967(int) { + return offset = 967; + } + + virtual unsigned int offset968(int) { + return offset = 968; + } + + virtual unsigned int offset969(int) { + return offset = 969; + } + + virtual unsigned int offset970(int) { + return offset = 970; + } + + virtual unsigned int offset971(int) { + return offset = 971; + } + + virtual unsigned int offset972(int) { + return offset = 972; + } + + virtual unsigned int offset973(int) { + return offset = 973; + } + + virtual unsigned int offset974(int) { + return offset = 974; + } + + virtual unsigned int offset975(int) { + return offset = 975; + } + + virtual unsigned int offset976(int) { + return offset = 976; + } + + virtual unsigned int offset977(int) { + return offset = 977; + } + + virtual unsigned int offset978(int) { + return offset = 978; + } + + virtual unsigned int offset979(int) { + return offset = 979; + } + + virtual unsigned int offset980(int) { + return offset = 980; + } + + virtual unsigned int offset981(int) { + return offset = 981; + } + + virtual unsigned int offset982(int) { + return offset = 982; + } + + virtual unsigned int offset983(int) { + return offset = 983; + } + + virtual unsigned int offset984(int) { + return offset = 984; + } + + virtual unsigned int offset985(int) { + return offset = 985; + } + + virtual unsigned int offset986(int) { + return offset = 986; + } + + virtual unsigned int offset987(int) { + return offset = 987; + } + + virtual unsigned int offset988(int) { + return offset = 988; + } + + virtual unsigned int offset989(int) { + return offset = 989; + } + + virtual unsigned int offset990(int) { + return offset = 990; + } + + virtual unsigned int offset991(int) { + return offset = 991; + } + + virtual unsigned int offset992(int) { + return offset = 992; + } + + virtual unsigned int offset993(int) { + return offset = 993; + } + + virtual unsigned int offset994(int) { + return offset = 994; + } + + virtual unsigned int offset995(int) { + return offset = 995; + } + + virtual unsigned int offset996(int) { + return offset = 996; + } + + virtual unsigned int offset997(int) { + return offset = 997; + } + + virtual unsigned int offset998(int) { + return offset = 998; + } + + virtual unsigned int offset999(int) { + return offset = 999; + } + + virtual unsigned int offset1000(int) { + return offset = 1000; + } + + }; +} +namespace fakeit { + + template + TARGET union_cast(SOURCE source) { + + union { + SOURCE source; + TARGET target; + } u; + u.source = source; + return u.target; + } + +} + +namespace fakeit { + class NoVirtualDtor { + }; + + class VTUtils { + public: + + template + static unsigned int getOffset(R (C::*vMethod)(arglist...)) { + auto sMethod = reinterpret_cast(vMethod); + VirtualOffsetSelector offsetSelctor; + return (offsetSelctor.*sMethod)(0); + } + + template + static typename std::enable_if::value, unsigned int>::type + getDestructorOffset() { + VirtualOffsetSelector offsetSelctor; + union_cast(&offsetSelctor)->~C(); + return offsetSelctor.offset; + } + + template + static typename std::enable_if::value, unsigned int>::type + getDestructorOffset() { + throw NoVirtualDtor(); + } + + template + static unsigned int getVTSize() { + struct Derrived : public C { + virtual void endOfVt() { + } + }; + + unsigned int vtSize = getOffset(&Derrived::endOfVt); + return vtSize; + } + }; + + +} +#ifdef _MSC_VER +namespace fakeit { + + typedef unsigned long DWORD; + + struct TypeDescriptor { + TypeDescriptor() : + ptrToVTable(0), spare(0) { + + int **tiVFTPtr = (int **) (&typeid(void)); + int *i = (int *) tiVFTPtr[0]; + char *type_info_vft_ptr = (char *) i; + ptrToVTable = type_info_vft_ptr; + } + + char *ptrToVTable; + DWORD spare; + char name[8]; + }; + + struct PMD { + + + + int mdisp; + + int pdisp; + int vdisp; + + PMD() : + mdisp(0), pdisp(-1), vdisp(0) { + } + }; + + struct RTTIBaseClassDescriptor { + RTTIBaseClassDescriptor() : + pTypeDescriptor(nullptr), numContainedBases(0), attributes(0) { + } + + const std::type_info *pTypeDescriptor; + DWORD numContainedBases; + struct PMD where; + DWORD attributes; + }; + + template + struct RTTIClassHierarchyDescriptor { + RTTIClassHierarchyDescriptor() : + signature(0), + attributes(0), + numBaseClasses(0), + pBaseClassArray(nullptr) { + pBaseClassArray = new RTTIBaseClassDescriptor *[1 + sizeof...(baseclasses)]; + addBaseClass < C, baseclasses...>(); + } + + ~RTTIClassHierarchyDescriptor() { + for (int i = 0; i < 1 + sizeof...(baseclasses); i++) { + RTTIBaseClassDescriptor *desc = pBaseClassArray[i]; + delete desc; + } + delete[] pBaseClassArray; + } + + DWORD signature; + DWORD attributes; + DWORD numBaseClasses; + RTTIBaseClassDescriptor **pBaseClassArray; + + template + void addBaseClass() { + static_assert(std::is_base_of::value, "C must be a derived class of BaseType"); + RTTIBaseClassDescriptor *desc = new RTTIBaseClassDescriptor(); + desc->pTypeDescriptor = &typeid(BaseType); + pBaseClassArray[numBaseClasses] = desc; + for (unsigned int i = 0; i < numBaseClasses; i++) { + pBaseClassArray[i]->numContainedBases++; + } + numBaseClasses++; + } + + template + void addBaseClass() { + static_assert(std::is_base_of::value, "invalid inheritance list"); + addBaseClass(); + addBaseClass(); + } + + }; + + template + struct RTTICompleteObjectLocator { +#ifdef _WIN64 + RTTICompleteObjectLocator(const std::type_info &unused) : + signature(0), offset(0), cdOffset(0), + typeDescriptorOffset(0), classDescriptorOffset(0) + { + } + + DWORD signature; + DWORD offset; + DWORD cdOffset; + DWORD typeDescriptorOffset; + DWORD classDescriptorOffset; +#else + RTTICompleteObjectLocator(const std::type_info &info) : + signature(0), offset(0), cdOffset(0), + pTypeDescriptor(&info), + pClassDescriptor(new RTTIClassHierarchyDescriptor()) { + } + + ~RTTICompleteObjectLocator() { + delete pClassDescriptor; + } + + DWORD signature; + DWORD offset; + DWORD cdOffset; + const std::type_info *pTypeDescriptor; + struct RTTIClassHierarchyDescriptor *pClassDescriptor; +#endif + }; + + + struct VirtualTableBase { + + static VirtualTableBase &getVTable(void *instance) { + fakeit::VirtualTableBase *vt = (fakeit::VirtualTableBase *) (instance); + return *vt; + } + + VirtualTableBase(void **firstMethod) : _firstMethod(firstMethod) { } + + void *getCookie(int index) { + return _firstMethod[-2 - index]; + } + + void setCookie(int index, void *value) { + _firstMethod[-2 - index] = value; + } + + void *getMethod(unsigned int index) const { + return _firstMethod[index]; + } + + void setMethod(unsigned int index, void *method) { + _firstMethod[index] = method; + } + + protected: + void **_firstMethod; + }; + + template + struct VirtualTable : public VirtualTableBase { + + class Handle { + + friend struct VirtualTable; + + void **firstMethod; + + Handle(void **method) : firstMethod(method) { } + + public: + + VirtualTable &restore() { + VirtualTable *vt = (VirtualTable *) this; + return *vt; + } + }; + + static VirtualTable &getVTable(C &instance) { + fakeit::VirtualTable *vt = (fakeit::VirtualTable *) (&instance); + return *vt; + } + + void copyFrom(VirtualTable &from) { + unsigned int size = VTUtils::getVTSize(); + for (unsigned int i = 0; i < size; i++) { + _firstMethod[i] = from.getMethod(i); + } + } + + VirtualTable() : VirtualTable(buildVTArray()) { + } + + ~VirtualTable() { + + } + + void dispose() { + _firstMethod--; + RTTICompleteObjectLocator *locator = (RTTICompleteObjectLocator *) _firstMethod[0]; + delete locator; + _firstMethod -= numOfCookies; + delete[] _firstMethod; + } + + + unsigned int dtor(int) { + C *c = (C *) this; + C &cRef = *c; + auto vt = VirtualTable::getVTable(cRef); + void *dtorPtr = vt.getCookie(numOfCookies - 1); + void(*method)(C *) = reinterpret_cast(dtorPtr); + method(c); + return 0; + } + + void setDtor(void *method) { + + + + + + void *dtorPtr = union_cast(&VirtualTable::dtor); + unsigned int index = VTUtils::getDestructorOffset(); + _firstMethod[index] = dtorPtr; + setCookie(numOfCookies - 1, method); + } + + unsigned int getSize() { + return VTUtils::getVTSize(); + } + + void initAll(void *value) { + auto size = getSize(); + for (unsigned int i = 0; i < size; i++) { + setMethod(i, value); + } + } + + Handle createHandle() { + Handle h(_firstMethod); + return h; + } + + private: + + class SimpleType { + }; + + static_assert(sizeof(unsigned int (SimpleType::*)()) == sizeof(unsigned int (C::*)()), + "Can't mock a type with multiple inheritance or with non-polymorphic base class"); + static const unsigned int numOfCookies = 3; + + static void **buildVTArray() { + int vtSize = VTUtils::getVTSize(); + auto array = new void *[vtSize + numOfCookies + 1]{}; + RTTICompleteObjectLocator *objectLocator = new RTTICompleteObjectLocator( + typeid(C)); + array += numOfCookies; + array[0] = objectLocator; + array++; + return array; + } + + VirtualTable(void **firstMethod) : VirtualTableBase(firstMethod) { + } + }; +} +#else +#ifndef __clang__ +#include +#include + +namespace fakeit { + template + class has_one_base { + }; + + template + class has_one_base> : public std::false_type { + }; + + template + class has_one_base> + : public has_one_base::type> { + }; + + template<> + class has_one_base> : public std::true_type { + }; + + template + class is_simple_inheritance_layout : public has_one_base::type> { + }; +} + +#endif + +namespace fakeit { + + struct VirtualTableBase { + + static VirtualTableBase &getVTable(void *instance) { + fakeit::VirtualTableBase *vt = (fakeit::VirtualTableBase *) (instance); + return *vt; + } + + VirtualTableBase(void **firstMethod) : _firstMethod(firstMethod) { } + + void *getCookie(int index) { + return _firstMethod[-3 - index]; + } + + void setCookie(int index, void *value) { + _firstMethod[-3 - index] = value; + } + + void *getMethod(unsigned int index) const { + return _firstMethod[index]; + } + + void setMethod(unsigned int index, void *method) { + _firstMethod[index] = method; + } + + protected: + void **_firstMethod; + }; + + template + struct VirtualTable : public VirtualTableBase { + +#ifndef __clang__ + static_assert(is_simple_inheritance_layout::value, "Can't mock a type with multiple inheritance"); +#endif + + class Handle { + + friend struct VirtualTable; + void **firstMethod; + + Handle(void **method) : + firstMethod(method) { + } + + public: + + VirtualTable &restore() { + VirtualTable *vt = (VirtualTable *) this; + return *vt; + } + }; + + static VirtualTable &getVTable(C &instance) { + fakeit::VirtualTable *vt = (fakeit::VirtualTable *) (&instance); + return *vt; + } + + void copyFrom(VirtualTable &from) { + unsigned int size = VTUtils::getVTSize(); + + for (size_t i = 0; i < size; ++i) { + _firstMethod[i] = from.getMethod(i); + } + } + + VirtualTable() : + VirtualTable(buildVTArray()) { + } + + void dispose() { + _firstMethod--; + _firstMethod--; + _firstMethod -= numOfCookies; + delete[] _firstMethod; + } + + unsigned int dtor(int) { + C *c = (C *) this; + C &cRef = *c; + auto vt = VirtualTable::getVTable(cRef); + unsigned int index = VTUtils::getDestructorOffset(); + void *dtorPtr = vt.getMethod(index); + void(*method)(C *) = union_cast(dtorPtr); + method(c); + return 0; + } + + + void setDtor(void *method) { + unsigned int index = VTUtils::getDestructorOffset(); + void *dtorPtr = union_cast(&VirtualTable::dtor); + + + _firstMethod[index] = method; + + _firstMethod[index + 1] = dtorPtr; + } + + + unsigned int getSize() { + return VTUtils::getVTSize(); + } + + void initAll(void *value) { + unsigned int size = getSize(); + for (unsigned int i = 0; i < size; i++) { + setMethod(i, value); + } + } + + const std::type_info *getTypeId() { + return (const std::type_info *) (_firstMethod[-1]); + } + + Handle createHandle() { + Handle h(_firstMethod); + return h; + } + + private: + static const unsigned int numOfCookies = 2; + + static void **buildVTArray() { + int size = VTUtils::getVTSize(); + auto array = new void *[size + 2 + numOfCookies]{}; + array += numOfCookies; + array++; + array[0] = const_cast(&typeid(C)); + array++; + return array; + } + + VirtualTable(void **firstMethod) : VirtualTableBase(firstMethod) { + } + + }; +} +#endif +namespace fakeit { + + struct NoMoreRecordedActionException { + }; + + template + struct MethodInvocationHandler : Destructible { + virtual R handleMethodInvocation(const typename fakeit::production_arg::type... args) = 0; + }; + +} +#include + +namespace fakeit { + +#ifdef __GNUG__ +#ifndef __clang__ +#pragma GCC diagnostic ignored "-Wpedantic" +#endif +#endif + + +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable : 4200 ) +#endif + + + template + class FakeObject { + + VirtualTable vtable; + + static const size_t SIZE = sizeof(C) - sizeof(VirtualTable); + char instanceArea[SIZE ? SIZE : 0]; + + FakeObject(FakeObject const &) = delete; + FakeObject &operator=(FakeObject const &) = delete; + + public: + + FakeObject() : vtable() { + initializeDataMembersArea(); + } + + ~FakeObject() { + vtable.dispose(); + } + + void initializeDataMembersArea() { + for (size_t i = 0; i < SIZE; ++i) instanceArea[i] = (char) 0; + } + + void setMethod(unsigned int index, void *method) { + vtable.setMethod(index, method); + } + + VirtualTable &getVirtualTable() { + return vtable; + } + + void setVirtualTable(VirtualTable &t) { + vtable = t; + } + + void setDtor(void *dtor) { + vtable.setDtor(dtor); + } + }; + +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + +#ifdef __GNUG__ +#ifndef __clang__ +#pragma GCC diagnostic pop +#endif +#endif + +} +namespace fakeit { + + struct MethodProxy { + + MethodProxy(unsigned int id, unsigned int offset, void *vMethod) : + _id(id), + _offset(offset), + _vMethod(vMethod) { + } + + unsigned int getOffset() const { + return _offset; + } + + unsigned int getId() const { + return _id; + } + + void *getProxy() const { + return union_cast(_vMethod); + } + + private: + unsigned int _id; + unsigned int _offset; + void *_vMethod; + }; +} +#include + + +namespace fakeit { + + struct InvocationHandlerCollection { + static const unsigned int VT_COOKIE_INDEX = 0; + + virtual Destructible *getInvocatoinHandlerPtrById(unsigned int index) = 0; + + static InvocationHandlerCollection *getInvocationHandlerCollection(void *instance) { + VirtualTableBase &vt = VirtualTableBase::getVTable(instance); + InvocationHandlerCollection *invocationHandlerCollection = (InvocationHandlerCollection *) vt.getCookie( + InvocationHandlerCollection::VT_COOKIE_INDEX); + return invocationHandlerCollection; + } + }; + + + template + class MethodProxyCreator { + + + + public: + + template + MethodProxy createMethodProxy(unsigned int offset) { + return MethodProxy(id, offset, union_cast(&MethodProxyCreator::methodProxyX < id > )); + } + + protected: + + R methodProxy(unsigned int id, const typename fakeit::production_arg::type... args) { + InvocationHandlerCollection *invocationHandlerCollection = InvocationHandlerCollection::getInvocationHandlerCollection( + this); + MethodInvocationHandler *invocationHandler = + (MethodInvocationHandler *) invocationHandlerCollection->getInvocatoinHandlerPtrById( + id); + return invocationHandler->handleMethodInvocation(std::forward::type>(args)...); + } + + template + R methodProxyX(arglist ... args) { + return methodProxy(id, std::forward::type>(args)...); + } + }; +} + +namespace fakeit { + + class InvocationHandlers : public InvocationHandlerCollection { + std::vector> &_methodMocks; + std::vector &_offsets; + + unsigned int getOffset(unsigned int id) const + { + unsigned int offset = 0; + for (; offset < _offsets.size(); offset++) { + if (_offsets[offset] == id) { + break; + } + } + return offset; + } + + public: + InvocationHandlers( + std::vector> &methodMocks, + std::vector &offsets) : + _methodMocks(methodMocks), _offsets(offsets) { + } + + Destructible *getInvocatoinHandlerPtrById(unsigned int id) override { + unsigned int offset = getOffset(id); + std::shared_ptr ptr = _methodMocks[offset]; + return ptr.get(); + } + + }; + + template + struct DynamicProxy { + + static_assert(std::is_polymorphic::value, "DynamicProxy requires a polymorphic type"); + + DynamicProxy(C &inst) : + instance(inst), + originalVtHandle(VirtualTable::getVTable(instance).createHandle()), + _methodMocks(VTUtils::getVTSize()), + _offsets(VTUtils::getVTSize()), + _invocationHandlers(_methodMocks, _offsets) { + _cloneVt.copyFrom(originalVtHandle.restore()); + _cloneVt.setCookie(InvocationHandlerCollection::VT_COOKIE_INDEX, &_invocationHandlers); + getFake().setVirtualTable(_cloneVt); + } + + void detach() { + getFake().setVirtualTable(originalVtHandle.restore()); + } + + ~DynamicProxy() { + _cloneVt.dispose(); + } + + C &get() { + return instance; + } + + void Reset() { + _methodMocks = {}; + _methodMocks.resize(VTUtils::getVTSize()); + _members = {}; + _offsets = {}; + _offsets.resize(VTUtils::getVTSize()); + _cloneVt.copyFrom(originalVtHandle.restore()); + } + + void Clear() + { + } + + template + void stubMethod(R(C::*vMethod)(arglist...), MethodInvocationHandler *methodInvocationHandler) { + auto offset = VTUtils::getOffset(vMethod); + MethodProxyCreator creator; + bind(creator.template createMethodProxy(offset), methodInvocationHandler); + } + + void stubDtor(MethodInvocationHandler *methodInvocationHandler) { + auto offset = VTUtils::getDestructorOffset(); + MethodProxyCreator creator; + bindDtor(creator.createMethodProxy<0>(offset), methodInvocationHandler); + } + + template + bool isMethodStubbed(R(C::*vMethod)(arglist...)) { + unsigned int offset = VTUtils::getOffset(vMethod); + return isBinded(offset); + } + + bool isDtorStubbed() { + unsigned int offset = VTUtils::getDestructorOffset(); + return isBinded(offset); + } + + template + Destructible *getMethodMock(R(C::*vMethod)(arglist...)) { + auto offset = VTUtils::getOffset(vMethod); + std::shared_ptr ptr = _methodMocks[offset]; + return ptr.get(); + } + + Destructible *getDtorMock() { + auto offset = VTUtils::getDestructorOffset(); + std::shared_ptr ptr = _methodMocks[offset]; + return ptr.get(); + } + + template + void stubDataMember(DATA_TYPE C::*member, const arglist &... initargs) { + DATA_TYPE C::*theMember = (DATA_TYPE C::*) member; + C &mock = get(); + DATA_TYPE *memberPtr = &(mock.*theMember); + _members.push_back( + std::shared_ptr > + {new DataMemeberWrapper < DATA_TYPE, arglist...>(memberPtr, + initargs...)}); + } + + template + void getMethodMocks(std::vector &into) const { + for (std::shared_ptr ptr : _methodMocks) { + DATA_TYPE p = dynamic_cast(ptr.get()); + if (p) { + into.push_back(p); + } + } + } + + VirtualTable &getOriginalVT() { + VirtualTable &vt = originalVtHandle.restore(); + return vt; + } + + private: + + template + class DataMemeberWrapper : public Destructible { + private: + DATA_TYPE *dataMember; + public: + DataMemeberWrapper(DATA_TYPE *dataMem, const arglist &... initargs) : + dataMember(dataMem) { + new(dataMember) DATA_TYPE{initargs ...}; + } + + ~DataMemeberWrapper() override + { + dataMember->~DATA_TYPE(); + } + }; + + static_assert(sizeof(C) == sizeof(FakeObject), "This is a problem"); + + C &instance; + typename VirtualTable::Handle originalVtHandle; + VirtualTable _cloneVt; + + std::vector> _methodMocks; + std::vector> _members; + std::vector _offsets; + InvocationHandlers _invocationHandlers; + + FakeObject &getFake() { + return reinterpret_cast &>(instance); + } + + void bind(const MethodProxy &methodProxy, Destructible *invocationHandler) { + getFake().setMethod(methodProxy.getOffset(), methodProxy.getProxy()); + _methodMocks[methodProxy.getOffset()].reset(invocationHandler); + _offsets[methodProxy.getOffset()] = methodProxy.getId(); + } + + void bindDtor(const MethodProxy &methodProxy, Destructible *invocationHandler) { + getFake().setDtor(methodProxy.getProxy()); + _methodMocks[methodProxy.getOffset()].reset(invocationHandler); + _offsets[methodProxy.getOffset()] = methodProxy.getId(); + } + + template + DATA_TYPE getMethodMock(unsigned int offset) { + std::shared_ptr ptr = _methodMocks[offset]; + return dynamic_cast(ptr.get()); + } + + template + void checkMultipleInheritance() { + C *ptr = (C *) (unsigned int) 1; + BaseClass *basePtr = ptr; + int delta = (unsigned long) basePtr - (unsigned long) ptr; + if (delta > 0) { + + + throw std::invalid_argument(std::string("multiple inheritance is not supported")); + } + } + + bool isBinded(unsigned int offset) { + std::shared_ptr ptr = _methodMocks[offset]; + return ptr.get() != nullptr; + } + + }; +} +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fakeit { + + template + struct apply_func { + template + static R applyTuple(std::function f, std::tuple &t, Args &... args) { + return apply_func::template applyTuple(f, t, std::get(t), args...); + } + }; + + template<> + struct apply_func < 0 > { + template + static R applyTuple(std::function f, std::tuple & , Args &... args) { + return f(args...); + } + }; + + struct TupleDispatcher { + + template + static R applyTuple(std::function f, std::tuple &t) { + return apply_func::template applyTuple(f, t); + } + + template + static R invoke(std::function func, const std::tuple &arguments) { + std::tuple &args = const_cast &>(arguments); + return applyTuple(func, args); + } + + template + static void for_each(TupleType &&, FunctionType &, + std::integral_constant::type>::value>) { + } + + template::type>::value>::type> + static void for_each(TupleType &&t, FunctionType &f, std::integral_constant) { + f(I, std::get < I >(t)); + for_each(std::forward < TupleType >(t), f, std::integral_constant()); + } + + template + static void for_each(TupleType &&t, FunctionType &f) { + for_each(std::forward < TupleType >(t), f, std::integral_constant()); + } + + template + static void for_each(TupleType1 &&, TupleType2 &&, FunctionType &, + std::integral_constant::type>::value>) { + } + + template::type>::value>::type> + static void for_each(TupleType1 &&t, TupleType2 &&t2, FunctionType &f, std::integral_constant) { + f(I, std::get < I >(t), std::get < I >(t2)); + for_each(std::forward < TupleType1 >(t), std::forward < TupleType2 >(t2), f, std::integral_constant()); + } + + template + static void for_each(TupleType1 &&t, TupleType2 &&t2, FunctionType &f) { + for_each(std::forward < TupleType1 >(t), std::forward < TupleType2 >(t2), f, std::integral_constant()); + } + }; +} +namespace fakeit { + + template + struct ActualInvocationHandler : Destructible { + virtual R handleMethodInvocation(ArgumentsTuple & args) = 0; + }; + +} +#include +#include +#include +#include +#include +#include + +namespace fakeit { + + struct DefaultValueInstatiationException { + virtual ~DefaultValueInstatiationException() = default; + + virtual std::string what() const = 0; + }; + + + template + struct is_constructible_type { + static const bool value = + std::is_default_constructible::type>::value + && !std::is_abstract::type>::value; + }; + + template + struct DefaultValue; + + template + struct DefaultValue::value>::type> { + static C &value() { + if (std::is_reference::value) { + typename naked_type::type *ptr = nullptr; + return *ptr; + } + + class Exception : public DefaultValueInstatiationException { + virtual std::string what() const + + override { + return (std::string("Type ") + std::string(typeid(C).name()) + + std::string( + " is not default constructible. Could not instantiate a default return value")).c_str(); + } + }; + + throw Exception(); + } + }; + + template + struct DefaultValue::value>::type> { + static C &value() { + static typename naked_type::type val{}; + return val; + } + }; + + + template<> + struct DefaultValue { + static void value() { + return; + } + }; + + template<> + struct DefaultValue { + static bool &value() { + static bool value{false}; + return value; + } + }; + + template<> + struct DefaultValue { + static char &value() { + static char value{0}; + return value; + } + }; + + template<> + struct DefaultValue { + static char16_t &value() { + static char16_t value{0}; + return value; + } + }; + + template<> + struct DefaultValue { + static char32_t &value() { + static char32_t value{0}; + return value; + } + }; + + template<> + struct DefaultValue { + static wchar_t &value() { + static wchar_t value{0}; + return value; + } + }; + + template<> + struct DefaultValue { + static short &value() { + static short value{0}; + return value; + } + }; + + template<> + struct DefaultValue { + static int &value() { + static int value{0}; + return value; + } + }; + + template<> + struct DefaultValue { + static long &value() { + static long value{0}; + return value; + } + }; + + template<> + struct DefaultValue { + static long long &value() { + static long long value{0}; + return value; + } + }; + + template<> + struct DefaultValue { + static std::string &value() { + static std::string value{}; + return value; + } + }; + +} +namespace fakeit { + + struct IMatcher : Destructible { + ~IMatcher() = default; + virtual std::string format() const = 0; + }; + + template + struct TypedMatcher : IMatcher { + virtual bool matches(const T &actual) const = 0; + }; + + template + struct TypedMatcherCreator { + + virtual ~TypedMatcherCreator() = default; + + virtual TypedMatcher *createMatcher() const = 0; + }; + + template + struct ComparisonMatcherCreator : public TypedMatcherCreator { + + virtual ~ComparisonMatcherCreator() = default; + + ComparisonMatcherCreator(const T &arg) + : _expected(arg) { + } + + struct Matcher : public TypedMatcher { + Matcher(const T &expected) + : _expected(expected) { + } + + const T _expected; + }; + + const T &_expected; + }; + + namespace internal { + template + struct TypedAnyMatcher : public TypedMatcherCreator { + + virtual ~TypedAnyMatcher() = default; + + TypedAnyMatcher() { + } + + struct Matcher : public TypedMatcher { + virtual bool matches(const T &) const override { + return true; + } + + virtual std::string format() const override { + return "Any"; + } + }; + + virtual TypedMatcher *createMatcher() const override { + return new Matcher(); + } + + }; + + template + struct EqMatcherCreator : public ComparisonMatcherCreator { + + virtual ~EqMatcherCreator() = default; + + EqMatcherCreator(const T &expected) + : ComparisonMatcherCreator(expected) { + } + + struct Matcher : public ComparisonMatcherCreator::Matcher { + Matcher(const T &expected) + : ComparisonMatcherCreator::Matcher(expected) { + } + + virtual std::string format() const override { + return TypeFormatter::format(this->_expected); + } + + virtual bool matches(const T &actual) const override { + return actual == this->_expected; + } + }; + + virtual TypedMatcher *createMatcher() const { + return new Matcher(this->_expected); + } + + }; + + template + struct GtMatcherCreator : public ComparisonMatcherCreator { + + virtual ~GtMatcherCreator() = default; + + GtMatcherCreator(const T &expected) + : ComparisonMatcherCreator(expected) { + } + + struct Matcher : public ComparisonMatcherCreator::Matcher { + Matcher(const T &expected) + : ComparisonMatcherCreator::Matcher(expected) { + } + + virtual bool matches(const T &actual) const override { + return actual > this->_expected; + } + + virtual std::string format() const override { + return std::string(">") + TypeFormatter::format(this->_expected); + } + }; + + virtual TypedMatcher *createMatcher() const override { + return new Matcher(this->_expected); + } + }; + + template + struct GeMatcherCreator : public ComparisonMatcherCreator { + + virtual ~GeMatcherCreator() = default; + + GeMatcherCreator(const T &expected) + : ComparisonMatcherCreator(expected) { + } + + struct Matcher : public ComparisonMatcherCreator::Matcher { + Matcher(const T &expected) + : ComparisonMatcherCreator::Matcher(expected) { + } + + virtual bool matches(const T &actual) const override { + return actual >= this->_expected; + } + + virtual std::string format() const override { + return std::string(">=") + TypeFormatter::format(this->_expected); + } + }; + + virtual TypedMatcher *createMatcher() const override { + return new Matcher(this->_expected); + } + }; + + template + struct LtMatcherCreator : public ComparisonMatcherCreator { + + virtual ~LtMatcherCreator() = default; + + LtMatcherCreator(const T &expected) + : ComparisonMatcherCreator(expected) { + } + + struct Matcher : public ComparisonMatcherCreator::Matcher { + Matcher(const T &expected) + : ComparisonMatcherCreator::Matcher(expected) { + } + + virtual bool matches(const T &actual) const override { + return actual < this->_expected; + } + + virtual std::string format() const override { + return std::string("<") + TypeFormatter::format(this->_expected); + } + }; + + virtual TypedMatcher *createMatcher() const override { + return new Matcher(this->_expected); + } + + }; + + template + struct LeMatcherCreator : public ComparisonMatcherCreator { + + virtual ~LeMatcherCreator() = default; + + LeMatcherCreator(const T &expected) + : ComparisonMatcherCreator(expected) { + } + + struct Matcher : public ComparisonMatcherCreator::Matcher { + Matcher(const T &expected) + : ComparisonMatcherCreator::Matcher(expected) { + } + + virtual bool matches(const T &actual) const override { + return actual <= this->_expected; + } + + virtual std::string format() const override { + return std::string("<=") + TypeFormatter::format(this->_expected); + } + }; + + virtual TypedMatcher *createMatcher() const override { + return new Matcher(this->_expected); + } + + }; + + template + struct NeMatcherCreator : public ComparisonMatcherCreator { + + virtual ~NeMatcherCreator() = default; + + NeMatcherCreator(const T &expected) + : ComparisonMatcherCreator(expected) { + } + + struct Matcher : public ComparisonMatcherCreator::Matcher { + Matcher(const T &expected) + : ComparisonMatcherCreator::Matcher(expected) { + } + + virtual bool matches(const T &actual) const override { + return actual != this->_expected; + } + + virtual std::string format() const override { + return std::string("!=") + TypeFormatter::format(this->_expected); + } + + }; + + virtual TypedMatcher *createMatcher() const override { + return new Matcher(this->_expected); + } + + }; + } + + struct AnyMatcher { + } static _; + + template + internal::TypedAnyMatcher Any() { + internal::TypedAnyMatcher rv; + return rv; + } + + template + internal::EqMatcherCreator Eq(const T &arg) { + internal::EqMatcherCreator rv(arg); + return rv; + } + + template + internal::GtMatcherCreator Gt(const T &arg) { + internal::GtMatcherCreator rv(arg); + return rv; + } + + template + internal::GeMatcherCreator Ge(const T &arg) { + internal::GeMatcherCreator rv(arg); + return rv; + } + + template + internal::LtMatcherCreator Lt(const T &arg) { + internal::LtMatcherCreator rv(arg); + return rv; + } + + template + internal::LeMatcherCreator Le(const T &arg) { + internal::LeMatcherCreator rv(arg); + return rv; + } + + template + internal::NeMatcherCreator Ne(const T &arg) { + internal::NeMatcherCreator rv(arg); + return rv; + } + +} + +namespace fakeit { + + template + struct ArgumentsMatcherInvocationMatcher : public ActualInvocation::Matcher { + + virtual ~ArgumentsMatcherInvocationMatcher() { + for (unsigned int i = 0; i < _matchers.size(); i++) + delete _matchers[i]; + } + + ArgumentsMatcherInvocationMatcher(const std::vector &args) + : _matchers(args) { + } + + virtual bool matches(ActualInvocation &invocation) override { + if (invocation.getActualMatcher() == this) + return true; + return matches(invocation.getActualArguments()); + } + + virtual std::string format() const override { + std::ostringstream out; + out << "("; + for (unsigned int i = 0; i < _matchers.size(); i++) { + if (i > 0) out << ", "; + IMatcher *m = dynamic_cast(_matchers[i]); + out << m->format(); + } + out << ")"; + return out.str(); + } + + private: + + struct MatchingLambda { + MatchingLambda(const std::vector &matchers) + : _matchers(matchers) { + } + + template + void operator()(int index, A &actualArg) { + TypedMatcher::type> *matcher = + dynamic_cast::type> *>(_matchers[index]); + if (_matching) + _matching = matcher->matches(actualArg); + } + + bool isMatching() { + return _matching; + } + + private: + bool _matching = true; + const std::vector &_matchers; + }; + + virtual bool matches(ArgumentsTuple& actualArguments) { + MatchingLambda l(_matchers); + fakeit::TupleDispatcher::for_each(actualArguments, l); + return l.isMatching(); + } + + const std::vector _matchers; + }; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + template + struct UserDefinedInvocationMatcher : ActualInvocation::Matcher { + virtual ~UserDefinedInvocationMatcher() = default; + + UserDefinedInvocationMatcher(std::function match) + : matcher{match} { + } + + virtual bool matches(ActualInvocation &invocation) override { + if (invocation.getActualMatcher() == this) + return true; + return matches(invocation.getActualArguments()); + } + + virtual std::string format() const override { + return {"( user defined matcher )"}; + } + + private: + virtual bool matches(ArgumentsTuple& actualArguments) { + return TupleDispatcher::invoke::type...>(matcher, actualArguments); + } + + const std::function matcher; + }; + + template + struct DefaultInvocationMatcher : public ActualInvocation::Matcher { + + virtual ~DefaultInvocationMatcher() = default; + + DefaultInvocationMatcher() { + } + + virtual bool matches(ActualInvocation &invocation) override { + return matches(invocation.getActualArguments()); + } + + virtual std::string format() const override { + return {"( Any arguments )"}; + } + + private: + + virtual bool matches(const ArgumentsTuple&) { + return true; + } + }; + +} + +namespace fakeit { + + + template + class RecordedMethodBody : public MethodInvocationHandler, public ActualInvocationsSource, public ActualInvocationsContainer { + + struct MatchedInvocationHandler : ActualInvocationHandler { + + virtual ~MatchedInvocationHandler() = default; + + MatchedInvocationHandler(typename ActualInvocation::Matcher *matcher, + ActualInvocationHandler *invocationHandler) : + _matcher{matcher}, _invocationHandler{invocationHandler} { + } + + virtual R handleMethodInvocation(ArgumentsTuple & args) override + { + Destructible &destructable = *_invocationHandler; + ActualInvocationHandler &invocationHandler = dynamic_cast &>(destructable); + return invocationHandler.handleMethodInvocation(args); + } + + typename ActualInvocation::Matcher &getMatcher() const { + Destructible &destructable = *_matcher; + typename ActualInvocation::Matcher &matcher = dynamic_cast::Matcher &>(destructable); + return matcher; + } + + private: + std::shared_ptr _matcher; + std::shared_ptr _invocationHandler; + }; + + + FakeitContext &_fakeit; + MethodInfo _method; + + std::vector> _invocationHandlers; + std::vector> _actualInvocations; + + MatchedInvocationHandler *buildMatchedInvocationHandler( + typename ActualInvocation::Matcher *invocationMatcher, + ActualInvocationHandler *invocationHandler) { + return new MatchedInvocationHandler(invocationMatcher, invocationHandler); + } + + MatchedInvocationHandler *getInvocationHandlerForActualArgs(ActualInvocation &invocation) { + for (auto i = _invocationHandlers.rbegin(); i != _invocationHandlers.rend(); ++i) { + std::shared_ptr curr = *i; + Destructible &destructable = *curr; + MatchedInvocationHandler &im = asMatchedInvocationHandler(destructable); + if (im.getMatcher().matches(invocation)) { + return &im; + } + } + return nullptr; + } + + MatchedInvocationHandler &asMatchedInvocationHandler(Destructible &destructable) { + MatchedInvocationHandler &im = dynamic_cast(destructable); + return im; + } + + ActualInvocation &asActualInvocation(Destructible &destructable) const { + ActualInvocation &invocation = dynamic_cast &>(destructable); + return invocation; + } + + public: + + RecordedMethodBody(FakeitContext &fakeit, std::string name) : + _fakeit(fakeit), _method{MethodInfo::nextMethodOrdinal(), name} { } + + virtual ~RecordedMethodBody() NO_THROWS { + } + + MethodInfo &getMethod() { + return _method; + } + + bool isOfMethod(MethodInfo &method) { + + return method.id() == _method.id(); + } + + void addMethodInvocationHandler(typename ActualInvocation::Matcher *matcher, + ActualInvocationHandler *invocationHandler) { + ActualInvocationHandler *mock = buildMatchedInvocationHandler(matcher, invocationHandler); + std::shared_ptr destructable{mock}; + _invocationHandlers.push_back(destructable); + } + + void reset() { + _invocationHandlers.clear(); + _actualInvocations.clear(); + } + + void clear() override { + _actualInvocations.clear(); + } + + R handleMethodInvocation(const typename fakeit::production_arg::type... args) override { + unsigned int ordinal = Invocation::nextInvocationOrdinal(); + MethodInfo &method = this->getMethod(); + auto actualInvocation = new ActualInvocation(ordinal, method, std::forward::type>(args)...); + + + std::shared_ptr actualInvocationDtor{actualInvocation}; + + auto invocationHandler = getInvocationHandlerForActualArgs(*actualInvocation); + if (invocationHandler) { + auto &matcher = invocationHandler->getMatcher(); + actualInvocation->setActualMatcher(&matcher); + _actualInvocations.push_back(actualInvocationDtor); + try { + return invocationHandler->handleMethodInvocation(actualInvocation->getActualArguments()); + } catch (NoMoreRecordedActionException &) { + } + } + + UnexpectedMethodCallEvent event(UnexpectedType::Unmatched, *actualInvocation); + _fakeit.handle(event); + std::string format{_fakeit.format(event)}; + UnexpectedMethodCallException e(format); + throw e; + } + + void scanActualInvocations(const std::function &)> &scanner) { + for (auto destructablePtr : _actualInvocations) { + ActualInvocation &invocation = asActualInvocation(*destructablePtr); + scanner(invocation); + } + } + + void getActualInvocations(std::unordered_set &into) const override { + for (auto destructablePtr : _actualInvocations) { + Invocation &invocation = asActualInvocation(*destructablePtr); + into.insert(&invocation); + } + } + + void setMethodDetails(const std::string &mockName, const std::string &methodName) { + const std::string fullName{mockName + "." + methodName}; + _method.setName(fullName); + } + + }; + +} +#include +#include +#include +#include +#include +#include + +namespace fakeit { + + struct Quantity { + Quantity(const int q) : + quantity(q) { + } + + const int quantity; + } static Once(1); + + template + struct Quantifier : public Quantity { + Quantifier(const int q, const R &val) : + Quantity(q), value(val) { + } + + const R &value; + }; + + template<> + struct Quantifier : public Quantity { + explicit Quantifier(const int q) : + Quantity(q) { + } + }; + + struct QuantifierFunctor : public Quantifier { + QuantifierFunctor(const int q) : + Quantifier(q) { + } + + template + Quantifier operator()(const R &value) { + return Quantifier(quantity, value); + } + }; + + template + struct Times : public Quantity { + + Times() : Quantity(q) { } + + template + static Quantifier of(const R &value) { + return Quantifier(q, value); + } + + static Quantifier Void() { + return Quantifier(q); + } + }; + +#if defined (__GNUG__) || (_MSC_VER >= 1900) + + inline QuantifierFunctor operator + "" + + _Times(unsigned long long n) { + return QuantifierFunctor((int) n); + } + + inline QuantifierFunctor operator + "" + + _Time(unsigned long long n) { + if (n != 1) + throw std::invalid_argument("Only 1_Time is supported. Use X_Times (with s) if X is bigger than 1"); + return QuantifierFunctor((int) n); + } + +#endif + +} +#include +#include +#include +#include + + +namespace fakeit { + + template + struct Action : Destructible { + virtual R invoke(const ArgumentsTuple &) = 0; + + virtual bool isDone() = 0; + }; + + template + struct Repeat : Action { + virtual ~Repeat() = default; + + Repeat(std::function::type...)> func) : + f(func), times(1) { + } + + Repeat(std::function::type...)> func, long t) : + f(func), times(t) { + } + + virtual R invoke(const ArgumentsTuple & args) override { + times--; + return TupleDispatcher::invoke(f, args); + } + + virtual bool isDone() override { + return times == 0; + } + + private: + std::function::type...)> f; + long times; + }; + + template + struct RepeatForever : public Action { + + virtual ~RepeatForever() = default; + + RepeatForever(std::function::type...)> func) : + f(func) { + } + + virtual R invoke(const ArgumentsTuple & args) override { + return TupleDispatcher::invoke(f, args); + } + + virtual bool isDone() override { + return false; + } + + private: + std::function::type...)> f; + }; + + template + struct ReturnDefaultValue : public Action { + virtual ~ReturnDefaultValue() = default; + + virtual R invoke(const ArgumentsTuple &) override { + return DefaultValue::value(); + } + + virtual bool isDone() override { + return false; + } + }; + + template + struct ReturnDelegateValue : public Action { + + ReturnDelegateValue(std::function::type...)> delegate) : _delegate(delegate) { } + + virtual ~ReturnDelegateValue() = default; + + virtual R invoke(const ArgumentsTuple & args) override { + return TupleDispatcher::invoke(_delegate, args); + } + + virtual bool isDone() override { + return false; + } + + private: + std::function::type...)> _delegate; + }; + +} + +namespace fakeit { + + template + struct MethodStubbingProgress { + + virtual ~MethodStubbingProgress() THROWS { + } + + template + typename std::enable_if::value, MethodStubbingProgress &>::type + Return(const R &r) { + return Do([r](const typename fakeit::test_arg::type...) -> R { return r; }); + } + + template + typename std::enable_if::value, MethodStubbingProgress &>::type + Return(const R &r) { + return Do([&r](const typename fakeit::test_arg::type...) -> R { return r; }); + } + + MethodStubbingProgress & + Return(const Quantifier &q) { + const R &value = q.value; + auto method = [value](const arglist &...) -> R { return value; }; + return DoImpl(new Repeat(method, q.quantity)); + } + + template + MethodStubbingProgress & + Return(const first &f, const second &s, const tail &... t) { + Return(f); + return Return(s, t...); + } + + + template + typename std::enable_if::value, void>::type + AlwaysReturn(const R &r) { + return AlwaysDo([r](const typename fakeit::test_arg::type...) -> R { return r; }); + } + + template + typename std::enable_if::value, void>::type + AlwaysReturn(const R &r) { + return AlwaysDo([&r](const typename fakeit::test_arg::type...) -> R { return r; }); + } + + MethodStubbingProgress & + Return() { + return Do([](const typename fakeit::test_arg::type...) -> R { return DefaultValue::value(); }); + } + + void AlwaysReturn() { + return AlwaysDo([](const typename fakeit::test_arg::type...) -> R { return DefaultValue::value(); }); + } + + template + MethodStubbingProgress &Throw(const E &e) { + return Do([e](const typename fakeit::test_arg::type...) -> R { throw e; }); + } + + template + MethodStubbingProgress & + Throw(const Quantifier &q) { + const E &value = q.value; + auto method = [value](const arglist &...) -> R { throw value; }; + return DoImpl(new Repeat(method, q.quantity)); + } + + template + MethodStubbingProgress & + Throw(const first &f, const second &s, const tail &... t) { + Throw(f); + return Throw(s, t...); + } + + template + void AlwaysThrow(const E &e) { + return AlwaysDo([e](const typename fakeit::test_arg::type...) -> R { throw e; }); + } + + virtual MethodStubbingProgress & + Do(std::function::type...)> method) { + return DoImpl(new Repeat(method)); + } + + template + MethodStubbingProgress & + Do(const Quantifier &q) { + return DoImpl(new Repeat(q.value, q.quantity)); + } + + template + MethodStubbingProgress & + Do(const first &f, const second &s, const tail &... t) { + Do(f); + return Do(s, t...); + } + + virtual void AlwaysDo(std::function::type...)> method) { + DoImpl(new RepeatForever(method)); + } + + protected: + + virtual MethodStubbingProgress &DoImpl(Action *action) = 0; + + private: + MethodStubbingProgress &operator=(const MethodStubbingProgress &other) = delete; + }; + + + template + struct MethodStubbingProgress { + + virtual ~MethodStubbingProgress() THROWS { + } + + MethodStubbingProgress &Return() { + auto lambda = [](const typename fakeit::test_arg::type...) -> void { + return DefaultValue::value(); + }; + return Do(lambda); + } + + virtual MethodStubbingProgress &Do( + std::function::type...)> method) { + return DoImpl(new Repeat(method)); + } + + + void AlwaysReturn() { + return AlwaysDo([](const typename fakeit::test_arg::type...) -> void { return DefaultValue::value(); }); + } + + MethodStubbingProgress & + Return(const Quantifier &q) { + auto method = [](const arglist &...) -> void { return DefaultValue::value(); }; + return DoImpl(new Repeat(method, q.quantity)); + } + + template + MethodStubbingProgress &Throw(const E &e) { + return Do([e](const typename fakeit::test_arg::type...) -> void { throw e; }); + } + + template + MethodStubbingProgress & + Throw(const Quantifier &q) { + const E &value = q.value; + auto method = [value](const typename fakeit::test_arg::type...) -> void { throw value; }; + return DoImpl(new Repeat(method, q.quantity)); + } + + template + MethodStubbingProgress & + Throw(const first &f, const second &s, const tail &... t) { + Throw(f); + return Throw(s, t...); + } + + template + void AlwaysThrow(const E e) { + return AlwaysDo([e](const typename fakeit::test_arg::type...) -> void { throw e; }); + } + + template + MethodStubbingProgress & + Do(const Quantifier &q) { + return DoImpl(new Repeat(q.value, q.quantity)); + } + + template + MethodStubbingProgress & + Do(const first &f, const second &s, const tail &... t) { + Do(f); + return Do(s, t...); + } + + virtual void AlwaysDo(std::function::type...)> method) { + DoImpl(new RepeatForever(method)); + } + + protected: + + virtual MethodStubbingProgress &DoImpl(Action *action) = 0; + + private: + MethodStubbingProgress &operator=(const MethodStubbingProgress &other) = delete; + }; + + +} +#include +#include + +namespace fakeit { + + class Finally { + private: + std::function _finallyClause; + + Finally(const Finally &); + + Finally &operator=(const Finally &); + + public: + explicit Finally(std::function f) : + _finallyClause(f) { + } + + ~Finally() { + _finallyClause(); + } + }; +} + +namespace fakeit { + + + template + struct ActionSequence : ActualInvocationHandler { + + ActionSequence() { + clear(); + } + + void AppendDo(Action *action) { + append(action); + } + + virtual R handleMethodInvocation(ArgumentsTuple & args) override + { + std::shared_ptr destructablePtr = _recordedActions.front(); + Destructible &destructable = *destructablePtr; + Action &action = dynamic_cast &>(destructable); + std::function finallyClause = [&]() -> void { + if (action.isDone()) + _recordedActions.erase(_recordedActions.begin()); + }; + Finally onExit(finallyClause); + return action.invoke(args); + } + + private: + + struct NoMoreRecordedAction : Action { + + + + + + + + virtual R invoke(const ArgumentsTuple &) override { + throw NoMoreRecordedActionException(); + } + + virtual bool isDone() override { + return false; + } + }; + + void append(Action *action) { + std::shared_ptr destructable{action}; + _recordedActions.insert(_recordedActions.end() - 1, destructable); + } + + void clear() { + _recordedActions.clear(); + auto actionPtr = std::shared_ptr {new NoMoreRecordedAction()}; + _recordedActions.push_back(actionPtr); + } + + std::vector> _recordedActions; + }; + +} + +namespace fakeit { + + template + class DataMemberStubbingRoot { + private: + + public: + DataMemberStubbingRoot(const DataMemberStubbingRoot &) = default; + + DataMemberStubbingRoot() = default; + + void operator=(const DATA_TYPE&) { + } + }; + +} +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fakeit { + + struct Xaction { + virtual void commit() = 0; + }; +} + +namespace fakeit { + + + template + struct SpyingContext : Xaction { + virtual void appendAction(Action *action) = 0; + + virtual std::function getOriginalMethod() = 0; + }; +} +namespace fakeit { + + + template + struct StubbingContext : public Xaction { + virtual void appendAction(Action *action) = 0; + }; +} +#include +#include +#include +#include +#include +#include + + +namespace fakeit { + + template + class MatchersCollector { + + std::vector &_matchers; + + public: + + + template + using ArgType = typename std::tuple_element>::type; + + template + using NakedArgType = typename naked_type>::type; + + template + using ArgMatcherCreatorType = decltype(std::declval>>()); + + MatchersCollector(std::vector &matchers) + : _matchers(matchers) { + } + + void CollectMatchers() { + } + + template + typename std::enable_if< + std::is_constructible, Head>::value, void> + ::type CollectMatchers(const Head &value) { + + TypedMatcher> *d = Eq>(value).createMatcher(); + _matchers.push_back(d); + } + + template + typename std::enable_if< + std::is_constructible, Head>::value + , void> + ::type CollectMatchers(const Head &head, const Tail &... tail) { + CollectMatchers(head); + MatchersCollector c(_matchers); + c.CollectMatchers(tail...); + } + + template + typename std::enable_if< + std::is_base_of>, Head>::value, void> + ::type CollectMatchers(const Head &creator) { + TypedMatcher> *d = creator.createMatcher(); + _matchers.push_back(d); + } + + template + + typename std::enable_if< + std::is_base_of>, Head>::value, void> + ::type CollectMatchers(const Head &head, const Tail &... tail) { + CollectMatchers(head); + MatchersCollector c(_matchers); + c.CollectMatchers(tail...); + } + + template + typename std::enable_if< + std::is_same::value, void> + ::type CollectMatchers(const Head &) { + TypedMatcher> *d = Any>().createMatcher(); + _matchers.push_back(d); + } + + template + typename std::enable_if< + std::is_same::value, void> + ::type CollectMatchers(const Head &head, const Tail &... tail) { + CollectMatchers(head); + MatchersCollector c(_matchers); + c.CollectMatchers(tail...); + } + + }; + +} + +namespace fakeit { + + template + class MethodMockingContext : + public Sequence, + public ActualInvocationsSource, + public virtual StubbingContext, + public virtual SpyingContext, + private Invocation::Matcher { + public: + + struct Context : Destructible { + + + virtual typename std::function getOriginalMethod() = 0; + + virtual std::string getMethodName() = 0; + + virtual void addMethodInvocationHandler(typename ActualInvocation::Matcher *matcher, + ActualInvocationHandler *invocationHandler) = 0; + + virtual void scanActualInvocations(const std::function &)> &scanner) = 0; + + virtual void setMethodDetails(std::string mockName, std::string methodName) = 0; + + virtual bool isOfMethod(MethodInfo &method) = 0; + + virtual ActualInvocationsSource &getInvolvedMock() = 0; + }; + + private: + class Implementation { + + Context *_stubbingContext; + ActionSequence *_recordedActionSequence; + typename ActualInvocation::Matcher *_invocationMatcher; + bool _commited; + + Context &getStubbingContext() const { + return *_stubbingContext; + } + + public: + + Implementation(Context *stubbingContext) + : _stubbingContext(stubbingContext), + _recordedActionSequence(new ActionSequence()), + _invocationMatcher + { + new DefaultInvocationMatcher()}, _commited(false) { + } + + ~Implementation() { + delete _stubbingContext; + if (!_commited) { + + delete _recordedActionSequence; + delete _invocationMatcher; + } + } + + ActionSequence &getRecordedActionSequence() { + return *_recordedActionSequence; + } + + std::string format() const { + std::string s = getStubbingContext().getMethodName(); + s += _invocationMatcher->format(); + return s; + } + + void getActualInvocations(std::unordered_set &into) const { + auto scanner = [&](ActualInvocation &a) { + if (_invocationMatcher->matches(a)) { + into.insert(&a); + } + }; + getStubbingContext().scanActualInvocations(scanner); + } + + + bool matches(Invocation &invocation) { + MethodInfo &actualMethod = invocation.getMethod(); + if (!getStubbingContext().isOfMethod(actualMethod)) { + return false; + } + + ActualInvocation &actualInvocation = dynamic_cast &>(invocation); + return _invocationMatcher->matches(actualInvocation); + } + + void commit() { + getStubbingContext().addMethodInvocationHandler(_invocationMatcher, _recordedActionSequence); + _commited = true; + } + + void appendAction(Action *action) { + getRecordedActionSequence().AppendDo(action); + } + + void setMethodBodyByAssignment(std::function::type...)> method) { + appendAction(new RepeatForever(method)); + commit(); + } + + void setMethodDetails(std::string mockName, std::string methodName) { + getStubbingContext().setMethodDetails(mockName, methodName); + } + + void getInvolvedMocks(std::vector &into) const { + into.push_back(&getStubbingContext().getInvolvedMock()); + } + + typename std::function getOriginalMethod() { + return getStubbingContext().getOriginalMethod(); + } + + void setInvocationMatcher(typename ActualInvocation::Matcher *matcher) { + delete _invocationMatcher; + _invocationMatcher = matcher; + } + }; + + protected: + + MethodMockingContext(Context *stubbingContext) + : _impl{new Implementation(stubbingContext)} { + } + + MethodMockingContext(MethodMockingContext &) = default; + + + + MethodMockingContext(MethodMockingContext &&other) + : _impl(std::move(other._impl)) { + } + + virtual ~MethodMockingContext() NO_THROWS { } + + std::string format() const override { + return _impl->format(); + } + + unsigned int size() const override { + return 1; + } + + + void getInvolvedMocks(std::vector &into) const override { + _impl->getInvolvedMocks(into); + } + + void getExpectedSequence(std::vector &into) const override { + const Invocation::Matcher *b = this; + Invocation::Matcher *c = const_cast(b); + into.push_back(c); + } + + + void getActualInvocations(std::unordered_set &into) const override { + _impl->getActualInvocations(into); + } + + + bool matches(Invocation &invocation) override { + return _impl->matches(invocation); + } + + void commit() override { + _impl->commit(); + } + + void setMethodDetails(std::string mockName, std::string methodName) { + _impl->setMethodDetails(mockName, methodName); + } + + void setMatchingCriteria(std::function predicate) { + typename ActualInvocation::Matcher *matcher{ + new UserDefinedInvocationMatcher(predicate)}; + _impl->setInvocationMatcher(matcher); + } + + void setMatchingCriteria(const std::vector &matchers) { + typename ActualInvocation::Matcher *matcher{ + new ArgumentsMatcherInvocationMatcher(matchers)}; + _impl->setInvocationMatcher(matcher); + } + + + void appendAction(Action *action) override { + _impl->appendAction(action); + } + + void setMethodBodyByAssignment(std::function::type...)> method) { + _impl->setMethodBodyByAssignment(method); + } + + template::type> + void setMatchingCriteria(const matcherCreators &... matcherCreator) { + std::vector matchers; + + MatchersCollector<0, arglist...> c(matchers); + c.CollectMatchers(matcherCreator...); + + MethodMockingContext::setMatchingCriteria(matchers); + } + + private: + + typename std::function getOriginalMethod() override { + return _impl->getOriginalMethod(); + } + + std::shared_ptr _impl; + }; + + template + class MockingContext : + public MethodMockingContext { + MockingContext &operator=(const MockingContext &) = delete; + + public: + + MockingContext(typename MethodMockingContext::Context *stubbingContext) + : MethodMockingContext(stubbingContext) { + } + + MockingContext(MockingContext &) = default; + + MockingContext(MockingContext &&other) + : MethodMockingContext(std::move(other)) { + } + + MockingContext &setMethodDetails(std::string mockName, std::string methodName) { + MethodMockingContext::setMethodDetails(mockName, methodName); + return *this; + } + + MockingContext &Using(const arglist &... args) { + MethodMockingContext::setMatchingCriteria(args...); + return *this; + } + + template + MockingContext &Using(const arg_matcher &... arg_matchers) { + MethodMockingContext::setMatchingCriteria(arg_matchers...); + return *this; + } + + MockingContext &Matching(std::function matcher) { + MethodMockingContext::setMatchingCriteria(matcher); + return *this; + } + + MockingContext &operator()(const arglist &... args) { + MethodMockingContext::setMatchingCriteria(args...); + return *this; + } + + MockingContext &operator()(std::function matcher) { + MethodMockingContext::setMatchingCriteria(matcher); + return *this; + } + + void operator=(std::function method) { + MethodMockingContext::setMethodBodyByAssignment(method); + } + + template + typename std::enable_if::value, void>::type operator=(const R &r) { + auto method = [r](const typename fakeit::test_arg::type...) -> R { return r; }; + MethodMockingContext::setMethodBodyByAssignment(method); + } + + template + typename std::enable_if::value, void>::type operator=(const R &r) { + auto method = [&r](const typename fakeit::test_arg::type...) -> R { return r; }; + MethodMockingContext::setMethodBodyByAssignment(method); + } + }; + + template + class MockingContext : + public MethodMockingContext { + MockingContext &operator=(const MockingContext &) = delete; + + public: + + MockingContext(typename MethodMockingContext::Context *stubbingContext) + : MethodMockingContext(stubbingContext) { + } + + MockingContext(MockingContext &) = default; + + MockingContext(MockingContext &&other) + : MethodMockingContext(std::move(other)) { + } + + MockingContext &setMethodDetails(std::string mockName, std::string methodName) { + MethodMockingContext::setMethodDetails(mockName, methodName); + return *this; + } + + MockingContext &Using(const arglist &... args) { + MethodMockingContext::setMatchingCriteria(args...); + return *this; + } + + template + MockingContext &Using(const arg_matcher &... arg_matchers) { + MethodMockingContext::setMatchingCriteria(arg_matchers...); + return *this; + } + + MockingContext &Matching(std::function matcher) { + MethodMockingContext::setMatchingCriteria(matcher); + return *this; + } + + MockingContext &operator()(const arglist &... args) { + MethodMockingContext::setMatchingCriteria(args...); + return *this; + } + + MockingContext &operator()(std::function matcher) { + MethodMockingContext::setMatchingCriteria(matcher); + return *this; + } + + void operator=(std::function method) { + MethodMockingContext::setMethodBodyByAssignment(method); + } + + }; + + class DtorMockingContext : public MethodMockingContext { + public: + + DtorMockingContext(MethodMockingContext::Context *stubbingContext) + : MethodMockingContext(stubbingContext) { + } + + DtorMockingContext(DtorMockingContext &other) : MethodMockingContext(other) { + } + + DtorMockingContext(DtorMockingContext &&other) : MethodMockingContext(std::move(other)) { + } + + void operator=(std::function method) { + MethodMockingContext::setMethodBodyByAssignment(method); + } + + DtorMockingContext &setMethodDetails(std::string mockName, std::string methodName) { + MethodMockingContext::setMethodDetails(mockName, methodName); + return *this; + } + }; + +} + +namespace fakeit { + + + template + class MockImpl : private MockObject, public virtual ActualInvocationsSource { + public: + + MockImpl(FakeitContext &fakeit, C &obj) + : MockImpl(fakeit, obj, true) { + } + + MockImpl(FakeitContext &fakeit) + : MockImpl(fakeit, *(createFakeInstance()), false) { + FakeObject *fake = reinterpret_cast *>(_instance); + fake->getVirtualTable().setCookie(1, this); + } + + virtual ~MockImpl() NO_THROWS { + _proxy.detach(); + if (_isOwner) { + FakeObject *fake = reinterpret_cast *>(_instance); + delete fake; + } + } + + void detach() { + _isOwner = false; + _proxy.detach(); + } + + + void getActualInvocations(std::unordered_set &into) const override { + std::vector vec; + _proxy.getMethodMocks(vec); + for (ActualInvocationsSource *s : vec) { + s->getActualInvocations(into); + } + } + + void initDataMembersIfOwner() + { + if (_isOwner) { + FakeObject *fake = reinterpret_cast *>(_instance); + fake->initializeDataMembersArea(); + } + } + + void reset() { + _proxy.Reset(); + initDataMembersIfOwner(); + } + + void clear() + { + std::vector vec; + _proxy.getMethodMocks(vec); + for (ActualInvocationsContainer *s : vec) { + s->clear(); + } + initDataMembersIfOwner(); + } + + virtual C &get() override { + return _proxy.get(); + } + + virtual FakeitContext &getFakeIt() override { + return _fakeit; + } + + template::value>::type> + DataMemberStubbingRoot stubDataMember(DATA_TYPE T::*member, const arglist &... ctorargs) { + _proxy.stubDataMember(member, ctorargs...); + return DataMemberStubbingRoot(); + } + + template::value>::type> + MockingContext stubMethod(R(T::*vMethod)(arglist...)) { + return MockingContext(new UniqueMethodMockingContextImpl < id, R, arglist... > + (*this, vMethod)); + } + + DtorMockingContext stubDtor() { + return DtorMockingContext(new DtorMockingContextImpl(*this)); + } + + private: + DynamicProxy _proxy; + C *_instance; + bool _isOwner; + FakeitContext &_fakeit; + + template + class MethodMockingContextBase : public MethodMockingContext::Context { + protected: + MockImpl &_mock; + + virtual RecordedMethodBody &getRecordedMethodBody() = 0; + + public: + MethodMockingContextBase(MockImpl &mock) : _mock(mock) { } + + virtual ~MethodMockingContextBase() = default; + + void addMethodInvocationHandler(typename ActualInvocation::Matcher *matcher, + ActualInvocationHandler *invocationHandler) { + getRecordedMethodBody().addMethodInvocationHandler(matcher, invocationHandler); + } + + void scanActualInvocations(const std::function &)> &scanner) { + getRecordedMethodBody().scanActualInvocations(scanner); + } + + void setMethodDetails(std::string mockName, std::string methodName) { + getRecordedMethodBody().setMethodDetails(mockName, methodName); + } + + bool isOfMethod(MethodInfo &method) { + return getRecordedMethodBody().isOfMethod(method); + } + + ActualInvocationsSource &getInvolvedMock() { + return _mock; + } + + std::string getMethodName() { + return getRecordedMethodBody().getMethod().name(); + } + + }; + + template + class MethodMockingContextImpl : public MethodMockingContextBase { + protected: + + R (C::*_vMethod)(arglist...); + + public: + virtual ~MethodMockingContextImpl() = default; + + MethodMockingContextImpl(MockImpl &mock, R (C::*vMethod)(arglist...)) + : MethodMockingContextBase(mock), _vMethod(vMethod) { + } + + + virtual std::function getOriginalMethod() override { + void *mPtr = MethodMockingContextBase::_mock.getOriginalMethod(_vMethod); + C * instance = &(MethodMockingContextBase::_mock.get()); + return [=](arglist&... args) -> R { + auto m = union_cast::type>(mPtr); + return m(instance, std::forward(args)...); + }; + } + }; + + + template + class UniqueMethodMockingContextImpl : public MethodMockingContextImpl { + protected: + + virtual RecordedMethodBody &getRecordedMethodBody() override { + return MethodMockingContextBase::_mock.template stubMethodIfNotStubbed( + MethodMockingContextBase::_mock._proxy, + MethodMockingContextImpl::_vMethod); + } + + public: + + UniqueMethodMockingContextImpl(MockImpl &mock, R (C::*vMethod)(arglist...)) + : MethodMockingContextImpl(mock, vMethod) { + } + }; + + class DtorMockingContextImpl : public MethodMockingContextBase { + + protected: + + virtual RecordedMethodBody &getRecordedMethodBody() override { + return MethodMockingContextBase::_mock.stubDtorIfNotStubbed( + MethodMockingContextBase::_mock._proxy); + } + + public: + virtual ~DtorMockingContextImpl() = default; + + DtorMockingContextImpl(MockImpl &mock) + : MethodMockingContextBase(mock) { + } + + virtual std::function getOriginalMethod() override { + C &instance = MethodMockingContextBase::_mock.get(); + return [=, &instance]() -> void { + }; + } + + }; + + static MockImpl *getMockImpl(void *instance) { + FakeObject *fake = reinterpret_cast *>(instance); + MockImpl *mock = reinterpret_cast *>(fake->getVirtualTable().getCookie( + 1)); + return mock; + } + + void unmocked() { + ActualInvocation<> invocation(Invocation::nextInvocationOrdinal(), UnknownMethod::instance()); + UnexpectedMethodCallEvent event(UnexpectedType::Unmocked, invocation); + auto &fakeit = getMockImpl(this)->_fakeit; + fakeit.handle(event); + + std::string format = fakeit.format(event); + UnexpectedMethodCallException e(format); + throw e; + } + + static C *createFakeInstance() { + FakeObject *fake = new FakeObject(); + void *unmockedMethodStubPtr = union_cast(&MockImpl::unmocked); + fake->getVirtualTable().initAll(unmockedMethodStubPtr); + return reinterpret_cast(fake); + } + + template + void *getOriginalMethod(R (C::*vMethod)(arglist...)) { + auto vt = _proxy.getOriginalVT(); + auto offset = VTUtils::getOffset(vMethod); + void *origMethodPtr = vt.getMethod(offset); + return origMethodPtr; + } + + void *getOriginalDtor() { + auto vt = _proxy.getOriginalVT(); + auto offset = VTUtils::getDestructorOffset(); + void *origMethodPtr = vt.getMethod(offset); + return origMethodPtr; + } + + template + RecordedMethodBody &stubMethodIfNotStubbed(DynamicProxy &proxy, + R (C::*vMethod)(arglist...)) { + if (!proxy.isMethodStubbed(vMethod)) { + proxy.template stubMethod(vMethod, createRecordedMethodBody < R, arglist... > (*this, vMethod)); + } + Destructible *d = proxy.getMethodMock(vMethod); + RecordedMethodBody *methodMock = dynamic_cast *>(d); + return *methodMock; + } + + RecordedMethodBody &stubDtorIfNotStubbed(DynamicProxy &proxy) { + if (!proxy.isDtorStubbed()) { + proxy.stubDtor(createRecordedDtorBody(*this)); + } + Destructible *d = proxy.getDtorMock(); + RecordedMethodBody *dtorMock = dynamic_cast *>(d); + return *dtorMock; + } + + MockImpl(FakeitContext &fakeit, C &obj, bool isSpy) + : _proxy{obj}, _instance(&obj), _isOwner(!isSpy), _fakeit(fakeit) { + } + + template + static RecordedMethodBody *createRecordedMethodBody(MockObject &mock, + R(C::*vMethod)(arglist...)) { + return new RecordedMethodBody(mock.getFakeIt(), typeid(vMethod).name()); + } + + static RecordedMethodBody *createRecordedDtorBody(MockObject &mock) { + return new RecordedMethodBody(mock.getFakeIt(), "dtor"); + } + + }; +} +namespace fakeit { + + template + struct Prototype; + + template + struct Prototype { + + typedef R Type(Args...); + + typedef R ConstType(Args...) const; + + template + struct MemberType { + + typedef Type(C::*type); + typedef ConstType(C::*cosntType); + + static type get(type t) { + return t; + } + + static cosntType getconst(cosntType t) { + return t; + } + + }; + + }; + + template + struct UniqueMethod { + R (C::*method)(arglist...); + + UniqueMethod(R (C::*vMethod)(arglist...)) : method(vMethod) { } + + int uniqueId() { + return X; + } + + + + + }; + +} + + +namespace fakeit { + namespace internal { + } + using namespace fakeit; + using namespace fakeit::internal; + + template + class Mock : public ActualInvocationsSource { + MockImpl impl; + public: + virtual ~Mock() = default; + + static_assert(std::is_polymorphic::value, "Can only mock a polymorphic type"); + + Mock() : impl(Fakeit) { + } + + explicit Mock(C &obj) : impl(Fakeit, obj) { + } + + virtual C &get() { + return impl.get(); + } + + C &operator()() { + return get(); + } + + void Reset() { + impl.reset(); + } + + void ClearInvocationHistory() { + impl.clear(); + } + + template::value>::type> + DataMemberStubbingRoot Stub(DATA_TYPE C::* member, const arglist &... ctorargs) { + return impl.stubDataMember(member, ctorargs...); + } + + template::value && std::is_base_of::value>::type> + MockingContext stub(R (T::*vMethod)(arglist...) const) { + auto methodWithoutConstVolatile = reinterpret_cast(vMethod); + return impl.template stubMethod(methodWithoutConstVolatile); + } + + template::value && std::is_base_of::value>::type> + MockingContext stub(R(T::*vMethod)(arglist...) volatile) { + auto methodWithoutConstVolatile = reinterpret_cast(vMethod); + return impl.template stubMethod(methodWithoutConstVolatile); + } + + template::value && std::is_base_of::value>::type> + MockingContext stub(R(T::*vMethod)(arglist...) const volatile) { + auto methodWithoutConstVolatile = reinterpret_cast(vMethod); + return impl.template stubMethod(methodWithoutConstVolatile); + } + + template::value && std::is_base_of::value>::type> + MockingContext stub(R(T::*vMethod)(arglist...)) { + return impl.template stubMethod(vMethod); + } + + template::value && std::is_base_of::value>::type> + MockingContext stub(R(T::*vMethod)(arglist...) const) { + auto methodWithoutConstVolatile = reinterpret_cast(vMethod); + return impl.template stubMethod(methodWithoutConstVolatile); + } + + template::value && std::is_base_of::value>::type> + MockingContext stub(R(T::*vMethod)(arglist...) volatile) { + auto methodWithoutConstVolatile = reinterpret_cast(vMethod); + return impl.template stubMethod(methodWithoutConstVolatile); + } + + template::value && std::is_base_of::value>::type> + MockingContext stub(R(T::*vMethod)(arglist...) const volatile) { + auto methodWithoutConstVolatile = reinterpret_cast(vMethod); + return impl.template stubMethod(methodWithoutConstVolatile); + } + + template::value && std::is_base_of::value>::type> + MockingContext stub(R(T::*vMethod)(arglist...)) { + auto methodWithoutConstVolatile = reinterpret_cast(vMethod); + return impl.template stubMethod(methodWithoutConstVolatile); + } + + DtorMockingContext dtor() { + return impl.stubDtor(); + } + + void getActualInvocations(std::unordered_set &into) const override { + impl.getActualInvocations(into); + } + + }; + +} + +#include + +namespace fakeit { + + class RefCount { + private: + int count; + + public: + void AddRef() { + count++; + } + + int Release() { + return --count; + } + }; + + template + class smart_ptr { + private: + T *pData; + RefCount *reference; + + public: + smart_ptr() : pData(0), reference(0) { + reference = new RefCount(); + reference->AddRef(); + } + + smart_ptr(T *pValue) : pData(pValue), reference(0) { + reference = new RefCount(); + reference->AddRef(); + } + + smart_ptr(const smart_ptr &sp) : pData(sp.pData), reference(sp.reference) { + reference->AddRef(); + } + + ~smart_ptr() THROWS { + if (reference->Release() == 0) { + delete reference; + delete pData; + } + } + + T &operator*() { + return *pData; + } + + T *operator->() { + return pData; + } + + smart_ptr &operator=(const smart_ptr &sp) { + if (this != &sp) { + + + if (reference->Release() == 0) { + delete reference; + delete pData; + } + + + + pData = sp.pData; + reference = sp.reference; + reference->AddRef(); + } + return *this; + } + }; + +} + +namespace fakeit { + + class WhenFunctor { + + struct StubbingChange { + + friend class WhenFunctor; + + virtual ~StubbingChange() THROWS { + + if (std::uncaught_exception()) { + return; + } + + _xaction.commit(); + } + + StubbingChange(StubbingChange &other) : + _xaction(other._xaction) { + } + + private: + + StubbingChange(Xaction &xaction) + : _xaction(xaction) { + } + + Xaction &_xaction; + }; + + public: + + template + struct MethodProgress : MethodStubbingProgress { + + friend class WhenFunctor; + + virtual ~MethodProgress() override = default; + + MethodProgress(MethodProgress &other) : + _progress(other._progress), _context(other._context) { + } + + MethodProgress(StubbingContext &xaction) : + _progress(new StubbingChange(xaction)), _context(xaction) { + } + + protected: + + virtual MethodStubbingProgress &DoImpl(Action *action) override { + _context.appendAction(action); + return *this; + } + + private: + smart_ptr _progress; + StubbingContext &_context; + }; + + + WhenFunctor() { + } + + template + MethodProgress operator()(const StubbingContext &stubbingContext) { + StubbingContext &rootWithoutConst = const_cast &>(stubbingContext); + MethodProgress progress(rootWithoutConst); + return progress; + } + + }; + +} +namespace fakeit { + + class FakeFunctor { + private: + template + void fake(const StubbingContext &root) { + StubbingContext &rootWithoutConst = const_cast &>(root); + rootWithoutConst.appendAction(new ReturnDefaultValue()); + rootWithoutConst.commit(); + } + + void operator()() { + } + + public: + + template + void operator()(const H &head, const M &... tail) { + fake(head); + this->operator()(tail...); + } + + }; + +} +#include +#include + + +namespace fakeit { + + struct InvocationUtils { + + static void sortByInvocationOrder(std::unordered_set &ivocations, + std::vector &result) { + auto comparator = [](Invocation *a, Invocation *b) -> bool { + return a->getOrdinal() < b->getOrdinal(); + }; + std::set sortedIvocations(comparator); + for (auto i : ivocations) + sortedIvocations.insert(i); + + for (auto i : sortedIvocations) + result.push_back(i); + } + + static void collectActualInvocations(std::unordered_set &actualInvocations, + std::vector &invocationSources) { + for (auto source : invocationSources) { + source->getActualInvocations(actualInvocations); + } + } + + static void selectNonVerifiedInvocations(std::unordered_set &actualInvocations, + std::unordered_set &into) { + for (auto invocation : actualInvocations) { + if (!invocation->isVerified()) { + into.insert(invocation); + } + } + } + + static void collectInvocationSources(std::vector &) { + } + + template + static void collectInvocationSources(std::vector &into, + const ActualInvocationsSource &mock, + const list &... tail) { + into.push_back(const_cast(&mock)); + collectInvocationSources(into, tail...); + } + + static void collectSequences(std::vector &) { + } + + template + static void collectSequences(std::vector &vec, const Sequence &sequence, const list &... tail) { + vec.push_back(&const_cast(sequence)); + collectSequences(vec, tail...); + } + + static void collectInvolvedMocks(std::vector &allSequences, + std::vector &involvedMocks) { + for (auto sequence : allSequences) { + sequence->getInvolvedMocks(involvedMocks); + } + } + + template + static T &remove_const(const T &s) { + return const_cast(s); + } + + }; + +} + +#include + +#include +#include + +namespace fakeit { + struct MatchAnalysis { + std::vector actualSequence; + std::vector matchedInvocations; + int count; + + void run(InvocationsSourceProxy &involvedInvocationSources, std::vector &expectedPattern) { + getActualInvocationSequence(involvedInvocationSources, actualSequence); + count = countMatches(expectedPattern, actualSequence, matchedInvocations); + } + + private: + static void getActualInvocationSequence(InvocationsSourceProxy &involvedMocks, + std::vector &actualSequence) { + std::unordered_set actualInvocations; + collectActualInvocations(involvedMocks, actualInvocations); + InvocationUtils::sortByInvocationOrder(actualInvocations, actualSequence); + } + + static int countMatches(std::vector &pattern, std::vector &actualSequence, + std::vector &matchedInvocations) { + int end = -1; + int count = 0; + int startSearchIndex = 0; + while (findNextMatch(pattern, actualSequence, startSearchIndex, end, matchedInvocations)) { + count++; + startSearchIndex = end; + } + return count; + } + + static void collectActualInvocations(InvocationsSourceProxy &involvedMocks, + std::unordered_set &actualInvocations) { + involvedMocks.getActualInvocations(actualInvocations); + } + + static bool findNextMatch(std::vector &pattern, std::vector &actualSequence, + int startSearchIndex, int &end, + std::vector &matchedInvocations) { + for (auto sequence : pattern) { + int index = findNextMatch(sequence, actualSequence, startSearchIndex); + if (index == -1) { + return false; + } + collectMatchedInvocations(actualSequence, matchedInvocations, index, sequence->size()); + startSearchIndex = index + sequence->size(); + } + end = startSearchIndex; + return true; + } + + + static void collectMatchedInvocations(std::vector &actualSequence, + std::vector &matchedInvocations, int start, + int length) { + int indexAfterMatchedPattern = start + length; + for (; start < indexAfterMatchedPattern; start++) { + matchedInvocations.push_back(actualSequence[start]); + } + } + + + static bool isMatch(std::vector &actualSequence, + std::vector &expectedSequence, int start) { + bool found = true; + for (unsigned int j = 0; found && j < expectedSequence.size(); j++) { + Invocation *actual = actualSequence[start + j]; + Invocation::Matcher *expected = expectedSequence[j]; + found = found && expected->matches(*actual); + } + return found; + } + + static int findNextMatch(Sequence *&pattern, std::vector &actualSequence, int startSearchIndex) { + std::vector expectedSequence; + pattern->getExpectedSequence(expectedSequence); + for (int i = startSearchIndex; i < ((int) actualSequence.size() - (int) expectedSequence.size() + 1); i++) { + if (isMatch(actualSequence, expectedSequence, i)) { + return i; + } + } + return -1; + } + + }; +} + +namespace fakeit { + + struct SequenceVerificationExpectation { + + friend class SequenceVerificationProgress; + + ~SequenceVerificationExpectation() THROWS { + if (std::uncaught_exception()) { + return; + } + VerifyExpectation(_fakeit); + } + + void setExpectedPattern(std::vector expectedPattern) { + _expectedPattern = expectedPattern; + } + + void setExpectedCount(const int count) { + _expectedCount = count; + } + + void setFileInfo(const char * file, int line, const char * callingMethod) { + _file = file; + _line = line; + _testMethod = callingMethod; + } + + private: + + VerificationEventHandler &_fakeit; + InvocationsSourceProxy _involvedInvocationSources; + std::vector _expectedPattern; + int _expectedCount; + + const char * _file; + int _line; + const char * _testMethod; + bool _isVerified; + + SequenceVerificationExpectation( + VerificationEventHandler &fakeit, + InvocationsSourceProxy mocks, + std::vector &expectedPattern) : + _fakeit(fakeit), + _involvedInvocationSources(mocks), + _expectedPattern(expectedPattern), + _expectedCount(-1), + _line(0), + _isVerified(false) { + } + + + void VerifyExpectation(VerificationEventHandler &verificationErrorHandler) { + if (_isVerified) + return; + _isVerified = true; + + MatchAnalysis ma; + ma.run(_involvedInvocationSources, _expectedPattern); + + if (isAtLeastVerification() && atLeastLimitNotReached(ma.count)) { + return handleAtLeastVerificationEvent(verificationErrorHandler, ma.actualSequence, ma.count); + } + + if (isExactVerification() && exactLimitNotMatched(ma.count)) { + return handleExactVerificationEvent(verificationErrorHandler, ma.actualSequence, ma.count); + } + + markAsVerified(ma.matchedInvocations); + } + + std::vector &collectSequences(std::vector &vec) { + return vec; + } + + template + std::vector &collectSequences(std::vector &vec, const Sequence &sequence, + const list &... tail) { + vec.push_back(&const_cast(sequence)); + return collectSequences(vec, tail...); + } + + + static void markAsVerified(std::vector &matchedInvocations) { + for (auto i : matchedInvocations) { + i->markAsVerified(); + } + } + + bool isAtLeastVerification() { + + return _expectedCount < 0; + } + + bool isExactVerification() { + return !isAtLeastVerification(); + } + + bool atLeastLimitNotReached(int count) { + return count < -_expectedCount; + } + + bool exactLimitNotMatched(int count) { + return count != _expectedCount; + } + + void handleExactVerificationEvent(VerificationEventHandler &verificationErrorHandler, + std::vector actualSequence, int count) { + SequenceVerificationEvent evt(VerificationType::Exact, _expectedPattern, actualSequence, _expectedCount, + count); + evt.setFileInfo(_file, _line, _testMethod); + return verificationErrorHandler.handle(evt); + } + + void handleAtLeastVerificationEvent(VerificationEventHandler &verificationErrorHandler, + std::vector actualSequence, int count) { + SequenceVerificationEvent evt(VerificationType::AtLeast, _expectedPattern, actualSequence, -_expectedCount, + count); + evt.setFileInfo(_file, _line, _testMethod); + return verificationErrorHandler.handle(evt); + } + + }; + +} +namespace fakeit { + class ThrowFalseEventHandler : public VerificationEventHandler { + + void handle(const SequenceVerificationEvent &) override { + throw false; + } + + void handle(const NoMoreInvocationsVerificationEvent &) override { + throw false; + } + }; +} +#include +#include +#include + +namespace fakeit { + + template + static std::string to_string(const T &n) { + std::ostringstream stm; + stm << n; + return stm.str(); + } + +} + + +namespace fakeit { + + struct FakeitContext; + + class SequenceVerificationProgress { + + friend class UsingFunctor; + + friend class VerifyFunctor; + + friend class UsingProgress; + + smart_ptr _expectationPtr; + + SequenceVerificationProgress(SequenceVerificationExpectation *ptr) : _expectationPtr(ptr) { + } + + SequenceVerificationProgress( + FakeitContext &fakeit, + InvocationsSourceProxy sources, + std::vector &allSequences) : + SequenceVerificationProgress(new SequenceVerificationExpectation(fakeit, sources, allSequences)) { + } + + virtual void verifyInvocations(const int times) { + _expectationPtr->setExpectedCount(times); + } + + class Terminator { + smart_ptr _expectationPtr; + + bool toBool() { + try { + ThrowFalseEventHandler eh; + _expectationPtr->VerifyExpectation(eh); + return true; + } + catch (bool e) { + return e; + } + } + + public: + Terminator(smart_ptr expectationPtr) : _expectationPtr(expectationPtr) { }; + + operator bool() { + return toBool(); + } + + bool operator!() const { return !const_cast(this)->toBool(); } + }; + + public: + + ~SequenceVerificationProgress() THROWS { }; + + operator bool() { + return Terminator(_expectationPtr); + } + + bool operator!() const { return !Terminator(_expectationPtr); } + + Terminator Never() { + Exactly(0); + return Terminator(_expectationPtr); + } + + Terminator Once() { + Exactly(1); + return Terminator(_expectationPtr); + } + + Terminator Twice() { + Exactly(2); + return Terminator(_expectationPtr); + } + + Terminator AtLeastOnce() { + verifyInvocations(-1); + return Terminator(_expectationPtr); + } + + Terminator Exactly(const int times) { + if (times < 0) { + throw std::invalid_argument(std::string("bad argument times:").append(fakeit::to_string(times))); + } + verifyInvocations(times); + return Terminator(_expectationPtr); + } + + Terminator Exactly(const Quantity &q) { + Exactly(q.quantity); + return Terminator(_expectationPtr); + } + + Terminator AtLeast(const int times) { + if (times < 0) { + throw std::invalid_argument(std::string("bad argument times:").append(fakeit::to_string(times))); + } + verifyInvocations(-times); + return Terminator(_expectationPtr); + } + + Terminator AtLeast(const Quantity &q) { + AtLeast(q.quantity); + return Terminator(_expectationPtr); + } + + SequenceVerificationProgress setFileInfo(const char * file, int line, const char * callingMethod) { + _expectationPtr->setFileInfo(file, line, callingMethod); + return *this; + } + }; +} + +namespace fakeit { + + class UsingProgress { + fakeit::FakeitContext &_fakeit; + InvocationsSourceProxy _sources; + + void collectSequences(std::vector &) { + } + + template + void collectSequences(std::vector &vec, const fakeit::Sequence &sequence, + const list &... tail) { + vec.push_back(&const_cast(sequence)); + collectSequences(vec, tail...); + } + + public: + + UsingProgress(fakeit::FakeitContext &fakeit, InvocationsSourceProxy source) : + _fakeit(fakeit), + _sources(source) { + } + + template + SequenceVerificationProgress Verify(const fakeit::Sequence &sequence, const list &... tail) { + std::vector allSequences; + collectSequences(allSequences, sequence, tail...); + SequenceVerificationProgress progress(_fakeit, _sources, allSequences); + return progress; + } + + }; +} + +namespace fakeit { + + class UsingFunctor { + + friend class VerifyFunctor; + + FakeitContext &_fakeit; + + public: + + UsingFunctor(FakeitContext &fakeit) : _fakeit(fakeit) { + } + + template + UsingProgress operator()(const ActualInvocationsSource &head, const list &... tail) { + std::vector allMocks{&InvocationUtils::remove_const(head), + &InvocationUtils::remove_const(tail)...}; + InvocationsSourceProxy aggregateInvocationsSource{new AggregateInvocationsSource(allMocks)}; + UsingProgress progress(_fakeit, aggregateInvocationsSource); + return progress; + } + + }; +} +#include + +namespace fakeit { + + class VerifyFunctor { + + FakeitContext &_fakeit; + + + public: + + VerifyFunctor(FakeitContext &fakeit) : _fakeit(fakeit) { + } + + template + SequenceVerificationProgress operator()(const Sequence &sequence, const list &... tail) { + std::vector allSequences{&InvocationUtils::remove_const(sequence), + &InvocationUtils::remove_const(tail)...}; + + std::vector involvedSources; + InvocationUtils::collectInvolvedMocks(allSequences, involvedSources); + InvocationsSourceProxy aggregateInvocationsSource{new AggregateInvocationsSource(involvedSources)}; + + UsingProgress usingProgress(_fakeit, aggregateInvocationsSource); + return usingProgress.Verify(sequence, tail...); + } + + }; + +} +#include +#include +namespace fakeit { + + class VerifyNoOtherInvocationsVerificationProgress { + + friend class VerifyNoOtherInvocationsFunctor; + + struct VerifyNoOtherInvocationsExpectation { + + friend class VerifyNoOtherInvocationsVerificationProgress; + + ~VerifyNoOtherInvocationsExpectation() THROWS { + if (std::uncaught_exception()) { + return; + } + + VerifyExpectation(_fakeit); + } + + void setFileInfo(const char * file, int line, const char * callingMethod) { + _file = file; + _line = line; + _callingMethod = callingMethod; + } + + private: + + VerificationEventHandler &_fakeit; + std::vector _mocks; + + const char * _file; + int _line; + const char * _callingMethod; + bool _isVerified; + + VerifyNoOtherInvocationsExpectation(VerificationEventHandler &fakeit, + std::vector mocks) : + _fakeit(fakeit), + _mocks(mocks), + _line(0), + _isVerified(false) { + } + + VerifyNoOtherInvocationsExpectation(VerifyNoOtherInvocationsExpectation &other) = default; + + void VerifyExpectation(VerificationEventHandler &verificationErrorHandler) { + if (_isVerified) + return; + _isVerified = true; + + std::unordered_set actualInvocations; + InvocationUtils::collectActualInvocations(actualInvocations, _mocks); + + std::unordered_set nonVerifiedInvocations; + InvocationUtils::selectNonVerifiedInvocations(actualInvocations, nonVerifiedInvocations); + + if (nonVerifiedInvocations.size() > 0) { + std::vector sortedNonVerifiedInvocations; + InvocationUtils::sortByInvocationOrder(nonVerifiedInvocations, sortedNonVerifiedInvocations); + + std::vector sortedActualInvocations; + InvocationUtils::sortByInvocationOrder(actualInvocations, sortedActualInvocations); + + NoMoreInvocationsVerificationEvent evt(sortedActualInvocations, sortedNonVerifiedInvocations); + evt.setFileInfo(_file, _line, _callingMethod); + return verificationErrorHandler.handle(evt); + } + } + + }; + + fakeit::smart_ptr _ptr; + + VerifyNoOtherInvocationsVerificationProgress(VerifyNoOtherInvocationsExpectation *ptr) : + _ptr(ptr) { + } + + VerifyNoOtherInvocationsVerificationProgress(FakeitContext &fakeit, + std::vector &invocationSources) + : VerifyNoOtherInvocationsVerificationProgress( + new VerifyNoOtherInvocationsExpectation(fakeit, invocationSources) + ) { + } + + bool toBool() { + try { + ThrowFalseEventHandler ev; + _ptr->VerifyExpectation(ev); + return true; + } + catch (bool e) { + return e; + } + } + + public: + + + ~VerifyNoOtherInvocationsVerificationProgress() THROWS { + }; + + VerifyNoOtherInvocationsVerificationProgress setFileInfo(const char * file, int line, + const char * callingMethod) { + _ptr->setFileInfo(file, line, callingMethod); + return *this; + } + + operator bool() { + return toBool(); + } + + bool operator!() const { return !const_cast(this)->toBool(); } + + }; + +} + + +namespace fakeit { + class VerifyNoOtherInvocationsFunctor { + + FakeitContext &_fakeit; + + public: + + VerifyNoOtherInvocationsFunctor(FakeitContext &fakeit) : _fakeit(fakeit) { + } + + void operator()() { + } + + template + VerifyNoOtherInvocationsVerificationProgress operator()(const ActualInvocationsSource &head, + const list &... tail) { + std::vector invocationSources{&InvocationUtils::remove_const(head), + &InvocationUtils::remove_const(tail)...}; + VerifyNoOtherInvocationsVerificationProgress progress{_fakeit, invocationSources}; + return progress; + } + }; + +} +namespace fakeit { + + class SpyFunctor { + private: + + template + void spy(const SpyingContext &root) { + SpyingContext &rootWithoutConst = const_cast &>(root); + auto methodFromOriginalVT = rootWithoutConst.getOriginalMethod(); + rootWithoutConst.appendAction(new ReturnDelegateValue(methodFromOriginalVT)); + rootWithoutConst.commit(); + } + + void operator()() { + } + + public: + + template + void operator()(const H &head, const M &... tail) { + spy(head); + this->operator()(tail...); + } + + }; + +} + +#include +#include + +namespace fakeit { + class VerifyUnverifiedFunctor { + + FakeitContext &_fakeit; + + public: + + VerifyUnverifiedFunctor(FakeitContext &fakeit) : _fakeit(fakeit) { + } + + template + SequenceVerificationProgress operator()(const Sequence &sequence, const list &... tail) { + std::vector allSequences{&InvocationUtils::remove_const(sequence), + &InvocationUtils::remove_const(tail)...}; + + std::vector involvedSources; + InvocationUtils::collectInvolvedMocks(allSequences, involvedSources); + + InvocationsSourceProxy aggregateInvocationsSource{new AggregateInvocationsSource(involvedSources)}; + InvocationsSourceProxy unverifiedInvocationsSource{ + new UnverifiedInvocationsSource(aggregateInvocationsSource)}; + + UsingProgress usingProgress(_fakeit, unverifiedInvocationsSource); + return usingProgress.Verify(sequence, tail...); + } + + }; + + class UnverifiedFunctor { + public: + UnverifiedFunctor(FakeitContext &fakeit) : Verify(fakeit) { + } + + VerifyUnverifiedFunctor Verify; + + template + UnverifiedInvocationsSource operator()(const ActualInvocationsSource &head, const list &... tail) { + std::vector allMocks{&InvocationUtils::remove_const(head), + &InvocationUtils::remove_const(tail)...}; + InvocationsSourceProxy aggregateInvocationsSource{new AggregateInvocationsSource(allMocks)}; + UnverifiedInvocationsSource unverifiedInvocationsSource{aggregateInvocationsSource}; + return unverifiedInvocationsSource; + } + + + + + + + + + + + + + + }; +} + +namespace fakeit { + + static UsingFunctor Using(Fakeit); + static VerifyFunctor Verify(Fakeit); + static VerifyNoOtherInvocationsFunctor VerifyNoOtherInvocations(Fakeit); + static UnverifiedFunctor Unverified(Fakeit); + static SpyFunctor Spy; + static FakeFunctor Fake; + static WhenFunctor When; + + template + class SilenceUnusedVariableWarnings { + + void use(void *) { + } + + SilenceUnusedVariableWarnings() { + use(&Fake); + use(&When); + use(&Spy); + use(&Using); + use(&Verify); + use(&VerifyNoOtherInvocations); + use(&_); + } + }; + +} +#ifdef _MSC_VER +#define __func__ __FUNCTION__ +#endif + +#define MOCK_TYPE(mock) \ + std::remove_reference::type + +#define OVERLOADED_METHOD_PTR(mock, method, prototype) \ + fakeit::Prototype::MemberType::get(&MOCK_TYPE(mock)::method) + +#define CONST_OVERLOADED_METHOD_PTR(mock, method, prototype) \ + fakeit::Prototype::MemberType::getconst(&MOCK_TYPE(mock)::method) + +#define Dtor(mock) \ + mock.dtor().setMethodDetails(#mock,"destructor") + +#define Method(mock, method) \ + mock.template stub<__COUNTER__>(&MOCK_TYPE(mock)::method).setMethodDetails(#mock,#method) + +#define OverloadedMethod(mock, method, prototype) \ + mock.template stub<__COUNTER__>(OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) + +#define ConstOverloadedMethod(mock, method, prototype) \ + mock.template stub<__COUNTER__>(CONST_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) + +#define Verify(...) \ + Verify( __VA_ARGS__ ).setFileInfo(__FILE__, __LINE__, __func__) + +#define Using(...) \ + Using( __VA_ARGS__ ) + +#define VerifyNoOtherInvocations(...) \ + VerifyNoOtherInvocations( __VA_ARGS__ ).setFileInfo(__FILE__, __LINE__, __func__) + +#define Fake(...) \ + Fake( __VA_ARGS__ ) + +#define When(call) \ + When(call) + + +#endif diff --git a/ci/.gitattributes b/ci/.gitattributes new file mode 100644 index 00000000..f728b2d8 --- /dev/null +++ b/ci/.gitattributes @@ -0,0 +1 @@ +*.sh test eol=lf diff --git a/ci/build.sh b/ci/build.sh new file mode 100755 index 00000000..f28b60a6 --- /dev/null +++ b/ci/build.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +source /opt/qt511/bin/qt511-env.sh +if [ ! -d build ]; then + mkdir build +fi +cd build +# build +echo Building +cmake -DCMAKE_BUILD_TYPE=Release .. && cmake --build . || exit 1 +# if succeeds, run unit tests +echo Running unit tests +./cliTest/cliTest && ./GuiUnitTest/GuiUnitTest && ./mgraph440Test/mgraph440Test && ./salaTest/salaTest && ./genlibTest/genlibTest && ./depthmapXTest/depthmapXTest || exit 1 +# if that succeeds, run regression tests +echo testing regression test framework +cd ../RegressionTest/test && echo pwd && python3.5 -u test_main.py || exit 1 +echo running standard regression tests +cd .. && pwd && python3.5 -u RegressionTestRunner.py || exit 1 +echo running agent test +python3.5 -u RegressionTestRunner.py regressionconfig_agents.json || exit 1 diff --git a/cliTest/CMakeLists.txt b/cliTest/CMakeLists.txt new file mode 100644 index 00000000..c7da228c --- /dev/null +++ b/cliTest/CMakeLists.txt @@ -0,0 +1,47 @@ +set(cliTest cliTest) +set(cliTest_SRCS + main.cpp + ../depthmapXcli/commandlineparser.cpp + testcommandlineparser.cpp + testradiusconverter.cpp + ../depthmapXcli/radiusconverter.cpp + testsimpletimer.cpp + testvgaparser.cpp + ../depthmapXcli/vgaparser.cpp + testlinkparser.cpp + ../depthmapXcli/linkparser.cpp + testagentparser.cpp + ../depthmapXcli/agentparser.cpp + testargumentholder.cpp + ../depthmapXcli/performancewriter.cpp + testperformancewriter.cpp + testselfcleaningfile.cpp + ../depthmapXcli/runmethods.cpp + ../depthmapXcli/modeparserregistry.cpp + testvisprepparser.cpp + ../depthmapXcli/visprepparser.cpp + testaxialparser.cpp + ../depthmapXcli/axialparser.cpp + testparsingutils.cpp + ../depthmapXcli/parsingutils.cpp + testisovistparser.cpp + ../depthmapXcli/isovistparser.cpp + testexportparser.cpp + ../depthmapXcli/exportparser.cpp + ../depthmapXcli/importparser.cpp + testimportparser.cpp + ../depthmapXcli/stepdepthparser.cpp + teststepdepthparser.cpp + ../depthmapXcli/segmentparser.cpp + testsegmentparser.cpp + ../depthmapXcli/mapconvertparser.cpp + testmapconvertparser.cpp) + + +include_directories("../ThirdParty/Catch" "../ThirdParty/FakeIt") + +set(LINK_LIBS salalib genlib mgraph440) + +add_executable(${cliTest} ${cliTest_SRCS}) +target_link_libraries(${cliTest} ${LINK_LIBS}) + diff --git a/cliTest/cliTest.pro b/cliTest/cliTest.pro deleted file mode 100644 index 85419906..00000000 --- a/cliTest/cliTest.pro +++ /dev/null @@ -1,24 +0,0 @@ -include(../defaults.pri) -TEMPLATE = app -CONFIG += console c++11 -CONFIG -= app_bundle -CONFIG -= qt -INCLUDEPATH += ../ThirdParty/Catch - -SOURCES += main.cpp \ - ../depthmapXcli/commandlineparser.cpp \ - testcommandlineparser.cpp \ - testradiusconverter.cpp \ - ../depthmapXcli/radiusconverter.cpp \ - testsimpletimer.cpp \ - testvgaparser.cpp \ - ../depthmapXcli/vgaparser.cpp \ - testargumentholder.cpp \ - testperformancewriter.cpp - -HEADERS += \ - ../depthmapXcli/commandlineparser.h \ - ../depthmapXcli/radiusconverter.h \ - ../depthmapXcli/simpletimer.h \ - ../depthmapXcli/vgaparser.h \ - argumentholder.h diff --git a/cliTest/selfcleaningfile.h b/cliTest/selfcleaningfile.h new file mode 100644 index 00000000..2d0d7c8c --- /dev/null +++ b/cliTest/selfcleaningfile.h @@ -0,0 +1,41 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include +#include +class SelfCleaningFile +{ +public: + SelfCleaningFile(const std::string &filename) : _filename(filename) + {} + ~SelfCleaningFile() + { + std::remove(_filename.c_str()); + } + + const std::string &Filename() + { + return _filename; + } + + + + +private: + const std::string _filename; + +}; diff --git a/cliTest/testagentparser.cpp b/cliTest/testagentparser.cpp new file mode 100644 index 00000000..6c49e07d --- /dev/null +++ b/cliTest/testagentparser.cpp @@ -0,0 +1,471 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "../depthmapXcli/agentparser.h" +#include "argumentholder.h" +#include "selfcleaningfile.h" + +TEST_CASE("AgentParserFail", "Parsing errors") +{ + // missing arguments + + SECTION("Missing argument to -am") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-am"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-am requires an argument")); + } + + SECTION("Missing argument to -ats") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-ats"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-ats requires an argument")); + } + + SECTION("Missing argument to -arr") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-arr"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-arr requires an argument")); + } + + SECTION("Missing argument to -afov") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-afov"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-afov requires an argument")); + } + + SECTION("Missing argument to -asteps") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-asteps"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-asteps requires an argument")); + } + + SECTION("Missing argument to -alife") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-alife"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-alife requires an argument")); + } + + SECTION("Missing argument to -alife") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-alife"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-alife requires an argument")); + } + + SECTION("Missing argument to -alocseed") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-alocseed"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-alocseed requires an argument")); + } + + SECTION("Missing argument to -alocfile") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-alocfile"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-alocfile requires an argument")); + } + + SECTION("Missing argument to -aloc") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-aloc"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-aloc requires an argument")); + } + + // rubbish input + + SECTION("Non-numeric input to -ats") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-ats", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-ats must be a number >0, got foo")); + } + + SECTION("Non-numeric input to -arr") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-arr", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-arr must be a number >0, got foo")); + } + + SECTION("Non-numeric input to -atrails") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-atrails", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-atrails must be a number >=1 or 0 for all (max possible = 50), got foo")); + } + + SECTION("Non-numeric input to -afov") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-afov", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-afov must be a number between 1 and 32, got foo")); + } + + SECTION("Out of range input to -afov (0)") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-afov", "0"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-afov must be a number between 1 and 32, got 0")); + } + + SECTION("Out of range input to -afov (33)") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-afov", "33"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-afov must be a number between 1 and 32, got 33")); + } + + SECTION("Non-numeric input to -asteps") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-asteps", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-asteps must be a number >0, got foo")); + } + + SECTION("Non-numeric input to -alife") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-alife", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-alife must be a number >0, got foo")); + } + + SECTION("Rubbish input to -alocseed") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-alocseed", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Invalid starting location seed provided (foo). Should only contain digits")); + } + + SECTION("Rubbish input to -aloc") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-aloc", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Invalid starting point provided (foo). Should only contain digits dots and commas")); + } + + SECTION("Define graph output twice") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-ot", "graph", "-ot", "graph"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Same output type argument (graph) provided twice")); + } + + SECTION("Define gatecounts output twice") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-ot", "gatecounts", "-ot", "gatecounts"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Same output type argument (gatecounts) provided twice")); + } + + SECTION("Define trails output twice") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-ot", "trails", "-ot", "trails"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Same output type argument (trails) provided twice")); + } +} +TEST_CASE("AgentParserInputFail", "Bad or missing input") +{ + SECTION("-ats not provided") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-arr", "0.1", "-afov","15", "-asteps", "3", "-alife", "1000", "-alocseed", "0"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Total number of timesteps (-ats ) is required")); + } + + SECTION("-arr not provided") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-ats", "5000", "-afov","15", "-asteps", "3", "-alife", "1000", "-alocseed", "0"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Release rate (-arr ) is required")); + } + + SECTION("-afov not provided") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-ats", "5000", "-arr", "0.1", "-asteps", "3", "-alife", "1000", "-alocseed", "0"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Agent field-of-view (-afov ) is required")); + } + + SECTION("-asteps not provided") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-ats", "5000", "-arr", "0.1", "-afov","15", "-alife", "1000", "-alocseed", "0"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Agent number of steps before turn decision (-asteps ) is required")); + } + + SECTION("-alife not provided") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-ats", "5000", "-arr", "0.1", "-afov","15", "-asteps", "3", "-alocseed", "0"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Agent life in timesteps (-alife ) is required")); + } + + SECTION("No random starting poins, manual points or point file provided") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-ats", "5000", "-arr", "0.1", "-afov","15", "-asteps", "3", "-alife", "1000"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Either -aloc, -alocfile or -alocseed must be given")); + } + + SECTION("Manual points and pointfile provided") + { + AgentParser parser; + SelfCleaningFile scf("testpoints.csv"); + { + std::ofstream f("testpoints.csv"); + f << "x\ty\n1\t2\n" << std::flush; + } + ArgumentHolder ah{"prog", "-aloc", "0.1,5.2", "-alocfile", "testpoints.csv", "-ats", "5000", "-arr", "0.1", "-afov","15", "-asteps", "3", "-alife", "1000"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-alocfile cannot be used together with -aloc")); + } + + SECTION("Pointfile and manual points provided") + { + AgentParser parser; + SelfCleaningFile scf("testpoints.csv"); + { + std::ofstream f("testpoints.csv"); + f << "x\ty\n1\t2\n" << std::flush; + } + ArgumentHolder ah{"prog", "-alocfile", "testpoints.csv", "-aloc", "0.1,5.2", "-ats", "5000", "-arr", "0.1", "-afov","15", "-asteps", "3", "-alife", "1000"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-aloc cannot be used together with -alocfile")); + } + + SECTION("Manual points and random points provided") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-aloc", "0.1,5.2", "-alocseed", "0", "-ats", "5000", "-arr", "0.1", "-afov","15", "-asteps", "3", "-alife", "1000"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-alocseed cannot be used together with -aloc")); + } + + SECTION("Pointfile and random points provided") + { + AgentParser parser; + SelfCleaningFile scf("testpoints.csv"); + { + std::ofstream f("testpoints.csv"); + f << "x\ty\n1\t2\n" << std::flush; + } + ArgumentHolder ah{"prog", "-alocfile", "testpoints.csv", "-alocseed", "0", "-ats", "5000", "-arr", "0.1", "-afov","15", "-asteps", "3", "-alife", "1000"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-alocseed cannot be used together with -alocfile")); + } + + SECTION("Random points and manual points provided") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-alocseed", "0", "-aloc", "0.1,5.2", "-ats", "5000", "-arr", "0.1", "-afov","15", "-asteps", "3", "-alife", "1000"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-aloc cannot be used together with -alocseed")); + } + + SECTION("Random points and Pointfile provided") + { + AgentParser parser; + SelfCleaningFile scf("testpoints.csv"); + { + std::ofstream f("testpoints.csv"); + f << "x\ty\n1\t2\n" << std::flush; + } + ArgumentHolder ah{"prog", "-alocseed", "0", "-alocfile", "testpoints.csv", "-ats", "5000", "-arr", "0.1", "-afov","15", "-asteps", "3", "-alife", "1000"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-alocfile cannot be used together with -alocseed")); + } + + SECTION("Non-existing file provided") + { + AgentParser parser; + ArgumentHolder ah{"prog", "-alocfile", "foo.csv", "-ats", "5000", "-arr", "0.1", "-afov","15", "-asteps", "3", "-alife", "1000"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Failed to load file foo.csv, error")); + } + + SECTION("Malformed pointfile") + { + AgentParser parser; + SelfCleaningFile scf("testpoints.csv"); + { + std::ofstream f("testpoints.csv"); + f << "x\ty\n1\n" << std::flush; + } + ArgumentHolder ah{"prog", "-alocfile", "testpoints.csv", "-ats", "5000", "-arr", "0.1", "-afov","15", "-asteps", "3", "-alife", "1000"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Error parsing line: 1")); + } + + SECTION("Malformed point arg") + { + AgentParser parser; + SelfCleaningFile scf("testpoints.csv"); + { + std::ofstream f("testpoints.csv"); + f << "x\ty\n1\n" << std::flush; + } + ArgumentHolder ah{"prog", "-aloc", "0.1", "-ats", "5000", "-arr", "0.1", "-afov","15", "-asteps", "3", "-alife", "1000"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Error parsing line: 0.1")); + } +} + +TEST_CASE("AgentParserSuccess", "Read successfully") +{ + AgentParser parser; + double x1 = 1.0; + double y1 = 2.0; + double x2 = 1.1; + double y2 = 1.2; + + int totalTimeSteps = 5000; + std::stringstream ats; + ats << totalTimeSteps << std::flush; + + double releaseRate = 0.1; + std::stringstream arr; + arr << releaseRate << std::flush; + + int agentFOV = 15; + std::stringstream afov; + afov << agentFOV << std::flush; + + int agentStepsBeforeTurnDecision = 3; + std::stringstream asteps; + asteps << agentStepsBeforeTurnDecision << std::flush; + + int agentLifeTimesteps = 1000; + std::stringstream alife; + alife << agentLifeTimesteps << std::flush; + + SECTION("Random starting locations (points vector should be empty, seed 0)") + { + ArgumentHolder ah{"prog", "-ats", ats.str(), "-arr", arr.str(), "-afov", afov.str(), "-asteps", asteps.str(), "-alife", alife.str(), "-alocseed", "0"}; + parser.parse(ah.argc(), ah.argv()); + + auto points = parser.getReleasePoints(); + REQUIRE(points.size() == 0); + REQUIRE(parser.randomReleaseLocationSeed() == 0); + } + + SECTION("Random starting locations (points vector should be empty, seed 1)") + { + ArgumentHolder ah{"prog", "-ats", ats.str(), "-arr", arr.str(), "-afov", afov.str(), "-asteps", asteps.str(), "-alife", alife.str(), "-alocseed", "1"}; + parser.parse(ah.argc(), ah.argv()); + + auto points = parser.getReleasePoints(); + REQUIRE(points.size() == 0); + REQUIRE(parser.randomReleaseLocationSeed() == 1); + } + + SECTION("Read from commandline") + { + std::stringstream p1; + p1 << x1 << "," << y1 << std::flush; + std::stringstream p2; + p2 << x2 << "," << y2 << std::flush; + + ArgumentHolder ah{"prog", "-ats", ats.str(), "-arr", arr.str(), "-afov", afov.str(), "-asteps", asteps.str(), "-alife", alife.str(), "-aloc", p1.str(), "-aloc", p2.str()}; + parser.parse(ah.argc(), ah.argv()); + + auto points = parser.getReleasePoints(); + REQUIRE(points.size() == 2); + REQUIRE(points[0].x == Approx(x1)); + REQUIRE(points[0].y == Approx(y1)); + REQUIRE(points[1].x == Approx(x2)); + REQUIRE(points[1].y == Approx(y2)); + } + + SECTION("Read from file") + { + SelfCleaningFile scf("testpoints.csv"); + { + std::ofstream f(scf.Filename().c_str()); + f << "x\ty\n" << x1 << "\t" << y1 << "\n" + << x2 << "\t" << y2 << "\n" << std::flush; + } + + ArgumentHolder ah{"prog", "-ats", ats.str(), "-arr", arr.str(), "-afov", afov.str(), "-asteps", asteps.str(), "-alife", alife.str(), "-alocfile", scf.Filename()}; + parser.parse(ah.argc(), ah.argv() ); + + auto points = parser.getReleasePoints(); + REQUIRE(points.size() == 2); + REQUIRE(points[0].x == Approx(x1)); + REQUIRE(points[0].y == Approx(y1)); + REQUIRE(points[1].x == Approx(x2)); + REQUIRE(points[1].y == Approx(y2)); + } + + SECTION("Output type not set") + { + ArgumentHolder ah{"prog", "-ats", ats.str(), "-arr", arr.str(), "-afov", afov.str(), "-asteps", asteps.str(), "-alife", alife.str(), "-alocseed", "0"}; + parser.parse(ah.argc(), ah.argv()); + + auto outputTypes = parser.outputTypes(); + REQUIRE(outputTypes.size() == 0); + } + + SECTION("Set output type to graph") + { + ArgumentHolder ah{"prog", "-ats", ats.str(), "-arr", arr.str(), "-afov", afov.str(), "-asteps", asteps.str(), "-alife", alife.str(), "-alocseed", "0", "-ot", "graph"}; + parser.parse(ah.argc(), ah.argv()); + + auto outputTypes = parser.outputTypes(); + REQUIRE(outputTypes.size() == 1); + REQUIRE(outputTypes[0] == AgentParser::OutputType::GRAPH); + } + + SECTION("Set output type to gatecounts") + { + ArgumentHolder ah{"prog", "-ats", ats.str(), "-arr", arr.str(), "-afov", afov.str(), "-asteps", asteps.str(), "-alife", alife.str(), "-alocseed", "0", "-ot", "gatecounts"}; + parser.parse(ah.argc(), ah.argv()); + + auto outputTypes = parser.outputTypes(); + REQUIRE(outputTypes.size() == 1); + REQUIRE(outputTypes[0] == AgentParser::OutputType::GATECOUNTS); + } + + SECTION("Set output type to trails") + { + ArgumentHolder ah{"prog", "-ats", ats.str(), "-arr", arr.str(), "-afov", afov.str(), "-asteps", asteps.str(), "-alife", alife.str(), "-alocseed", "0", "-atrails", "1", "-ot", "trails"}; + parser.parse(ah.argc(), ah.argv()); + + auto noOfTrails = parser.recordTrailsForAgents(); + REQUIRE(noOfTrails == 1); + + auto outputTypes = parser.outputTypes(); + REQUIRE(outputTypes.size() == 1); + REQUIRE(outputTypes[0] == AgentParser::OutputType::TRAILS); + } + + SECTION("Set two output types") + { + ArgumentHolder ah{"prog", "-ats", ats.str(), "-arr", arr.str(), "-afov", afov.str(), "-asteps", asteps.str(), "-alife", alife.str(), "-alocseed", "0", "-ot", "graph", "-ot", "gatecounts"}; + parser.parse(ah.argc(), ah.argv()); + + auto outputTypes = parser.outputTypes(); + REQUIRE(outputTypes.size() == 2); + REQUIRE(outputTypes[0] == AgentParser::OutputType::GRAPH); + REQUIRE(outputTypes[1] == AgentParser::OutputType::GATECOUNTS); + } + + REQUIRE(parser.totalSystemTimestemps() == totalTimeSteps); + REQUIRE(parser.releaseRate() == Approx(releaseRate)); + REQUIRE(parser.agentFOV() == agentFOV); + REQUIRE(parser.agentStepsBeforeTurnDecision() == agentStepsBeforeTurnDecision); + REQUIRE(parser.agentLifeTimesteps() == agentLifeTimesteps); + +} diff --git a/cliTest/testargumentholder.cpp b/cliTest/testargumentholder.cpp index cd13a625..d5e9bc14 100644 --- a/cliTest/testargumentholder.cpp +++ b/cliTest/testargumentholder.cpp @@ -23,7 +23,7 @@ TEST_CASE("Test ArgumentHolder", "Constructor") { ArgumentHolder ah{"foo", "bar"}; REQUIRE(ah.argc() == 2); - REQUIRE(strcmp(ah.argv()[0], "foo") == 0 ); - REQUIRE(strcmp(ah.argv()[1], "bar") == 0 ); + REQUIRE(std::strcmp(ah.argv()[0], "foo") == 0 ); + REQUIRE(std::strcmp(ah.argv()[1], "bar") == 0 ); } diff --git a/cliTest/testaxialparser.cpp b/cliTest/testaxialparser.cpp new file mode 100644 index 00000000..9ff18f41 --- /dev/null +++ b/cliTest/testaxialparser.cpp @@ -0,0 +1,142 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" + +#include "../depthmapXcli/axialparser.h" +#include "argumentholder.h" + +TEST_CASE("Test mode and help") +{ + AxialParser parser; + REQUIRE(parser.getModeName() == "AXIAL"); + REQUIRE(parser.getHelp() == "Mode options for Axial Analysis:\n"\ + " -xl , Calculate all lines map from this seed point (can be used more than once)\n" + " -xf Calculate fewest lines map from all lines map\n"\ + " -xa run axial anlysis\n"\ + " All modes expect to find the required input in the in graph\n"\ + " Any combination of flags above can be specified, they will always be run in the order -aa -af -au -ax\n"\ + " Further flags for axial analysis are:\n"\ + " -xac Include choice (betweenness)\n"\ + " -xal Include local measures\n"\ + " -xar Inlcude RA, RRA and total depth\n\n"); + +} + +TEST_CASE("Test Parsing Exceptions","") +{ + AxialParser parser; + SECTION("No axial mode") + { + ArgumentHolder ah{"prog"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), "No axial analysis mode present" ); + } + + SECTION("Argument missing") + { + ArgumentHolder ah{"prog", "-xl"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), "-xl requires an argument" ); + } +} + +TEST_CASE("Test mode parsing", "") +{ + AxialParser parser; + SECTION("All lines") + { + ArgumentHolder ah{"prog", "-xl", "1.2,1.5"}; + parser.parse(ah.argc(), ah.argv()); + REQUIRE(parser.runAllLines()); + REQUIRE(parser.getAllAxesRoots().size() == 1); + REQUIRE(parser.getAllAxesRoots()[0].x == Approx(1.2)); + REQUIRE(parser.getAllAxesRoots()[0].y == Approx(1.5)); + REQUIRE_FALSE(parser.runFewestLines()); + REQUIRE_FALSE(parser.runUnlink()); + REQUIRE_FALSE(parser.runAnalysis()); + } + SECTION("Fewest lines") + { + ArgumentHolder ah{"prog", "-xf"}; + parser.parse(ah.argc(), ah.argv()); + REQUIRE_FALSE(parser.runAllLines()); + REQUIRE(parser.runFewestLines()); + REQUIRE_FALSE(parser.runUnlink()); + REQUIRE_FALSE(parser.runAnalysis()); + } + SECTION("Analysis") + { + ArgumentHolder ah{"prog", "-xa", "n"}; + parser.parse(ah.argc(), ah.argv()); + REQUIRE_FALSE(parser.runAllLines()); + REQUIRE_FALSE(parser.runFewestLines()); + REQUIRE_FALSE(parser.runUnlink()); + REQUIRE(parser.runAnalysis()); + REQUIRE_FALSE(parser.calculateRRA()); + REQUIRE_FALSE(parser.useChoice()); + REQUIRE_FALSE(parser.useLocal()); + } + SECTION("Analysis -rra") + { + ArgumentHolder ah{"prog", "-xa", "n", "-xar"}; + parser.parse(ah.argc(), ah.argv()); + REQUIRE_FALSE(parser.runAllLines()); + REQUIRE_FALSE(parser.runFewestLines()); + REQUIRE_FALSE(parser.runUnlink()); + REQUIRE(parser.runAnalysis()); + REQUIRE(parser.calculateRRA()); + REQUIRE_FALSE(parser.useChoice()); + REQUIRE_FALSE(parser.useLocal()); + } + SECTION("Analysis + choice") + { + ArgumentHolder ah{"prog", "-xa", "n", "-xac"}; + parser.parse(ah.argc(), ah.argv()); + REQUIRE_FALSE(parser.runAllLines()); + REQUIRE_FALSE(parser.runFewestLines()); + REQUIRE_FALSE(parser.runUnlink()); + REQUIRE(parser.runAnalysis()); + REQUIRE_FALSE(parser.calculateRRA()); + REQUIRE(parser.useChoice()); + REQUIRE_FALSE(parser.useLocal()); + } + SECTION("Analysis + local") + { + ArgumentHolder ah{"prog", "-xa", "n", "-xal"}; + parser.parse(ah.argc(), ah.argv()); + REQUIRE_FALSE(parser.runAllLines()); + REQUIRE_FALSE(parser.runFewestLines()); + REQUIRE_FALSE(parser.runUnlink()); + REQUIRE(parser.runAnalysis()); + REQUIRE_FALSE(parser.calculateRRA()); + REQUIRE_FALSE(parser.useChoice()); + REQUIRE(parser.useLocal()); + } + + SECTION("Multiple") + { + ArgumentHolder ah{"prog", "-xl", "1.2,1.5", "-xa", "n", "-xl", "2.4,1.0"}; + parser.parse(ah.argc(), ah.argv()); + REQUIRE(parser.runAllLines()); + REQUIRE(parser.getAllAxesRoots().size() == 2); + REQUIRE(parser.getAllAxesRoots()[0].x == Approx(1.2)); + REQUIRE(parser.getAllAxesRoots()[0].y == Approx(1.5)); + REQUIRE(parser.getAllAxesRoots()[1].x == Approx(2.4)); + REQUIRE(parser.getAllAxesRoots()[1].y == Approx(1.0)); + REQUIRE_FALSE(parser.runFewestLines()); + REQUIRE_FALSE(parser.runUnlink()); + REQUIRE(parser.runAnalysis()); + } + +} diff --git a/cliTest/testcommandlineparser.cpp b/cliTest/testcommandlineparser.cpp index 79b8dfa3..ef772e9b 100644 --- a/cliTest/testcommandlineparser.cpp +++ b/cliTest/testcommandlineparser.cpp @@ -14,84 +14,270 @@ // along with this program. If not, see . #include "catch.hpp" +#include "Catch/fakeit.hpp" #include "../depthmapXcli/commandlineparser.h" +#include "../depthmapXcli/imodeparser.h" +#include "../depthmapXcli/imodeparserfactory.h" #include +#include #include "argumentholder.h" + +using namespace fakeit; + +class TestParser: public IModeParser +{ +public: + TestParser(const std::string &modeName) : _parseCalled(false), _runCalled(false), _modeName(modeName) + { + } + + virtual std::string getModeName()const + { + return _modeName; + } + + virtual std::string getHelp() const + { + return formatTestHelpString(_runCalled, _parseCalled); + } + + virtual void parse(int , char ** ) + { + _parseCalled = true; + } + + virtual void run(const CommandLineParser &, IPerformanceSink &) const + { + _runCalled = true; + } + + static std::string formatTestHelpString(bool runCalled, bool parseCalled) + { + std::stringstream buf; + buf << "runCalled " << (runCalled ? "yes" : "no") + << " : parseCalled " << (parseCalled? "yes": "no") + << std::flush; + return buf.str(); + } + +private: + bool _parseCalled; + mutable bool _runCalled; + std::string _modeName; +}; + + TEST_CASE("Invalid Parser","Constructor"){ + std::vector > parsers; + parsers.push_back(std::unique_ptr(new TestParser("TEST1"))); + parsers.push_back(std::unique_ptr(new TestParser("TEST2"))); + + Mock factoryMock; + When(Method(factoryMock,getModeParsers)).AlwaysReturn(parsers); { - REQUIRE_THROWS_WITH(auto cmdP = CommandLineParser(0, 0), Catch::Contains("No commandline parameters provided - don't know what to do")); + CommandLineParser cmdP(factoryMock.get()); + REQUIRE_THROWS_WITH(cmdP.parse(0, 0), Catch::Contains("No commandline parameters provided - don't know what to do")); } { + CommandLineParser cmdP(factoryMock.get()); ArgumentHolder ah{"prog", "-m"}; - REQUIRE_THROWS_WITH(auto cmdP = CommandLineParser(ah.argc(), ah.argv()), "-m requires an argument"); + REQUIRE_THROWS_WITH(cmdP.parse(ah.argc(), ah.argv()), "-m requires an argument"); } { + CommandLineParser cmdP(factoryMock.get()); ArgumentHolder ah{"prog", "-f"}; - REQUIRE_THROWS_WITH(auto cmdP = CommandLineParser(ah.argc(), ah.argv()), "-f requires an argument"); + REQUIRE_THROWS_WITH(cmdP.parse(ah.argc(), ah.argv()), "-f requires an argument"); } { + CommandLineParser cmdP(factoryMock.get()); ArgumentHolder ah{"prog", "-o"}; - REQUIRE_THROWS_WITH(auto cmdP = CommandLineParser(ah.argc(), ah.argv()), "-o requires an argument"); + REQUIRE_THROWS_WITH(cmdP.parse(ah.argc(), ah.argv()), "-o requires an argument"); } { + CommandLineParser cmdP(factoryMock.get()); ArgumentHolder ah{"prog", "-t", "-o"}; - REQUIRE_THROWS_WITH(auto cmdP = CommandLineParser(ah.argc(), ah.argv()), "-t requires an argument"); + REQUIRE_THROWS_WITH(cmdP.parse(ah.argc(), ah.argv()), "-t requires an argument"); } { + CommandLineParser cmdP(factoryMock.get()); ArgumentHolder ah{"prog", "-m", "-f"}; - REQUIRE_THROWS_WITH(auto cmdP = CommandLineParser(ah.argc(), ah.argv()), "-m requires an argument"); + REQUIRE_THROWS_WITH(cmdP.parse(ah.argc(), ah.argv()), "-m requires an argument"); } { + CommandLineParser cmdP(factoryMock.get()); ArgumentHolder ah{"prog", "-m", "LaLaLa"}; - REQUIRE_THROWS_WITH(auto cmdP = CommandLineParser(ah.argc(), ah.argv()), "Invalid mode: LaLaLa"); + REQUIRE_THROWS_WITH(cmdP.parse(ah.argc(), ah.argv()), "Invalid mode: LaLaLa"); } { + CommandLineParser cmdP(factoryMock.get()); ArgumentHolder ah{"prog", "-f", "inputfile.graph", "-o", "outputfile.graph"}; - REQUIRE_THROWS_WITH(CommandLineParser(ah.argc(), ah.argv()), Catch::Contains("-m for mode is required")); + REQUIRE_THROWS_WITH(cmdP.parse(ah.argc(), ah.argv()), Catch::Contains("-m for mode is required")); } { - ArgumentHolder ah{"prog", "-m", "VGA", "-o", "outputfile.graph"}; - REQUIRE_THROWS_WITH(CommandLineParser(ah.argc(), ah.argv()), Catch::Contains("-f for input file is required")); + CommandLineParser cmdP(factoryMock.get()); + ArgumentHolder ah{"prog", "-m", "TEST1", "-m", "TEST2","-f", "inputfile.graph"}; + REQUIRE_THROWS_WITH(cmdP.parse(ah.argc(), ah.argv()), Catch::Contains("-m can only be used once")); } + { - ArgumentHolder ah{"prog", "-m", "VGA", "-f", "inputfile.graph"}; - REQUIRE_THROWS_WITH(CommandLineParser(ah.argc(), ah.argv()), Catch::Contains("-o for output file is required")); + CommandLineParser cmdP(factoryMock.get()); + ArgumentHolder ah{"prog", "-m", "TEST1", "-o", "outputfile.graph"}; + REQUIRE_THROWS_WITH(cmdP.parse(ah.argc(), ah.argv()), Catch::Contains("-f for input file is required")); + } + { + CommandLineParser cmdP(factoryMock.get()); + ArgumentHolder ah{"prog", "-m", "TEST1", "-f", "inputfile.graph"}; + REQUIRE_THROWS_WITH(cmdP.parse(ah.argc(), ah.argv()), Catch::Contains("-o for output file is required")); } } TEST_CASE("Valid Parser","CheckValues"){ + std::vector > parsers; + parsers.push_back(std::unique_ptr(new TestParser("TEST1"))); + parsers.push_back(std::unique_ptr(new TestParser("TEST2"))); + + Mock factoryMock; + When(Method(factoryMock,getModeParsers)).AlwaysReturn(parsers); + + SECTION("Parser test2 used") + { + CommandLineParser cmdP(factoryMock.get()); + ArgumentHolder ah{"prog", "-m", "TEST2", "-f", "inputfile.graph", "-o", "outputfile.graph", "-lnk", "1.2,3.4,5.6,7.8"}; + cmdP.parse(ah.argc(), ah.argv()); + REQUIRE(cmdP.isValid()); + REQUIRE(cmdP.getTimingFile().empty()); + REQUIRE(parsers[0]->getHelp() == TestParser::formatTestHelpString(false, false)); + REQUIRE(parsers[1]->getHelp() == TestParser::formatTestHelpString(false, true)); + } + SECTION("Parser test1 used") { - ArgumentHolder ah{"prog", "-m", "VGA", "-f", "inputfile.graph", "-o", "outputfile.graph"}; - CommandLineParser cmdP(ah.argc(), ah.argv()); + CommandLineParser cmdP(factoryMock.get()); + ArgumentHolder ah{"prog", "-m", "TEST1", "-f", "inputfile.graph", "-o", "outputfile.graph"}; + cmdP.parse(ah.argc(), ah.argv()); REQUIRE(cmdP.isValid()); REQUIRE_FALSE(cmdP.simpleMode()); + REQUIRE(cmdP.getTimingFile().empty()); + REQUIRE(cmdP.modeOptions().getModeName() == "TEST1"); + REQUIRE(parsers[0]->getHelp() == TestParser::formatTestHelpString(false, true)); + REQUIRE(parsers[1]->getHelp() == TestParser::formatTestHelpString(false, false)); } + SECTION("Parser test1 used, timings file, simple mode") { - ArgumentHolder ah{"prog", "-m", "VGA", "-f", "inputfile.graph", "-o", "outputfile.graph", "-s", "-t", "timings.csv"}; - CommandLineParser cmdP(ah.argc(), ah.argv()); + CommandLineParser cmdP(factoryMock.get()); + ArgumentHolder ah{"prog", "-m", "TEST1", "-f", "inputfile.graph", "-o", "outputfile.graph", "-s", "-t", "timings.csv"}; + cmdP.parse(ah.argc(), ah.argv()); REQUIRE(cmdP.isValid()); REQUIRE(cmdP.simpleMode()); REQUIRE(cmdP.getTimingFile() == "timings.csv"); + REQUIRE(parsers[0]->getHelp() == TestParser::formatTestHelpString(false, true)); + REQUIRE(parsers[1]->getHelp() == TestParser::formatTestHelpString(false, false)); } } -TEST_CASE("Invalid Parser Need Help", "CheckForHelp") -{ - ArgumentHolder ah{ "prog", "-h"}; - CommandLineParser cmdP(ah.argc(), ah.argv()); - REQUIRE_FALSE(cmdP.isValid()); +TEST_CASE("Run Tests","Check we only run if it's appropriate"){ + std::vector > parsers; + parsers.push_back(std::unique_ptr(new TestParser("TEST1"))); + parsers.push_back(std::unique_ptr(new TestParser("TEST2"))); + + Mock factoryMock; + When(Method(factoryMock,getModeParsers)).AlwaysReturn(parsers); + + Mock perfSink; + + SECTION("Fail - run without parsing") + { + CommandLineParser cmdP(factoryMock.get()); + REQUIRE_THROWS_WITH(cmdP.run(perfSink.get()), Catch::Contains("Trying to run with invalid command line parameters")); + } + + SECTION("Fail run with help on the command line") + { + CommandLineParser cmdP(factoryMock.get()); + ArgumentHolder ah{"prog", "-h", "-m", "TEST1", "-f", "inputfile.graph", "-o", "outputfile.graph"}; + cmdP.parse(ah.argc(), ah.argv()); + REQUIRE_FALSE(cmdP.isValid()); + REQUIRE_THROWS_WITH(cmdP.run(perfSink.get()), Catch::Contains("Trying to run with invalid command line parameters")); + } + + SECTION("Fail run with version on the command line") + { + CommandLineParser cmdP(factoryMock.get()); + ArgumentHolder ah{"prog", "-v", "-m", "TEST1", "-f", "inputfile.graph", "-o", "outputfile.graph"}; + cmdP.parse(ah.argc(), ah.argv()); + REQUIRE_FALSE(cmdP.isValid()); + REQUIRE_THROWS_WITH(cmdP.run(perfSink.get()), Catch::Contains("Trying to run with invalid command line parameters")); + } + + SECTION("Fail run with version on the command line as last parameter") + { + CommandLineParser cmdP(factoryMock.get()); + ArgumentHolder ah{"prog", "-m", "TEST1", "-f", "inputfile.graph", "-o", "outputfile.graph", "-v"}; + cmdP.parse(ah.argc(), ah.argv()); + REQUIRE_FALSE(cmdP.isValid()); + REQUIRE_THROWS_WITH(cmdP.run(perfSink.get()), Catch::Contains("Trying to run with invalid command line parameters")); + } + + SECTION("Fail run without sub parser") + { + CommandLineParser cmdP(factoryMock.get()); + ArgumentHolder ah{"prog" "-f", "inputfile.graph", "-o", "outputfile.graph"}; + REQUIRE_THROWS(cmdP.parse(ah.argc(), ah.argv())); + REQUIRE_FALSE(cmdP.isValid()); + REQUIRE_THROWS_WITH(cmdP.run(perfSink.get()), Catch::Contains("Trying to run with invalid command line parameters")); + } + + + SECTION("Parser test1 used, timings file, simple mode") + { + CommandLineParser cmdP(factoryMock.get()); + ArgumentHolder ah{"prog", "-m", "TEST1", "-f", "inputfile.graph", "-o", "outputfile.graph", "-s", "-t", "timings.csv"}; + cmdP.parse(ah.argc(), ah.argv()); + REQUIRE(cmdP.isValid()); + REQUIRE(cmdP.simpleMode()); + REQUIRE(cmdP.getTimingFile() == "timings.csv"); + REQUIRE(parsers[0]->getHelp() == TestParser::formatTestHelpString(false, true)); + REQUIRE(parsers[1]->getHelp() == TestParser::formatTestHelpString(false, false)); + cmdP.run(perfSink.get()); + REQUIRE(parsers[0]->getHelp() == TestParser::formatTestHelpString(true, true)); + REQUIRE(parsers[1]->getHelp() == TestParser::formatTestHelpString(false, false)); + + } } +TEST_CASE("Invalid Parser Need Help", "CheckForHelp") +{ + std::vector > parsers; + parsers.push_back(std::unique_ptr(new TestParser("TEST1"))); + parsers.push_back(std::unique_ptr(new TestParser("TEST2"))); + + Mock factoryMock; + When(Method(factoryMock,getModeParsers)).AlwaysReturn(parsers); + + SECTION("Help requested") + { + CommandLineParser cmdP(factoryMock.get()); + ArgumentHolder ah{ "prog", "-h"}; + cmdP.parse(ah.argc(), ah.argv()); + REQUIRE_FALSE(cmdP.isValid()); + } + SECTION("Version requested") + { + CommandLineParser cmdP(factoryMock.get()); + ArgumentHolder ah{ "prog", "-v"}; + cmdP.parse(ah.argc(), ah.argv()); + REQUIRE_FALSE(cmdP.isValid()); + } +} diff --git a/cliTest/testexportparser.cpp b/cliTest/testexportparser.cpp new file mode 100644 index 00000000..47dcad6a --- /dev/null +++ b/cliTest/testexportparser.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "../depthmapXcli/exportparser.h" +#include "argumentholder.h" + +TEST_CASE("ExportParser Fail", "Parsing errors") +{ + // missing arguments + + SECTION("Missing argument to -em") + { + ExportParser parser; + ArgumentHolder ah{"prog", "-em"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-em requires an argument")); + } +} + +TEST_CASE("ExportParser Success", "Read successfully") +{ + ExportParser parser; + + SECTION("Correctly parse mode pointmap-connections-csv") + { + ArgumentHolder ah{"prog", "-em", "pointmap-connections-csv"}; + parser.parse(ah.argc(), ah.argv()); + REQUIRE(parser.getExportMode() == ExportParser::POINTMAP_CONNECTIONS_CSV); + } + + SECTION("Correctly parse mode pointmap-data-csv") + { + ArgumentHolder ah{"prog", "-em", "pointmap-data-csv"}; + parser.parse(ah.argc(), ah.argv()); + REQUIRE(parser.getExportMode() == ExportParser::POINTMAP_DATA_CSV); + } + + SECTION("Correctly parse mode pointmap-links-csv") + { + ArgumentHolder ah{"prog", "-em", "pointmap-links-csv"}; + parser.parse(ah.argc(), ah.argv()); + REQUIRE(parser.getExportMode() == ExportParser::POINTMAP_LINKS_CSV); + } +} diff --git a/cliTest/testimportparser.cpp b/cliTest/testimportparser.cpp new file mode 100644 index 00000000..b4c082c3 --- /dev/null +++ b/cliTest/testimportparser.cpp @@ -0,0 +1,37 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "../depthmapXcli/importparser.h" +#include "argumentholder.h" + +TEST_CASE("Import args valid", "valid") +{ + { + ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "IMPORT", "-if", "importfile"}; + ImportParser cmdP; + cmdP.parse(ah.argc(), ah.argv()); + REQUIRE(cmdP.getFilesToImport().size() == 1); + REQUIRE(cmdP.getFilesToImport()[0] == "importfile"); + } + { + ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "IMPORT", "-if", "importfile1", "-if", "importfile2"}; + ImportParser cmdP; + cmdP.parse(ah.argc(), ah.argv()); + REQUIRE(cmdP.getFilesToImport().size() == 2); + REQUIRE(cmdP.getFilesToImport()[0] == "importfile1"); + REQUIRE(cmdP.getFilesToImport()[1] == "importfile2"); + } +} diff --git a/cliTest/testisovistparser.cpp b/cliTest/testisovistparser.cpp new file mode 100644 index 00000000..95e95f3d --- /dev/null +++ b/cliTest/testisovistparser.cpp @@ -0,0 +1,143 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#include "catch.hpp" +#include "depthmapXcli/isovistparser.h" +#include "argumentholder.h" +#include "selfcleaningfile.h" + +TEST_CASE("Isovistparser string constants") +{ + IsovistParser parser; + REQUIRE(parser.getModeName() == "ISOVIST"); + REQUIRE(parser.getHelp() == "Arguments for isovist mode:\n" \ + " -ii Define an isoivist at position x,y with\n"\ + " optional direction angle and view angle for partial isovists\n"\ + " -if load isovist definitions from a file (csv)\n"\ + " the relevant headers must be called x, y, angle and viewangle\n"\ + " the latter two are optional.\n"\ + " Those two arguments cannot be mixed\n"\ + " Angles for partial isovists are in degrees, counted anti-clockwise with 0°\n"\ + " pointing to the right.\n\n" ); +} + +TEST_CASE("Parse isovist on the command line") +{ + ArgumentHolder ah{"prog", "-ii", "1,2", "-ii", "1,5,27,180"}; + IsovistParser parser; + parser.parse(ah.argc(), ah.argv()); + + REQUIRE(parser.getIsovists().size() == 2); + REQUIRE(parser.getIsovists()[0].getLocation().y == Approx(2.0)); + REQUIRE(parser.getIsovists()[0].getViewAngle() == 0.0); + + REQUIRE(parser.getIsovists()[1].getLocation().y == Approx(5.0)); + REQUIRE(parser.getIsovists()[1].getViewAngle() == Approx(3.141592)); + +} + + +TEST_CASE("Parse isovists from file") +{ + IsovistParser parser; + + SECTION("Full isovists") + { + SelfCleaningFile scf("fullisovists.csv"); + { + std::ofstream file(scf.Filename()); + file << "id,x,y,angle\n1,1,1,27\n2,2.2,1.1,190\n" << std::flush; + } + + ArgumentHolder ah{"prog", "-if", scf.Filename()}; + parser.parse(ah.argc(), ah.argv()); + + REQUIRE(parser.getIsovists().size() == 2); + REQUIRE(parser.getIsovists()[0].getLocation().y == Approx(1.0)); + REQUIRE(parser.getIsovists()[0].getAngle() == 0.0); + REQUIRE(parser.getIsovists()[0].getViewAngle() == 0.0); + + REQUIRE(parser.getIsovists()[1].getLocation().y == Approx(1.1)); + REQUIRE(parser.getIsovists()[1].getAngle() == 0.0); + REQUIRE(parser.getIsovists()[1].getViewAngle() == 0.0); + } + + SECTION("Partial isovists") + { + SelfCleaningFile scf("fullisovists.csv"); + { + std::ofstream file(scf.Filename()); + file << "id,x,y,angle,foo,ViewAngle\n1,1,1,27,bar,180\n2,2.2,1.1,180,baz,90\n" << std::flush; + } + + ArgumentHolder ah{"prog", "-if", scf.Filename()}; + parser.parse(ah.argc(), ah.argv()); + + REQUIRE(parser.getIsovists().size() == 2); + REQUIRE(parser.getIsovists()[0].getLocation().y == Approx(1.0)); + REQUIRE(parser.getIsovists()[0].getAngle() == Approx(0.4712388) ); + REQUIRE(parser.getIsovists()[0].getViewAngle() == Approx(3.141592)); + + REQUIRE(parser.getIsovists()[1].getLocation().y == Approx(1.1)); + REQUIRE(parser.getIsovists()[1].getAngle() == Approx(3.141592)); + REQUIRE(parser.getIsovists()[1].getViewAngle() == Approx(1.57079)); + } + +} + +TEST_CASE("Command line failures") +{ + IsovistParser parser; + + SECTION( "Missing arguments for -ii") + { + ArgumentHolder ah{"prog", "-ii"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-ii requires an argument")); + } + + SECTION( "Missing arguments for -if") + { + ArgumentHolder ah{"prog", "-if"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-if requires an argument")); + } + + SECTION( "Using -if twice") + { + ArgumentHolder ah{"prog", "-if", "foo.csv", "-if", "bar.csv"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-if can only be used once")); + } + + SECTION( "Using -ii and -if") + { + ArgumentHolder ah{"prog", "-ii", "1,1", "-if", "bar.csv"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-if cannot be used together with -ii")); + + } + + SECTION( "Using -if and -ii") + { + ArgumentHolder ah{"prog", "-if", "foo.csv", "-ii", "1,1"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-ii cannot be used together with -if")); + } + + SECTION("Nothing to do") + { + ArgumentHolder ah{"prog"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("No isovists defined. Use -ii or -if")); + } + + +} diff --git a/cliTest/testlinkparser.cpp b/cliTest/testlinkparser.cpp new file mode 100644 index 00000000..6934c0af --- /dev/null +++ b/cliTest/testlinkparser.cpp @@ -0,0 +1,87 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "../depthmapXcli/linkparser.h" +#include "argumentholder.h" + +TEST_CASE("LINK args invalid", "") +{ + { + ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "LINK", "-lf"}; + LinkParser p; + REQUIRE_THROWS_WITH(p.parse(ah.argc(), ah.argv()), Catch::Contains("-lf requires an argument")); + } + + { + ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "LINK", "-lnk"}; + LinkParser p; + REQUIRE_THROWS_WITH(p.parse(ah.argc(), ah.argv()), Catch::Contains("-lnk requires an argument")); + } + + { + ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "LINK", "-lf", "linksfile1", "-lf", "linksfile2"}; + LinkParser p; + REQUIRE_THROWS_WITH(p.parse(ah.argc(), ah.argv()), Catch::Contains("-lf can only be used once at the moment")); + } + + { + ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "LINK", "-lf", "linksfile1", "-lnk", "0,0,0,0"}; + LinkParser p; + REQUIRE_THROWS_WITH(p.parse(ah.argc(), ah.argv()), Catch::Contains("-lf can not be used in conjunction with -lnk")); + } + + { + ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "LINK", "-lnk", "LaLaLaLa"}; + LinkParser p; + REQUIRE_THROWS_WITH(p.parse(ah.argc(), ah.argv()), Catch::Contains("Invalid link provided")); + } + + { + ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "LINK", "-lnk", "1.2;3.4;5.6;7.8"}; + LinkParser p; + REQUIRE_THROWS_WITH(p.parse(ah.argc(), ah.argv()), Catch::Contains("Invalid link provided")); + } + { + ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "LINK", "-lnk", "1.2,3.4,5.6,7.8", "-lm", "unlink", "-lmt", "pointmaps"}; + LinkParser p; + REQUIRE_THROWS_WITH(p.parse(int(ah.argc()), ah.argv()), Catch::Contains("unlinking is not supported for pointmaps")); + } +} + +TEST_CASE("LINK args valid", "valid") +{ + // for this set of tests a difference less than 0.001 should + // suffice to signify that two floats are the same + const float EPSILON = 0.001f; + + { + ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "LINK", "-lnk", "1.2,3.4,5.6,7.8"}; + LinkParser cmdP; + cmdP.parse(int(ah.argc()), ah.argv()); + REQUIRE(cmdP.getManualLinks().size() == 1); + REQUIRE(cmdP.getManualLinks()[0] == "1.2,3.4,5.6,7.8"); + } + + { + ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "LINK", "-lnk", "1.2,3.4,5.6,7.8", "-lnk", "0.1,0.2,0.3,0.4"}; + LinkParser cmdP; + cmdP.parse(ah.argc(), ah.argv()); + REQUIRE(cmdP.getManualLinks().size() == 2); + REQUIRE(cmdP.getManualLinks()[0] == "1.2,3.4,5.6,7.8"); + REQUIRE(cmdP.getManualLinks()[1] == "0.1,0.2,0.3,0.4"); + } + +} diff --git a/cliTest/testmapconvertparser.cpp b/cliTest/testmapconvertparser.cpp new file mode 100644 index 00000000..be63f643 --- /dev/null +++ b/cliTest/testmapconvertparser.cpp @@ -0,0 +1,103 @@ +// Copyright (C) 2018 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include "depthmapXcli/mapconvertparser.h" +#include "argumentholder.h" +#include "selfcleaningfile.h" + +TEST_CASE("MapConvertParserFail", "Error cases") +{ + SECTION("Missing argument to co") + { + MapConvertParser parser; + ArgumentHolder ah{"prog", "-co"}; + REQUIRE_THROWS_WITH(parser.parse(int(ah.argc()), ah.argv()), Catch::Contains("-co requires an argument")); + } + SECTION("Missing argument to con") + { + MapConvertParser parser; + ArgumentHolder ah{"prog", "-con"}; + REQUIRE_THROWS_WITH(parser.parse(int(ah.argc()), ah.argv()), Catch::Contains("-con requires an argument")); + } + SECTION("Missing argument to crsl") + { + MapConvertParser parser; + ArgumentHolder ah{"prog", "-crsl"}; + REQUIRE_THROWS_WITH(parser.parse(int(ah.argc()), ah.argv()), Catch::Contains("-crsl requires an argument")); + } + + SECTION("Non-numeric input to -crsl") + { + MapConvertParser parser; + ArgumentHolder ah{"prog", "-crsl", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(int(ah.argc()), ah.argv()), Catch::Contains("-crsl must be a number >0, got foo")); + } + + SECTION("Under-zero input to -crsl") + { + MapConvertParser parser; + ArgumentHolder ah{"prog", "-crsl", "-1"}; + REQUIRE_THROWS_WITH(parser.parse(int(ah.argc()), ah.argv()), Catch::Contains("-crsl must be a number >0, got -1")); + } + + SECTION("Zero input to -crsl") + { + MapConvertParser parser; + ArgumentHolder ah{"prog", "-crsl", "-1"}; + REQUIRE_THROWS_WITH(parser.parse(int(ah.argc()), ah.argv()), Catch::Contains("-crsl must be a number >0, got -1")); + } + + SECTION("rubbish input to -co") + { + MapConvertParser parser; + ArgumentHolder ah{"prog", "-co", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(int(ah.argc()), ah.argv()), Catch::Contains("Invalid map output (-co) type: foo")); + } + + SECTION("output type (-co) provided twice") + { + MapConvertParser parser; + ArgumentHolder ah{"prog", "-co", "axial", "-co", "drawing"}; + REQUIRE_THROWS_WITH(parser.parse(int(ah.argc()), ah.argv()), Catch::Contains("-co can only be used once, modes are mutually exclusive")); + } + + SECTION("Don't provide output type") + { + MapConvertParser parser; + ArgumentHolder ah{"prog"}; + REQUIRE_THROWS_WITH(parser.parse(int(ah.argc()), ah.argv()), Catch::Contains("A valid output map type (-co) is required")); + } + + SECTION("Don't provide output name") + { + MapConvertParser parser; + ArgumentHolder ah{"prog", "-co", "axial"}; + REQUIRE_THROWS_WITH(parser.parse(int(ah.argc()), ah.argv()), Catch::Contains("A valid output map name (-con) is required")); + } +} + +TEST_CASE("MapConvertParserSuccess", "Read successfully") +{ + MapConvertParser parser; + + SECTION("Plain axial") + { + ArgumentHolder ah{"prog", "-co", "axial", "-con", "new_axial"}; + parser.parse(int(ah.argc()), ah.argv()); + REQUIRE(parser.outputMapName() == "new_axial"); + REQUIRE(parser.outputMapType() == ShapeMap::AXIALMAP); + } +} diff --git a/cliTest/testparsingutils.cpp b/cliTest/testparsingutils.cpp new file mode 100644 index 00000000..03abbabe --- /dev/null +++ b/cliTest/testparsingutils.cpp @@ -0,0 +1,34 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "../depthmapXcli/parsingutils.h" + +TEST_CASE("AxialRadiusParsing success") +{ + std::string testString = "5,1,n"; + auto result = depthmapX::parseRadiusList(testString); + std::vector expectedResult = {1.0 ,5.0,-1.0}; + REQUIRE( result == expectedResult ); +} + +TEST_CASE("AxialRadiusParsing failure") +{ + REQUIRE_THROWS_WITH(depthmapX::parseRadiusList("5,1.1"), Catch::Contains("Found non integer radius 1.1")); + REQUIRE_THROWS_WITH(depthmapX::parseRadiusList("5,foo"), Catch::Contains("Found either 0 or unparsable radius foo")); + REQUIRE_THROWS_WITH(depthmapX::parseRadiusList("5,0"), Catch::Contains("Found either 0 or unparsable radius 0")); + REQUIRE_THROWS_WITH(depthmapX::parseRadiusList("5,-1"), Catch::Contains("Radius must be either n or a positive integer")); +} + diff --git a/cliTest/testperformancewriter.cpp b/cliTest/testperformancewriter.cpp index 5e4bc4cf..d38bd72c 100644 --- a/cliTest/testperformancewriter.cpp +++ b/cliTest/testperformancewriter.cpp @@ -1,3 +1,42 @@ #include #include "../depthmapXcli/performancewriter.h" +#include "selfcleaningfile.h" +#include +TEST_CASE("TestPerformanceWriting", "Simple test case") +{ + SelfCleaningFile scf("timertest.csv"); + PerformanceWriter writer(scf.Filename()); + + writer.addData("test1", 100.0); + writer.addData("test2", 200.0 ); + + writer.write(); + + std::ifstream f(scf.Filename()); + REQUIRE(f.good()); + char line[1000]; + std::vector lines; + while( !f.eof()) + { + f.getline(line, 1000); + lines.push_back(line); + } + std::vector expected{"\"action\",\"duration\"", "\"test1\",100", "\"test2\",200", ""}; + REQUIRE(lines == expected); + +} + +TEST_CASE("TestPerformanceNotWriting", "No filename no writing") +{ + SelfCleaningFile scf("timertest.csv"); + PerformanceWriter writer(""); + + writer.addData("test1", 100.0); + writer.addData("test2", 200.0 ); + + writer.write(); + + std::ifstream f(scf.Filename()); + REQUIRE_FALSE(f.good()); +} diff --git a/cliTest/testsegmentparser.cpp b/cliTest/testsegmentparser.cpp new file mode 100644 index 00000000..54b02de2 --- /dev/null +++ b/cliTest/testsegmentparser.cpp @@ -0,0 +1,184 @@ +// Copyright (C) 2018 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" + +#include "../depthmapXcli/segmentparser.h" +#include "argumentholder.h" + +TEST_CASE("Test segment mode and help") +{ + SegmentParser parser; + REQUIRE(parser.getModeName() == "SEGMENT"); + REQUIRE(parser.getHelp() == "Mode options for Segment Analysis:\n"\ + " -st one of:\n" + " tulip (Angular Tulip - Faster)\n"\ + " angular (Angular Full - Slower)\n"\ + " topological\n"\ + " metric\n"\ + " -sr \n"\ + " -srt (only for Tulip) one of:\n"\ + " steps\n"\ + " metric\n"\ + " angular\n"\ + " -sic to include choice (only for Tulip)\n"\ + " -stb (4 to 1024, 1024 approximates full angular)\n"\ + " -swa perform weighted analysis using this attribute (only for Tulip)\n"); + +} + +TEST_CASE("Test Segment Parsing Exceptions","") +{ + SegmentParser parser; + SECTION("No segment mode") + { + ArgumentHolder ah{"prog"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), "No analysis type given" ); + } + + SECTION("Argument missing -st") + { + ArgumentHolder ah{"prog", "-st"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), "-st requires an argument" ); + } + + SECTION("Invalid SEGMENT mode") + { + ArgumentHolder ah{"prog", "-st", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), "Invalid SEGMENT mode: foo" ); + } + + SECTION("Argument missing -sr") + { + ArgumentHolder ah{"prog", "-sr"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), "-sr requires an argument" ); + } + + SECTION("Argument missing -srt") + { + ArgumentHolder ah{"prog", "-srt"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), "-srt requires an argument" ); + } + + SECTION("Invalid SEGMENT radius type") + { + ArgumentHolder ah{"prog", "-srt", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), "Invalid SEGMENT radius type: foo" ); + } + + SECTION("Argument missing -stb") + { + ArgumentHolder ah{"prog", "-stb"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), "-stb requires an argument" ); + } + + SECTION("Missung radius metric") + { + ArgumentHolder ah{"prog", "-st", "metric"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), "At least one radius must be provided" ); + } + + SECTION("Missung radius topological") + { + ArgumentHolder ah{"prog", "-st", "topological"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), "At least one radius must be provided" ); + } + + SECTION("Missung radius angular") + { + ArgumentHolder ah{"prog", "-st", "angular"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), "At least one radius must be provided" ); + } + + SECTION("Missung radius tulip") + { + ArgumentHolder ah{"prog", "-st", "tulip"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), "At least one radius must be provided" ); + } + + SECTION("Missing tulip radius type") + { + ArgumentHolder ah{"prog", "-st", "tulip", "-sr", "n"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), "Radius type is required for tulip analysis" ); + } + + SECTION("Missing tulip bins") + { + ArgumentHolder ah{"prog", "-st", "tulip", "-sr", "n", "-srt", "steps"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), "Tulip bins are required for tulip analysis" ); + } + + SECTION("Tulip bins out of range") + { + ArgumentHolder ah{"prog", "-st", "tulip", "-sr", "n", "-srt", "steps", "-stb", "2"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), "-stb must be a number between 4 and 1024, got 2" ); + } + + SECTION("Tulip bins out of range") + { + ArgumentHolder ah{"prog", "-st", "tulip", "-sr", "n", "-srt", "steps", "-stb", "1025"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), "-stb must be a number between 4 and 1024, got 1025" ); + } +} + +TEST_CASE("Test segment mode parsing", "") +{ + SegmentParser parser; + SECTION("Analysis Metric") + { + ArgumentHolder ah{"prog", "-st", "metric", "-sr", "n"}; + parser.parse(ah.argc(), ah.argv()); + REQUIRE_FALSE(parser.includeChoice()); + REQUIRE(parser.getTulipBins() == 0); + REQUIRE(parser.getAnalysisType() == SegmentParser::AnalysisType::METRIC); + REQUIRE(parser.getRadiusType() == SegmentParser::RadiusType::NONE); + REQUIRE(parser.getRadii().size() == 1); + REQUIRE(int(parser.getRadii()[0]) == -1); + } + SECTION("Analysis Angular Full") + { + ArgumentHolder ah{"prog", "-st", "angular", "-sr", "n"}; + parser.parse(ah.argc(), ah.argv()); + REQUIRE_FALSE(parser.includeChoice()); + REQUIRE(parser.getTulipBins() == 0); + REQUIRE(parser.getAnalysisType() == SegmentParser::AnalysisType::ANGULAR_FULL); + REQUIRE(parser.getRadiusType() == SegmentParser::RadiusType::NONE); + REQUIRE(parser.getRadii().size() == 1); + REQUIRE(int(parser.getRadii()[0]) == -1); + } + SECTION("Analysis Topological") + { + ArgumentHolder ah{"prog", "-st", "topological", "-sr", "n"}; + parser.parse(ah.argc(), ah.argv()); + REQUIRE_FALSE(parser.includeChoice()); + REQUIRE(parser.getTulipBins() == 0); + REQUIRE(parser.getAnalysisType() == SegmentParser::AnalysisType::TOPOLOGICAL); + REQUIRE(parser.getRadiusType() == SegmentParser::RadiusType::NONE); + REQUIRE(parser.getRadii().size() == 1); + REQUIRE(int(parser.getRadii()[0]) == -1); + } + SECTION("Analysis Tulip") + { + ArgumentHolder ah{"prog", "-st", "tulip", "-sr", "n", "-srt", "steps", "-stb", "1024", "-sic"}; + parser.parse(ah.argc(), ah.argv()); + REQUIRE(parser.includeChoice()); + REQUIRE(parser.getTulipBins() == 1024); + REQUIRE(parser.getAnalysisType() == SegmentParser::AnalysisType::ANGULAR_TULIP); + REQUIRE(parser.getRadiusType() == SegmentParser::RadiusType::SEGMENT_STEPS); + REQUIRE(parser.getRadii().size() == 1); + REQUIRE(int(parser.getRadii()[0]) == -1); + } + +} diff --git a/cliTest/testselfcleaningfile.cpp b/cliTest/testselfcleaningfile.cpp new file mode 100644 index 00000000..23980db1 --- /dev/null +++ b/cliTest/testselfcleaningfile.cpp @@ -0,0 +1,62 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#include "catch.hpp" +#include "selfcleaningfile.h" +#include + +namespace +{ + bool fileExists(const std::string &filename) + { + std::ifstream f(filename.c_str()); + return f.good(); + } + + bool writeToFile(const std::string &filename, const std::string &content) + { + std::ofstream f(filename.c_str()); + if (!f.good()) + { + return false; + } + f << content; + f.flush(); + return true; + } +} + + +TEST_CASE("TestSelfCleaningFile", "Check it is deleted, doesn't fail when not present") +{ + { + SelfCleaningFile scf("foo.txt"); + REQUIRE(scf.Filename() == "foo.txt"); + REQUIRE(fileExists("foo.txt") == false); + REQUIRE(writeToFile(scf.Filename(), "bla bla bla")); + REQUIRE(fileExists(scf.Filename())); + } + REQUIRE(fileExists("foo.txt") == false); + + { + SelfCleaningFile scf("foo.txt"); + REQUIRE(scf.Filename() == "foo.txt"); + REQUIRE(fileExists("foo.txt") == false); + } + REQUIRE(fileExists("foo.txt") == false); + +} + diff --git a/cliTest/teststepdepthparser.cpp b/cliTest/teststepdepthparser.cpp new file mode 100644 index 00000000..003c65a1 --- /dev/null +++ b/cliTest/teststepdepthparser.cpp @@ -0,0 +1,159 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include "depthmapXcli/stepdepthparser.h" +#include "argumentholder.h" +#include "selfcleaningfile.h" + +TEST_CASE("StepDepthParserFail", "Error cases") +{ + SECTION("Missing argument to -sdp") + { + StepDepthParser parser; + ArgumentHolder ah{"prog", "-sdp"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-sdp requires an argument")); + } + + SECTION("Missing argument to -sdf") + { + StepDepthParser parser; + ArgumentHolder ah{"prog", "-sdf"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-sdf requires an argument")); + } + + SECTION("Missing argument to -sdt") + { + StepDepthParser parser; + ArgumentHolder ah{"prog", "-sdt"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-sdt requires an argument")); + } + + SECTION("rubbish input to -sdp") + { + StepDepthParser parser; + ArgumentHolder ah{"prog", "-sdp", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Invalid step depth point provided (foo). Should only contain digits dots and commas")); + } + + SECTION("rubbish input to -sdt") + { + StepDepthParser parser; + ArgumentHolder ah{"prog", "-sdt", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Invalid step type: foo")); + } + + SECTION("Non-existing file provided") + { + StepDepthParser parser; + ArgumentHolder ah{"prog", "-sdf", "foo.csv"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Failed to load file foo.csv, error")); + } + + SECTION("Neiter points nor point file provided") + { + StepDepthParser parser; + ArgumentHolder ah{"prog"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Either -sdp or -sdf must be given")); + } + + SECTION("Points and pointfile provided") + { + StepDepthParser parser; + SelfCleaningFile scf("testpoints.csv"); + { + std::ofstream f("testpoints.csv"); + f << "x\ty\n1\t2\n" << std::flush; + } + ArgumentHolder ah{"prog", "-sdp", "0.1,5.2", "-sdf", "testpoints.csv"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-sdf cannot be used together with -sdp")); + } + + SECTION("Pointfile and points provided") + { + StepDepthParser parser; + SelfCleaningFile scf("testpoints.csv"); + { + std::ofstream f("testpoints.csv"); + f << "x\ty\n1\t2\n" << std::flush; + } + ArgumentHolder ah{"prog", "-sdf", "testpoints.csv", "-sdp", "0.1,5.2"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-sdp cannot be used together with -sdf")); + } + + SECTION("Malformed pointfile") + { + StepDepthParser parser; + SelfCleaningFile scf("testpoints.csv"); + { + std::ofstream f("testpoints.csv"); + f << "x\ty\n1\n" << std::flush; + } + ArgumentHolder ah{"prog", "-sdf", "testpoints.csv"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Error parsing line: 1")); + } + + SECTION("Malformed point arg") + { + StepDepthParser parser; + SelfCleaningFile scf("testpoints.csv"); + { + std::ofstream f("testpoints.csv"); + f << "x\ty\n1\n" << std::flush; + } + ArgumentHolder ah{"prog", "-sdp", "0.1"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Error parsing line: 0.1")); + } + +} + +TEST_CASE("StepDepthParserSuccess", "Read successfully") +{ + StepDepthParser parser; + double x1 = 1.0; + double y1 = 2.0; + double x2 = 1.1; + double y2 = 1.2; + + SECTION("Read from commandline") + { + std::stringstream p1; + p1 << x1 << "," << y1 << std::flush; + std::stringstream p2; + p2 << x2 << "," << y2 << std::flush; + + ArgumentHolder ah{"prog", "-sdp", p1.str(), "-sdp", p2.str(), "-sdt", "visual"}; + parser.parse(ah.argc(), ah.argv()); + } + + SECTION("Read from file") + { + SelfCleaningFile scf("testpoints.csv"); + { + std::ofstream f(scf.Filename().c_str()); + f << "x\ty\n" << x1 << "\t" << y1 << "\n" + << x2 << "\t" << y2 << "\n" << std::flush; + } + ArgumentHolder ah{"prog", "-sdf", scf.Filename(), "-sdt", "visual"}; + parser.parse(ah.argc(), ah.argv() ); + } + + auto points = parser.getStepDepthPoints(); + REQUIRE(points.size() == 2); + REQUIRE(points[0].x == Approx(x1)); + REQUIRE(points[0].y == Approx(y1)); + REQUIRE(points[1].x == Approx(x2)); + REQUIRE(points[1].y == Approx(y2)); +} diff --git a/cliTest/testvgaparser.cpp b/cliTest/testvgaparser.cpp index f2e38c9a..a1975b3c 100644 --- a/cliTest/testvgaparser.cpp +++ b/cliTest/testvgaparser.cpp @@ -21,39 +21,46 @@ TEST_CASE("VGA args invalid", "") { { ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "VGA", "-vm"}; - REQUIRE_THROWS_WITH(VgaParser(ah.argc(), ah.argv()), Catch::Contains("-vm requires an argument")); + VgaParser p; + REQUIRE_THROWS_WITH(p.parse(ah.argc(), ah.argv()), Catch::Contains("-vm requires an argument")); } { ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "VGA", "-vm", "foo"}; - REQUIRE_THROWS_WITH(VgaParser(ah.argc(), ah.argv()), Catch::Contains("Invalid VGA mode: foo")); + VgaParser p; + REQUIRE_THROWS_WITH(p.parse(ah.argc(), ah.argv()), Catch::Contains("Invalid VGA mode: foo")); } { ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "VGA", "-vm", "visibility", "-vm", "metric"}; - REQUIRE_THROWS_WITH(VgaParser(ah.argc(), ah.argv()), Catch::Contains("-vm can only be used once")); + VgaParser p; + REQUIRE_THROWS_WITH(p.parse(ah.argc(), ah.argv()), Catch::Contains("-vm can only be used once")); } { ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "VGA", "-vm", "visibility", "-vg"}; - REQUIRE_THROWS_WITH(VgaParser(ah.argc(), ah.argv()), Catch::Contains("Global measures in VGA/visibility analysis require a radius, use -vr ")); + VgaParser p; + REQUIRE_THROWS_WITH(p.parse(ah.argc(), ah.argv()), Catch::Contains("Global measures in VGA/visibility analysis require a radius, use -vr ")); } { ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "VGA", "-vm", "visibility", "-vg", "-vr"}; - REQUIRE_THROWS_WITH(VgaParser(ah.argc(), ah.argv()), Catch::Contains("-vr requires an argument")); + VgaParser p; + REQUIRE_THROWS_WITH(p.parse(ah.argc(), ah.argv()), Catch::Contains("-vr requires an argument")); } { ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "VGA", "-vm", "visibility", "-vg", "-vr", "foo"}; - REQUIRE_THROWS_WITH(VgaParser(ah.argc(), ah.argv()), Catch::Contains("Radius must be a positive integer number or n, got foo")); + VgaParser p; + REQUIRE_THROWS_WITH(p.parse(ah.argc(), ah.argv()), Catch::Contains("Radius must be a positive integer number or n, got foo")); } { ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "VGA", "-vm", "metric"}; - REQUIRE_THROWS_WITH(VgaParser(ah.argc(), ah.argv()), Catch::Contains("Metric vga requires a radius, use -vr ")); + VgaParser p; + REQUIRE_THROWS_WITH(p.parse(ah.argc(), ah.argv()), Catch::Contains("Metric vga requires a radius, use -vr ")); } } @@ -61,19 +68,22 @@ TEST_CASE("VGA args valid", "valid") { { ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "VGA"}; - VgaParser cmdP(ah.argc(), ah.argv()); + VgaParser cmdP; + cmdP.parse(ah.argc(), ah.argv()); REQUIRE(cmdP.getVgaMode() == VgaParser::VgaMode::ISOVIST); } { ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "VGA", "-vm", "isovist"}; - VgaParser cmdP(ah.argc(), ah.argv()); + VgaParser cmdP; + cmdP.parse(ah.argc(), ah.argv()); REQUIRE(cmdP.getVgaMode() == VgaParser::VgaMode::ISOVIST); } { ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "VGA", "-vm", "visibility"}; - VgaParser cmdP(ah.argc(), ah.argv()); + VgaParser cmdP; + cmdP.parse(ah.argc(), ah.argv()); REQUIRE(cmdP.getVgaMode() == VgaParser::VgaMode::VISBILITY); REQUIRE_FALSE(cmdP.localMeasures()); REQUIRE_FALSE(cmdP.globalMeasures()); @@ -82,12 +92,20 @@ TEST_CASE("VGA args valid", "valid") { ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "VGA", "-vm", "visibility", "-vl", "-vg", "-vr", "4"}; - VgaParser cmdP(ah.argc(), ah.argv()); + VgaParser cmdP; + cmdP.parse(ah.argc(), ah.argv()); REQUIRE(cmdP.getVgaMode() == VgaParser::VgaMode::VISBILITY); REQUIRE(cmdP.globalMeasures()); REQUIRE(cmdP.localMeasures()); REQUIRE(cmdP.getRadius() == "4"); } + { + ArgumentHolder ah{"prog", "-f", "infile", "-o", "outfile", "-m", "VGA", "-vm", "thruvision"}; + VgaParser cmdP; + cmdP.parse(ah.argc(), ah.argv()); + REQUIRE(cmdP.getVgaMode() == VgaParser::VgaMode::THRU_VISION); + } + } diff --git a/cliTest/testvisprepparser.cpp b/cliTest/testvisprepparser.cpp new file mode 100644 index 00000000..e5e19532 --- /dev/null +++ b/cliTest/testvisprepparser.cpp @@ -0,0 +1,216 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include "depthmapXcli/visprepparser.h" +#include "argumentholder.h" +#include "selfcleaningfile.h" + +TEST_CASE("VisPrepParserFail", "Error cases") +{ + SECTION("Missing argument to pg") + { + VisPrepParser parser; + ArgumentHolder ah{"prog", "-pg", "-pp", "1.2,1.3"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-pg requires an argument")); + } + SECTION("Missing argument to pp") + { + VisPrepParser parser; + ArgumentHolder ah{"prog", "-pp"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-pp requires an argument")); + } + SECTION("Missing argument to pf") + { + VisPrepParser parser; + ArgumentHolder ah{"prog", "-pf", "-pg", "1.2"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-pf requires an argument")); + } + + SECTION("Non-numeric input to -pg") + { + VisPrepParser parser; + ArgumentHolder ah{"prog", "-pg", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-pg must be a number >0, got foo")); + } + + SECTION("rubbish input to -pp") + { + VisPrepParser parser; + ArgumentHolder ah{"prog", "-pp", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Invalid fill point provided (foo). Should only contain digits dots and commas")); + } + + SECTION("Non-existing file provide") + { + VisPrepParser parser; + ArgumentHolder ah{"prog", "-pg", "0.1", "-pf", "foo.csv"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Failed to load file foo.csv, error")); + } + + SECTION("Neither points nor point file provided") + { + VisPrepParser parser; + ArgumentHolder ah{"prog", "-pg", "0.1", "-pm"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Either -pp or -pf must be given")); + } + + SECTION("Nothing to do") + { + VisPrepParser parser; + ArgumentHolder ah{"prog"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Nothing to do")); + } + + SECTION("Points and pointfile provided") + { + VisPrepParser parser; + SelfCleaningFile scf("testpoints.csv"); + { + std::ofstream f("testpoints.csv"); + f << "x\ty\n1\t2\n" << std::flush; + } + ArgumentHolder ah{"prog", "-pg", "0.1", "-pp", "0.1,5.2", "-pf", "testpoints.csv"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-pf cannot be used together with -pp")); + } + + SECTION("Pointfile and points provided") + { + VisPrepParser parser; + SelfCleaningFile scf("testpoints.csv"); + { + std::ofstream f("testpoints.csv"); + f << "x\ty\n1\t2\n" << std::flush; + } + ArgumentHolder ah{"prog", "-pg", "0.1", "-pf", "testpoints.csv", "-pp", "0.1,5.2"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-pp cannot be used together with -pf")); + } + + SECTION("Malformed pointfile") + { + VisPrepParser parser; + SelfCleaningFile scf("testpoints.csv"); + { + std::ofstream f("testpoints.csv"); + f << "x\ty\n1\n" << std::flush; + } + ArgumentHolder ah{"prog", "-pg", "0.1", "-pf", "testpoints.csv"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Error parsing line: 1")); + } + + SECTION("Malformed point arg") + { + VisPrepParser parser; + SelfCleaningFile scf("testpoints.csv"); + { + std::ofstream f("testpoints.csv"); + f << "x\ty\n1\n" << std::flush; + } + ArgumentHolder ah{"prog", "-pg", "0.1", "-pp", "0.1"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Error parsing line: 0.1")); + } + + SECTION("Nonsensical visibility restriction") + { + VisPrepParser parser; + ArgumentHolder ah{"prog", "-pr", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Restricted visibility of 'foo' makes no sense, use a positive number or -1 for unrestricted")); + } + + SECTION("Nonsensical visibility restriction") + { + VisPrepParser parser; + ArgumentHolder ah{"prog", "-pr", "0.0"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Restricted visibility of '0.0' makes no sense, use a positive number or -1 for unrestricted")); + } + + SECTION("Make and unmake") + { + VisPrepParser parser; + ArgumentHolder ah{"prog", "-pm", "-pu"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-pu cannot be used together with -pm")); + } + + SECTION("Grid and unmake") + { + VisPrepParser parser; + ArgumentHolder ah{"prog", "-pg", "1", "-pu"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-pu can not be used with any other option apart from -pl")); + } +} + +TEST_CASE("VisprepParserMakeSuccess", "Read successfully - Make") +{ + VisPrepParser parser; + double x1 = 1.0; + double y1 = 2.0; + double x2 = 1.1; + double y2 = 1.2; + double grid = 0.5; + std::stringstream gstring; + gstring << grid << std::flush; + + SECTION("Read from commandline") + { + std::stringstream p1; + p1 << x1 << "," << y1 << std::flush; + std::stringstream p2; + p2 << x2 << "," << y2 << std::flush; + + ArgumentHolder ah{"prog", "-pg", gstring.str(), "-pp", p1.str(), "-pp", p2.str(), "-pb", "-pr", "2.1", "-pm"}; + parser.parse(ah.argc(), ah.argv()); + REQUIRE(parser.getBoundaryGraph()); + REQUIRE(parser.getMakeGraph()); + REQUIRE_FALSE(parser.getUnmakeGraph()); + REQUIRE_FALSE(parser.getRemoveLinksWhenUnmaking()); + REQUIRE(parser.getMaxVisibility() == Approx(2.1)); + } + + SECTION("Read from file") + { + SelfCleaningFile scf("testpoints.csv"); + { + std::ofstream f(scf.Filename().c_str()); + f << "x\ty\n" << x1 << "\t" << y1 << "\n" + << x2 << "\t" << y2 << "\n" << std::flush; + } + ArgumentHolder ah{"prog", "-pg", gstring.str(), "-pf", scf.Filename()}; + parser.parse(ah.argc(), ah.argv() ); + REQUIRE_FALSE(parser.getBoundaryGraph()); + REQUIRE_FALSE(parser.getMakeGraph()); + REQUIRE_FALSE(parser.getUnmakeGraph()); + REQUIRE_FALSE(parser.getRemoveLinksWhenUnmaking()); + REQUIRE(parser.getMaxVisibility() == Approx(-1.0)); + } + + REQUIRE(parser.getGrid() == Approx(grid)); + auto points = parser.getFillPoints(); + REQUIRE(points.size() == 2); + REQUIRE(points[0].x == Approx(x1)); + REQUIRE(points[0].y == Approx(y1)); + REQUIRE(points[1].x == Approx(x2)); + REQUIRE(points[1].y == Approx(y2)); +} + +TEST_CASE("VisprepParserUnmakeSuccess", "Read successfully - Unmake") +{ + VisPrepParser parser; + ArgumentHolder ah{"prog", "-pu", "-pl"}; + parser.parse(ah.argc(), ah.argv()); + REQUIRE_FALSE(parser.getBoundaryGraph()); + REQUIRE_FALSE(parser.getMakeGraph()); + REQUIRE(parser.getUnmakeGraph()); + REQUIRE(parser.getRemoveLinksWhenUnmaking()); +} diff --git a/defaults.pri b/defaults.pri deleted file mode 100644 index c7e0aa80..00000000 --- a/defaults.pri +++ /dev/null @@ -1,13 +0,0 @@ -INCLUDEPATH += $$PWD/depthmapX $$PWD - -Release:DESTDIR = release -Release:OBJECTS_DIR = release/.obj -Release:MOC_DIR = release/.moc -Release:RCC_DIR = release/.rcc -Release:UI_DIR = release/.ui - -Debug:DESTDIR = debug -Debug:OBJECTS_DIR = debug/.obj -Debug:MOC_DIR = debug/.moc -Debug:RCC_DIR = debug/.rcc -Debug:UI_DIR = debug/.ui diff --git a/depthmapX.pro b/depthmapX.pro deleted file mode 100644 index 7dacc18a..00000000 --- a/depthmapX.pro +++ /dev/null @@ -1,11 +0,0 @@ -TEMPLATE = subdirs -CONFIG+=ordered -SUBDIRS = \ - genlib \ - salalib \ - depthmapX \ - GuiUnitTest \ - GuiApp \ - depthmapXcli \ - cliTest -GuiApp.depends = depthmapX genlib salalib diff --git a/depthmapX/AxialAnalysisOptionsDlg.cpp b/depthmapX/AxialAnalysisOptionsDlg.cpp deleted file mode 100644 index 926031af..00000000 --- a/depthmapX/AxialAnalysisOptionsDlg.cpp +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#include "AxialAnalysisOptionsDlg.h" -#include "mainwindow.h" -#include - -CAxialAnalysisOptionsDlg::CAxialAnalysisOptionsDlg(MetaGraph *graph, QWidget *parent) -: QDialog(parent) -{ - setupUi(this); - m_radius = QString(tr("")); - m_choice = false; - m_attribute = -1; - m_weighted = false; - m_rra = false; - m_local = false; - - m_meta_graph = graph; - - foreach (QWidget *widget, QApplication::topLevelWidgets()) { - MainWindow *mainWin = qobject_cast(widget); - if (mainWin) - { - m_choice = mainWin->m_options.choice; - m_local = mainWin->m_options.local; - m_rra = mainWin->m_options.fulloutput; - - m_radius = QString(tr("n")); - - if (mainWin->m_options.weighted_measure_col == -1) { - m_weighted = false; - m_attribute = -1; - } - else { - m_weighted = true; - m_attribute = 0; - } - break; - } - } - - if (m_choice) - c_choice->setCheckState(Qt::Checked); - else - c_choice->setCheckState(Qt::Unchecked); - - if (m_local) - c_local->setCheckState(Qt::Checked); - else - c_local->setCheckState(Qt::Unchecked); - - if (m_rra) - c_rra->setCheckState(Qt::Checked); - else - c_rra->setCheckState(Qt::Unchecked); - - if (m_weighted) - c_weighted->setCheckState(Qt::Checked); - else - c_weighted->setCheckState(Qt::Unchecked); - - c_attribute_chooser->setCurrentIndex(m_attribute); - c_radius->setText(m_radius); -} - -void CAxialAnalysisOptionsDlg::OnUpdateRadius() -{ - QString text; - text = c_radius->text(); - if (!text.isEmpty() && text.indexOf("n") == -1 && text.indexOf("N") == -1 && - text.indexOf("1") == -1 && text.indexOf("2") == -1 && text.indexOf("3") == -1 && - text.indexOf("4") == -1 && text.indexOf("5") == -1 && text.indexOf("6") == -1 && - text.indexOf("7") == -1 && text.indexOf("8") == -1 && text.indexOf("9") == -1) { - QMessageBox::warning(this, tr("Warning"), tr("The radius must either be numeric or 'n'\n Alternatively, for multiple radii, type a list of comma separated numeric radii (you can include 'n')"), QMessageBox::Ok, QMessageBox::Ok); - c_radius->setText(tr("n")); - c_radius->setFocus(Qt::OtherFocusReason); - } -} - -void CAxialAnalysisOptionsDlg::OnWeighted() -{ - if (c_weighted->checkState()) { - UpdateData(true); - c_attribute_chooser->setEnabled(true); - m_attribute = 0; - UpdateData(false); - } - else { - UpdateData(true); - c_attribute_chooser->setEnabled(false); - m_attribute = -1; - UpdateData(false); - } -} - -void CAxialAnalysisOptionsDlg::OnOK() -{ - UpdateData(true); - - if (m_radius.isEmpty() || (m_radius.indexOf("n") == -1 && m_radius.indexOf("N") == -1 && - m_radius.indexOf("1") == -1 && m_radius.indexOf("2") == -1 && m_radius.indexOf("3") == -1 && - m_radius.indexOf("4") == -1 && m_radius.indexOf("5") == -1 && m_radius.indexOf("6") == -1 && - m_radius.indexOf("7") == -1 && m_radius.indexOf("8") == -1 && m_radius.indexOf("9") == -1)) { - QMessageBox::warning(this, tr("Warning"), tr("The radius must either be numeric or 'n'\n Alternatively, for multiple radii, type a list of comma separated numeric radii (you can include 'n')"), QMessageBox::Ok, QMessageBox::Ok); - m_radius = tr("n"); - UpdateData(false); - c_radius->setFocus(Qt::OtherFocusReason); - return; - } - // now parse radius list: - foreach (QWidget *widget, QApplication::topLevelWidgets()) { - MainWindow *mainWin = qobject_cast(widget); - if (mainWin) - { - mainWin->m_options.radius_list.clear(); - QString curr_radius; - int curr_comma = -1, last_comma = 0; - bool add_rn = false; - do { - curr_comma = m_radius.indexOf(',',last_comma); - if (curr_comma != -1) { - curr_radius = m_radius.mid(last_comma, curr_comma-last_comma); - last_comma = curr_comma + 1; - } - else { - curr_radius = m_radius.mid(last_comma); - } - if (!curr_radius.isEmpty()) { - if (curr_radius == "n" || curr_radius == "N") { - add_rn = true; - } - else { - int radius = curr_radius.toInt(); - if (radius <= 0) { - QMessageBox::warning(this, tr("Warning"), tr("Each radius in the list must either be 'n' or a number in the range 1-99"), QMessageBox::Ok, QMessageBox::Ok); - c_radius->setFocus(Qt::OtherFocusReason); - return; - } - mainWin->m_options.radius_list.add((double) radius); - } - } - } - while (curr_comma != -1); - if (mainWin->m_options.radius_list.size() == 0 || add_rn) { - mainWin->m_options.radius_list.push_back(-1); - } - - mainWin->m_options.choice = m_choice; - mainWin->m_options.local = m_local; - mainWin->m_options.fulloutput = m_rra; - - // attributes: - if (!m_weighted) { - mainWin->m_options.weighted_measure_col = -1; - } - else { - mainWin->m_options.weighted_measure_col = m_attribute; - } - break; - } - } - - accept(); -} - -void CAxialAnalysisOptionsDlg::OnCancel() -{ - reject(); -} - -void CAxialAnalysisOptionsDlg::UpdateData(bool value) -{ - if (value) - { - m_radius = c_radius->text(); - if (c_choice->checkState()) - m_choice = true; - else - m_choice = false; - - m_attribute = c_attribute_chooser->currentIndex(); - - if (c_weighted->checkState()) - m_weighted = true; - else - m_weighted = false; - - if (c_rra->checkState()) - m_rra = true; - else - m_rra = false; - - if (c_local->checkState()) - m_local = true; - else - m_local = false; - } - else - { - c_radius->setText(m_radius); - if (m_choice) - c_choice->setCheckState(Qt::Checked); - else - c_choice->setCheckState(Qt::Unchecked); - - c_attribute_chooser->setCurrentIndex(m_attribute); - if (m_weighted) - c_weighted->setCheckState(Qt::Checked); - else - c_weighted->setCheckState(Qt::Unchecked); - - if (m_rra) - c_rra->setCheckState(Qt::Checked); - else - c_rra->setCheckState(Qt::Unchecked); - - if (m_local) - c_local->setCheckState(Qt::Checked); - else - c_local->setCheckState(Qt::Unchecked); - } - -} - -void CAxialAnalysisOptionsDlg::showEvent(QShowEvent * event) -{ - const ShapeGraph& map = m_meta_graph->getDisplayedShapeGraph(); - const AttributeTable& table = map.getAttributeTable(); - for (int i = 0; i < table.getColumnCount(); i++) { - c_attribute_chooser->addItem( QString(table.getColumnName(i).c_str()) ); - } - - if (m_weighted) { - c_attribute_chooser->setEnabled(true); - m_attribute = 0; - c_attribute_chooser->setCurrentIndex(m_attribute); - } - else { - m_attribute = -1; - c_attribute_chooser->setCurrentIndex(m_attribute); - c_attribute_chooser->setEnabled(true); - } - - //UpdateData(false); -} diff --git a/depthmapX/CMakeLists.txt b/depthmapX/CMakeLists.txt new file mode 100644 index 00000000..c89c7ca1 --- /dev/null +++ b/depthmapX/CMakeLists.txt @@ -0,0 +1,90 @@ +set(depthmapX depthmapX) + +# Find includes in corresponding build directories +set(CMAKE_INCLUDE_CURRENT_DIR ON) +# Instruct CMake to run moc automatically when needed +set(CMAKE_AUTOMOC ON) +# Create code from a list of Qt designer ui files +# set(CMAKE_AUTOUIC ON) +# set(CMAKE_AUTORCC ON) + +# Find the QtWidgets library +find_package(Qt5 COMPONENTS Core Widgets Gui OpenGL REQUIRED) + +add_compile_definitions(_DEPTHMAP) + +set(depthmapX_SRCS + GraphDoc.cpp + indexWidget.cpp + mainwindow.cpp + mdichild.cpp + renderthread.cpp + treeWindow.cpp + mainwindowfactory.cpp + settingsimpl.cpp + compatibilitydefines.h + mainwindow.h + settings.h + GraphDoc.h + mainwindowfactory.h + settingsimpl.h + indexWidget.h + mdichild.h + treeWindow.h + main.cpp + coreapplication.cpp + coreapplication.h) + +qt5_wrap_ui(UI_HDRS + UI/TopoMetDlg.ui + UI/SegmentAnalysisDlg.ui + UI/RenameObjectDlg.ui + UI/PushDialog.ui + UI/PromptReplace.ui + UI/OptionsDlg.ui + UI/NewLayerDlg.ui + UI/MakeOptionsDlg.ui + UI/MakeLayerDlg.ui + UI/LicenceDialog.ui + UI/LayerChooserDlg.ui + UI/IsovistPathDlg.ui + UI/InsertColumnDlg.ui + UI/GridDialog.ui + UI/FindLocDlg.ui + UI/FilePropertiesDlg.ui + UI/FewestLineOptionsDlg.ui + UI/EditConnectionsDlg.ui + UI/DepthmapOptionsDlg.ui + UI/DepthmapAlert.ui + UI/ConvertShapesDlg.ui + UI/ColumnPropertiesDlg.ui + UI/ColourScaleDlg.ui + UI/AxialAnalysisOptionsDlg.ui + UI/AttributeSummary.ui + UI/AttributeChooserDlg.ui + UI/AgentAnalysisDlg.ui + UI/AboutDlg.ui + UI/licenseagreement.ui) + +qt5_add_resources(DM_RSRC resource.qrc dialogs/settings/settingsdialog.qrc) + +if (MSVC) + add_executable(${depthmapX} WIN32 ${depthmapX_SRCS} ${UI_HDRS} ${DM_RSRC} icons.rc) +endif(MSVC) +if(UNIX AND NOT APPLE) + add_executable(${depthmapX} ${depthmapX_SRCS} ${UI_HDRS} ${DM_RSRC}) +endif() +if(APPLE) + add_definitions(-DGL_SILENCE_DEPRECATION) + add_executable(${depthmapX} MACOSX_BUNDLE ${depthmapX_SRCS} ${UI_HDRS} ${DM_RSRC}) + set_target_properties(${depthmapX} PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/resources/Info.plist) +endif(APPLE) + +find_package(OpenGL REQUIRED) + +target_link_libraries(${depthmapX} salalib genlib mgraph440 Qt5::Core Qt5::Gui Qt5::Widgets Qt5::OpenGL + OpenGL::GL OpenGL::GLU) + +add_subdirectory(dialogs) +add_subdirectory(views) diff --git a/depthmapX/ColourScaleDlg.cpp b/depthmapX/ColourScaleDlg.cpp deleted file mode 100644 index 8dd9c724..00000000 --- a/depthmapX/ColourScaleDlg.cpp +++ /dev/null @@ -1,375 +0,0 @@ -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - - -#include "mainwindow.h" - -CColourScaleDlg::CColourScaleDlg(QWidget *parent) -: QDialog(parent) -{ - setupUi(this); - setWindowFlags(Qt::WindowStaysOnTopHint); - - m_show_lines = false; - m_show_fill = false; - m_show_centroids = false; - m_blue = tr(""); - m_red = tr(""); - m_color = -1; - - m_docked = false; - - m_viewDoc = NULL; - - m_red_brush.setColor(QColor(255,128,128));//CreateSolidBrush(RGB(255,128,128)); - m_blue_brush.setColor(QColor(128,128,255)); - - c_blue_slider_ctrl->setMinimum(0); - c_blue_slider_ctrl->setMaximum(100); - c_red_slider_ctrl->setMinimum(0); - c_red_slider_ctrl->setMaximum(100); - c_blue_slider_ctrl->setTickInterval(10); - c_red_slider_ctrl->setTickInterval(10); - - // these are out of order... - c_color_type->addItem(QString(tr("Equal Ranges (3-Colour)")));// 0 - c_color_type->addItem(QString(tr("Equal Ranges (Blue-Red)")));// 5 - c_color_type->addItem(QString(tr("Equal Ranges (Purple-Orange)"))); // 4 - c_color_type->addItem(QString(tr("depthmapX Classic"))); // 3 - c_color_type->addItem(QString(tr("Equal Ranges (Greyscale)"))); // 1 - c_color_type->addItem(QString(tr("Equal Ranges (Monochrome)"))); // 2 - - m_color_type_map.push_back(0); - m_color_type_map.push_back(5); - m_color_type_map.push_back(4); - m_color_type_map.push_back(3); - m_color_type_map.push_back(1); - m_color_type_map.push_back(2); - - Clear(); - - UpdateData(false); -} - -void CColourScaleDlg::OnChangeBlueValue() -{ - QString str; - str = c_blue_value_window->text(); - m_displayparams.blue = GetNormValue(str.toDouble()); - c_blue_slider_ctrl->setValue(m_displayparams.blue * 100.0); - c_ok->setEnabled(true); - c_applytoall->setEnabled(true); -} - -void CColourScaleDlg::OnChangeRedValue() -{ - QString str; - str = c_red_value_window->text(); - m_displayparams.red = GetNormValue(str.toDouble()); - c_red_slider_ctrl->setValue(m_displayparams.red * 100); - c_ok->setEnabled(true); - c_applytoall->setEnabled(true); -} - -void CColourScaleDlg::OnReleasedRedSlider(int val) -{ - double value = double(c_red_slider_ctrl->value()) / 100.0; - QString text; - text.sprintf("%.2f", GetActualValue(value)); - c_red_value_window->setText(text); -} - -void CColourScaleDlg::OnReleasedBlueSlider(int val) -{ - double value = double(c_blue_slider_ctrl->value()) / 100.0; - QString text; - text.sprintf("%.2f", GetActualValue(value)); - c_blue_value_window->setText(text); -} - -void CColourScaleDlg::OnSelchangeColor(int value) -{ - UpdateData(true); - - if(m_color_type_map.size() <= (size_t)value) - return; - - m_color = m_color_type_map[value]; - - if (m_color == 0 || m_color == 3 || m_color == 5) { - m_red = "Red"; - m_blue = "Blue"; - } - else if (m_color == 4) { - m_red = "Orange"; - m_blue = "Purple"; - } - else if (m_color == 1) { - m_red = "White"; - m_blue = "Black"; - } - else { - m_red = "Thick"; - m_blue = "Thin"; - } - - UpdateData(false); - - c_ok->setEnabled(true); - c_applytoall->setEnabled(true); -} - -void CColourScaleDlg::OnBnClickedShowLines(bool value) -{ - c_ok->setEnabled(true); -} - -void CColourScaleDlg::OnBnClickedShowFill(bool value) -{ - c_ok->setEnabled(true); -} - -void CColourScaleDlg::OnBnClickedShowCentroids(bool value) -{ - c_ok->setEnabled(true); -} - -void CColourScaleDlg::OnBnClickedApplytoall() -{ - MyUpdateData(true,true); - - // don't destroy - c_ok->setEnabled(false); - c_applytoall->setEnabled(false); -} - -void CColourScaleDlg::OnOK() -{ - MyUpdateData(true,false); - - // don't destroy - c_ok->setEnabled(false); -} - -void CColourScaleDlg::OnCancel() -{ - // don't destroy, simply hide: - hide(); -} - -void CColourScaleDlg::UpdateData(bool value) -{ - if (value) - { - m_blue = c_blue->text(); - m_red = c_red->text(); - if (c_show_lines->checkState()) - m_show_lines = true; - else - m_show_lines = false; - - if (c_show_fill->checkState()) - m_show_fill = true; - else - m_show_fill = false; - - if (c_show_centroids->checkState()) - m_show_centroids = true; - else - m_show_centroids = false; - } - else // push data to controls: - { - c_blue->setText(m_blue); - c_red->setText(m_red); - if (m_show_lines) - c_show_lines->setCheckState(Qt::Checked); - else - c_show_lines->setCheckState(Qt::Unchecked); - - if (m_show_fill) - c_show_fill->setCheckState(Qt::Checked); - else - c_show_fill->setCheckState(Qt::Unchecked); - - if (m_show_centroids) - c_show_centroids->setCheckState(Qt::Checked); - else - c_show_centroids->setCheckState(Qt::Unchecked); - } -} - -void CColourScaleDlg::Clear() -{ - m_color = -1; - c_color_type->setEnabled(false); - m_blue = "Min"; - m_red = "Max"; - c_blue_value_window->setEnabled(false); - c_blue_value_window->setText(tr("")); - c_red_value_window->setEnabled(false); - c_red_value_window->setText(tr("")); - c_blue_slider_ctrl->setEnabled(false); - c_blue_slider_ctrl->setValue(0); - c_red_slider_ctrl->setEnabled(false); - c_red_slider_ctrl->setValue(100); - c_ok->setEnabled(false); - c_applytoall->setEnabled(false); - - UpdateData(false); -} - -double CColourScaleDlg::GetActualValue(double sliderpos) -{ - return sliderpos * (m_display_max - m_display_min) + m_display_min; -} - -float CColourScaleDlg::GetNormValue(double actualval) -{ - return ((actualval - m_display_min) / (m_display_max - m_display_min)); -} - -void CColourScaleDlg::Fill() -{ - if (m_color == 0 || m_color == 3 || m_color == 5) { - m_red = "Red"; - m_blue = "Blue"; - } - else if (m_color == 4) { - m_red = "Orange"; - m_blue = "Purple"; - } - else if (m_color == 1) { - m_red = "White"; - m_blue = "Black"; - } - else { - m_red = "Thick"; - m_blue = "Thin"; - } - - QString text; - text.sprintf("%.2f", GetActualValue(m_displayparams.blue)); - c_blue_value_window->setText(text); - text.sprintf("%.2f", GetActualValue(m_displayparams.red)); - c_red_value_window->setText(text); - - c_blue_slider_ctrl->setValue(int(m_displayparams.blue * 100)); - c_red_slider_ctrl->setValue(int(m_displayparams.red * 100)); - - c_color_type->setEnabled(true); - c_blue_value_window->setEnabled(true); - c_red_value_window->setEnabled(true); - c_blue_slider_ctrl->setEnabled(true); - c_red_slider_ctrl->setEnabled(true); - c_ok->setEnabled(false); - c_applytoall->setEnabled(false); - - UpdateData(false); -} - -void CColourScaleDlg::OnFocusGraph(QGraphDoc* pDoc, int lParam) -{ - if (lParam == QGraphDoc::CONTROLS_DESTROYALL && pDoc == m_viewDoc) { // Lost graph - m_viewDoc = NULL; - MyUpdateData(false,false); - } - else if (lParam == QGraphDoc::CONTROLS_LOADALL && pDoc != m_viewDoc) { // [Possible] change of window (sent on focus) - m_viewDoc = pDoc; - MyUpdateData(false,false); - } - else if (lParam != QGraphDoc::CONTROLS_LOADALL && pDoc == m_viewDoc) { // Force update if match current window - MyUpdateData(false,false); - } -} - -void CColourScaleDlg::MyUpdateData(bool dir, bool apply_to_all) -{ - if (dir == false) { - // push data to controls: - if (m_viewDoc == NULL) { - Clear(); - } - else { - MetaGraph *graph = m_viewDoc->m_meta_graph; - if (graph->viewingProcessed()) { - if (graph->getViewClass() & MetaGraph::VIEWVGA) { - PointMap& map = graph->getDisplayedPointMap(); - m_display_min = map.getDisplayMinValue(); - m_display_max = map.getDisplayMaxValue(); - m_displayparams = map.getDisplayParams(); - m_color = m_displayparams.colorscale; - } - else if (graph->getViewClass() & MetaGraph::VIEWAXIAL) { - ShapeGraph& map = graph->getDisplayedShapeGraph(); - m_display_min = map.getDisplayMinValue(); - m_display_max = map.getDisplayMaxValue(); - m_displayparams = map.getDisplayParams(); - m_color = m_displayparams.colorscale; - bool show_lines = m_show_lines, show_fill = m_show_fill, show_centroids = m_show_centroids; - map.getPolygonDisplay(show_lines,show_fill,show_centroids); - m_show_lines = show_lines; m_show_fill = show_fill; m_show_centroids = show_centroids; - } - else if (graph->getViewClass() & MetaGraph::VIEWDATA) { - ShapeMap& map = graph->getDisplayedDataMap(); - m_display_min = map.getDisplayMinValue(); - m_display_max = map.getDisplayMaxValue(); - m_displayparams = map.getDisplayParams(); - m_color = m_displayparams.colorscale; - bool show_lines = m_show_lines, show_fill = m_show_fill, show_centroids = m_show_centroids; - map.getPolygonDisplay(show_lines,show_fill,show_centroids); - m_show_lines = show_lines; m_show_fill = show_fill; m_show_centroids = show_centroids; - } - for (size_t i = 0; i < m_color_type_map.size(); i++) { - if (m_color == m_color_type_map[i]) { - c_color_type->setCurrentIndex(i); - } - } - Fill(); - } - else { - Clear(); - } - } - UpdateData(false); - } - else { - // get data from controls: - UpdateData(true); - - if (m_viewDoc != NULL) { - MetaGraph *graph = m_viewDoc->m_meta_graph; - m_color = m_color_type_map[c_color_type->currentIndex()]; - m_displayparams.colorscale = m_color; - if (graph->getViewClass() & MetaGraph::VIEWVGA) { - graph->getDisplayedPointMap().setDisplayParams( m_displayparams, apply_to_all ); - } - else if (graph->getViewClass() & MetaGraph::VIEWAXIAL) { - graph->getDisplayedShapeGraph().setDisplayParams( m_displayparams, apply_to_all ); - graph->getDisplayedShapeGraph().setPolygonDisplay(m_show_lines,m_show_fill,m_show_centroids); - } - else if (graph->getViewClass() & MetaGraph::VIEWDATA) { - graph->getDisplayedDataMap().setDisplayParams( m_displayparams, apply_to_all ); - graph->getDisplayedDataMap().setPolygonDisplay(m_show_lines,m_show_fill,m_show_centroids); - } - } - m_viewDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP); - } -} - -void CColourScaleDlg::showEvent(QShowEvent * event) -{ - //UpdateData(false); -} diff --git a/depthmapX/ColourScaleDlg.h b/depthmapX/ColourScaleDlg.h deleted file mode 100644 index af232c7a..00000000 --- a/depthmapX/ColourScaleDlg.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef ColourScaleDlg_H -#define ColourScaleDlg_H - -#include "ui_ColourScaleDlg.h" -#include "GraphDoc.h" - -class CColourScaleDlg : public QDialog, public Ui::CColourScaleDlg -{ - Q_OBJECT -public: - CColourScaleDlg(QWidget *parent = 0); - QGraphDoc *m_viewDoc; - QString m_blue; - QString m_red; - int m_color; - - bool m_docked; - - double m_display_min; - double m_display_max; - double GetActualValue(double sliderpos); - float GetNormValue(double actualval); - - QBrush m_red_brush; - QBrush m_blue_brush; - DisplayParams m_displayparams; - - void MyUpdateData(bool dir, bool apply_to_all); - void Clear(); - void Fill(); - bool m_show_lines; - bool m_show_fill; - bool m_show_centroids; - pvecint m_color_type_map; - void UpdateData(bool value); - void showEvent(QShowEvent * event); - void OnFocusGraph(QGraphDoc* pDoc, int lParam); - -private slots: - void OnChangeBlueValue(); - void OnChangeRedValue(); - void OnReleasedRedSlider(int); - void OnReleasedBlueSlider(int); - void OnSelchangeColor(int); - void OnBnClickedShowLines(bool); - void OnBnClickedShowFill(bool); - void OnBnClickedShowCentroids(bool); - void OnBnClickedApplytoall(); - void OnOK(); - void OnCancel(); -}; - -#endif diff --git a/depthmapX/ColumnPropertiesDlg.cpp b/depthmapX/ColumnPropertiesDlg.cpp deleted file mode 100644 index 9ecd0300..00000000 --- a/depthmapX/ColumnPropertiesDlg.cpp +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#include "ColumnPropertiesDlg.h" - -CColumnPropertiesDlg::CColumnPropertiesDlg(AttributeTable *table, int col, QWidget *parent) -: QDialog(parent) -{ - setupUi(this); - m_formula = tr(""); - m_name = tr(""); - m_name_text = tr(""); - m_creator = tr(""); - m_formula_note = tr(""); - - m_table = table; - m_col = col; - - m_name = m_table->getColumnName(m_col).c_str(); - m_formula = m_table->getColumnFormula(m_col).c_str(); - - if (!m_table->isColumnLocked(m_col)) { - m_name_text = "Name"; - } - else { - m_name_text = "Name (column locked and cannot be edited)"; - } - - if (m_formula.isEmpty()) { - //m_formula_note.Empty(); - } - else { - m_formula_note = tr("Note: the formula may have been applied to a subset of objects"); - } - - UpdateData(false); -} - -void CColumnPropertiesDlg::OnOK() -{ - UpdateData(true); - accept(); -} - -void CColumnPropertiesDlg::UpdateData(bool value) -{ - pqvector rows; - pvecdouble summary_all; - pvecdouble summary_sel; - - rows.push_back(tr("Average")); - rows.push_back(tr("Minimum")); - rows.push_back(tr("Maximum")); - rows.push_back(tr("Std Dev")); - rows.push_back(tr("Count")); - - int i; - for (i = 0; i < 15; i++) { - if (i == 1 || i == 2) { - // minimum and maximum - summary_all.push_back(-1.0); - summary_sel.push_back(-1.0); - } - else { - summary_all.push_back(0.0); - summary_sel.push_back(0.0); - } - } - - for (i = 0; i < m_table->getRowCount(); i++) { - double val = m_table->getValue(i,m_col); - if (val != -1.0 && m_table->isVisible(i)) { - summary_all[0] += val; - summary_all[4] += 1.0; - if (summary_all[1] == -1.0 || val < summary_all[1]) { - summary_all[1] = val; - } - if (summary_all[2] == -1.0 || val > summary_all[2]) { - summary_all[2] = val; - } - if (m_table->isSelected(i)) { - summary_sel[0] += val; - summary_sel[4] += 1.0; - if (summary_sel[1] == -1.0 || val < summary_sel[1]) { - summary_sel[1] = val; - } - if (summary_sel[2] == -1.0 || val > summary_sel[2]) { - summary_sel[2] = val; - } - } - } - } - - bool freqrows = false; - double unit; - if (summary_all[1] != -1.0 && summary_all[2] != -1.0 && summary_all[1] != summary_all[2]) { - freqrows = true; - unit = (summary_all[2] - summary_all[1]) / 10.0; - for (int i = 0; i < 10; i++) { - pstring name; - if (i == 0) { - name = pstringify(summary_all[1]+unit,"< %f"); - } - else if (i == 9) { - name = pstringify(summary_all[2]-unit,"> %f"); - } - else { - name = pstringify(summary_all[1]+unit*i,"%f") + " to " + - pstringify(summary_all[1]+unit*(i+1),"%f"); - } - // Unicode conversion a bit of a mess here AT (01.02.11) - rows.push_back( QString(name.c_str()) ); - } - } - - if (summary_all[4] != 0) { - summary_all[0] /= summary_all[4]; - } - if (summary_sel[4] != 0) { - summary_sel[0] /= summary_sel[4]; - } - - // count of things rows: just for visible at the moment - - double var_all = 0.0; - double var_sel = 0.0; - for (i = 0; i < m_table->getRowCount(); i++) { - double val = m_table->getValue(i,m_col); - if (val != -1.0 && m_table->isVisible(i)) { - var_all += sqr(val-summary_all[0]); - if (freqrows) { - int pos = floor((val - summary_all[1])/unit); - if (pos == 10) pos = 9; // irritating exactly equal to max - summary_all[5+pos] += 1; - } - if (m_table->isSelected(i)) { - var_sel += sqr(val-summary_sel[0]); - if (freqrows) { - // note: must use summary_all even on selected to make difference - int pos = floor((val - summary_all[1])/unit); - if (pos == 10) pos = 9; // irritating exactly equal to max - summary_sel[5+pos] += 1; - } - } - } - } - - if (summary_all[4] != 0) { - summary_all[3] = sqrt(var_all / summary_all[4]); - } - if (summary_sel[4] != 0) { - summary_sel[3] = sqrt(var_sel / summary_sel[4]); - } - - c_summary->setSelectionBehavior(QAbstractItemView::SelectRows); - c_summary->setColumnCount(3); - - QTableWidgetItem *Item; - Item = new QTableWidgetItem("Value"); - c_summary->setColumnWidth(0, 100); - Item->setTextAlignment(Qt::AlignLeft); - c_summary->setHorizontalHeaderItem(0, Item); - - Item = new QTableWidgetItem("Attribute"); - c_summary->setColumnWidth(1, 100); - Item->setTextAlignment(Qt::AlignRight); - c_summary->setHorizontalHeaderItem(1, Item); - - Item = new QTableWidgetItem("Selection"); - c_summary->setColumnWidth(2, 100); - Item->setTextAlignment(Qt::AlignRight); - c_summary->setHorizontalHeaderItem(2, Item); - - c_summary->clearContents(); - - c_summary->setRowCount(15); - for (i = 0; i < 15; i++) { - if (i == 5 && !freqrows) { - break; - } - Item = new QTableWidgetItem(rows[i]); - Item->setFlags(Qt::NoItemFlags); - c_summary->setRowHeight(i, 20); - c_summary->setItem(i, 0, Item); - // - char text[64]; - // All - if (i == 4 || summary_all[4] != 0) { - sprintf(text,"%g",summary_all[i]); - } - else { - strcpy(text,"No Value"); - } - Item = new QTableWidgetItem(QString(text)); - Item->setFlags(Qt::NoItemFlags); - c_summary->setItem(i, 1, Item); - // Sel - if (i == 4 || summary_sel[4] != 0) { - sprintf(text,"%g",summary_sel[i]); - } - else { - strcpy(text,"No Value"); - } - Item = new QTableWidgetItem(QString(text)); - Item->setFlags(Qt::NoItemFlags); - c_summary->setItem(i, 2, Item); - } - if (value) - { - m_formula = c_formula->toPlainText(); - m_name = c_name->text(); - m_name_text = c_name_text->text(); - m_formula_note = c_formula_note->text(); - } - else - { - c_formula->setPlainText(m_formula); - c_name->setText(m_name); - c_name_text->setText(m_name_text); - c_formula_note->setText(m_formula_note); - } -} - -void CColumnPropertiesDlg::showEvent(QShowEvent * event) -{ - UpdateData(false); -} diff --git a/depthmapX/DepthmapOptionsDlg.cpp b/depthmapX/DepthmapOptionsDlg.cpp deleted file mode 100644 index bd6dbe04..00000000 --- a/depthmapX/DepthmapOptionsDlg.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (C) 2011-2012, Tasos Varoudis -// Copyright (C) 2017 Christian Sailer - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#include "DepthmapOptionsDlg.h" - -CDepthmapOptionsDlg::CDepthmapOptionsDlg(QWidget *parent, bool simpleVersion) -: QDialog(parent), m_show_simple_version(simpleVersion) -{ - setupUi(this); - m_show_research_toolbar = false; -} - -void CDepthmapOptionsDlg::OnOK() -{ - //UpdateData(true); - accept(); -} - -void CDepthmapOptionsDlg::OnCancel() -{ - reject(); -} - -void CDepthmapOptionsDlg::UpdateData(bool value) -{ - if (value) - { - if (m_show_research_toolbar) - c_show_research_toolbar->setCheckState(Qt::Checked); - else - c_show_research_toolbar->setCheckState(Qt::Unchecked); - - if (m_show_simple_version) - c_show_simple_version->setCheckState(Qt::Checked); - else - c_show_simple_version->setCheckState(Qt::Unchecked); - } - else - { - if (c_show_research_toolbar->checkState()) - m_show_research_toolbar = true; - else - m_show_research_toolbar = false; - - if (c_show_simple_version->checkState()) - m_show_simple_version = true; - else - m_show_simple_version = false; - } -} - -void CDepthmapOptionsDlg::showEvent(QShowEvent * event) -{ - //c_show_research_toolbar->setEnabled(true); - UpdateData(true); -} diff --git a/depthmapX/GraphDoc.cpp b/depthmapX/GraphDoc.cpp index 3eca0bf2..4c874a84 100644 --- a/depthmapX/GraphDoc.cpp +++ b/depthmapX/GraphDoc.cpp @@ -25,38 +25,43 @@ #include "mainwindow.h" -#include "MakeLayerDlg.h" -#include "OptionsDlg.h" -#include "AxialAnalysisOptionsDlg.h" -#include "SegmentAnalysisDlg.h" -#include "GridDialog.h" -#include "MakeOptionsDlg.h" -#include "EditConnectionsDlg.h" -#include "ColourScaleDlg.h" -#include "FewestLineOptionsDlg.h" -#include "PromptReplace.h" -#include "FilePropertiesDlg.h" -#include "InsertColumnDlg.h" -#include "PushDialog.h" -#include "AgentAnalysisDlg.h" -#include "NewLayerDlg.h" -#include "AttributeChooserDlg.h" -#include "LayerChooserDlg.h" -#include "RenameObjectDlg.h" -#include "ColumnPropertiesDlg.h" -#include "IsovistPathDlg.h" -#include "ConvertShapesDlg.h" -#include "TopoMetDlg.h" -#include "AttributeSummary.h" -#include "depthmapView.h" -#include "viewhelpers.h" +#include "dialogs/MakeLayerDlg.h" +#include "dialogs/OptionsDlg.h" +#include "dialogs/AxialAnalysisOptionsDlg.h" +#include "dialogs/SegmentAnalysisDlg.h" +#include "dialogs/GridDialog.h" +#include "dialogs/MakeOptionsDlg.h" +#include "dialogs/EditConnectionsDlg.h" +#include "dialogs/ColourScaleDlg.h" +#include "dialogs/FewestLineOptionsDlg.h" +#include "dialogs/PromptReplace.h" +#include "dialogs/FilePropertiesDlg.h" +#include "dialogs/InsertColumnDlg.h" +#include "dialogs/PushDialog.h" +#include "dialogs/AgentAnalysisDlg.h" +#include "dialogs/NewLayerDlg.h" +#include "dialogs/AttributeChooserDlg.h" +#include "dialogs/LayerChooserDlg.h" +#include "dialogs/RenameObjectDlg.h" +#include "dialogs/ColumnPropertiesDlg.h" +#include "dialogs/IsovistPathDlg.h" +#include "dialogs/ConvertShapesDlg.h" +#include "dialogs/TopoMetDlg.h" +#include "dialogs/AttributeSummary.h" + +#include "views/depthmapview/depthmapview.h" +#include "views/viewhelpers.h" + +#include #ifdef _WIN32 #include #endif #include "compatibilitydefines.h" +#include "salalib/importutils.h" QT_BEGIN_NAMESPACE +Q_DECLARE_METATYPE(std::string) QGraphDoc::QGraphDoc(const QString &author, const QString &organisation) { @@ -83,15 +88,43 @@ QGraphDoc::QGraphDoc(const QString &author, const QString &organisation) m_step = 0; m_num_records = 0; - pstring date = ViewHelpers::getCurrentDate(); - QString version = QString("depthmapX v%1.%2").arg(DEPTHMAPX_VERSION).arg(DEPTHMAPX_MINOR_VERSION); + std::string date = ViewHelpers::getCurrentDate(); + QString version = QString(TITLE_BASE); - m_meta_graph->setProperties(pstring(author.toLatin1()),pstring(organisation.toLatin1()),date,pstring(version.toLatin1())); + m_meta_graph->setProperties(author.toStdString(),organisation.toStdString(),date,version.toStdString()); + qRegisterMetaType< std::string >(); + connect(&m_thread, &RenderThread::runtimeExceptionThrown, this, &QGraphDoc::exceptionThrownInRenderThread); + connect(&m_thread, &RenderThread::showWarningMessage, this, &QGraphDoc::messageFromRenderThread); + connect(&m_thread, &RenderThread::closeWaitDialog, this, &QGraphDoc::DestroyWaitDialog); +} +void QGraphDoc::exceptionThrownInRenderThread(int type, std::string message) { + if(type == depthmapX::PointMapExceptionType::NO_ISOVIST_ANALYSIS) { + std::stringstream message; + message << "This operation requires isovist analysis. To run it go to: "; + message << "Tools -> Visibility -> Run Visibility Graph Analysis... "; + message << "and select \"Calculate isovist properties\""; + QMessageBox::warning(this, tr("Warning"), tr(message.str().c_str()), + QMessageBox::Ok, QMessageBox::Ok); + } +} + +void QGraphDoc::messageFromRenderThread(QString title, QString message) { + QMessageBox::warning(this, title, message, QMessageBox::Ok, QMessageBox::Ok); } bool QGraphDoc::SetRedrawFlag(int viewtype, int flag, int reason, QWidget *originator) // (almost) thread safe { + + if(viewtype == VIEW_ALL && flag != REDRAW_DONE) + { + ((MainWindow *) m_mainFrame)->updateGLWindows(true, flag == REDRAW_TOTAL); + } + if(viewtype == VIEW_MAP && flag == REDRAW_TOTAL) + { + ((MainWindow *) m_mainFrame)->updateGLWindows(false, true); + } + if (!m_flag_lock) { m_flag_lock = true; if (viewtype) { @@ -136,7 +169,7 @@ void QGraphDoc::UpdateMainframestatus() } // either showing or constructing the VGA graph else if ((state & MetaGraph::POINTMAPS) && m_meta_graph->getViewClass() & MetaGraph::VIEWVGA) { - n = (int) m_meta_graph->getDisplayedPointMap().getPointCount(); + n = (int) m_meta_graph->getDisplayedPointMap().getFilledPointCount(); } if (n > 0) { s1 = QString("%1 ").arg(n); @@ -183,24 +216,28 @@ void QGraphDoc::OnLayerNew() // for now, 0 = axial map, and 1 = data map ShapeMap *map; if (dlg.m_layer_type == 0) { - int ref = m_meta_graph->addShapeMap(pstring(dlg.m_name.toLatin1())); - map = &(m_meta_graph->getDataMaps().getMap(ref)); + int ref = m_meta_graph->addShapeMap(dlg.m_name.toStdString()); + m_meta_graph->setDisplayedDataMapRef(ref); + map = &(m_meta_graph->getDataMaps()[ref]); } else if (dlg.m_layer_type == 1) { - int ref = m_meta_graph->addShapeGraph(pstring(dlg.m_name.toLatin1()),ShapeMap::CONVEXMAP); - map = &(m_meta_graph->getShapeGraphs().getMap(ref)); + int ref = m_meta_graph->addShapeGraph(dlg.m_name.toStdString(),ShapeMap::CONVEXMAP); + m_meta_graph->setDisplayedShapeGraphRef(ref); + map = m_meta_graph->getShapeGraphs()[size_t(ref)].get(); } else if (dlg.m_layer_type == 2) { - int ref = m_meta_graph->addShapeGraph(pstring(dlg.m_name.toLatin1()),ShapeMap::AXIALMAP); - map = &(m_meta_graph->getShapeGraphs().getMap(ref)); + int ref = m_meta_graph->addShapeGraph(dlg.m_name.toStdString(),ShapeMap::AXIALMAP); + m_meta_graph->setDisplayedShapeGraphRef(ref); + map = m_meta_graph->getShapeGraphs()[size_t(ref)].get(); } else if (dlg.m_layer_type == 3) { - int ref = m_meta_graph->addShapeGraph(pstring(dlg.m_name.toLatin1()),ShapeMap::PESHMAP); - map = &(m_meta_graph->getShapeGraphs().getMap(ref)); + int ref = m_meta_graph->addShapeGraph(dlg.m_name.toStdString(),ShapeMap::PESHMAP); + m_meta_graph->setDisplayedShapeGraphRef(ref); + map = m_meta_graph->getShapeGraphs()[size_t(ref)].get(); } QtRegion r = m_meta_graph->getBoundingBox(); - if (r.isNull()) { + if (r.atZero()) { r = QtRegion(Point2f(-50.0,-50.0),Point2f(50.0,50.0)); } map->init(0,r); @@ -291,7 +328,7 @@ void QGraphDoc::timerEvent(QTimerEvent *event) } } -void QGraphDoc::ProcPostMessage(int m, int x, int y) +void QGraphDoc::ProcPostMessage(int m, int x) { switch (m) { case Communicator::NUM_STEPS: @@ -312,6 +349,78 @@ void QGraphDoc::ProcPostMessage(int m, int x, int y) } } +void QGraphDoc::OnVGALinksFileImport() +{ + if (m_communicator) { + return; // Locked + } + + // change the view before loading the file to make the changes apparent + if(m_view[VIEW_MAP]) + ((QDepthmapView*)m_view[VIEW_MAP])->m_showlinks = true; + SetRedrawFlag(VIEW_MAP,REDRAW_POINTS, NEW_DEPTHMAPVIEW_SETUP); + + QString template_string; + template_string += "Text files (*.txt *.csv)\n"; + template_string += "All files (*.*)"; + + QFileDialog::Options options = 0; + QString selectedFilter; + QString infile = QFileDialog::getOpenFileName( + 0, tr("Import Links File"), + "", + template_string, + &selectedFilter, + options); + + if (!infile.size()) + { + // no file selected + return; + } + + std::string fileName = infile.toStdString(); + + std::ifstream fileStream(fileName); + if (fileStream.fail()) + { + QMessageBox::warning(this, tr("Warning"), tr("Unable to read text file.\nPlease check that another program is not using it."), + QMessageBox::Ok, QMessageBox::Ok); + return; + } + else + { + try + { + PointMap& currentMap = m_meta_graph->getDisplayedPointMap(); + std::vector newLinks = depthmapX::pixelateMergeLines( + EntityParsing::parseLines(fileStream, '\t'), currentMap); + depthmapX::mergePixelPairs(newLinks, currentMap); + SetRedrawFlag(VIEW_MAP,REDRAW_POINTS, NEW_DEPTHMAPVIEW_SETUP); + } + catch (EntityParsing::EntityParseException& e) + { + std::stringstream message; + message << "Unable to parse text file\n\n"; + message << fileName; + message << "\n\n Error: "; + message << e.what(); + QMessageBox::warning(this, tr("Warning"), tr(message.str().c_str()), + QMessageBox::Ok, QMessageBox::Ok); + } + catch (depthmapX::InvalidLinkException& e) + { + std::stringstream message; + message << "Unable to import links\n\n"; + message << fileName; + message << "\n\n Error: "; + message << e.what(); + QMessageBox::warning(this, tr("Warning"), tr(message.str().c_str()), + QMessageBox::Ok, QMessageBox::Ok); + } + } +} + void QGraphDoc::OnFileImport() { if (m_communicator) { @@ -337,6 +446,12 @@ void QGraphDoc::OnFileImport() return; } + // this is placed here as a proxy to be queried later so that we can find + // if there was something else in the graph after importing. If there was + // then the view should not be reset, if there wasn't then the view can + // be reset to point to the newly imported objects + bool graphHadNullBoundsBeforeImport = m_meta_graph->getBoundingBox().atZero(); + QFilePath filepath(infiles[0]); QString ext = filepath.m_ext; if (ext == tr("CAT") || ext == tr("DXF") || ext == tr("NTF") || ext == tr("RT1") || ext == tr("MIF") || ext == tr("GML") || ext == tr("")) { @@ -344,7 +459,7 @@ void QGraphDoc::OnFileImport() QFilePath filepath(infiles[i]); if (filepath.m_ext != ext || !(filepath.m_ext == tr("RT1") || filepath.m_ext == tr("NTF") || filepath.m_ext == tr("GML") || filepath.m_ext == tr(""))) { QMessageBox::warning(this, tr("Warning"), tr("You have selected more than one file. Unfortunately, this feature is only currently available with NTF, GML and Tiger line files.\nPlease select a single file to import only."), - QMessageBox::Yes, QMessageBox::Yes); + QMessageBox::Ok, QMessageBox::Ok); return; } } @@ -358,11 +473,7 @@ void QGraphDoc::OnFileImport() if (ok) { m_communicator = new CMSCommunicator; if (ext != tr("RT1") && ext != tr("NTF") && ext != tr("GML")) { // ntf, gml & rt1 use filesets (all others use standard file at a time) -#ifndef _WIN32 - m_communicator->SetInfile( (comm_char *)(infiles[0].toLatin1().data()) ); -#else - m_communicator->SetInfile( (comm_char *)(infiles[0].utf16()) ); -#endif + m_communicator->SetInfile( qPrintable(infiles[0]) ); } if (ext != tr("MIF")) { CreateWaitDialog(tr("Importing file...")); @@ -389,11 +500,7 @@ void QGraphDoc::OnFileImport() else { int thedot = infiles[0].lastIndexOf('.'); QString infile2 = infiles[0].left(thedot+1) + tr("mid"); -#ifndef _WIN32 - m_communicator->SetInfile2( (comm_char *)infile2.toLatin1().data()); -#else - m_communicator->SetInfile2( (comm_char *)infile2.utf16() ); -#endif + m_communicator->SetInfile2( qPrintable(infile2)); CreateWaitDialog(tr("Importing file...")); m_communicator->SetFunction( CMSCommunicator::IMPORTMIF ); } @@ -401,16 +508,28 @@ void QGraphDoc::OnFileImport() } } else if (ext == tr("TXT") || ext == tr("CSV")) { - ifstream file( infiles[0].toLatin1() ); + std::ifstream file( infiles[0].toLatin1() ); if (file.fail()) { QMessageBox::warning(this, tr("Warning"), tr("Unable to read text file.\nPlease check that another program is not using it."), - QMessageBox::Yes, QMessageBox::Yes); + QMessageBox::Ok, QMessageBox::Ok); } else { - if (m_meta_graph->importTxt( file, pstring(filepath.m_name.toLatin1()), (ext == tr("CSV")) ) != -1) { + std::unique_ptr comm(new ICommunicator()); + bool mapParsed = depthmapX::importFile(*m_meta_graph, + file, + comm.get(), + filepath.m_name.toStdString(), + depthmapX::ImportType::DATAMAP, + (ext == tr("CSV")) ? depthmapX::ImportFileType::CSV : depthmapX::ImportFileType::TSV); + if(mapParsed) { // This should have added a new data map: SetUpdateFlag(NEW_TABLE); - SetRedrawFlag(VIEW_ALL,REDRAW_GRAPH, NEW_TABLE); + + if(graphHadNullBoundsBeforeImport) { + SetRedrawFlag(VIEW_ALL, REDRAW_TOTAL, NEW_TABLE); + } else { + SetRedrawFlag(VIEW_ALL, REDRAW_GRAPH, NEW_TABLE); + } } else { QMessageBox::warning(this, tr("Warning"), tr("Unable to import text file.\n \ @@ -421,13 +540,13 @@ void QGraphDoc::OnFileImport() Points with X and Y values, or\n\ points with Easting and Northing values, or\n\ lines with X1,Y1 and X2,Y2 values"), - QMessageBox::Yes, QMessageBox::Yes); + QMessageBox::Ok, QMessageBox::Ok); } } } else { QMessageBox::warning(this, tr("Warning"), tr("Unrecognised file format. Sorry, unable to import this file."), - QMessageBox::Yes, QMessageBox::Yes); + QMessageBox::Ok, QMessageBox::Ok); } } @@ -447,39 +566,19 @@ void QGraphDoc::OnFileExport() QString suffix; int mode = -1; - bool showlinks = ((QDepthmapView*)m_view[VIEW_MAP])->m_showlinks; - int view_class = m_meta_graph->getViewClass(); if (view_class & MetaGraph::VIEWAXIAL) { - if (showlinks) { - mode = 5; - suffix = tr("unlinks"); - } - else { - mode = 0; - suffix = m_meta_graph->getDisplayedShapeGraph().getName().c_str(); - } + mode = 0; + suffix = m_meta_graph->getDisplayedShapeGraph().getName().c_str(); } else if (view_class & MetaGraph::VIEWDATA) { - if (showlinks) { - mode = 6; - suffix = tr("links"); - } - else { - mode = 1; - suffix = m_meta_graph->getDisplayedDataMap().getName().c_str(); - } + mode = 1; + suffix = m_meta_graph->getDisplayedDataMap().getName().c_str(); } else if (view_class & MetaGraph::VIEWVGA) { if (m_meta_graph->getDisplayedPointMap().isProcessed()) { - if (showlinks) { - mode = 4; - suffix = tr("merge_lines"); - } - else { - mode = 2; - suffix = tr("vga"); - } + mode = 2; + suffix = tr("vga"); } else { mode = 3; @@ -526,7 +625,7 @@ void QGraphDoc::OnFileExport() if (ext != tr("MIF") && ext != tr("GRAPH") && ext != tr("NET")) { - ofstream stream(outfile.toLatin1()); + std::ofstream stream(outfile.toLatin1()); char delimiter = '\t'; if (ext == tr("CSV")) { delimiter = ','; @@ -549,13 +648,6 @@ void QGraphDoc::OnFileExport() case 3: m_meta_graph->getDisplayedPointMap().outputPoints( stream, delimiter ); break; - case 4: - m_meta_graph->getDisplayedPointMap().outputMergeLines( stream, delimiter ); - break; - case 5: - // note: specific to line graphs - m_meta_graph->getDisplayedShapeGraph().outputUnlinkPoints( stream, delimiter ); - break; default: break; } @@ -567,7 +659,7 @@ void QGraphDoc::OnFileExport() return; } - if (m_meta_graph->write(pstring(outfile.toLatin1()), METAGRAPH_VERSION, true) != MetaGraph::OK) { // <- true writes current layer only + if (m_meta_graph->write(outfile.toStdString(), METAGRAPH_VERSION, true) != MetaGraph::OK) { // <- true writes current layer only QMessageBox::warning(this, tr("Notice"), tr("Sorry, unable to open file for export"), QMessageBox::Ok, QMessageBox::Ok); } } @@ -576,7 +668,7 @@ void QGraphDoc::OnFileExport() QMessageBox::warning(this, tr("Notice"), tr("Sorry, depthmapX can only export VGA graphs or shape graphs to Pajek .net files"), QMessageBox::Ok, QMessageBox::Ok); return; } - ofstream stream(outfile.toLatin1()); + std::ofstream stream(outfile.toLatin1()); if (!stream) { QMessageBox::warning(this, tr("Notice"), tr("Sorry, unable to open file for export"), QMessageBox::Ok, QMessageBox::Ok); } @@ -598,13 +690,13 @@ void QGraphDoc::OnFileExport() int thedot = outfile.indexOf('.'); QString outfile2 = outfile.left(thedot+1) + tr("mid"); - ofstream miffile(outfile.toLatin1()); + std::ofstream miffile(outfile.toLatin1()); if (miffile.fail() || miffile.bad()) { QMessageBox::warning(this, tr("Notice"), tr("Sorry, unable to open file for export"), QMessageBox::Ok, QMessageBox::Ok); mode = -1; } - ofstream midfile(outfile2.toLatin1()); + std::ofstream midfile(outfile2.toLatin1()); if (midfile.fail() || midfile.bad()) { QMessageBox::warning(this, tr("Notice"), tr("Sorry, unable to open associated .mid file for export"), QMessageBox::Ok, QMessageBox::Ok); mode = -1; @@ -622,6 +714,374 @@ void QGraphDoc::OnFileExport() } } +void QGraphDoc::OnFileExportMapGeometry() { + if (m_communicator) { + QMessageBox::warning(this, tr("Notice"), tr("Sorry, cannot export as another process is running"), + QMessageBox::Ok, QMessageBox::Ok); + return; // Locked + } + if (m_meta_graph->viewingNone()) { + QMessageBox::warning(this, tr("Notice"), tr("Sorry, cannot export as there is no data to export"), + QMessageBox::Ok, QMessageBox::Ok); + return; // No graph to export + } + + QString suffix; + int mode = -1; + + int view_class = m_meta_graph->getViewClass(); + if (view_class & MetaGraph::VIEWAXIAL) { + mode = 0; + suffix = m_meta_graph->getDisplayedShapeGraph().getName().c_str(); + } else if (view_class & MetaGraph::VIEWDATA) { + mode = 1; + suffix = m_meta_graph->getDisplayedDataMap().getName().c_str(); + } + + if (mode == -1) { + QMessageBox::warning(this, tr("Notice"), + tr("Sorry, depthmapX does not support saving the currently displayed layer"), + QMessageBox::Ok, QMessageBox::Ok); + return; + } + suffix.replace(' ', '_'); + + QFilePath path(m_opened_name); + QString defaultname = path.m_path + (path.m_name.isEmpty() ? windowTitle() : path.m_name) + tr("_") + suffix; + + QString template_string = tr("Chiron and Alasdair Transfer Format file (*.cat)\n"); + + QFileDialog::Options options = 0; + QString selectedFilter; + QString outfile = + QFileDialog::getSaveFileName(0, tr("Save Output As"), defaultname, template_string, &selectedFilter, options); + if (outfile.isEmpty()) { + return; + } + + FILE *fp = fopen(outfile.toLatin1(), "wb"); + fclose(fp); + + QFilePath filepath(outfile); + QString ext = filepath.m_ext; + + if (ext == "CAT") { + std::ofstream stream(outfile.toLatin1()); + if (stream.fail() || stream.bad()) { + QMessageBox::warning(this, tr("Notice"), tr("Sorry, unable to open file for export"), QMessageBox::Ok, + QMessageBox::Ok); + mode = -1; + } + + switch (mode) { + case 0: + m_meta_graph->writeMapShapesAsCat(m_meta_graph->getDisplayedShapeGraph(), stream); + break; + case 1: + m_meta_graph->writeMapShapesAsCat(m_meta_graph->getDisplayedDataMap(), stream); + break; + default: + break; + } + stream.close(); + } +} + +void QGraphDoc::OnFileExportLinks() +{ + if (m_communicator) { + QMessageBox::warning(this, tr("Notice"), tr("Sorry, cannot export as another process is running"), QMessageBox::Ok, QMessageBox::Ok); + return; // Locked + } + if (m_meta_graph->viewingNone()) { + QMessageBox::warning(this, tr("Notice"), tr("Sorry, cannot export as there is no data to export"), QMessageBox::Ok, QMessageBox::Ok); + return; // No graph to export + } + + QString suffix; + int mode = -1; + + int view_class = m_meta_graph->getViewClass(); + if (view_class & MetaGraph::VIEWAXIAL) { + mode = 5; + suffix = tr("unlinks"); + } + else if (view_class & MetaGraph::VIEWDATA) { + mode = 6; + suffix = tr("links"); + } + else if (view_class & MetaGraph::VIEWVGA) { + if (m_meta_graph->getDisplayedPointMap().isProcessed()) { + mode = 4; + suffix = tr("merge_lines"); + } + } + + if (mode == -1) { + QMessageBox::warning(this, tr("Notice"), tr("Sorry, depthmapX does not support saving the currently displayed layer"), QMessageBox::Ok, QMessageBox::Ok); + return; + } + suffix.replace(' ','_'); + + QFilePath path(m_opened_name); + QString defaultname = path.m_path + (path.m_name.isEmpty() ? windowTitle() : path.m_name) + tr("_") + suffix; + + QString template_string = tr("Tab-delimited text file (*.txt)\n"); + template_string += tr("Comma separated values file (*.csv)\n"); + template_string += tr("All files (*.*)"); + + QFileDialog::Options options = 0; + QString selectedFilter; + QString outfile = QFileDialog::getSaveFileName( + 0, tr("Save Output As"), + defaultname, + template_string, + &selectedFilter, + options); + if(outfile.isEmpty()) + { + return; + } + + FILE* fp = fopen(outfile.toLatin1(), "wb"); + fclose(fp); + + QFilePath filepath(outfile); + QString ext = filepath.m_ext; + + std::ofstream stream(outfile.toLatin1()); + char delimiter = '\t'; + if (ext == "CSV") { + delimiter = ','; + } + if (stream.fail() || stream.bad()) { + QMessageBox::warning(this, tr("Notice"), tr("Sorry, unable to open file for export"), QMessageBox::Ok, QMessageBox::Ok); + mode = -1; + } + + switch (mode) { + case 0: + m_meta_graph->getDisplayedShapeGraph().output(stream, delimiter); + break; + case 1: + m_meta_graph->getDisplayedDataMap().output(stream, delimiter); + break; + case 2: + m_meta_graph->getDisplayedPointMap().outputSummary( stream, delimiter ); + break; + case 3: + m_meta_graph->getDisplayedPointMap().outputPoints( stream, delimiter ); + break; + case 4: + m_meta_graph->getDisplayedPointMap().outputMergeLines( stream, delimiter ); + break; + case 5: + // note: specific to line graphs + m_meta_graph->getDisplayedShapeGraph().outputUnlinkPoints( stream, delimiter ); + break; + default: + break; + } + stream.close(); +} + +void QGraphDoc::OnAxialConnectionsExportAsDot() +{ + if (m_communicator) { + QMessageBox::warning(this, tr("Notice"), tr("Sorry, cannot export as another process is running"), QMessageBox::Ok, QMessageBox::Ok); + return; // Locked + } + if (m_meta_graph->viewingNone()) { + QMessageBox::warning(this, tr("Notice"), tr("Sorry, cannot export as there is no data to export"), QMessageBox::Ok, QMessageBox::Ok); + return; // No graph to export + } + + ShapeGraph& shapeGraph = m_meta_graph->getDisplayedShapeGraph(); + + QString suffix = tr("axial_connections"); + + QFilePath path(m_opened_name); + QString defaultname = path.m_path + (path.m_name.isEmpty() ? windowTitle() : path.m_name) + tr("_") + suffix; + + QString template_string = tr("Dot graph file (*.dot)"); + + QFileDialog::Options options = 0; + QString selectedFilter; + QString outfile = QFileDialog::getSaveFileName( + 0, tr("Save Output As"), + defaultname, + template_string, + &selectedFilter, + options); + if(outfile.isEmpty()) + { + return; + } + + FILE* fp = fopen(outfile.toLatin1(), "wb"); + fclose(fp); + + std::ofstream stream(outfile.toLatin1()); + + if (stream.fail() || stream.bad()) { + QMessageBox::warning(this, tr("Notice"), tr("Sorry, unable to open file for export"), QMessageBox::Ok, QMessageBox::Ok); + return; + } + shapeGraph.writeAxialConnectionsAsDotGraph(stream); + + stream.close(); +} + +void QGraphDoc::OnAxialConnectionsExportAsPairCSV() +{ + if (m_communicator) { + QMessageBox::warning(this, tr("Notice"), tr("Sorry, cannot export as another process is running"), QMessageBox::Ok, QMessageBox::Ok); + return; // Locked + } + if (m_meta_graph->viewingNone()) { + QMessageBox::warning(this, tr("Notice"), tr("Sorry, cannot export as there is no data to export"), QMessageBox::Ok, QMessageBox::Ok); + return; // No graph to export + } + + ShapeGraph& shapeGraph = m_meta_graph->getDisplayedShapeGraph(); + + QString suffix = tr("axial_connections"); + + QFilePath path(m_opened_name); + QString defaultname = path.m_path + (path.m_name.isEmpty() ? windowTitle() : path.m_name) + tr("_") + suffix; + + QString template_string = tr("CSV graph file (*.csv)"); + + QFileDialog::Options options = 0; + QString selectedFilter; + QString outfile = QFileDialog::getSaveFileName( + 0, tr("Save Output As"), + defaultname, + template_string, + &selectedFilter, + options); + if(outfile.isEmpty()) + { + return; + } + + FILE* fp = fopen(outfile.toLatin1(), "wb"); + fclose(fp); + + std::ofstream stream(outfile.toLatin1()); + + if (stream.fail() || stream.bad()) { + QMessageBox::warning(this, tr("Notice"), tr("Sorry, unable to open file for export"), QMessageBox::Ok, QMessageBox::Ok); + return; + } + shapeGraph.writeAxialConnectionsAsPairsCSV(stream); + + stream.close(); +} + +void QGraphDoc::OnSegmentConnectionsExportAsPairCSV() +{ + if (m_communicator) { + QMessageBox::warning(this, tr("Notice"), tr("Sorry, cannot export as another process is running"), QMessageBox::Ok, QMessageBox::Ok); + return; // Locked + } + if (m_meta_graph->viewingNone()) { + QMessageBox::warning(this, tr("Notice"), tr("Sorry, cannot export as there is no data to export"), QMessageBox::Ok, QMessageBox::Ok); + return; // No graph to export + } + + ShapeGraph& shapeGraph = m_meta_graph->getDisplayedShapeGraph(); + + QString suffix = tr("segment_connections"); + + QFilePath path(m_opened_name); + QString defaultname = path.m_path + (path.m_name.isEmpty() ? windowTitle() : path.m_name) + tr("_") + suffix; + + QString template_string = tr("CSV graph file (*.csv)"); + + QFileDialog::Options options = 0; + QString selectedFilter; + QString outfile = QFileDialog::getSaveFileName( + 0, tr("Save Output As"), + defaultname, + template_string, + &selectedFilter, + options); + if(outfile.isEmpty()) + { + return; + } + + FILE* fp = fopen(outfile.toLatin1(), "wb"); + fclose(fp); + + std::ofstream stream(outfile.toLatin1()); + + if (stream.fail() || stream.bad()) { + QMessageBox::warning(this, tr("Notice"), tr("Sorry, unable to open file for export"), QMessageBox::Ok, QMessageBox::Ok); + return; + } + shapeGraph.writeSegmentConnectionsAsPairsCSV(stream); + + stream.close(); +} + +void QGraphDoc::OnPointmapExportConnectionsAsCSV() +{ + if (m_communicator) { + QMessageBox::warning(this, tr("Notice"), tr("Sorry, cannot export as another process is running"), QMessageBox::Ok, QMessageBox::Ok); + return; // Locked + } + if (m_meta_graph->viewingNone()) { + QMessageBox::warning(this, tr("Notice"), tr("Sorry, cannot export as there is no data to export"), QMessageBox::Ok, QMessageBox::Ok); + return; // No graph to export + } + if (!(m_meta_graph->getViewClass() & MetaGraph::VIEWVGA)) { + QMessageBox::warning(this, tr("Error"), tr("Make sure a Visibility Graph is visible"), QMessageBox::Ok, QMessageBox::Ok); + return; // No graph to export + } + if (!m_meta_graph->viewingProcessedPoints()) { + QMessageBox::warning(this, tr("Error"), + tr("Make sure the visibility graph was created (Tools -> Visibility -> Make Visibility Graph)"), + QMessageBox::Ok, QMessageBox::Ok); + return; // No graph to export + } + + PointMap& pointMap = m_meta_graph->getDisplayedPointMap(); + + QString suffix = tr("connectivity"); + + QFilePath path(m_opened_name); + QString defaultname = path.m_path + (path.m_name.isEmpty() ? windowTitle() : path.m_name) + tr("_") + suffix; + + QString template_string = tr("CSV graph file (*.csv)"); + + QFileDialog::Options options = 0; + QString selectedFilter; + QString outfile = QFileDialog::getSaveFileName( + 0, tr("Save Output As"), + defaultname, + template_string, + &selectedFilter, + options); + if(outfile.isEmpty()) + { + return; + } + + FILE* fp = fopen(outfile.toLatin1(), "wb"); + fclose(fp); + + std::ofstream stream(outfile.toLatin1()); + + if (stream.fail() || stream.bad()) { + QMessageBox::warning(this, tr("Notice"), tr("Sorry, unable to open file for export"), QMessageBox::Ok, QMessageBox::Ok); + return; + } + pointMap.outputConnectionsAsCSV(stream, ","); + + stream.close(); +} void QGraphDoc::OnSwapColours() { @@ -661,45 +1121,28 @@ void QGraphDoc::OnEditGrid() } bool newmap = false; - if (!m_meta_graph->PointMaps::size() || m_meta_graph->getDisplayedPointMap().isProcessed()) { + if (m_meta_graph->getPointMaps().empty() || m_meta_graph->getDisplayedPointMap().isProcessed()) { // this can happen if there are no displayed maps -- so flag new map required: newmap = true; } - else if (m_meta_graph->getDisplayedPointMap().getPointCount() != 0) { + else if (m_meta_graph->getDisplayedPointMap().getFilledPointCount() != 0) { if ( QMessageBox::Yes != QMessageBox::question(this, tr("depthmapX"), tr("This will clear existing points. Do you want to continue?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::No) ) return; } - CGridDialog dlg; - QtRegion r = m_meta_graph->SuperSpacePixel::getRegion(); - dlg.m_maxdimension = __max(r.width(), r.height()); + QtRegion r = m_meta_graph->getRegion(); + CGridDialog dlg(__max(r.width(), r.height())); if (QDialog::Accepted == dlg.exec()) { if (newmap) { - m_meta_graph->PointMaps::addNewMap(); + m_meta_graph->addNewPointMap(); } - m_meta_graph->setGrid( dlg.m_spacing, Point2f(0.0f, 0.0f) ); + m_meta_graph->setGrid( dlg.getSpacing(), Point2f(0.0f, 0.0f) ); m_meta_graph->m_showgrid = true; SetUpdateFlag(NEW_TABLE); SetRedrawFlag(VIEW_ALL,REDRAW_GRAPH, NEW_DATA); } } -void QGraphDoc::OnEditFixgrid() -{ -} - -void QGraphDoc::OnEditFixFill() -{ - // only used in Developer mode - if (m_communicator) { - QMessageBox::warning(this, tr("Notice"), tr("Please wait, another task is running"), QMessageBox::Ok, QMessageBox::Ok); - return; - } - m_meta_graph->getDisplayedPointMap().fillLines(); - - SetRedrawFlag(VIEW_ALL,REDRAW_GRAPH, NEW_DATA); -} - // AV TV // semifilled void QGraphDoc::OnFillPoints( const Point2f& p, int fill_type ) // semifilled = 0 (intention to use semifilled steps for part filled) { @@ -730,29 +1173,6 @@ void QGraphDoc::OnFillPoints( const Point2f& p, int fill_type ) // semifilled = m_thread.render(this); } -///////////////////////////////////////////////////////////////////////////////////////////////////// - -void QGraphDoc::OnToolsBoundaryToAxial() -{ - int state = m_meta_graph->getState(); - if (m_communicator) { - QMessageBox::warning(this, tr("Notice"), tr("Please wait, another task is running"), QMessageBox::Ok, QMessageBox::Ok); - return; - } - if (!m_meta_graph->getDisplayedPointMap().isProcessed()) { - QMessageBox::warning(this, tr("Notice"), tr("Sorry, a graph must exist to construct map"), QMessageBox::Ok, QMessageBox::Ok); - return; - } - - // This is easy too... too easy... hmm... crossed-fingers, here goes: - m_communicator = new CMSCommunicator(); - CreateWaitDialog(tr("Constructing boundary axial map...")); - m_communicator->SetFunction( CMSCommunicator::MAKEBOUNDARYMAP ); - - m_thread.render(this); -} - - // convert any shape layer to any other (certain rules apply) void QGraphDoc::OnLayerConvert() @@ -982,11 +1402,7 @@ void QGraphDoc::OnToolsMakeFewestLineMap() int replace = 0; // check for existing axial maps and warn user if necessary: - ShapeGraphs& axialmaps = m_meta_graph->getShapeGraphs(); - if (axialmaps.getMapRef("Fewest-Line Map (Subsets)") != paftl::npos || - axialmaps.getMapRef("Fewest Line Map (Subsets)") != paftl::npos || - axialmaps.getMapRef("Fewest-Line Map (Minimal)") != paftl::npos || - axialmaps.getMapRef("Fewest Line Map (Minimal)") != paftl::npos) { + if (m_meta_graph->hasFewestLineMaps()) { CPromptReplace dlg; dlg.m_message = tr("There is already a fewest line axial map, would you like to add to it or replace it?"); int result = dlg.exec(); @@ -1037,7 +1453,8 @@ void QGraphDoc::OnToolsRunSeg() if (QDialog::Accepted == dlg.exec()) { m_communicator = new CMSCommunicator(); CreateWaitDialog(tr("Performing segment line analysis...")); - m_communicator->SetFunction( CMSCommunicator::SEGMENTANALYSIS ); + m_communicator->SetFunction( dlg.m_analysis_type == 1 ? CMSCommunicator::SEGMENTANALYSISANGULAR : + CMSCommunicator::SEGMENTANALYSISTULIP ); m_thread.render(this); } } @@ -1057,7 +1474,7 @@ void QGraphDoc::OnToolsTopomet() ((MainWindow*)m_mainFrame)->m_options.output_type = dlg.m_topological; ((MainWindow*)m_mainFrame)->m_options.radius = dlg.m_dradius; ((MainWindow*)m_mainFrame)->m_options.sel_only = dlg.m_selected_only; - if (dlg.m_topological == 0) { + if (dlg.isAnalysisTopological()) { CreateWaitDialog(tr("Performing topological analysis...")); } else { @@ -1068,22 +1485,6 @@ void QGraphDoc::OnToolsTopomet() } } -//////////////////////////////////////////////////////////////////////// - -void QGraphDoc::OnToolsAxialClearLinks() -{ - if(QMessageBox::Yes == QMessageBox::warning(this, tr("depthmapX"), - tr("Are you sure you want to clear all links and unlinks?"), - QMessageBox::Yes | QMessageBox::No - | QMessageBox::Yes, - QMessageBox::No)) - { - m_meta_graph->getDisplayedShapeGraph().clearLinks(); - // if currently in join mode, then redraw: - SetRedrawFlag(VIEW_ALL, REDRAW_GRAPH, NEW_DATA ); - } -} - /////////////////////////////////////////////////////////////////////////////////////////// // New agent functionality: @@ -1098,27 +1499,27 @@ void QGraphDoc::OnToolsAgentRun() AgentEngine& eng = m_meta_graph->getAgentEngine(); // set up eng here... - if (!eng.size()) { - eng.push_back(AgentSet()); + if (!eng.agentSets.size()) { + eng.agentSets.push_back(AgentSet()); } CAgentAnalysisDlg dlg; dlg.m_timesteps = eng.m_timesteps; - dlg.m_release_rate = eng.tail().m_release_rate; - dlg.m_release_location = eng.tail().m_release_locations.size() ? 1 : 0; - dlg.m_frames = eng.tail().m_lifetime; - if (eng.tail().m_vbin == -1) { + dlg.m_release_rate = eng.agentSets.back().m_release_rate; + dlg.m_release_location = eng.agentSets.back().m_release_locations.size() ? 1 : 0; + dlg.m_frames = eng.agentSets.back().m_lifetime; + if (eng.agentSets.back().m_vbin == -1) { dlg.m_fov = 32; } else { - dlg.m_fov = eng.tail().m_vbin * 2 + 1; + dlg.m_fov = eng.agentSets.back().m_vbin * 2 + 1; } - dlg.m_steps = eng.tail().m_steps; + dlg.m_steps = eng.agentSets.back().m_steps; dlg.m_record_trails = eng.m_record_trails; dlg.m_trail_count = eng.m_trail_count; - dlg.m_names.push_back(pstring("")); - for (size_t i = 0; i < m_meta_graph->getDataMaps().getMapCount(); i++) { - dlg.m_names.push_back(m_meta_graph->getDataMaps().getMap(i).getName()); + dlg.m_names.push_back(""); + for (size_t i = 0; i < m_meta_graph->getDataMaps().size(); i++) { + dlg.m_names.push_back(m_meta_graph->getDataMaps()[i].getName()); } dlg.m_gatelayer = eng.m_gatelayer; @@ -1127,33 +1528,34 @@ void QGraphDoc::OnToolsAgentRun() } eng.m_timesteps = dlg.m_timesteps; - eng.tail().m_release_rate = dlg.m_release_rate; - eng.tail().m_lifetime = dlg.m_frames; + eng.agentSets.back().m_release_rate = dlg.m_release_rate; + eng.agentSets.back().m_lifetime = dlg.m_frames; if (dlg.m_fov == 32) { - eng.tail().m_vbin = -1; + eng.agentSets.back().m_vbin = -1; } else { - eng.tail().m_vbin = (dlg.m_fov - 1) / 2; + eng.agentSets.back().m_vbin = (dlg.m_fov - 1) / 2; } - eng.tail().m_steps = dlg.m_steps; + eng.agentSets.back().m_steps = dlg.m_steps; if (dlg.m_occlusion == 0) { - eng.tail().m_sel_type = AgentProgram::SEL_STANDARD; + eng.agentSets.back().m_sel_type = AgentProgram::SEL_STANDARD; } else if (dlg.m_occlusion == 1) { - eng.tail().m_sel_type = AgentProgram::SEL_LOS; + eng.agentSets.back().m_sel_type = AgentProgram::SEL_LOS; } else if (dlg.m_occlusion == 2) { - eng.tail().m_sel_type = AgentProgram::SEL_LOS_OCC; + eng.agentSets.back().m_sel_type = AgentProgram::SEL_LOS_OCC; } else { // (dlg.m_occlusion - 2) should be from 1...8 - eng.tail().m_sel_type = AgentProgram::SEL_OCCLUSION + (dlg.m_occlusion - 2); + eng.agentSets.back().m_sel_type = AgentProgram::SEL_OCCLUSION + (dlg.m_occlusion - 2); } if (dlg.m_release_location == 1) { - eng.tail().m_release_locations = m_meta_graph->getSelSet(); + std::set selected = m_meta_graph->getSelSet(); + std::copy(selected.begin(), selected.end(), std::back_inserter(eng.agentSets.back().m_release_locations));; } else { - eng.tail().m_release_locations.clear(); + eng.agentSets.back().m_release_locations.clear(); } eng.m_gatelayer = dlg.m_gatelayer; @@ -1172,36 +1574,6 @@ void QGraphDoc::OnToolsAgentRun() m_thread.render(this); } -// some evo agent code... not sure if this works or not! - -void QGraphDoc::OnEvoAgent() -{ -/* if (!m_evoagent) { - m_evoagent = (CEvoAgent *) AfxBeginThread(RUNTIME_CLASS(CEvoAgent)); - if (!m_evoagent) { - AfxMessageBox(tr("An error occurred trying to start the agent simulation module")); - return; - } - else { - CEvoAgentSetup dlg; - if (dlg.DoModal() == IDOK) { - m_evoagent->Init(this,dlg.m_evolveapply,dlg.m_filename,dlg.m_seed); - m_evoagent->PostThreadMessage(WM_DMP_RUN,0,0); - } - else { - m_evoagent->PostThreadMessage(WM_DMP_FINISHED_MESSAGE,0,0); - m_evoagent = NULL; - } - } - } - else { - // turn off pause (typically pauses after evaluation run) - m_evoagent->m_paused = false; - m_evoagent->PostThreadMessage(WM_DMP_RUN,0,0); - } - */ -} - ///////////////////////////////////////////////////////////////////////////// void QGraphDoc::OnEditUndo() @@ -1231,14 +1603,19 @@ void QGraphDoc::OnEditClear() return; } + bool modified = false; if (m_meta_graph->viewingUnprocessedPoints()) { - m_meta_graph->clearPoints(); + modified = m_meta_graph->clearPoints(); } else if (m_meta_graph->viewingProcessedLines()) { - m_meta_graph->getDisplayedShapeGraph().removeSelected(); + modified = m_meta_graph->getDisplayedShapeGraph().removeSelected(); } else if (m_meta_graph->viewingProcessedShapes()) { - m_meta_graph->getDisplayedDataMap().removeSelected(); + modified = m_meta_graph->getDisplayedDataMap().removeSelected(); + } + + if(modified) { + modifiedFlag = true; } SetRedrawFlag(VIEW_ALL, REDRAW_GRAPH, NEW_DATA ); @@ -1258,9 +1635,6 @@ void QGraphDoc::OnToolsMakeGraph() QMessageBox::warning(this, tr("Warning"), tr("Sorry, you need an unprocessed set of points to make the visibility graph"), QMessageBox::Ok, QMessageBox::Ok); return; } - /*if (!CheckMemory()) { - return; - }*/ CMakeOptionsDlg dlg; dlg.m_boundarygraph = false; @@ -1287,21 +1661,38 @@ void QGraphDoc::OnToolsMakeGraph() m_thread.render(this); } -///////////////////////////////////////////////////////////////////////////// - - -void QGraphDoc::OnVGAOptions() +void QGraphDoc::OnToolsUnmakeGraph() { - COptionsDlg dlg; - - dlg.m_layer_names.push_back(pstring("")); - for (size_t i = 0; i < m_meta_graph->getDataMaps().getMapCount(); i++) { - dlg.m_layer_names.push_back(m_meta_graph->getDataMaps().getMap(i).getName()); - } - - dlg.exec(); + int state = m_meta_graph->getState(); + if (m_communicator) { + QMessageBox::warning(this, tr("Notice"), tr("Please wait, another task is running"), QMessageBox::Ok, QMessageBox::Ok); + return; + } + if (~state & MetaGraph::POINTMAPS) { + QMessageBox::warning(this, tr("Notice"), tr("Please make grid before filling"), QMessageBox::Ok, QMessageBox::Ok); + return; + } + if (m_meta_graph->viewingProcessed()) { + if ( QMessageBox::Yes != QMessageBox::question(this, tr("Notice"), + tr("This will clear existing data and attributes. Do you want to continue?"), + QMessageBox::Yes|QMessageBox::No, QMessageBox::No) ) + return; + } + bool removeLinks = false; + if(m_meta_graph->getDisplayedPointMap().getMergedPixelPairs().size() > 0) { + removeLinks = QMessageBox::Yes == QMessageBox::question(this, tr("Notice"), + tr("Would you also like to clear the links?"), + QMessageBox::Yes|QMessageBox::No, QMessageBox::No); + } + bool ok = m_meta_graph->unmakeGraph(removeLinks); + if (ok) { + SetUpdateFlag(QGraphDoc::NEW_DATA); + } + SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); } +///////////////////////////////////////////////////////////////////////////// + void QGraphDoc::OnToolsRun() { if (m_communicator) { @@ -1312,9 +1703,9 @@ void QGraphDoc::OnToolsRun() // This is easy! COptionsDlg dlg; - dlg.m_layer_names.push_back(pstring("")); - for (size_t i = 0; i < m_meta_graph->getDataMaps().getMapCount(); i++) { - dlg.m_layer_names.push_back(m_meta_graph->getDataMaps().getMap(i).getName()); + dlg.m_layer_names.push_back(""); + for (auto& dataMap: m_meta_graph->getDataMaps()) { + dlg.m_layer_names.push_back(dataMap.getName()); } if (QDialog::Accepted != dlg.exec()) { @@ -1389,17 +1780,6 @@ void QGraphDoc::OnToolsAPD() } } } -/* -void QGraphDoc::OnUpdateToolsTPD()//CCmdUI *pCmdUI) -{ - // segment maps only (with selection) - if (m_meta_graph->viewingProcessedLines() && m_meta_graph->getDisplayedShapeGraph().isSegmentMap() && m_meta_graph->isSelected()) { - pCmdUI->Enable(TRUE); - } - else { - pCmdUI->Enable(FALSE); - } -}*/ void QGraphDoc::OnToolsTPD() { @@ -1421,42 +1801,6 @@ void QGraphDoc::OnToolsTPD() } } -void QGraphDoc::OnBinDisplay() -{ - if (m_communicator) { - QMessageBox::warning(this, tr("Warning"), tr("Please wait, another process is running"), QMessageBox::Ok, QMessageBox::Ok); - return; - } - - if (m_meta_graph->viewingProcessedPoints()) { - if (m_meta_graph->isSelected()) { - - // This is easy too... too easy... hmm... crossed-fingers, here goes: - m_communicator = new CMSCommunicator(); - CreateWaitDialog(tr("Showing bins...")); - m_communicator->SetFunction( CMSCommunicator::BINDISPLAY ); - - m_thread.render(this); - } - } -} - -///////////////////////////////////////////////////////////////////////////// - -void QGraphDoc::OnToolsAxialLines() -{ - if (m_communicator) { - QMessageBox::warning(this, tr("Warning"), tr("Please wait, another process is running"), QMessageBox::Ok, QMessageBox::Ok); - return; - } - - // This is easy too... too easy... hmm... crossed-fingers, here goes: - m_communicator = new CMSCommunicator(); - CreateWaitDialog(tr("Analysing graph...")); - m_communicator->SetFunction( CMSCommunicator::MAKEAXIALLINES ); - m_thread.render(this); -} - ///////////////////////////////////////////////////////////////////////////// static int sequenceNumber = 1; bool QGraphDoc::OnNewDocument() @@ -1476,7 +1820,7 @@ int QGraphDoc::OnOpenDocument(char* lpszPathName) m_opened_name = QString(lpszPathName); - int ok = m_meta_graph->read( lpszPathName ); + int ok = m_meta_graph->readFromFile( lpszPathName ); QFilePath path(m_opened_name); SetUpdateFlag(QGraphDoc::NEW_FILE,false); @@ -1488,33 +1832,33 @@ int QGraphDoc::OnOpenDocument(char* lpszPathName) ret = TRUE; break; case MetaGraph::WARN_BUGGY_VERSION: - QMessageBox::warning(this, tr("Warning"), tr("this graph was made with a version of depthmapX that contained slight errors"), QMessageBox::Yes, QMessageBox::Yes); + QMessageBox::warning(this, tr("Warning"), tr("this graph was made with a version of depthmapX that contained slight errors"), QMessageBox::Ok, QMessageBox::Ok); ret = TRUE; break; case MetaGraph::WARN_CONVERTED: QMessageBox::warning(this, tr("Warning"), tr("Warning: this graph was made with an older version of depthmapX.\n" \ - "Some aspects of the graph may not have been translated to the new depthmapX properly."), QMessageBox::Yes, QMessageBox::Yes); + "Some aspects of the graph may not have been translated to the new depthmapX properly."), QMessageBox::Ok, QMessageBox::Ok); ret = TRUE; break; case MetaGraph::NOT_A_GRAPH: - QMessageBox::warning(this, tr("Warning"), tr("Unable to open graph: not recognised as a graph file."), QMessageBox::Yes, QMessageBox::Yes); + QMessageBox::warning(this, tr("Warning"), tr("Unable to open graph: not recognised as a graph file."), QMessageBox::Ok, QMessageBox::Ok); break; case MetaGraph::DAMAGED_FILE: - QMessageBox::warning(this, tr("Warning"), tr("Unable to open graph: the graph file is damaged."), QMessageBox::Yes, QMessageBox::Yes); + QMessageBox::warning(this, tr("Warning"), tr("Unable to open graph: the graph file is damaged."), QMessageBox::Ok, QMessageBox::Ok); break; case MetaGraph::DISK_ERROR: - QMessageBox::warning(this, tr("Warning"), tr("Unable to open graph: an error occurred while trying to read from the disk."), QMessageBox::Yes, QMessageBox::Yes); + QMessageBox::warning(this, tr("Warning"), tr("Unable to open graph: an error occurred while trying to read from the disk."), QMessageBox::Ok, QMessageBox::Ok); break; case MetaGraph::NEWER_VERSION: - QMessageBox::warning(this, tr("Warning"), tr("Unable to open graph: this graph has been written by a newer version of depthmapX."), QMessageBox::Yes, QMessageBox::Yes); + QMessageBox::warning(this, tr("Warning"), tr("Unable to open graph: this graph has been written by a newer version of depthmapX."), QMessageBox::Ok, QMessageBox::Ok); break; case MetaGraph::DEPRECATED_VERSION: - QMessageBox::warning(this, tr("Warning"), tr("Unable to open graph: this is a graph file format not supported by this version of depthmapX."), QMessageBox::Yes, QMessageBox::Yes); + QMessageBox::warning(this, tr("Warning"), tr("Unable to open graph: this is a graph file format not supported by this version of depthmapX."), QMessageBox::Ok, QMessageBox::Ok); break; default: { - pstring err = pstringify(ok); - QMessageBox::warning(this, tr("Warning"), tr("Unable to open graph: error number "), QMessageBox::Yes, QMessageBox::Yes); + std::string err = dXstring::formatString(ok); + QMessageBox::warning(this, tr("Warning"), tr("Unable to open graph: error number "), QMessageBox::Ok, QMessageBox::Ok); } break; } @@ -1522,11 +1866,11 @@ int QGraphDoc::OnOpenDocument(char* lpszPathName) return ret; } -void QGraphDoc::OnFileSave() +bool QGraphDoc::OnFileSave() { QString newName = m_opened_name; if (newName.isEmpty()) { - newName = windowTitle() + tr(".graph"); + newName = m_base_title + tr(".graph"); QFileDialog::Options options = 0; QString outfile = QFileDialog::getSaveFileName( 0, tr("Save As"), @@ -1534,21 +1878,25 @@ void QGraphDoc::OnFileSave() tr("Graph file (*.graph)\nAll files (*.*)"), 0, options); - if (outfile.isEmpty()) return; + if (outfile.isEmpty()) return false; m_opened_name = outfile; FILE* fp = fopen(m_opened_name.toLatin1(), "wb"); fclose(fp); - OnSaveDocument(outfile); - return; + OnSaveDocument(outfile); + + QFilePath path(m_opened_name); + m_base_title = path.m_name; + return true; } - OnSaveDocument(newName); + OnSaveDocument(newName); + return true; } -void QGraphDoc::OnFileSaveAs() +bool QGraphDoc::OnFileSaveAs() { // This is based on Microsoft's "DoSave" function, but // it allows two options for saving: one as the current @@ -1556,7 +1904,7 @@ void QGraphDoc::OnFileSaveAs() QString newName = m_opened_name; if (newName.isEmpty()) { - newName = windowTitle() + tr(".graph"); + newName = m_base_title + tr(".graph"); } QFileDialog::Options options = 0; @@ -1568,7 +1916,7 @@ void QGraphDoc::OnFileSaveAs() options); if (outfile.isEmpty()) - return; + return false; FILE* fp = fopen(outfile.toLatin1(), "wb"); fclose(fp); @@ -1576,7 +1924,10 @@ void QGraphDoc::OnFileSaveAs() OnSaveDocument(outfile.toLatin1()); // reset the title and change the document name - m_opened_name = newName; + m_opened_name = outfile; + QFilePath path(m_opened_name); + m_base_title = path.m_name; + return true; } int QGraphDoc::OnSaveDocument(QString lpszPathName) @@ -1606,7 +1957,7 @@ int QGraphDoc::OnSaveDocument(QString lpszPathName, int version) modifiedFlag = true; - int ok = m_meta_graph->write( pstring(lpszPathName.toLatin1()), version ); + int ok = m_meta_graph->write( lpszPathName.toStdString(), version ); if (ok == MetaGraph::OK) { modifiedFlag = false; return TRUE; @@ -1660,51 +2011,31 @@ bool QGraphDoc::OnCloseDocument(int index) return true; } -void QGraphDoc::OnAddGate() -{ - if (m_communicator) { - QMessageBox::warning(this, tr("Warning"), tr("Please wait, another process is running"), QMessageBox::Ok, QMessageBox::Ok); - return; - } - if (m_meta_graph->getViewClass() & MetaGraph::VIEWVGA) { - // try the new thingy: - if (m_meta_graph->convertPointsToShape()) { - // redraw all as change of view is affected here: - // (also possibly even the sidebar menu: -// GetApp()->GetMainWnd()->PostMessage( WM_DMP_FOCUS_GRAPH, (WPARAM) this, QGraphDoc::CONTROLS_LOADGRAPH ); - SetRedrawFlag(VIEW_ALL, REDRAW_GRAPH, NEW_DEPTHMAPVIEW_SETUP ); - } - else { - QMessageBox::warning(this, tr("Warning"), tr("There was an error trying to convert points to a shape.\nPlease check that you have selected a single polygon without holes.") ); - } - } -} - void QGraphDoc::OnPushToLayer() { if (m_meta_graph->viewingProcessed()) { int toplayerclass = (m_meta_graph->getViewClass() & MetaGraph::VIEWFRONT); - pstring origin_layer; - pstring origin_attribute; - pqmap names; + std::string origin_layer; + std::string origin_attribute; + std::map, std::string> names; // I'm just going to allow push from any layer to any other layer // (apart from VGA graphs, which cannot map onto themselves if (toplayerclass == MetaGraph::VIEWVGA) { // bit clunky just to get two names out... PointMap& map = m_meta_graph->getDisplayedPointMap(); - origin_layer = pstring("Visibility Graphs: ") + map.getName(); + origin_layer = std::string("Visibility Graphs: ") + map.getName(); origin_attribute = map.getAttributeTable().getColumnName(map.getDisplayedAttribute()); } else if (toplayerclass == MetaGraph::VIEWAXIAL) { // bit clunky just to get two names out... ShapeGraph& map = m_meta_graph->getDisplayedShapeGraph(); - origin_layer = pstring("Shape Graphs: ") + map.getName(); + origin_layer = std::string("Shape Graphs: ") + map.getName(); origin_attribute = map.getAttributeTable().getColumnName(map.getDisplayedAttribute()); } else if (toplayerclass == MetaGraph::VIEWDATA) { // bit clunky just to get two names out... ShapeMap& map = m_meta_graph->getDisplayedDataMap(); - origin_layer = pstring("Data Maps: ") + map.getName(); + origin_layer = std::string("Data Maps: ") + map.getName(); origin_attribute = map.getAttributeTable().getColumnName(map.getDisplayedAttribute()); } else { @@ -1714,23 +2045,24 @@ void QGraphDoc::OnPushToLayer() } // layers to push to: size_t i; - ShapeMaps& datamaps = m_meta_graph->getDataMaps(); - for (i = 0; i < datamaps.getMapCount(); i++) { - if (toplayerclass != MetaGraph::VIEWDATA || i != datamaps.getDisplayedMapRef()) { - names.add(IntPair(MetaGraph::VIEWDATA,int(i)),pstring("Data Maps: ") + datamaps.getMap(i).getName()); + std::vector& datamaps = m_meta_graph->getDataMaps(); + for (i = 0; i < datamaps.size(); i++) { + if (toplayerclass != MetaGraph::VIEWDATA || i != m_meta_graph->getDisplayedDataMapRef()) { + names.insert(std::make_pair(std::pair(MetaGraph::VIEWDATA,int(i)),std::string("Data Maps: ") + datamaps[i].getName())); } } - ShapeGraphs& shapegraphs = m_meta_graph->getShapeGraphs(); - for (i = 0; i < shapegraphs.getMapCount(); i++) { - if (toplayerclass != MetaGraph::VIEWAXIAL || i != shapegraphs.getDisplayedMapRef()) { - names.add(IntPair(MetaGraph::VIEWAXIAL,int(i)),pstring("Shape Graphs: ") + shapegraphs.getMap(i).getName()); + auto& shapegraphs = m_meta_graph->getShapeGraphs(); + for (i = 0; i < shapegraphs.size(); i++) { + if (toplayerclass != MetaGraph::VIEWAXIAL || i != m_meta_graph->getDisplayedShapeGraphRef()) { + names.insert(std::make_pair(std::pair(MetaGraph::VIEWAXIAL,int(i)), + std::string("Shape Graphs: ") + shapegraphs[i]->getName())); } } - for (i = 0; i < m_meta_graph->PointMaps::size(); i++) { + for (i = 0; i < m_meta_graph->getPointMaps().size(); i++) { // note 1: no VGA graph can push to another VGA graph (point onto point transforms) // note 2: I simply haven't written "axial" -> vga yet, not that it can't be possible (e.g., "axial" could actually be a convex map) if (toplayerclass != MetaGraph::VIEWVGA && toplayerclass != MetaGraph::VIEWAXIAL) { - names.add(IntPair(MetaGraph::VIEWVGA,int(i)),pstring("Visibility Graphs: ") + m_meta_graph->PointMaps::at(i).getName()); + names.insert(std::make_pair(std::pair(MetaGraph::VIEWVGA,int(i)),std::string("Visibility Graphs: ") + m_meta_graph->getPointMaps()[i].getName())); } } CPushDialog dlg(names); @@ -1740,9 +2072,9 @@ void QGraphDoc::OnPushToLayer() m_communicator = new CMSCommunicator; // dummy value to prevent draw while this operation is in progress // now have to separate vga and axial layers again: int sel = dlg.m_layer_selection; - IntPair dest = names.key(sel); + std::pair dest = depthmapX::getMapAtIndex(names, sel)->first; // CWaitCursor c; - m_meta_graph->pushValuesToLayer(dest.a, dest.b, dlg.m_function, dlg.m_count_intersections); + m_meta_graph->pushValuesToLayer(dest.first, dest.second, dlg.m_function, dlg.m_count_intersections); delete m_communicator; m_communicator = NULL; SetUpdateFlag(NEW_TABLE); @@ -1750,215 +2082,6 @@ void QGraphDoc::OnPushToLayer() } } -/////////////////////////////////////////////////////////////////////////// - -void QGraphDoc::OnRedtest() -{ - // OzlemSpecial2 - // chop rays if they intersect other buildings, - // exclude them altogether if there is just a short gap between buildings - - // OzlemSpecial3 - // chop rays according to encountered feature codes - - // expect this to be the rays: - int a = (int) m_meta_graph->getDataMaps().getMapRef("Axis Rays"); - - // expect this to be the buildings: - int b = 2; // hmm -- just guess a number! (0 for OzlemSpecial2 and 2 for OzlemSpecial3 as designed to be run) - - m_meta_graph->getDataMaps().getMap(a).ozlemSpecial3( m_meta_graph->getDataMaps().getMap(b) ); - - SetUpdateFlag(QGraphDoc::NEW_DATA); - SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DATA ); -} - -void QGraphDoc::OnGreentest() -{ - // OzlemSpecial5 - // mark up buildings according to exposure types - - // expect this to be the rays: - int a = (int) m_meta_graph->getDataMaps().getMapRef("Axis Rays"); - - // expect this to be the buildings: - int b = 0; // hmm -- just guess a number! (0 for OzlemSpecial5) - - m_meta_graph->getDataMaps().getMap(a).ozlemSpecial5( m_meta_graph->getDataMaps().getMap(b) ); - -// m_meta_graph->getDisplayedDataMap().ozlemSpecial6(); -} - -void QGraphDoc::OnPinktest() -{ - // note: expects 0 to be points, 1 to be lines - m_meta_graph->getDataMaps().getMap(0).ozlemSpecial7( m_meta_graph->getDataMaps().getMap(1) ); -} - -void QGraphDoc::OnTestButton() -{ -/* AfxMessageBox(tr("test!")); - AttributeTable *tester = new AttributeTable(); - for (int i = 0; i < 1000000; i++) { - tester->insertRow(i); - } - delete tester; - AfxMessageBox(tr("tested!")); -*/ - - /* - if (saveDialog.DoModal() == IDOK) { - CWaitCursor; - QString outfile = saveDialog.GetPathName(); - ofstream stream(outfile); - stream << "Building\tRoad1\tRoad2\tangle" << endl; - m_meta_graph->getDataMaps().at(1).ozlemSpecial( stream, m_meta_graph->getDataMaps().at(0)); - } -*/ - /* - ifstream file("F:\\alasdair\\apps\\saladtester\\paths.txt"); - // << - m_evolved_paths.clear(); - for (int i = 0; i < 19; i++) { - m_evolved_paths.push_back(pvecpoint()); - for (int j = 0; j < 1200; j++) { - Point2f p; - file >> p.x >> p.y; - m_evolved_paths.tail().push_back(p); - } - } -*/ - - /* - int counter = 0; - - int seed = 1; - pafsrand(seed); - int nextrand; - - int buckets[100]; - for (int i = 0; i < 100; i++) - { - buckets[i] = 0; - } - - do { - nextrand = pafrand(); - buckets[nextrand % 100] += 1; - } while (++counter < PAF_RAND_MAX * 10); - - ofstream data("data.txt"); - - for (int j = 0; j < 100; j++) { - data << buckets[j] << endl; - } - - if (counter == PAF_RAND_MAX) { - AfxMessageBox(tr("blah!")); - } - else { - AfxMessageBox(tr("wah!")); - } -*/ - //m_meta_graph->highlightBorder(); - //SetRedrawFlag(VIEW_ALL,REDRAW_GRAPH); -/* if (m_agent_manager && m_agent_manager->isPaused()) { - Evoecomorph& evo = m_agent_manager->getEvoecomorph(); - double val = evo.getLatestFitness(); - char out[64]; - printf(out,"%f",val); - AfxMessageBox(out); - m_agent_manager->unPause(); - }*/ -/* - m_meta_graph->loadGraphAgent(); - m_meta_graph->getLineLayer(0,0).setEditable(true); - */ -/* - for (int run = 0; run < 3; run++) { - int seed = run + 2; - int return_time = 600; - // - if (m_evoecomorph) { - delete m_evoecomorph; - m_evoecomorph = NULL; - } - pafsrand(seed); - m_evoecomorph = new Evoecomorph; - delete m_meta_graph; - m_meta_graph = new MetaGraph; - m_evoecomorph->init( *m_meta_graph, return_time ); - for (int genset = 0; genset < 10; genset++) { - if (genset != 0) { - delete m_meta_graph; - m_meta_graph = new MetaGraph; - m_evoecomorph->next( *m_meta_graph ); - //m_evoecomorph->blank( *m_meta_graph ); // this was set to blank, I don't know why - } - for (int i = 0; i < 500; i++) { - char blah2[128]; - for (int j = 0; j < 300 + (return_time * 3) / 2; j++) { // moved down from 600 to 300 in line with changes to evoecomorph loading - m_evoecomorph->step(*m_meta_graph); - } - m_evoecomorph->evaluate(*m_meta_graph); - sprintf(blah2, "seed %d gen %d fit %f", seed, i + genset * 500, m_evoecomorph->m_fitness); - SetTitle(blah2); - delete m_meta_graph; - if (i < 499) { - m_meta_graph = new MetaGraph; - m_evoecomorph->next( *m_meta_graph ); - } - } - m_meta_graph = new MetaGraph; - m_evoecomorph->best( *m_meta_graph ); - for (int k = 0; k < 300 + (return_time * 3) / 2; k++) { // moved down from 600 to 300 - m_evoecomorph->step(*m_meta_graph); - } - m_evoecomorph->evaluate(*m_meta_graph); - char blah3[128]; - char blah4[128]; - sprintf(blah3, "dcc%d-seed%d-gen%d-noexit.graph", return_time, seed, i + genset * 500); - sprintf(blah4, "dcc%d-seed%d-gen%d-noexit.txt", return_time, seed, i + genset * 500); - ofstream summary(blah4); - char blah[256]; - sprintf(blah, "Bad rooms %d, bad agents %d, avg diff %f, fitness %f", - m_evoecomorph->m_bad_rooms, m_evoecomorph->m_bad_agents, m_evoecomorph->m_avg_diff, m_evoecomorph->m_fitness); - summary << blah << endl; - m_meta_graph->write(blah3, METAGRAPH_VERSION); - } - } - - SetUpdateFlag(QGraphDoc::NEW_DATA); - SetRedrawFlag(VIEW_ALL, REDRAW_GRAPH, NEW_DATA ); - - char blah[256]; - sprintf(blah, "Bad rooms %d, bad agents %d, avg diff %f, fitness %f", - m_evoecomorph->m_bad_rooms, m_evoecomorph->m_bad_agents, m_evoecomorph->m_avg_diff, m_evoecomorph->m_fitness); - - AfxMessageBox(blah); -*/ - /* - static int x = 0; - static bool widdywoo = false; - - if (m_meta_graph && m_meta_graph->getState() & MetaGraph::GRAPH) { - // cross fingers and go for it! - if (!widdywoo) { - x = m_meta_graph->addLineDynamic(Line(Point2f(0.0,0.0),Point2f(10.0,10.0))); - widdywoo = true; - } - else { - m_meta_graph->removeLineDynamic(x); - widdywoo = false; - } - - m_meta_graph->dynamicSparkGraph2(); - } - */ -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////// - void QGraphDoc::OnAddColumn() { CRenameObjectDlg dlg(tr("Column")); // using the constructor without a column name sets rename column dialog to insert column name mode @@ -1970,8 +2093,8 @@ void QGraphDoc::OnAddColumn() else { AttributeTable& tab = m_meta_graph->getAttributeTable(); bool found = false; - for (int i = 0; i < tab.getColumnCount(); i++) { - if (tab.getColumnName(i) == pstring(dlg.m_object_name.toLatin1())) { + for (int i = 0; i < tab.getNumColumns(); i++) { + if (tab.getColumnName(i) == dlg.m_object_name.toStdString()) { QMessageBox::warning(this, tr("Notice"), tr("Sorry, another column already has this name, please choose a unique column name"), QMessageBox::Ok, QMessageBox::Ok); found = true; break; @@ -1984,7 +2107,7 @@ void QGraphDoc::OnAddColumn() } } if (success) { - int col = m_meta_graph->addAttribute(pstring(dlg.m_object_name.toLatin1())); + int col = m_meta_graph->addAttribute(dlg.m_object_name.toStdString()); m_meta_graph->setDisplayedAttribute(col); SetUpdateFlag(QGraphDoc::NEW_DATA); // Tell the views to update their menus @@ -2016,12 +2139,13 @@ int QGraphDoc::RenameColumn(AttributeTable *tab, int col) CRenameObjectDlg dlg("Column",colname); // using the column name sets the dialog to replace column name mode bool success = false; while (dlg.exec() == QDialog::Accepted && !success && dlg.m_object_name != colname) { - int newcol = tab->renameColumn(col,pstring(dlg.m_object_name.toLatin1())); - if (newcol == -1) { + std::string newColName = dlg.m_object_name.toStdString(); + if (tab->hasColumn(newColName)) { QMessageBox::warning(this, tr("Notice"), tr("Sorry, another column already has this name, please choose a unique column name"), QMessageBox::Ok, QMessageBox::Ok); } else { - return newcol; + tab->renameColumn(tab->getColumnName(col), newColName); + return tab->getColumnIndex(newColName); } } return -1; @@ -2030,9 +2154,10 @@ int QGraphDoc::RenameColumn(AttributeTable *tab, int col) void QGraphDoc::OnColumnProperties() { AttributeTable *tab = &(m_meta_graph->getAttributeTable()); + LayerManagerImpl *layers = &(m_meta_graph->getLayers()); int col = m_meta_graph->getDisplayedAttribute(); - CColumnPropertiesDlg dlg(tab,col); + CColumnPropertiesDlg dlg(tab, layers, col); dlg.exec(); } @@ -2103,7 +2228,7 @@ bool QGraphDoc::ReplaceColumnContents(PointMap *pointmap, ShapeMap *shapemap, in } else { strcpy(text,dlg.m_formula_text.c_str()); - istringstream stream(text); + std::istringstream stream(text); SalaProgram proggy(program_context); if (!proggy.parse(stream)) { QString msg = QString("There was an error parsing your formula:\n\n") + @@ -2129,7 +2254,7 @@ bool QGraphDoc::ReplaceColumnContents(PointMap *pointmap, ShapeMap *shapemap, in } } if (!error) { - table->setColumnFormula(col,text); + table->getColumn(col).setFormula(text); } delete [] text; } @@ -2181,11 +2306,10 @@ bool QGraphDoc::SelectByQuery(PointMap *pointmap, ShapeMap *shapemap) bool error = true; while (error && QDialog::Accepted == dlg.exec()) { error = false; - // unicode conversion (AT 31.01.11) -- seems easiest at the mo to simply feed through pstring converter - pstring multibytetext(((MainWindow*)m_mainFrame)->m_formula_cache.toLatin1()); + std::string multibytetext(((MainWindow*)m_mainFrame)->m_formula_cache.toStdString()); char *text = new char[multibytetext.length()+1]; strcpy(text,multibytetext.c_str()); - istringstream stream(text); + std::istringstream stream(text); SalaProgram proggy(program_context); if (!proggy.parse(stream)) { QString msg = QString("There was an error parsing your formula:\n") + @@ -2196,7 +2320,7 @@ bool QGraphDoc::SelectByQuery(PointMap *pointmap, ShapeMap *shapemap) else { // just check you really are viewing the layers: bool retvar; - pvecint selset; + std::vector selset; if (dlg.m_selection_only) { retvar = proggy.runselect(selset,pointmap ? pointmap->getSelSet() : shapemap->getSelSet()); } @@ -2236,7 +2360,7 @@ void QGraphDoc::OnEditSelectToLayer() CRenameObjectDlg dlg("Layer"); // note, without specifying existing layer name, this defaults to "New layer" behaviour if (QDialog::Accepted == dlg.exec()) { - pstring layer_name = pstring(dlg.m_object_name.toLatin1()); + auto layer_name = dlg.m_object_name.toStdString(); if (layer_name.empty()) { layer_name = "Untitled"; } @@ -2305,74 +2429,13 @@ void QGraphDoc::OnFileProperties() dlg.m_file_version = tr(""); } if (QDialog::Accepted == dlg.exec()) { - m_meta_graph->setTitle(pstring(dlg.m_title.toLatin1())); - m_meta_graph->setLocation(pstring(dlg.m_location.toLatin1())); - m_meta_graph->setDescription(pstring(dlg.m_description.toLatin1())); - } - } -} - -//////////////////////////////////////////////////////////////////////////////// - -// a bit of testing - -void QGraphDoc::OnMagiMif() -{ - if (m_meta_graph && !m_communicator) { - if (m_meta_graph->getState() & MetaGraph::SHAPEGRAPHS) { - - QFilePath path(m_opened_name); - QString defaultname = path.m_path + (path.m_name.isEmpty() ? "" : path.m_name) + tr("_polys"); - - QFileDialog::Options options = 0; - QString outfile = QFileDialog::getOpenFileName( - 0, tr("Save As"), - defaultname, - tr("MapInfo file (*.mif)"), - 0, - options); - - if(!outfile.isEmpty()){ - QFilePath filepath(outfile); - QString ext = filepath.m_ext; - if (ext == QString("MIF")) - { - int thedot = outfile.indexOf('.'); - QString outfile2 = outfile.left(thedot+1) + tr("mid"); - - ofstream miffile(outfile.toLatin1()); - if (miffile.fail() || miffile.bad()) { - QMessageBox::warning(this, tr("Warning"), tr("Sorry, unable to open file for export"), QMessageBox::Ok, QMessageBox::Ok); - } - - ofstream midfile(outfile2.toLatin1()); - if (midfile.fail() || midfile.bad()) { - QMessageBox::warning(this, tr("Warning"), tr("Sorry, unable to open associated .mid file for export"), QMessageBox::Ok, QMessageBox::Ok); - } - m_meta_graph->getDisplayedShapeGraph().outputMifPolygons(miffile,midfile); - } - } + m_meta_graph->setTitle(dlg.m_title.toStdString()); + m_meta_graph->setLocation(dlg.m_location.toStdString()); + m_meta_graph->setDescription(dlg.m_description.toStdString()); } } } -void QGraphDoc::OnBinDistances() -{ - m_meta_graph->getDisplayedPointMap().binMap(NULL); -} - -void QGraphDoc::OnShowBinDistances() -{ - pvecint a = m_meta_graph->getDisplayedPointMap().getSelSet(); - Point& p = m_meta_graph->getDisplayedPointMap().getPoint(a.head()); - QString all; - for (int i = 0; i < 32; i++) { - QString blah = QString(tr("%2d: %f\n")).arg(i).arg(p.getBinDistance(i)); - all += blah; - } - QMessageBox::information(this, tr("BinDistances"), all, QMessageBox::Ok, QMessageBox::Ok); -} - void QGraphDoc::OnViewShowGrid() { if (m_meta_graph->m_showgrid) { @@ -2384,17 +2447,6 @@ void QGraphDoc::OnViewShowGrid() SetRedrawFlag(VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP); } -void QGraphDoc::OnViewShowText() -{ - if (m_meta_graph->m_showtext) { - m_meta_graph->m_showtext = false; - } - else { - m_meta_graph->m_showtext = true; - } - SetRedrawFlag(VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP); -} - //#include "AttributeSummary.h" void QGraphDoc::OnViewSummary() @@ -2403,19 +2455,6 @@ void QGraphDoc::OnViewSummary() dlg.exec(); } -//////////////////////////////////////////////////////////////////////////////////////////// - -// Red button tests the rapid agent program: - -void QGraphDoc::OnRedButton() -{ -/* AfxMessageBox(tr("Disabled: use main through vision calculator (with vga analysis) instead")); - // m_meta_graph->analyseThruVision(); - // - SetUpdateFlag(QGraphDoc::NEW_DATA); - SetRedrawFlag(VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA );*/ -} - void QGraphDoc::OnToolsPointConvShapeMap() { //CWaitCursor wait; @@ -2428,14 +2467,14 @@ void QGraphDoc::OnToolsPointConvShapeMap() // this is unlink from a set of points! void QGraphDoc::OnToolsAxialConvShapeMap() { - if (m_meta_graph->getDataMaps().getMapCount() == 0) { + if (m_meta_graph->getDataMaps().empty()) { QMessageBox::warning(this, tr("Warning"), tr("No data source layers for unlink points"), QMessageBox::Ok, QMessageBox::Ok); return; } - pvecstring names; - for (size_t i = 0; i < m_meta_graph->getDataMaps().getMapCount(); i++) { - names.push_back(pstring("Data Maps: ") + m_meta_graph->getDataMaps().getMap(i).getName()); + std::vector names; + for (size_t i = 0; i < m_meta_graph->getDataMaps().size(); i++) { + names.push_back(std::string("Data Maps: ") + m_meta_graph->getDataMaps()[i].getName()); } // choose shape map... @@ -2444,7 +2483,7 @@ void QGraphDoc::OnToolsAxialConvShapeMap() if (dlg.exec()) { //CWaitCursor wait; - m_meta_graph->getDisplayedShapeGraph().unlinkFromShapeMap(m_meta_graph->getDataMaps().getMap(dlg.m_layer)); + m_meta_graph->getDisplayedShapeGraph().unlinkFromShapeMap(m_meta_graph->getDataMaps()[dlg.m_layer]); m_meta_graph->setViewClass(MetaGraph::SHOWAXIALTOP); SetUpdateFlag(QGraphDoc::NEW_TABLE); SetRedrawFlag(VIEW_ALL,REDRAW_GRAPH, NEW_DATA); @@ -2463,7 +2502,7 @@ void QGraphDoc::OnToolsLineLoadUnlinks() options); if(outfile.isEmpty()) return; - ifstream stream(outfile.toLatin1()); + std::ifstream stream(outfile.toLatin1()); if (stream.fail()) { QMessageBox::warning(this, tr("Warning"), tr("There was an error opening the file.\nPlease check the file is not already open"), QMessageBox::Ok, QMessageBox::Ok); return; @@ -2502,103 +2541,6 @@ void QGraphDoc::OnConvertMapShapes() } } -// Point depth either lines, axials or segments: - -// Deprecated, now in CViewSelector - -bool QGraphDoc::ViewHandler(int nCode, void *pExtra, int viewing, int layer) -{ -/* - if (nCode == CN_COMMAND) { - if (layer != -1) { - if (!m_meta_graph->setCurrentLayerRef(layer)) { - // Layer doesn't exist for some reason... - return false; - } - SetTitle(m_base_title + " - " + m_meta_graph->getCurrentLayer().getLayerName().c_str()); - } - else { - SetTitle(m_base_title + " - Attributes"); - } - if (m_meta_graph->getViewing() != viewing) { - m_meta_graph->setViewing(viewing, *m_meta_graph); - } - SetRedrawFlag(VIEW_ALL, true ); - SetRedrawFlag(VIEW_ALL, QGraphDoc::REDRAW_GRAPH ); - } - else if (nCode == CN_UPDATE_COMMAND_UI) { - (()//CCmdUI*)pExtra)->Enable(TRUE); - if (m_meta_graph->getViewing() == viewing && - (layer == -1 || m_meta_graph->getCurrentLayerRef() == layer)) { - (()//CCmdUI*)pExtra)->SetCheck(1); - } - else { - (()//CCmdUI*)pExtra)->SetCheck(0); - } - } -*/ - return true; -} - -bool QGraphDoc::CheckMemory(const QString& filename) -{ -/* // Check there's enough memory to hold the graph (based on benchmarks) - MEMORYSTATUS memstat; - memstat.dwLength = sizeof(MEMORYSTATUS); - GlobalMemoryStatus(&memstat); - double avail = double(memstat.dwAvailPhys) / double(1024 * 1024); - - double min_required = double(m_meta_graph->getDisplayedPointMap().getPointCount()) * 0.0050; - double absolute_min_req = double(m_meta_graph->getDisplayedPointMap().getPointCount()) * 0.0025; - - if (!filename.IsEmpty()) { - ifstream test(filename, ios::binary); - if (test.fail()) { - AfxMessageBox(QString("Couldn't open ") + filename); - if (test.is_open()) { - test.close(); - } - return false; - } - char header[3]; - test.read( (char *) &header, 3 ); - if (header[0] != 'g' || header[1] != 'r' || header[2] != 'f') { - AfxMessageBox(tr("Sorry: this is not a depthmapX graph file")); - test.close(); - return false; - } - int version; - test.read( (char *) &version, sizeof(version)); - test.seekg(0,ios::end); - if (version < VERSION_NGRAPH_INTROD) { - // Should be able to fit old graphs into about the same memory: - min_required = 1.1 * double(test.tellg()) / double(1024 * 1024); - } - else { - // Don't know why, but the current version appears double the file size when in memory: - min_required = 1.1 * double(test.tellg()) / double(1024 * 1024); // .... did use to be 2.2 - } - test.close(); - if (version < VERSION_NGRAPH_INTROD) { - if (IDYES != AfxMessageBox(tr("Warning, this graph will require conversion, which may take a few minutes.\nDo you want to continue?"), MB_YESNO)) { - return false; - } - } - } - - if (avail < min_required) { - QString str; - str.Format(tr("%.1f MB available, %.1f MB advised"), avail, min_required ); - if ( IDYES != AfxMessageBox( QString("According to benchmark stats, there may not be enough memory to process this graph.\n") + - tr("(") + str + tr(")\n") + - tr("The analysis may take much longer than usual. Do you still want to continue?"), MB_YESNO ) ) { - return false; - } - } -*/ - return true; -} - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// QT_END_NAMESPACE diff --git a/depthmapX/GraphDoc.h b/depthmapX/GraphDoc.h index ab16395d..1f97f93e 100644 --- a/depthmapX/GraphDoc.h +++ b/depthmapX/GraphDoc.h @@ -30,13 +30,13 @@ #include #include #include -#include #include +#include // Sala #include #include "salalib/salaprogram.h" -#include -#include +#include +#include QT_BEGIN_NAMESPACE @@ -56,6 +56,9 @@ class RenderThread : public QThread signals: void renderedImage(const QImage &image, double scaleFactor); + void runtimeExceptionThrown(int type, std::string message); + void showWarningMessage(QString title, QString message); + void closeWaitDialog(); protected: void run(); @@ -71,18 +74,16 @@ class CMSCommunicator : public Communicator { public: enum { IMPORT, IMPORTMIF, MAKEPOINTS, MAKEGRAPH, ANALYSEGRAPH, - POINTDEPTH, METRICPOINTDEPTH, ANGULARPOINTDEPTH, TOPOLOGICALPOINTDEPTH, ANALYSEANGULAR, + POINTDEPTH, METRICPOINTDEPTH, ANGULARPOINTDEPTH, TOPOLOGICALPOINTDEPTH, MAKEISOVIST, MAKEISOVISTPATH, - MAKEAXIALLINES, MAKEALLLINEMAP, MAKEFEWESTLINEMAP, MAKEDRAWING, - MAKEUSERMAP, MAKEUSERMAPSHAPE, MAKEUSERSEGMAP, MAKEUSERSEGMAPSHAPE, MAKEGATESMAP, MAKEBOUNDARYMAP, MAKESEGMENTMAP, + MAKEALLLINEMAP, MAKEFEWESTLINEMAP, MAKEDRAWING, + MAKEUSERMAP, MAKEUSERMAPSHAPE, MAKEUSERSEGMAP, MAKEUSERSEGMAPSHAPE, MAKEGATESMAP, MAKEBOUNDARYMAP, MAKESEGMENTMAP, MAKECONVEXMAP, - AXIALANALYSIS, SEGMENTANALYSIS, TOPOMETANALYSIS, AGENTANALYSIS, BINDISPLAY, IMPORTEDANALYSIS }; - + AXIALANALYSIS, SEGMENTANALYSISTULIP, SEGMENTANALYSISANGULAR, TOPOMETANALYSIS, AGENTANALYSIS }; public: - void ProcPostMessage(int m, int x, int y); CMSCommunicator(); virtual ~CMSCommunicator(); - virtual void CommPostMessage(int m, int x, int y) const; // Inline below CWaitDialog + virtual void CommPostMessage(int m, int x) const; // Inline below CWaitDialog void * parent_doc; @@ -95,9 +96,6 @@ class CMSCommunicator : public Communicator { while (which >= m_options.size()) m_options.push_back(-1); m_options[which] = option; } int GetOption(size_t which = 0) const { return (which >= m_options.size()) ? -1 : m_options[which]; } - void ClearOptions() - { m_options.clear(); } - // void SetSeedPoint(const Point2f& p) { m_seed_point = p; } const Point2f& GetSeedPoint() const @@ -116,23 +114,18 @@ class CMSCommunicator : public Communicator { m_string= str; } const QString& GetString() const { return m_string; } - - // void SetFileSet(QStringList strings) { -/* m_fileset.clear(); - comm_string strs; + m_fileset.clear(); for (int i = 0; i < strings.size(); i++) - { - strs.clear(); - for(int j=0; j m_options; int m_function; Point2f m_seed_point; double m_seed_angle; @@ -172,7 +165,9 @@ struct QFilePath { class QGraphDoc : public QWidget { Q_OBJECT - +private: + void exceptionThrownInRenderThread(int type, std::string message); + void messageFromRenderThread(QString title, QString message); public: QGraphDoc(const QString &author, const QString &organisation); CMSCommunicator *m_communicator; @@ -188,10 +183,10 @@ class QGraphDoc : public QWidget bool modifiedFlag; // Redraw commands - enum {REDRAW_DONE, REDRAW_MARKEDSET, REDRAW_POINTS, REDRAW_GRAPH, REDRAW_TOTAL }; + enum {REDRAW_DONE, REDRAW_POINTS, REDRAW_GRAPH, REDRAW_TOTAL }; // Redraw reasons enum {UNDECLARED, NEW_FOCUS, NEW_DEPTHMAPVIEW_SETUP, - NEW_VIEWER, NEW_LINESET, NEW_DATA, + NEW_LINESET, NEW_DATA, NEW_SELECTION, NEW_TABLE, NEW_COLUMN, NEW_FILE, DELETED_TABLE }; // Mainframe table changes: enum {CONTROLS_DESTROYALL,CONTROLS_LOADALL, @@ -199,7 +194,7 @@ class QGraphDoc : public QWidget CONTROLS_LOADATTRIBUTES,CONTROLS_CHANGEATTRIBUTE}; // Views attached (by viewtypes) - enum {VIEW_ALL = 0, VIEW_MAP = 1, VIEW_SCATTER = 2, VIEW_TABLE = 3, VIEW_3D = 4, VIEW_TYPES = 5}; + enum {VIEW_ALL = 0, VIEW_MAP = 1, VIEW_SCATTER = 2, VIEW_TABLE = 3, VIEW_3D = 4, VIEW_MAP_GL = 5, VIEW_TYPES = 6}; void* m_mainFrame; QWidget *m_view[VIEW_TYPES]; @@ -235,7 +230,7 @@ class QGraphDoc : public QWidget Point2f m_position; // Last known mouse position, in DXF units // Paths for the March 05 evolved agents // (loaded from file using the test button) - prefvec m_evolved_paths; + std::vector> m_evolved_paths; RenderThread m_thread; QProgressDialog* m_waitdlg; @@ -247,7 +242,7 @@ class QGraphDoc : public QWidget int m_step; int m_num_records; QTime m_timer; - void ProcPostMessage(int m, int x, int y); + void ProcPostMessage(int m, int x); void UpdateMainframestatus(); public slots: @@ -261,11 +256,6 @@ public slots: void OnFillPoints(const Point2f& p, int fill_type = 0 ); void OnMakeIsovist(const Point2f& seed, double angle = -1.0); void OnToolsAxialMap( const Point2f& seed ); - // - bool CheckMemory(const QString& filename = QString()); - // - bool ViewHandler(int nCode, void *pExtra, int viewing, int layer = -1); - // int RenameColumn(AttributeTable *tab, int col); bool ReplaceColumnContents(PointMap* pointmap, ShapeMap *shapemap, int col); bool SelectByQuery(PointMap* pointmap, ShapeMap *shapemap); @@ -276,66 +266,52 @@ public slots: int OnSaveDocument(QString lpszPathName, int version); bool OnCloseDocument(int); int OnOpenDocument(char* lpszPathName); - void OnToolsTPD(); - void OnFileImport(); + void OnToolsTPD(); + void OnVGALinksFileImport(); + void OnFileImport(); void OnFileExport(); + void OnFileExportMapGeometry(); + void OnFileExportLinks(); + void OnAxialConnectionsExportAsDot(); + void OnAxialConnectionsExportAsPairCSV(); + void OnSegmentConnectionsExportAsPairCSV(); void OnToolsMakeGraph(); - void OnEditClear(); - void OnVGAOptions(); + void OnToolsUnmakeGraph(); + void OnEditClear(); void OnToolsRun(); void OnEditUndo(); - void OnToolsPD(); - void OnAddGate(); + void OnToolsPD(); void OnPushToLayer(); void OnEditGrid(); - void OnToolsAxialLines(); - void OnEditFixgrid(); - void OnEditFixFill(); - void OnToolsMPD(); - void OnTestButton(); - void OnEvoAgent(); - void OnBinDisplay(); + void OnToolsMPD(); void OnToolsMakeFewestLineMap(); void OnToolsRunSeg(); - void OnAddColumn(); - void OnMagiMif(); - void OnRemoveColumn(); - void OnBinDistances(); - void OnShowBinDistances(); + void OnAddColumn(); + void OnRemoveColumn(); void OnFileProperties(); void OnToolsAPD(); void OnViewShowGrid(); - void OnViewSummary(); - void OnViewShowText(); void OnToolsRunAxa(); void OnSwapColours(); - void OnRedButton(); - void OnToolsAxialClearLinks(); + void OnViewSummary(); void OnToolsPointConvShapeMap(); void OnToolsAxialConvShapeMap(); - void OnUpdateColumn(); - void OnWindow3dView(); - void OnViewScatterplot(); - void OnWindowMap(); - void OnViewTable(); - void OnToolsAgentRun(); - void OnRedtest(); - void OnGreentest(); + void OnUpdateColumn(); + void OnToolsAgentRun(); void OnRenameColumn(); void OnEditQuery(); - void OnColumnProperties(); - void OnPinktest(); + void OnColumnProperties(); void OnLayerNew(); void OnLayerDelete(); void OnLayerConvert(); void OnLayerConvertDrawing(); void OnEditSelectToLayer(); void OnToolsIsovistpath(); - void OnFileSave(); - void OnFileSaveAs(); - void OnConvertMapShapes(); - void OnToolsBoundaryToAxial(); + bool OnFileSave(); + bool OnFileSaveAs(); + void OnConvertMapShapes(); void OnToolsLineLoadUnlinks(); + void OnPointmapExportConnectionsAsCSV(); protected: virtual void timerEvent(QTimerEvent *event); diff --git a/depthmapX/GridDialog.cpp b/depthmapX/GridDialog.cpp deleted file mode 100644 index e74a5583..00000000 --- a/depthmapX/GridDialog.cpp +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#include "GridDialog.h" -#include - -CGridDialog::CGridDialog(QWidget *parent) -: QDialog(parent) -{ - setupUi(this); - m_spacing = 0.01; - m_maxdimension = 1.0; -} - -void CGridDialog::showEvent(QShowEvent * event) -{ - m_maxexponent = (int) floor(log10(m_maxdimension)) - 1; - m_minexponent = m_maxexponent - 2; - m_basemantissa = (int) floor(m_maxdimension / pow(10.0,double(m_maxexponent+1))); - - // current: - m_mantissa = m_basemantissa; - m_exponent = m_maxexponent - 1; - - m_spacing = (double) m_mantissa * pow(10.0, double(m_exponent)); - - double truemax = (double) 2 * m_mantissa * pow(10.0, double(m_maxexponent)); - double truemin = (double) m_mantissa * pow(10.0, double(m_minexponent)); - c_spacing_ctrl->setRange(truemin, truemax); - - UpdateData(false); -} - -void CGridDialog::OnDeltaposSpinSpacing(double iDelta) -{ - // New slot for this ready userValue(double value) // slot link here though // TV - // m_spacing = c_spacing_ctrl->value(); // bug or not? - - if (int(iDelta / 1.0) > 1) c_spacing_ctrl->setSingleStep(1); - else if (int(iDelta / 0.1) > 1) c_spacing_ctrl->setSingleStep(0.1); - else if (int(iDelta / 0.01) > 1) c_spacing_ctrl->setSingleStep(0.01); - else c_spacing_ctrl->setSingleStep(0.001); - -} - -void CGridDialog::OnOK() -{ - UpdateData(true); - - double truemax = (double) 2 * m_mantissa * pow(10.0, double(m_maxexponent)); - double truemin = (double) m_mantissa * pow(10.0, double(m_minexponent)); - if (m_spacing > truemax || m_spacing < truemin) { - QString formatabsmin, formatmin, formatmax; - if (m_minexponent < 0) { - formatmin.sprintf("%%.%df", abs(m_minexponent)); - } - else { - formatmin = tr("%.0f"); - } - if (m_minexponent-1 < 0) { - formatabsmin.sprintf("%%.%df", abs(m_minexponent-1)); - } - else { - formatabsmin = tr("%.0f"); - } - if (m_maxexponent < 0) { - formatmax.sprintf("%%.%df" ,abs(m_maxexponent)); - } - else { - formatmax = tr("%.0f"); - } - QString absminstr, minstr, maxstr; - absminstr.sprintf(formatabsmin.toLatin1(), truemin/10); - minstr.sprintf(formatmin.toLatin1(), truemin); - maxstr.sprintf(formatmax.toLatin1(), truemax); - if (m_spacing >= truemin / 10 && m_spacing < truemin) { - QString msg; - msg = tr("You are below the suggested minimum grid spacing of ") + minstr + tr(". If you use this grid spacing, it may cause processing problems.\nAre you sure you want to proceed with this grid spacing?"); - if (QMessageBox::No == QMessageBox::question(this, tr("Question"), msg, QMessageBox::Yes | QMessageBox::No)) { - return; - } - } - else { - QString msg; - msg = tr("Please enter a spacing between ") + absminstr + tr(" (at the absolute minimum) and ") + maxstr; - QMessageBox::warning(this, "Notice", msg, QMessageBox::Ok, QMessageBox::Ok); - return; - } - } - - accept(); -} - -void CGridDialog::OnCancel() -{ - reject(); -} - -void CGridDialog::UpdateData(bool value) -{ - if (value) - { - m_spacing = c_spacing_ctrl->value(); - } - else - { - c_spacing_ctrl->setValue(m_spacing); - } -} - -void CGridDialog::userValue(double value) -{ - m_spacing = c_spacing_ctrl->value(); -} diff --git a/depthmapX/Info.plist b/depthmapX/Info.plist deleted file mode 100644 index ce417e22..00000000 --- a/depthmapX/Info.plist +++ /dev/null @@ -1,20 +0,0 @@ - - - - - CFBundleIconFile - - CFBundlePackageType - APPL - CFBundleGetInfoString - Created by Qt/QMake - CFBundleSignature - ???? - CFBundleExecutable - depthmapX - CFBundleIdentifier - com.yourcompany.depthmapX - NOTE - This file was generated by Qt/QMake. - - diff --git a/depthmapX/PlotView.cpp b/depthmapX/PlotView.cpp deleted file mode 100644 index 646bf625..00000000 --- a/depthmapX/PlotView.cpp +++ /dev/null @@ -1,777 +0,0 @@ -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// depthmapX - spatial network analysis platform - -// PlotView.cpp : implementation file -// -#include -#include - -#include "mainwindow.h" -#include "PlotView.h" - -#ifdef _WIN32 -#define finite _finite -#endif - -///////////////////////////////////////////////////////////////////////////// -// PlotView -static int pressed_nFlags; -QPlotView::QPlotView() -{ - m_x_axis = -1; - m_y_axis = -1; - curr_x = -1; - curr_y = -1; - - - m_queued_redraw = false; - m_view_trend_line = false; - m_view_rsquared = false; - m_view_monochrome = false; - m_view_origin = false; - m_view_equation = false; - - // for drawing drag rect - m_drawdragrect = false; - m_selecting = false; - - setAttribute(Qt::WA_NoBackground, 1); - setMouseTracking( true ); - setWindowIcon(QIcon(tr(":/images/cur/icon-1-2.png"))); - - installEventFilter(this); -} - -///////////////////////////////////////////////////////////////////////////// -// QPlotView drawing - -int QPlotView::screenX(double x) -{ - return m_screen_bounds.left() + m_screen_bounds.width() * (m_data_bounds.width() ? (x - m_data_bounds.bottom_left.x) / m_data_bounds.width() : 0.5); -} - -int QPlotView::screenY(double y) -{ - return m_screen_bounds.top() - (abs(m_screen_bounds.height()) * (m_data_bounds.height() ? (y - m_data_bounds.bottom_left.y) / m_data_bounds.height(): 0.5)); -} - -double QPlotView::dataX(int x) -{ - return m_data_bounds.bottom_left.x + m_data_bounds.width() * double(x - m_screen_bounds.left()) / double(m_screen_bounds.width()); -} - -double QPlotView::dataY(int y) -{ - return m_data_bounds.bottom_left.y + m_data_bounds.height() * double(m_screen_bounds.top() - y) / double(abs(m_screen_bounds.height())); -} - -QSize QPlotView::sizeHint() const -{ - return QSize(2000, 2000); -} - -static QPoint hit_point; -bool QPlotView::eventFilter(QObject *object, QEvent *e) -{ - if(e->type() == QEvent::ToolTip) - { - if (!pDoc->m_communicator) { - // first, check you have a meta graph - if (pDoc->m_meta_graph) { - if (pDoc->m_meta_graph->viewingProcessed()) { - AttributeTable& table = pDoc->m_meta_graph->getAttributeTable(); - size_t xfloor = idx_x.searchfloorindex(ValuePair(-1,dataX(hit_point.x()-2))); - size_t xceil = idx_x.searchceilindex(ValuePair(-1,dataX(hit_point.x()+2))); - size_t yfloor = idx_y.searchfloorindex(ValuePair(-1,dataY(hit_point.y()+2))); - size_t yceil = idx_y.searchceilindex(ValuePair(-1,dataY(hit_point.y()-2))); - // work out anything near this point... - pvecint xkeys; - for (size_t i = xfloor + 1; i < xceil; i++) { - int index = idx_x[i].index; - xkeys.add(index); - } - pvecint finalkeys; - for (size_t j = yfloor + 1; j < yceil; j++) { - size_t index = idx_y[j].index; - if (xkeys.searchindex(index) != paftl::npos) { - finalkeys.push_back( table.getRowKey(index) ); - } - } - if (finalkeys.size()) { - AttributeTable& table = pDoc->m_meta_graph->getAttributeTable(); - // and that it has an appropriate state to display a hover wnd - float val = table.getValue( finalkeys[0], pDoc->m_meta_graph->getDisplayedAttribute() ); - if (val == -1.0f) - setToolTip("No value"); - else if (val != -2.0f) - setToolTip(QString("%1").arg(val)); - } - } - } - } - } - return QObject::eventFilter(object, e); -} - - -void QPlotView::paintEvent(QPaintEvent *event) -{ - QPainter pDC(this); - - QRect rect = QRect(0, 0, width(), height()); - PafColor selcol(SALA_SELECTED_COLOR); - pDC.setPen(QPen(QBrush(QColor(selcol.redb(), selcol.greenb(), selcol.blueb())), 1, Qt::DotLine, Qt::RoundCap)); - -/* if (pDC->IsPrinting()) - { - PrintOutput(pDC, pDoc); - } - else */ - { // if (m_clear) - if (m_drawdragrect) - { - pDC.setCompositionMode(QPainter::RasterOp_SourceAndNotDestination); - if(!m_drag_rect_b.isEmpty()) pDC.drawRect( m_drag_rect_b); - if(!m_drag_rect_a.isEmpty()) pDC.drawRect( m_drag_rect_a); - pDC.setCompositionMode(QPainter::CompositionMode_SourceOver); - m_drag_rect_b = m_drag_rect_a; - m_drawdragrect = false; - } - else { - m_background = ((MainWindow*)m_parent)->m_background; - m_foreground = ((MainWindow*)m_parent)->m_foreground; - pDC.fillRect(rect, QBrush(QColor(m_background))); - // m_clear = false; - Output(&pDC, pDoc, true); - OnRedraw(0, 0); - } - } -} - -void QPlotView::resizeEvent(QResizeEvent *event) -{ - pDoc->m_view[QGraphDoc::VIEW_SCATTER] = this; - setWindowTitle(pDoc->m_base_title+":Scatter Plot"); -} - -void QPlotView::closeEvent(QCloseEvent *event) -{ - pDoc->m_view[QGraphDoc::VIEW_SCATTER] = NULL; - if (!pDoc->OnCloseDocument(QGraphDoc::VIEW_SCATTER)) - { - pDoc->m_view[QGraphDoc::VIEW_SCATTER] = this; - event->ignore(); - } -} - -void QPlotView::OnEditCopy() -{ -/* // Copy to Clipboard - if (OpenClipboard() && EmptyClipboard()) { - - CMetaFileDC *pDC = new CMetaFileDC; - - QRect rect; - GetClientRect(rect); - QPainter *dummyDC = new QPainter; - dummyDC->CreateCompatibleDC(GetDC()); - int oldmm = dummyDC->SetMapMode(MM_HIMETRIC); - QSize size(rect.width(),rect.height()); - dummyDC->DPtoLP(&size); - rect.SetRect(0,0,size.width(),size.height()); - dummyDC->SetMapMode(oldmm); - pDC->CreateEnhanced(dummyDC,NULL,rect,_T("Depthmap\0Graph\0\0")); - pDC->SetAttribDC(dummyDC->m_hAttribDC); - PrintOutput(pDC, pDoc); - dummyDC->DeleteDC(); - delete dummyDC; - - HENHMETAFILE hMF = pDC->CloseEnhanced(); - - HANDLE h = SetClipboardData(CF_ENHMETAFILE, hMF); - - CloseClipboard(); - - pDC->DeleteDC(); - delete pDC; - }*/ -} - -void QPlotView::PrintOutput(QPainter *pDC, QGraphDoc *pDoc) -{ -/* QRect rectin, rectout; - GetClientRect(rectin); - - int pixels; - if (pDC->IsPrinting()) { - pixels = __min( pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES) ); - - if (rectin.width() > rectin.height()) { - rectout.SetRect( QPoint(0,0), QPoint(pixels * rectin.height() / rectin.width(), pixels) ); - } - else { - rectout.SetRect( QPoint(0,0), QPoint(pixels, pixels * rectin.width() / rectin.height()) ); - } - // Not sure what isotropic does for us - pDC->SetMapMode( MM_ISOTROPIC ); - } - else { - // When 'copy'ing, the rectin and rectout are set one to one: - rectout = rectin; - } - - pDC->SetWindowExt( rectin.Size() ); - pDC->SetViewportExt( rectout.Size() ); - - CGdiObject *oldpen = pDC->SelectStockObject( NULL_PEN ); - QBrush brush( GetApp()->m_background ); - CGdiObject *oldbrush = pDC->SelectObject( &brush ); - - pDC->Rectangle( rectin ); - - pDC->SelectObject( oldbrush ); - pDC->SelectObject( oldpen ); - - if (!Output( pDC, pDoc, false )) { - AfxMessageBox(_T("Unable to print / copy screen at this time")); - pDC->AbortDoc(); - return; - }*/ -} - -bool QPlotView::Output(QPainter *pDC, QGraphDoc *pDoc, bool screendraw) -{ -// this is going to need a timer at somepoint, but for now, it's all very easy to start off: - if (!pDoc->m_meta_graph->setLock(this)) { - return false; - } - - if (pDoc->m_communicator || !pDoc->m_meta_graph->viewingProcessed()) { - pDoc->m_meta_graph->releaseLock(this); - return false; - } - - AttributeTable& table = pDoc->m_meta_graph->getAttributeTable(); - int displaycol = pDoc->m_meta_graph->getDisplayedAttribute(); - - QRect rect = QRect(0, 0, width(), height()); - int mindim = __min(rect.width(),rect.height()); - int viscount = table.getVisibleRowCount(); - if(!viscount) m_x_axis = m_y_axis = 0; - - int spacer = floor(2.0 * sqrt(double(mindim)/double(viscount != 0 ? viscount : 1))); - if (!screendraw && spacer < 4) { - spacer = 4; - } - - // text formatting - int pointsize; - if (mindim > 200) { - pointsize = 100; - } - else { - pointsize = 50+mindim/4; - } - - QFont font = QFont("Arial", 10, 10); - setFont(font); - - QPen pen = QPen(QBrush(QColor(m_foreground)), 1, Qt::SolidLine, Qt::RoundCap); - QPen oldpen = pDC->pen(); - pDC->setPen(pen); - - float minx, miny, maxx, maxy; - QString str_minx, str_miny, str_maxx, str_maxy; - - minx = m_data_bounds.bottom_left.x = m_view_origin ? 0.0 : table.getVisibleMinValue(m_x_axis); - miny = m_data_bounds.bottom_left.y = m_view_origin ? 0.0 : table.getVisibleMinValue(m_y_axis); - maxx = m_data_bounds.top_right.x = table.getVisibleMaxValue(m_x_axis); - maxy = m_data_bounds.top_right.y = table.getVisibleMaxValue(m_y_axis); - - str_minx = QString(tr("%1")).arg(minx); - str_miny = QString(tr("%1")).arg(miny); - str_maxx = QString(tr("%1")).arg(maxx); - str_maxy = QString(tr("%1")).arg(maxy); - - // now work out the drawing window for - QSize sizex = QSize(str_maxx.length()*7, 16); - QSize sizey = QSize(str_miny.length()*7, 16); - QSize sizey2 = QSize(str_maxy.length()*7, 16); - if (sizey2.width() > sizey.width()) { - sizey.rwidth() = sizey2.width(); - } - // doesn't matter which, just want a height: - int texth = sizex.height(); - - int xaxis_pos = 99*rect.height()/100 - 2 * texth; - int yaxis_pos = rect.width()/100 + sizey.width() + texth; - int miny_pos = xaxis_pos - texth; - m_screen_bounds.setTop(miny_pos); - int maxy_pos = rect.height()/100 + texth / 2; - m_screen_bounds.setBottom(maxy_pos); - int minx_pos = yaxis_pos + texth; - m_screen_bounds.setLeft(minx_pos); - int maxx_pos = 99*rect.width()/100 - sizex.width() / 2; - m_screen_bounds.setRight(maxx_pos); - - int width = maxx_pos -minx_pos; - if (minx == maxx) { - minx_pos = maxx_pos = minx_pos + width / 2; - m_screen_bounds.setRight(minx_pos); - m_screen_bounds.setLeft(minx_pos); - width = 0; - } - int height = maxy_pos - miny_pos; - if (miny == maxy) { - miny_pos = maxy_pos = miny_pos + height / 2; - m_screen_bounds.setBottom(miny_pos); - m_screen_bounds.setTop(miny_pos); - height = 0; - } - - pDC->setPen(pen); - pDC->drawText(minx_pos-50, 99*rect.height()/100 - texth, 100, 16, Qt::AlignCenter, str_minx); - if (minx != maxx) { - pDC->drawText(maxx_pos-50, 99*rect.height()/100 - texth, 100, 16, Qt::AlignCenter, str_maxx); - } - - pDC->drawText(yaxis_pos-texth-100, miny_pos - texth/2, 100, 16, Qt::AlignRight , str_miny); - if (miny != maxy) { - pDC->drawText(yaxis_pos-texth-100, maxy_pos - texth/2, 100, 16, Qt::AlignRight , str_maxy); - } - - pDC->drawLine(QPoint(yaxis_pos-texth/2,miny_pos), QPoint(yaxis_pos,miny_pos)); - if (miny != maxy) { - pDC->drawLine(QPoint(yaxis_pos,miny_pos), QPoint(yaxis_pos,maxy_pos)); - pDC->drawLine(QPoint(yaxis_pos,maxy_pos), QPoint(yaxis_pos-texth/2,maxy_pos)); - } - - pDC->drawLine(QPoint(minx_pos,xaxis_pos+texth/2), QPoint(minx_pos,xaxis_pos)); - if (minx != maxx) { - pDC->drawLine(QPoint(minx_pos,xaxis_pos), QPoint(maxx_pos,xaxis_pos)); - pDC->drawLine(QPoint(maxx_pos,xaxis_pos), QPoint(maxx_pos,xaxis_pos+texth/2)); - } - - int sel_parity = 0; - QPen pen2; - for (int i = 0; i < table.getRowCount(); i++) { - if (!table.isVisible(i)) { - continue; - } - float x = table.getValue(i,m_x_axis); - float y = table.getValue(i,m_y_axis); - if (!finite(x) || !finite(y) || x == -1.0f || y == -1.0f) { - continue; - } - QRgb rgb; - if (m_view_monochrome) { - rgb = m_foreground; - } - else { - PafColor color = table.getDisplayColor(i); - rgb = qRgb(color.redb(),color.greenb(),color.blueb()); - } - int tempspacer = spacer; - if (table.isSelected(i)) { - tempspacer = (spacer + 1) * 2 - 1; - if (m_view_monochrome) { - rgb = qRgb(0xff,0,0); - } - } - if (tempspacer == 0) { - tempspacer = 1; - } - if (!m_view_monochrome) { - pen2 = QPen(QBrush(QColor(rgb)), spacer, Qt::SolidLine, Qt::FlatCap); - //pDC->setPen(QPen(QBrush(QColor(rgb)), spacer, Qt::SolidLine, Qt::FlatCap)); - } - else if (sel_parity != (table.isSelected(i) ? 1 : -1)) { - pen2 = QPen(QBrush(QColor(rgb)), spacer, Qt::SolidLine, Qt::FlatCap); - //pDC->setPen(QPen(QBrush(QColor(rgb)), spacer, Qt::SolidLine, Qt::FlatCap)); - sel_parity = (table.isSelected(i) ? 1 : -1); - } - pDC->setPen(pen2); - // - QPoint point(screenX(x),screenY(y)); - pDC->drawLine(QPoint(point.x()-tempspacer, point.y()-tempspacer), QPoint(point.x()+tempspacer+1, point.y()+tempspacer+1)); - pDC->drawLine(QPoint(point.x()-tempspacer,point.y()+tempspacer), QPoint(point.x()+tempspacer+1,point.y()-tempspacer-1)); - pDC->setPen(pen); - } - - // trend line if reqd - if (m_view_trend_line) { - QPoint bl, tr; - QString string; - if (m_regression.model(m_data_bounds.bottom_left.x) < m_data_bounds.bottom_left.y) { - // check line is on page - if (m_regression.model(m_data_bounds.top_right.x) > m_data_bounds.bottom_left.y) { - bl = QPoint(screenX(m_regression.invmodel(m_data_bounds.bottom_left.y)),m_screen_bounds.top()); - if (m_regression.model(m_data_bounds.top_right.x) < m_data_bounds.top_right.y) { - tr = QPoint(m_screen_bounds.right(), screenY(m_regression.model(m_data_bounds.top_right.x))); - } - else { - tr = QPoint(screenX(m_regression.invmodel(m_data_bounds.top_right.y)),m_screen_bounds.bottom()); - } - pDC->drawLine(bl, tr); - } - } - else if (m_regression.model(m_data_bounds.bottom_left.x) > m_data_bounds.top_right.y) { - // check line is on page - if (m_regression.model(m_data_bounds.top_right.x) < m_data_bounds.top_right.y) { - bl = QPoint(screenX(m_regression.invmodel(m_data_bounds.bottom_left.x)),m_screen_bounds.bottom()); - if (m_regression.model(m_data_bounds.top_right.x) > m_data_bounds.bottom_left.x) { - tr = QPoint(m_screen_bounds.right(), screenY(m_regression.model(m_data_bounds.top_right.x))); - } - else { - tr = QPoint(screenX(m_regression.invmodel(m_data_bounds.top_right.y)),m_screen_bounds.top()); - } - pDC->drawLine(bl, tr); - } - } - else { - bl = QPoint(m_screen_bounds.left(),screenY(m_regression.model(m_data_bounds.bottom_left.x))); - double trv = m_regression.model(m_data_bounds.top_right.x); - if (trv >= m_data_bounds.bottom_left.y && trv <= m_data_bounds.top_right.y) { - string += " v1"; - tr = QPoint(m_screen_bounds.right(), screenY(trv)); - } - else if (m_regression.b() > 0) { // upward inclined - string += " v2"; - tr = QPoint(screenX(m_regression.invmodel(m_data_bounds.top_right.y)),m_screen_bounds.bottom()); - } - else { // downward inclined - string += " v3"; - tr = QPoint(screenX(m_regression.invmodel(m_data_bounds.bottom_left.y)),m_screen_bounds.top()); - } - pDC->drawLine(bl, tr); - } - } - - QString string; - int textpos = texth; - if (m_view_rsquared) { - // set text formating - // hope ascii superscript 2 in place! - string = QString(tr("R\xb2 = %1").arg(sqr(m_regression.r()))); - pDC->drawText(QPointF(rect.width()-string.length()*7, textpos), string); - textpos += texth; - } - if (m_view_equation) { - if (m_regression.a() >= 0) { - string = QString(tr("y = %1 x + %1").arg(m_regression.b()).arg(m_regression.a())); - } - else { - string = QString(tr("y = %1 x - %1").arg(m_regression.b()).arg(fabs(m_regression.a()))); - } - pDC->drawText(QPointF(rect.width()-string.length()*7, textpos), string); - } - - QString xlabel(table.getColumnName(m_x_axis).c_str()); - pDC->drawText(QPointF(width/2+minx_pos, 99*rect.height()/100-texth), xlabel); - - - QString ylabel(table.getColumnName(m_y_axis).c_str()); - // this is last to avoid switch between hfont and vfont - QMatrix matrix; - matrix.translate(sizey.width(), rect.height()/2+ylabel.length()*7/2); - matrix.rotate(270); - pDC->setMatrix(matrix); - - pDC->drawText(QPointF(sizey.width()/2, height+miny_pos), ylabel); - - pDC->setPen(oldpen); - - pDoc->m_meta_graph->releaseLock(this); - - return true; -} -/* -///////////////////////////////////////////////////////////////////////////// -// QPlotView printing - -void QPlotView::OnBeginPrinting(QPainter* pDC, CPrintInfo* pInfo) -{ - CView::OnBeginPrinting(pDC, pInfo); -} - -void QPlotView::OnEndPrinting(QPainter* pDC, CPrintInfo* pInfo) -{ - CView::OnEndPrinting(pDC, pInfo); -} - -BOOL QPlotView::OnPreparePrinting(CPrintInfo* pInfo) -{ - // default preparation - return DoPreparePrinting(pInfo); -} -*/ -///////////////////////////////////////////////////////////////////////////// -// QPlotView message handlers - -int QPlotView::OnRedraw(int wParam, int lParam) -{ - if (pDoc->GetRemenuFlag(QGraphDoc::VIEW_SCATTER)) { - pDoc->SetRemenuFlag(QGraphDoc::VIEW_SCATTER, false); - MainWindow* m_Frm = (MainWindow*)pDoc->m_mainFrame; - m_Frm->RedoPlotViewMenu(pDoc); - } - if (pDoc->GetRedrawFlag(QGraphDoc::VIEW_SCATTER) != QGraphDoc::REDRAW_DONE) { - - if (!pDoc->m_communicator) { - - m_queued_redraw = false; - - while (!pDoc->SetRedrawFlag(QGraphDoc::VIEW_SCATTER,QGraphDoc::REDRAW_DONE)) { - // prefer waitformultipleobjects here -// Sleep(1); - } - } - else { -// killTimer(Tid_redraw); -// Tid_redraw = startTimer(100); - m_queued_redraw = true; - } - } - - return 0; -} - -void QPlotView::keyPressEvent(QKeyEvent *e) -{ - char key = e->key(); -} - -void QPlotView::RedoIndices() -{ - if (pDoc->m_meta_graph && pDoc->m_meta_graph->viewingProcessed()) { - AttributeTable& table = pDoc->m_meta_graph->getAttributeTable(); - idx_x.makeIndex(table, m_x_axis, false); - idx_y.makeIndex(table, m_y_axis, false); - } -} - - -void QPlotView::timerEvent(QTimerEvent *event) -{ - if (event->timerId() == Tid_redraw) { - - if (m_queued_redraw) { - - // Internal own redraw - OnRedraw(0, 0); - } - } -} - -void QPlotView::OnViewTrendLine() -{ - if (m_view_trend_line) { - m_view_trend_line = false; - } - else { - m_view_trend_line = true; - } - update(); -} - -void QPlotView::OnViewRsquared() -{ - if (m_view_rsquared) { - m_view_rsquared = false; - } - else { - m_view_rsquared = true; - } - update(); -} - -void QPlotView::OnViewColor() -{ - if (m_view_monochrome) { - m_view_monochrome = false; - } - else { - m_view_monochrome = true; - } - update(); -} - -void QPlotView::SetAxis(int axis, int col, bool reset) -{ - if (axis == 0) { - if (m_x_axis != col) { - m_x_axis = col; - } - } - else { - if (m_y_axis != col) { - m_y_axis = col; - } - } - if (reset) { - RedoIndices(); - ResetRegression(); - } -} - -void QPlotView::ResetRegression() -{ - m_regression.clear(); - if (pDoc->m_meta_graph && pDoc->m_meta_graph->viewingProcessed()) { - AttributeTable& table = pDoc->m_meta_graph->getAttributeTable(); - for (int i = 0; i < table.getRowCount(); i++) { - if (table.isVisible(i)) { - float x = table.getValue(i,m_x_axis); - float y = table.getValue(i,m_y_axis); - if (finite(x) && finite(y) && x != -1.0f && y != -1.0f) { - m_regression.add(x,y); - } - } - } - } -} - -void QPlotView::mousePressEvent(QMouseEvent *e) -{ - switch(e->button()) - { - case Qt::LeftButton: - pressed_nFlags = MK_LBUTTON; - break; - case Qt::RightButton: - pressed_nFlags = MK_RBUTTON; - break; - } - m_mouse_point = e->pos(); - m_drag_rect_a = QRect(0,0,0,0); - m_drag_rect_b = QRect(0,0,0,0); - m_selecting = true; - m_drawdragrect = true; - update(); -} - -void QPlotView::mouseMoveEvent(QMouseEvent *e) -{ - if(pressed_nFlags == MK_RBUTTON) return; - QPoint point = e->pos(); - if (m_selecting) { - int x1, y1, x2, y2; - if (m_mouse_point.x()>point.x()) - { - x1 = point.x(); - x2 = m_mouse_point.x(); - } - else - { - x1 = m_mouse_point.x(); - x2 = point.x(); - } - - if (m_mouse_point.y()>point.y()) - { - y1 = point.y(); - y2 = m_mouse_point.y(); - } - else - { - y1 = m_mouse_point.y(); - y2 = point.y(); - } - m_drag_rect_a = QRect(x1, y1, x2-x1, y2-y1); - m_drawdragrect = true; - update(); - } - hit_point = point; -} - -void QPlotView::mouseReleaseEvent(QMouseEvent *e) -{ - if(pressed_nFlags == MK_RBUTTON) - { - pDoc->m_meta_graph->clearSel(); - pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_SELECTION); - return; - } - m_selecting = false; - - size_t xfloor = idx_x.searchfloorindex(ValuePair(-1,dataX(m_drag_rect_a.left()-2))); - size_t xceil = idx_x.searchceilindex(ValuePair(-1,dataX(m_drag_rect_a.right()+2))); - size_t yfloor = idx_y.searchfloorindex(ValuePair(-1,dataY(m_drag_rect_a.bottom()+2))); - size_t yceil = idx_y.searchceilindex(ValuePair(-1,dataY(m_drag_rect_a.top()-2))); - - // Stop drag rect... - m_drag_rect_a = QRect(0,0,0,0); - m_drawdragrect = false; - update(); - AttributeTable& table = pDoc->m_meta_graph->getAttributeTable(); - - // work out selection - pvecint xkeys; - for (size_t i = xfloor + 1; i < xceil; i++) { - int index = idx_x[i].index; - xkeys.add(index); - } - pvecint finalkeys; - for (size_t j = yfloor + 1; j < yceil; j++) { - int index = idx_y[j].index; - if (xkeys.searchindex(index) != paftl::npos) { - finalkeys.push_back( table.getRowKey(index) ); - } - } - - // redraw selection set - bool add = false; - if (pressed_nFlags & MK_SHIFT) { - add = true; - } - pDoc->m_meta_graph->setSelSet(finalkeys, add); - pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_SELECTION); -} - -void QPlotView::OnViewOrigin() -{ - m_view_origin = !m_view_origin; - update(); -} - -/* -void QPlotView::OnUpdateViewOrigin(CCmdUI* pCmdUI) -{ - if (m_view_origin) { - pCmdUI->SetCheck(1); - } - else { - pCmdUI->SetCheck(0); - } -} -void QPlotView::OnUpdateViewEquation(CCmdUI* pCmdUI) -{ - if (m_view_equation) { - pCmdUI->SetCheck(1); - } - else { - pCmdUI->SetCheck(0); - } -} -*/ - -void QPlotView::OnViewEquation() -{ - m_view_equation = !m_view_equation; - update(); -} - diff --git a/depthmapX/PlotView.h b/depthmapX/PlotView.h deleted file mode 100644 index 8e8adf49..00000000 --- a/depthmapX/PlotView.h +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// depthmapX - spatial network analysis platform - -#include - -///////////////////////////////////////////////////////////////////////////// -// PlotView view - -//class CHoverWnd; - -#include -#include -#include - -#include "GraphDoc.h" - -#define MK_LBUTTON 0x0001 -#define MK_RBUTTON 0x0002 -#define MK_SHIFT 0x0004 -#define MK_CONTROL 0x0008 -#define MK_MBUTTON 0x0010 - -class QPlotView : public QWidget -{ - Q_OBJECT - -// Attributes -public: - QGraphDoc* pDoc; - QPlotView(); - QSize sizeHint() const; - - int m_x_axis; - int m_y_axis; - int curr_x; - int curr_y; - - AttributeIndex idx_x; - AttributeIndex idx_y; - void RedoIndices(); - - bool m_queued_redraw; - bool m_view_origin; - bool m_view_trend_line; - bool m_view_equation; - bool m_view_rsquared; - bool m_view_monochrome; - - LinReg m_regression; - - // - double dataX(int x); - int screenX(double x); - double dataY(int x); - int screenY(double x); - // - QtRegion m_data_bounds; - QRect m_screen_bounds; - // - QPoint m_mouse_point; - QRect m_drag_rect_a; - QRect m_drag_rect_b; - bool m_selecting; - bool m_drawdragrect; - QRgb m_background; - QRgb m_foreground; - - void* m_parent;//MainWindow* - - -// Operations -public: - void SetAxis(int axis, int col, bool reset); - void ResetRegression(); - - bool Output(QPainter *pDC, QGraphDoc *pDoc, bool screendraw); - void PrintOutput(QPainter *pDC, QGraphDoc *pDoc); - - // this is a tells us how many 100ms ticks have passed since the mouse moved - int Tid_redraw; - - void OnViewTrendLine(); - void OnViewRsquared(); - void OnViewColor(); - void OnViewOrigin(); - void OnViewEquation(); - int OnRedraw(int wParam, int lParam); - void OnEditCopy(); - void OnLButtonDown(bool nFlags, QPoint point); - void OnMouseMove(bool nFlags, QPoint point); - void OnLButtonUp(bool nFlags, QPoint point); - -// Implementation -protected: - virtual bool eventFilter(QObject *object, QEvent *e); - virtual void keyPressEvent(QKeyEvent *event); - virtual void paintEvent(QPaintEvent *event); - virtual void resizeEvent(QResizeEvent *event); - virtual void mouseMoveEvent(QMouseEvent *event); - virtual void mousePressEvent(QMouseEvent *event); - virtual void mouseReleaseEvent(QMouseEvent *event); - virtual void closeEvent(QCloseEvent *event); - virtual void timerEvent(QTimerEvent *event); -}; diff --git a/depthmapX/UI/AboutDlg.ui b/depthmapX/UI/AboutDlg.ui index 486c7be0..82f683e7 100644 --- a/depthmapX/UI/AboutDlg.ui +++ b/depthmapX/UI/AboutDlg.ui @@ -33,7 +33,7 @@ - Version information + Version information diff --git a/depthmapX/UI/licenseagreement.ui b/depthmapX/UI/licenseagreement.ui index e2118510..4ae9ba1e 100644 --- a/depthmapX/UI/licenseagreement.ui +++ b/depthmapX/UI/licenseagreement.ui @@ -34,7 +34,7 @@ - <html><head/><body><p><span style=" font-size:24pt;">depthmapX</span></p><p><span style=" font-size:12pt;">Multi-Platform Spatial Network Analysis Software</span></p><p><a href="https://github.com/varoudis/depthmapX"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/varoudis/depthmapX</span></a></p><p><span style=" font-size:10pt;">(C) 2000-2010 University College London, Alasdair Turner, Eva Friedrich<br/>(C) 2011-2014 Tasos Varoudis, UCL<br/>(C) 2017 Christian Sailer</span></p><p><br/></p><p><span style=" font-size:12pt;">In memory of Alasdair Turner </span></p></body></html> + <html><head/><body><p><span style=" font-size:24pt;">depthmapX</span></p><p><span style=" font-size:12pt;">Multi-Platform Spatial Network Analysis Software</span></p><p><a href="https://github.com/varoudis/depthmapX"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/varoudis/depthmapX</span></a></p><p><span style=" font-size:10pt;">(C) 2000-2010 University College London, Alasdair Turner, Eva Friedrich<br/>(C) 2011-2014 Tasos Varoudis, UCL<br/>(C) 2017 Christian Sailer, Petros Koutsolampros</span></p><p><br/></p><p><span style=" font-size:12pt;">In memory of Alasdair Turner </span></p></body></html> @@ -46,13 +46,13 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; font-size:14pt; color:#000000;">(c) 2000-2010 University College London, Alasdair Turner, Eva Friedrich<br />(c) 2011-2014, Tasos Varoudis<br />(c) 2017 Christian Sailer</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +</style></head><body style=" font-family:'.SF NS Text'; font-size:13pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; font-size:14pt; color:#000000;">(c) 2000-2010 University College London, Alasdair Turner, Eva Friedrich<br />(c) 2011-2014, Tasos Varoudis<br />(c) 2017 Christian Sailer, Petros Koutsolampros</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt;"><br /></span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; font-size:14pt; color:#000000;">This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt;"><br /></span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; font-size:14pt; color:#000000;">This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt;"><br /></span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; font-size:14pt; color:#000000;">You should have received a copy of the GNU General Public License along with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;.</span></p></body></html> diff --git a/depthmapX/coreapplication.cpp b/depthmapX/coreapplication.cpp new file mode 100644 index 00000000..a027c9d1 --- /dev/null +++ b/depthmapX/coreapplication.cpp @@ -0,0 +1,44 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "depthmapX/coreapplication.h" +#include + +int CoreApplication::exec() { + SettingsImpl settings(new DefaultSettingsFactory); + + if (!settings.readSetting(SettingTag::licenseAccepted, false).toBool()) + { + auto dummy = MainWindowFactory::getLicenseDialog(); + dummy->setModal(true); + dummy->setWindowTitle(TITLE_BASE); + dummy->exec(); + if ( dummy->result() == QDialog::Rejected) { + return 0; + } + settings.writeSetting(SettingTag::licenseAccepted, true); + } + + auto args = arguments(); + QString fileToLoad = mFileToLoad; + if (args.length() == 2) + { + fileToLoad = args[1]; + } + + mMainWindow = MainWindowFactory::getMainWindow(fileToLoad, settings); + mMainWindow->show(); + return QApplication::exec(); +} diff --git a/depthmapX/coreapplication.h b/depthmapX/coreapplication.h new file mode 100644 index 00000000..0d26c7c7 --- /dev/null +++ b/depthmapX/coreapplication.h @@ -0,0 +1,51 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "depthmapX/mainwindowfactory.h" +#include "version.h" +#include "settingsimpl.h" +#include +#include +#include + +class CoreApplication : public QApplication +{ +private: + QString mFileToLoad; + std::unique_ptr mMainWindow; +public: + CoreApplication(int &argc, char **argv) + : QApplication(argc, argv) + { + } + + bool event(QEvent *event) + { + // this event is triggered in macOS, either by calling "Open with..." + // in Finder, or by dropping a file on the depthmapX icon on the dock + // more info: http://doc.qt.io/qt-5/qfileopenevent.html + if (event->type() == QEvent::FileOpen) { + QFileOpenEvent *openEvent = static_cast(event); + mFileToLoad = openEvent->file(); + mMainWindow->loadFile(openEvent->file()); + } + + return QApplication::event(event); + } + + int exec(); +}; diff --git a/depthmapX/depthmapX.pro b/depthmapX/depthmapX.pro deleted file mode 100644 index aa9dcdaa..00000000 --- a/depthmapX/depthmapX.pro +++ /dev/null @@ -1,127 +0,0 @@ -include(../defaults.pri) -QT += core gui opengl widgets -DEFINES += _DEPTHMAP -TEMPLATE = lib -CONFIG += staticlib -TARGET = depthmapX -HEADERS = depthmapView.h \ - GraphDoc.h \ - indexWidget.h \ - mainwindow.h \ - mdichild.h \ - treeWindow.h \ - 3DView.h \ - PlotView.h \ - tableView.h \ - TopoMetDlg.h \ - SegmentAnalysisDlg.h \ - RenameObjectDlg.h \ - PushDialog.h \ - PromptReplace.h \ - OptionsDlg.h \ - NewLayerDlg.h \ - MakeOptionsDlg.h \ - MakeLayerDlg.h \ - LicenceDialog.h \ - LayerChooserDlg.h \ - IsovistPathDlg.h \ - InsertColumnDlg.h \ - GridDialog.h \ - FindLocDlg.h \ - FilePropertiesDlg.h \ - FewestLineOptionsDlg.h \ - EditConnectionsDlg.h \ - DepthmapOptionsDlg.h \ - ConvertShapesDlg.h \ - ColumnPropertiesDlg.h \ - ColourScaleDlg.h \ - AxialAnalysisOptionsDlg.h \ - AttributeSummary.h \ - AttributeChooserDlg.h \ - AgentAnalysisDlg.h \ - AboutDlg.h \ - licenseagreement.h \ - compatibilitydefines.h \ - mainwindowfactory.h \ - viewhelpers.h \ - version.h - -SOURCES = depthmapView.cpp \ - GraphDoc.cpp \ - indexWidget.cpp \ - mainwindow.cpp \ - mdichild.cpp \ - renderthread.cpp \ - treeWindow.cpp \ - 3DView.cpp \ - PlotView.cpp \ - tableView.cpp \ - TopoMetDlg.cpp \ - SegmentAnalysisDlg.cpp \ - RenameObjectDlg.cpp \ - PushDialog.cpp \ - PromptReplace.cpp \ - OptionsDlg.cpp \ - NewLayerDlg.cpp \ - MakeOptionsDlg.cpp \ - MakeLayerDlg.cpp \ - LicenceDialog.cpp \ - LayerChooserDlg.cpp \ - IsovistPathDlg.cpp \ - InsertColumnDlg.cpp \ - GridDialog.cpp \ - FindLocDlg.cpp \ - FilePropertiesDlg.cpp \ - FewestLineOptionsDlg.cpp \ - EditConnectionsDlg.cpp \ - DepthmapOptionsDlg.cpp \ - ConvertShapesDlg.cpp \ - ColumnPropertiesDlg.cpp \ - ColourScaleDlg.cpp \ - AxialAnalysisOptionsDlg.cpp \ - AttributeSummary.cpp \ - AttributeChooserDlg.cpp \ - AgentAnalysisDlg.cpp \ - AboutDlg.cpp \ - licenseagreement.cpp \ - mainwindowfactory.cpp \ - viewhelpers.cpp - -RESOURCES = resource.qrc - -OTHER_FILES += \ - Libs/include/generic/lgpl.txt - -QMAKE_CXXFLAGS_WARN_ON = - -FORMS += \ - UI/TopoMetDlg.ui \ - UI/SegmentAnalysisDlg.ui \ - UI/RenameObjectDlg.ui \ - UI/PushDialog.ui \ - UI/PromptReplace.ui \ - UI/OptionsDlg.ui \ - UI/NewLayerDlg.ui \ - UI/MakeOptionsDlg.ui \ - UI/MakeLayerDlg.ui \ - UI/LicenceDialog.ui \ - UI/LayerChooserDlg.ui \ - UI/IsovistPathDlg.ui \ - UI/InsertColumnDlg.ui \ - UI/GridDialog.ui \ - UI/FindLocDlg.ui \ - UI/FilePropertiesDlg.ui \ - UI/FewestLineOptionsDlg.ui \ - UI/EditConnectionsDlg.ui \ - UI/DepthmapOptionsDlg.ui \ - UI/DepthmapAlert.ui \ - UI/ConvertShapesDlg.ui \ - UI/ColumnPropertiesDlg.ui \ - UI/ColourScaleDlg.ui \ - UI/AxialAnalysisOptionsDlg.ui \ - UI/AttributeSummary.ui \ - UI/AttributeChooserDlg.ui \ - UI/AgentAnalysisDlg.ui \ - UI/AboutDlg.ui \ - UI/licenseagreement.ui - diff --git a/depthmapX/AboutDlg.cpp b/depthmapX/dialogs/AboutDlg.cpp similarity index 86% rename from depthmapX/AboutDlg.cpp rename to depthmapX/dialogs/AboutDlg.cpp index f78fc5da..346b595f 100644 --- a/depthmapX/AboutDlg.cpp +++ b/depthmapX/dialogs/AboutDlg.cpp @@ -21,9 +21,9 @@ CAboutDlg::CAboutDlg(QWidget *parent) { setupUi(this); QString m_version_info; - m_version_info = QString(tr("Version %1%2")).arg(DEPTHMAPX_VERSION).arg(DEPTHMAPX_MINOR_VERSION); + m_version_info = QString(tr("Version %1.%2.%3 (%4, %5)")).arg(DEPTHMAPX_MAJOR_VERSION).arg(DEPTHMAPX_MINOR_VERSION).arg(DEPTHMAPX_REVISION_VERSION).arg(APP_GIT_BRANCH).arg(APP_GIT_COMMIT); QString m_copyright; - m_copyright = QString(tr("(C) 2000-2010 University College London, Alasdair Turner, Eva Friedrich\n(C) 2011-2014 Tasos Varoudis\n(C) 2017 Christian Sailer")); + m_copyright = QString(tr("(C) 2000-2010 University College London, Alasdair Turner, Eva Friedrich\n(C) 2011-2014 Tasos Varoudis\n(C) 2017 Christian Sailer, Petros Koutsolampros")); QString m_agreement; m_agreement = QString(tr("This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\x0D\x0D\x0A\x0D\x0D\x0AThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\x0D\x0D\x0A\x0D\x0D\x0AYou should have received a copy of the GNU General Public License along with this program. If not, see .")); diff --git a/depthmapX/AboutDlg.h b/depthmapX/dialogs/AboutDlg.h similarity index 100% rename from depthmapX/AboutDlg.h rename to depthmapX/dialogs/AboutDlg.h diff --git a/depthmapX/AgentAnalysisDlg.cpp b/depthmapX/dialogs/AgentAnalysisDlg.cpp similarity index 100% rename from depthmapX/AgentAnalysisDlg.cpp rename to depthmapX/dialogs/AgentAnalysisDlg.cpp diff --git a/depthmapX/AgentAnalysisDlg.h b/depthmapX/dialogs/AgentAnalysisDlg.h similarity index 92% rename from depthmapX/AgentAnalysisDlg.h rename to depthmapX/dialogs/AgentAnalysisDlg.h index e5909390..9cbb3b0a 100644 --- a/depthmapX/AgentAnalysisDlg.h +++ b/depthmapX/dialogs/AgentAnalysisDlg.h @@ -15,7 +15,6 @@ #include "ui_AgentAnalysisDlg.h" #include -#include #include #include @@ -36,7 +35,7 @@ class CAgentAnalysisDlg : public QDialog, public Ui::CAgentAnalysisDlg //}}AFX_DATA int m_gatelayer; - pvecstring m_names; + std::vector m_names; void UpdateData(bool value); void showEvent(QShowEvent * event); diff --git a/depthmapX/AttributeChooserDlg.cpp b/depthmapX/dialogs/AttributeChooserDlg.cpp similarity index 93% rename from depthmapX/AttributeChooserDlg.cpp rename to depthmapX/dialogs/AttributeChooserDlg.cpp index e4be4900..30f634b4 100644 --- a/depthmapX/AttributeChooserDlg.cpp +++ b/depthmapX/dialogs/AttributeChooserDlg.cpp @@ -45,7 +45,7 @@ void CAttributeChooserDlg::UpdateData(bool value) void CAttributeChooserDlg::showEvent(QShowEvent * event) { c_attribute_chooser->addItem(QString(tr("Ref Number"))); - for (int i = 0; i < m_table->getColumnCount(); i++) { + for (int i = 0; i < m_table->getNumColumns(); i++) { c_attribute_chooser->addItem( QString(m_table->getColumnName(i).c_str()) ); } c_attribute_chooser->setCurrentIndex(0); diff --git a/depthmapX/AttributeChooserDlg.h b/depthmapX/dialogs/AttributeChooserDlg.h similarity index 86% rename from depthmapX/AttributeChooserDlg.h rename to depthmapX/dialogs/AttributeChooserDlg.h index 35eae93d..338b8e61 100644 --- a/depthmapX/AttributeChooserDlg.h +++ b/depthmapX/dialogs/AttributeChooserDlg.h @@ -15,7 +15,6 @@ #include "ui_AttributeChooserDlg.h" #include -#include #include #include @@ -23,10 +22,10 @@ class CAttributeChooserDlg : public QDialog, public Ui::CAttributeChooserDlg { Q_OBJECT public: - CAttributeChooserDlg(AttributeTable& table, QWidget *parent = 0); + CAttributeChooserDlg(AttributeTable& table, QWidget *parent = 0); int m_attribute; QString m_text; - AttributeTable *m_table; + AttributeTable *m_table; void UpdateData(bool value); void showEvent(QShowEvent * event); diff --git a/depthmapX/AttributeSummary.cpp b/depthmapX/dialogs/AttributeSummary.cpp similarity index 77% rename from depthmapX/AttributeSummary.cpp rename to depthmapX/dialogs/AttributeSummary.cpp index a645fed9..3722f808 100644 --- a/depthmapX/AttributeSummary.cpp +++ b/depthmapX/dialogs/AttributeSummary.cpp @@ -32,7 +32,7 @@ void CAttributeSummary::OnOK() void CAttributeSummary::OnDblclkList(int row, int column) { if (row != -1) { - CColumnPropertiesDlg dlg(&(m_pDoc->m_meta_graph->getAttributeTable()), row); + CColumnPropertiesDlg dlg(&(m_pDoc->m_meta_graph->getAttributeTable()), &(m_pDoc->m_meta_graph->getLayers()), row); dlg.exec(); } } @@ -44,7 +44,7 @@ void CAttributeSummary::UpdateData(bool value) void CAttributeSummary::showEvent(QShowEvent * event) { - const AttributeTable& table = m_pDoc->m_meta_graph->getAttributeTable(); + const AttributeTable& table = m_pDoc->m_meta_graph->getAttributeTable(); c_list->setSelectionBehavior(QAbstractItemView::SelectRows); @@ -73,26 +73,27 @@ void CAttributeSummary::showEvent(QShowEvent * event) c_list->clearContents(); - c_list->setRowCount(table.getColumnCount()); - for (int i = 0; i < table.getColumnCount(); i++) { - Item = new QTableWidgetItem(QString(table.getColumnName(i).c_str())); + c_list->setRowCount(table.getNumColumns()); + for (int i = 0; i < table.getNumColumns(); i++) { + const AttributeColumn& column = table.getColumn(i); + Item = new QTableWidgetItem(QString(column.getName().c_str())); Item->setFlags(Qt::NoItemFlags); c_list->setRowHeight(i, 20); c_list->setItem(i, 0, Item); // char text[64]; // Min - sprintf(text, "%g", table.getMinValue(i)); + sprintf(text, "%g", column.getStats().min); Item = new QTableWidgetItem(QString(text)); Item->setFlags(Qt::NoItemFlags); c_list->setItem(i, 1, Item); // Avg - sprintf(text,"%g",table.getAvgValue(i)); + sprintf(text,"%g", column.getStats().total/table.getNumRows()); Item = new QTableWidgetItem(QString(text)); Item->setFlags(Qt::NoItemFlags); c_list->setItem(i, 2, Item); // Max - sprintf(text,"%g",table.getMaxValue(i)); + sprintf(text,"%g",column.getStats().max); Item = new QTableWidgetItem(QString(text)); Item->setFlags(Qt::NoItemFlags); c_list->setItem(i, 3, Item); diff --git a/depthmapX/AttributeSummary.h b/depthmapX/dialogs/AttributeSummary.h similarity index 100% rename from depthmapX/AttributeSummary.h rename to depthmapX/dialogs/AttributeSummary.h diff --git a/depthmapX/dialogs/AxialAnalysisOptionsDlg.cpp b/depthmapX/dialogs/AxialAnalysisOptionsDlg.cpp new file mode 100644 index 00000000..79c7afb2 --- /dev/null +++ b/depthmapX/dialogs/AxialAnalysisOptionsDlg.cpp @@ -0,0 +1,243 @@ +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "AxialAnalysisOptionsDlg.h" +#include "mainwindow.h" +#include + +CAxialAnalysisOptionsDlg::CAxialAnalysisOptionsDlg(MetaGraph *graph, QWidget *parent) : QDialog(parent) { + setupUi(this); + m_radius = QString(tr("")); + m_choice = false; + m_attribute = -1; + m_weighted = false; + m_rra = false; + m_local = false; + + m_meta_graph = graph; + + foreach (QWidget *widget, QApplication::topLevelWidgets()) { + MainWindow *mainWin = qobject_cast(widget); + if (mainWin) { + m_choice = mainWin->m_options.choice; + m_local = mainWin->m_options.local; + m_rra = mainWin->m_options.fulloutput; + + m_radius = QString(tr("n")); + + if (mainWin->m_options.weighted_measure_col == -1) { + m_weighted = false; + m_attribute = -1; + } else { + m_weighted = true; + m_attribute = 0; + } + break; + } + } + + if (m_choice) + c_choice->setCheckState(Qt::Checked); + else + c_choice->setCheckState(Qt::Unchecked); + + if (m_local) + c_local->setCheckState(Qt::Checked); + else + c_local->setCheckState(Qt::Unchecked); + + if (m_rra) + c_rra->setCheckState(Qt::Checked); + else + c_rra->setCheckState(Qt::Unchecked); + + if (m_weighted) + c_weighted->setCheckState(Qt::Checked); + else + c_weighted->setCheckState(Qt::Unchecked); + + c_attribute_chooser->setCurrentIndex(m_attribute); + c_radius->setText(m_radius); +} + +void CAxialAnalysisOptionsDlg::OnUpdateRadius() { + QString text; + text = c_radius->text(); + if (!text.isEmpty() && text.indexOf("n") == -1 && text.indexOf("N") == -1 && text.indexOf("1") == -1 && + text.indexOf("2") == -1 && text.indexOf("3") == -1 && text.indexOf("4") == -1 && text.indexOf("5") == -1 && + text.indexOf("6") == -1 && text.indexOf("7") == -1 && text.indexOf("8") == -1 && text.indexOf("9") == -1) { + QMessageBox::warning(this, tr("Warning"), + tr("The radius must either be numeric or 'n'\n Alternatively, for multiple radii, type a " + "list of comma separated numeric radii (you can include 'n')"), + QMessageBox::Ok, QMessageBox::Ok); + c_radius->setText(tr("n")); + c_radius->setFocus(Qt::OtherFocusReason); + } +} + +void CAxialAnalysisOptionsDlg::OnWeighted() { + if (c_weighted->checkState()) { + UpdateData(true); + c_attribute_chooser->setEnabled(true); + m_attribute = 0; + UpdateData(false); + } else { + UpdateData(true); + c_attribute_chooser->setEnabled(false); + m_attribute = -1; + UpdateData(false); + } +} + +void CAxialAnalysisOptionsDlg::OnOK() { + UpdateData(true); + + if (m_radius.isEmpty() || + (m_radius.indexOf("n") == -1 && m_radius.indexOf("N") == -1 && m_radius.indexOf("1") == -1 && + m_radius.indexOf("2") == -1 && m_radius.indexOf("3") == -1 && m_radius.indexOf("4") == -1 && + m_radius.indexOf("5") == -1 && m_radius.indexOf("6") == -1 && m_radius.indexOf("7") == -1 && + m_radius.indexOf("8") == -1 && m_radius.indexOf("9") == -1)) { + QMessageBox::warning(this, tr("Warning"), + tr("The radius must either be numeric or 'n'\n Alternatively, for multiple radii, type a " + "list of comma separated numeric radii (you can include 'n')"), + QMessageBox::Ok, QMessageBox::Ok); + m_radius = tr("n"); + UpdateData(false); + c_radius->setFocus(Qt::OtherFocusReason); + return; + } + // now parse radius list: + foreach (QWidget *widget, QApplication::topLevelWidgets()) { + MainWindow *mainWin = qobject_cast(widget); + if (mainWin) { + mainWin->m_options.radius_set.clear(); + QString curr_radius; + int curr_comma = -1, last_comma = 0; + bool add_rn = false; + do { + curr_comma = m_radius.indexOf(',', last_comma); + if (curr_comma != -1) { + curr_radius = m_radius.mid(last_comma, curr_comma - last_comma); + last_comma = curr_comma + 1; + } else { + curr_radius = m_radius.mid(last_comma); + } + if (!curr_radius.isEmpty()) { + if (curr_radius == "n" || curr_radius == "N") { + add_rn = true; + } else { + int radius = curr_radius.toInt(); + if (radius <= 0) { + QMessageBox::warning( + this, tr("Warning"), + tr("Each radius in the list must either be 'n' or a number in the range 1-99"), + QMessageBox::Ok, QMessageBox::Ok); + c_radius->setFocus(Qt::OtherFocusReason); + return; + } + mainWin->m_options.radius_set.insert(static_cast(radius)); + } + } + } while (curr_comma != -1); + if (mainWin->m_options.radius_set.size() == 0 || add_rn) { + mainWin->m_options.radius_set.insert(-1); + } + + mainWin->m_options.choice = m_choice; + mainWin->m_options.local = m_local; + mainWin->m_options.fulloutput = m_rra; + + // attributes: + if (!m_weighted) { + mainWin->m_options.weighted_measure_col = -1; + } else { + mainWin->m_options.weighted_measure_col = m_attribute; + } + break; + } + } + + accept(); +} + +void CAxialAnalysisOptionsDlg::UpdateData(bool value) { + if (value) { + m_radius = c_radius->text(); + if (c_choice->checkState()) + m_choice = true; + else + m_choice = false; + + m_attribute = c_attribute_chooser->currentIndex(); + + if (c_weighted->checkState()) + m_weighted = true; + else + m_weighted = false; + + if (c_rra->checkState()) + m_rra = true; + else + m_rra = false; + + if (c_local->checkState()) + m_local = true; + else + m_local = false; + } else { + c_radius->setText(m_radius); + if (m_choice) + c_choice->setCheckState(Qt::Checked); + else + c_choice->setCheckState(Qt::Unchecked); + + c_attribute_chooser->setCurrentIndex(m_attribute); + if (m_weighted) + c_weighted->setCheckState(Qt::Checked); + else + c_weighted->setCheckState(Qt::Unchecked); + + if (m_rra) + c_rra->setCheckState(Qt::Checked); + else + c_rra->setCheckState(Qt::Unchecked); + + if (m_local) + c_local->setCheckState(Qt::Checked); + else + c_local->setCheckState(Qt::Unchecked); + } +} + +void CAxialAnalysisOptionsDlg::showEvent(QShowEvent *event) { + const ShapeGraph &map = m_meta_graph->getDisplayedShapeGraph(); + const AttributeTable &table = map.getAttributeTable(); + for (int i = 0; i < table.getNumColumns(); i++) { + c_attribute_chooser->addItem(QString(table.getColumnName(i).c_str())); + } + + if (m_weighted) { + c_attribute_chooser->setEnabled(true); + m_attribute = 0; + c_attribute_chooser->setCurrentIndex(m_attribute); + } else { + m_attribute = -1; + c_attribute_chooser->setCurrentIndex(m_attribute); + c_attribute_chooser->setEnabled(true); + } + + // UpdateData(false); +} diff --git a/depthmapX/AxialAnalysisOptionsDlg.h b/depthmapX/dialogs/AxialAnalysisOptionsDlg.h similarity index 93% rename from depthmapX/AxialAnalysisOptionsDlg.h rename to depthmapX/dialogs/AxialAnalysisOptionsDlg.h index 6eadd114..6dd2bd1a 100644 --- a/depthmapX/AxialAnalysisOptionsDlg.h +++ b/depthmapX/dialogs/AxialAnalysisOptionsDlg.h @@ -15,7 +15,6 @@ #include "ui_AxialAnalysisOptionsDlg.h" #include -#include #include #include @@ -38,5 +37,5 @@ private slots: void OnUpdateRadius(); void OnWeighted(); void OnOK(); - void OnCancel(); + void OnCancel() { reject(); } }; diff --git a/depthmapX/dialogs/CMakeLists.txt b/depthmapX/dialogs/CMakeLists.txt new file mode 100644 index 00000000..5fe12fed --- /dev/null +++ b/depthmapX/dialogs/CMakeLists.txt @@ -0,0 +1,64 @@ +target_sources(depthmapX + PUBLIC + TopoMetDlg.h + SegmentAnalysisDlg.h + RenameObjectDlg.h + PushDialog.h + PromptReplace.h + OptionsDlg.h + NewLayerDlg.h + MakeOptionsDlg.h + MakeLayerDlg.h + LicenceDialog.h + LayerChooserDlg.h + IsovistPathDlg.h + InsertColumnDlg.h + GridDialog.h + FindLocDlg.h + FilePropertiesDlg.h + FewestLineOptionsDlg.h + EditConnectionsDlg.h + ConvertShapesDlg.h + ColumnPropertiesDlg.h + ColourScaleDlg.h + AxialAnalysisOptionsDlg.h + AttributeSummary.h + AttributeChooserDlg.h + AgentAnalysisDlg.h + AboutDlg.h + licenseagreement.h + settings/generalpage.h + settings/interfacepage.h + settings/settingspage.h + settings/settingsdialog.h + PRIVATE + TopoMetDlg.cpp + SegmentAnalysisDlg.cpp + RenameObjectDlg.cpp + PushDialog.cpp + PromptReplace.cpp + OptionsDlg.cpp + NewLayerDlg.cpp + MakeOptionsDlg.cpp + MakeLayerDlg.cpp + LicenceDialog.cpp + LayerChooserDlg.cpp + IsovistPathDlg.cpp + InsertColumnDlg.cpp + GridDialog.cpp + FindLocDlg.cpp + FilePropertiesDlg.cpp + FewestLineOptionsDlg.cpp + EditConnectionsDlg.cpp + ConvertShapesDlg.cpp + ColumnPropertiesDlg.cpp + ColourScaleDlg.cpp + AxialAnalysisOptionsDlg.cpp + AttributeSummary.cpp + AttributeChooserDlg.cpp + AgentAnalysisDlg.cpp + AboutDlg.cpp + licenseagreement.cpp + settings/generalpage.cpp + settings/interfacepage.cpp + settings/settingsdialog.cpp) diff --git a/depthmapX/dialogs/ColourScaleDlg.cpp b/depthmapX/dialogs/ColourScaleDlg.cpp new file mode 100644 index 00000000..349010f8 --- /dev/null +++ b/depthmapX/dialogs/ColourScaleDlg.cpp @@ -0,0 +1,341 @@ +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "mainwindow.h" + +CColourScaleDlg::CColourScaleDlg(QWidget *parent) : QDialog(parent) { + setupUi(this); + setWindowFlags(Qt::WindowStaysOnTopHint); + + m_show_lines = false; + m_show_fill = false; + m_show_centroids = false; + m_blue = tr(""); + m_red = tr(""); + m_color = -1; + + m_docked = false; + + m_viewDoc = NULL; + + m_red_brush.setColor(QColor(255, 128, 128)); // CreateSolidBrush(RGB(255,128,128)); + m_blue_brush.setColor(QColor(128, 128, 255)); + + c_blue_slider_ctrl->setMinimum(0); + c_blue_slider_ctrl->setMaximum(100); + c_red_slider_ctrl->setMinimum(0); + c_red_slider_ctrl->setMaximum(100); + c_blue_slider_ctrl->setTickInterval(10); + c_red_slider_ctrl->setTickInterval(10); + + // these are out of order... + c_color_type->addItem(QString(tr("Equal Ranges (3-Colour)"))); // AXMANESQUE + c_color_type->addItem(QString(tr("Equal Ranges (Blue-Red)"))); // BLUERED + c_color_type->addItem(QString(tr("Equal Ranges (Purple-Orange)"))); // PURPLEORANGE + c_color_type->addItem(QString(tr("depthmapX Classic"))); // DEPTHMAPCLASSIC + c_color_type->addItem(QString(tr("Equal Ranges (Greyscale)"))); // GREYSCALE + c_color_type->addItem(QString(tr("Equal Ranges (Monochrome)"))); // MONOCHROME + c_color_type->addItem(QString(tr("Equal Ranges (3-Colour Hue Only)"))); // HUEONLYAXMANESQUE + + m_color_type_map.push_back(DisplayParams::AXMANESQUE); + m_color_type_map.push_back(DisplayParams::BLUERED); + m_color_type_map.push_back(DisplayParams::PURPLEORANGE); + m_color_type_map.push_back(DisplayParams::DEPTHMAPCLASSIC); + m_color_type_map.push_back(DisplayParams::GREYSCALE); + m_color_type_map.push_back(DisplayParams::MONOCHROME); + m_color_type_map.push_back(DisplayParams::HUEONLYAXMANESQUE); + + Clear(); + + UpdateData(false); +} + +void CColourScaleDlg::OnChangeBlueValue() { + QString str; + str = c_blue_value_window->text(); + m_displayparams.blue = GetNormValue(str.toDouble()); + c_blue_slider_ctrl->setValue(m_displayparams.blue * 100.0); + c_ok->setEnabled(true); + c_applytoall->setEnabled(true); +} + +void CColourScaleDlg::OnChangeRedValue() { + QString str; + str = c_red_value_window->text(); + m_displayparams.red = GetNormValue(str.toDouble()); + c_red_slider_ctrl->setValue(m_displayparams.red * 100); + c_ok->setEnabled(true); + c_applytoall->setEnabled(true); +} + +void CColourScaleDlg::OnReleasedRedSlider(int val) { + double value = double(c_red_slider_ctrl->value()) / 100.0; + QString text; + text.sprintf("%.2f", GetActualValue(value)); + c_red_value_window->setText(text); +} + +void CColourScaleDlg::OnReleasedBlueSlider(int val) { + double value = double(c_blue_slider_ctrl->value()) / 100.0; + QString text; + text.sprintf("%.2f", GetActualValue(value)); + c_blue_value_window->setText(text); +} + +void CColourScaleDlg::OnSelchangeColor(int value) { + UpdateData(true); + + if (m_color_type_map.size() <= (size_t)value) + return; + + m_color = m_color_type_map[value]; + + if (m_color == 0 || m_color == 3 || m_color == 5 || m_color == 6) { + m_red = "Red"; + m_blue = "Blue"; + } else if (m_color == 4) { + m_red = "Orange"; + m_blue = "Purple"; + } else if (m_color == 1) { + m_red = "White"; + m_blue = "Black"; + } else { + m_red = "Thick"; + m_blue = "Thin"; + } + + UpdateData(false); + + c_ok->setEnabled(true); + c_applytoall->setEnabled(true); +} + +void CColourScaleDlg::OnBnClickedShowLines(bool value) { c_ok->setEnabled(true); } + +void CColourScaleDlg::OnBnClickedShowFill(bool value) { c_ok->setEnabled(true); } + +void CColourScaleDlg::OnBnClickedShowCentroids(bool value) { c_ok->setEnabled(true); } + +void CColourScaleDlg::OnBnClickedApplytoall() { + MyUpdateData(true, true); + + // don't destroy + c_ok->setEnabled(false); + c_applytoall->setEnabled(false); +} + +void CColourScaleDlg::OnOK() { + MyUpdateData(true, false); + + // don't destroy + c_ok->setEnabled(false); +} + +void CColourScaleDlg::OnCancel() { + // don't destroy, simply hide: + hide(); +} + +void CColourScaleDlg::UpdateData(bool value) { + if (value) { + m_blue = c_blue->text(); + m_red = c_red->text(); + if (c_show_lines->checkState()) + m_show_lines = true; + else + m_show_lines = false; + + if (c_show_fill->checkState()) + m_show_fill = true; + else + m_show_fill = false; + + if (c_show_centroids->checkState()) + m_show_centroids = true; + else + m_show_centroids = false; + } else // push data to controls: + { + c_blue->setText(m_blue); + c_red->setText(m_red); + if (m_show_lines) + c_show_lines->setCheckState(Qt::Checked); + else + c_show_lines->setCheckState(Qt::Unchecked); + + if (m_show_fill) + c_show_fill->setCheckState(Qt::Checked); + else + c_show_fill->setCheckState(Qt::Unchecked); + + if (m_show_centroids) + c_show_centroids->setCheckState(Qt::Checked); + else + c_show_centroids->setCheckState(Qt::Unchecked); + } +} + +void CColourScaleDlg::Clear() { + m_color = -1; + c_color_type->setEnabled(false); + m_blue = "Min"; + m_red = "Max"; + c_blue_value_window->setEnabled(false); + c_blue_value_window->setText(tr("")); + c_red_value_window->setEnabled(false); + c_red_value_window->setText(tr("")); + c_blue_slider_ctrl->setEnabled(false); + c_blue_slider_ctrl->setValue(0); + c_red_slider_ctrl->setEnabled(false); + c_red_slider_ctrl->setValue(100); + c_ok->setEnabled(false); + c_applytoall->setEnabled(false); + + UpdateData(false); +} + +double CColourScaleDlg::GetActualValue(double sliderpos) { + return sliderpos * (m_display_max - m_display_min) + m_display_min; +} + +float CColourScaleDlg::GetNormValue(double actualval) { + return ((actualval - m_display_min) / (m_display_max - m_display_min)); +} + +void CColourScaleDlg::Fill() { + if (m_color == 0 || m_color == 3 || m_color == 5) { + m_red = "Red"; + m_blue = "Blue"; + } else if (m_color == 4) { + m_red = "Orange"; + m_blue = "Purple"; + } else if (m_color == 1) { + m_red = "White"; + m_blue = "Black"; + } else { + m_red = "Thick"; + m_blue = "Thin"; + } + + QString text; + text.sprintf("%.2f", GetActualValue(m_displayparams.blue)); + c_blue_value_window->setText(text); + text.sprintf("%.2f", GetActualValue(m_displayparams.red)); + c_red_value_window->setText(text); + + c_blue_slider_ctrl->setValue(int(m_displayparams.blue * 100)); + c_red_slider_ctrl->setValue(int(m_displayparams.red * 100)); + + c_color_type->setEnabled(true); + c_blue_value_window->setEnabled(true); + c_red_value_window->setEnabled(true); + c_blue_slider_ctrl->setEnabled(true); + c_red_slider_ctrl->setEnabled(true); + c_ok->setEnabled(false); + c_applytoall->setEnabled(false); + + UpdateData(false); +} + +void CColourScaleDlg::OnFocusGraph(QGraphDoc *pDoc, int lParam) { + if (lParam == QGraphDoc::CONTROLS_DESTROYALL && pDoc == m_viewDoc) { // Lost graph + m_viewDoc = NULL; + MyUpdateData(false, false); + } else if (lParam == QGraphDoc::CONTROLS_LOADALL && + pDoc != m_viewDoc) { // [Possible] change of window (sent on focus) + m_viewDoc = pDoc; + MyUpdateData(false, false); + } else if (lParam != QGraphDoc::CONTROLS_LOADALL && pDoc == m_viewDoc) { // Force update if match current window + MyUpdateData(false, false); + } +} + +void CColourScaleDlg::MyUpdateData(bool dir, bool apply_to_all) { + if (dir == false) { + // push data to controls: + if (m_viewDoc == NULL) { + Clear(); + } else { + MetaGraph *graph = m_viewDoc->m_meta_graph; + if (graph->viewingProcessed()) { + if (graph->getViewClass() & MetaGraph::VIEWVGA) { + PointMap &map = graph->getDisplayedPointMap(); + m_display_min = map.getDisplayMinValue(); + m_display_max = map.getDisplayMaxValue(); + m_displayparams = map.getDisplayParams(); + m_color = m_displayparams.colorscale; + } else if (graph->getViewClass() & MetaGraph::VIEWAXIAL) { + ShapeGraph &map = graph->getDisplayedShapeGraph(); + if (map.getShapeCount() > 0) { + m_display_min = map.getDisplayMinValue(); + m_display_max = map.getDisplayMaxValue(); + } + m_displayparams = map.getDisplayParams(); + m_color = m_displayparams.colorscale; + bool show_lines = m_show_lines, show_fill = m_show_fill, show_centroids = m_show_centroids; + map.getPolygonDisplay(show_lines, show_fill, show_centroids); + m_show_lines = show_lines; + m_show_fill = show_fill; + m_show_centroids = show_centroids; + } else if (graph->getViewClass() & MetaGraph::VIEWDATA) { + ShapeMap &map = graph->getDisplayedDataMap(); + if (map.getShapeCount() > 0) { + m_display_min = map.getDisplayMinValue(); + m_display_max = map.getDisplayMaxValue(); + } + m_displayparams = map.getDisplayParams(); + m_color = m_displayparams.colorscale; + bool show_lines = m_show_lines, show_fill = m_show_fill, show_centroids = m_show_centroids; + map.getPolygonDisplay(show_lines, show_fill, show_centroids); + m_show_lines = show_lines; + m_show_fill = show_fill; + m_show_centroids = show_centroids; + } + for (size_t i = 0; i < m_color_type_map.size(); i++) { + if (m_color == m_color_type_map[i]) { + c_color_type->setCurrentIndex(i); + } + } + Fill(); + } else { + Clear(); + } + } + UpdateData(false); + } else { + // get data from controls: + UpdateData(true); + + if (m_viewDoc != NULL) { + MetaGraph *graph = m_viewDoc->m_meta_graph; + m_color = m_color_type_map[c_color_type->currentIndex()]; + m_displayparams.colorscale = m_color; + if (graph->getViewClass() & MetaGraph::VIEWVGA) { + graph->getDisplayedPointMap().setDisplayParams(m_displayparams, apply_to_all); + } else if (graph->getViewClass() & MetaGraph::VIEWAXIAL) { + graph->getDisplayedShapeGraph().setDisplayParams(m_displayparams, apply_to_all); + graph->getDisplayedShapeGraph().setPolygonDisplay(m_show_lines, m_show_fill, m_show_centroids); + } else if (graph->getViewClass() & MetaGraph::VIEWDATA) { + graph->getDisplayedDataMap().setDisplayParams(m_displayparams, apply_to_all); + graph->getDisplayedDataMap().setPolygonDisplay(m_show_lines, m_show_fill, m_show_centroids); + } + } + m_viewDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP); + } +} + +void CColourScaleDlg::showEvent(QShowEvent *event) { + // UpdateData(false); +} diff --git a/depthmapX/dialogs/ColourScaleDlg.h b/depthmapX/dialogs/ColourScaleDlg.h new file mode 100644 index 00000000..c5ba9531 --- /dev/null +++ b/depthmapX/dialogs/ColourScaleDlg.h @@ -0,0 +1,67 @@ +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef ColourScaleDlg_H +#define ColourScaleDlg_H + +#include "GraphDoc.h" +#include "ui_ColourScaleDlg.h" + +class CColourScaleDlg : public QDialog, public Ui::CColourScaleDlg { + Q_OBJECT + public: + CColourScaleDlg(QWidget *parent = 0); + QGraphDoc *m_viewDoc; + QString m_blue; + QString m_red; + int m_color; + + bool m_docked; + + double m_display_min; + double m_display_max; + double GetActualValue(double sliderpos); + float GetNormValue(double actualval); + + QBrush m_red_brush; + QBrush m_blue_brush; + DisplayParams m_displayparams; + + void MyUpdateData(bool dir, bool apply_to_all); + void Clear(); + void Fill(); + bool m_show_lines; + bool m_show_fill; + bool m_show_centroids; + std::vector m_color_type_map; + void UpdateData(bool value); + void showEvent(QShowEvent *event); + void OnFocusGraph(QGraphDoc *pDoc, int lParam); + + private slots: + void OnChangeBlueValue(); + void OnChangeRedValue(); + void OnReleasedRedSlider(int); + void OnReleasedBlueSlider(int); + void OnSelchangeColor(int); + void OnBnClickedShowLines(bool); + void OnBnClickedShowFill(bool); + void OnBnClickedShowCentroids(bool); + void OnBnClickedApplytoall(); + void OnOK(); + void OnCancel(); +}; + +#endif diff --git a/depthmapX/dialogs/ColumnPropertiesDlg.cpp b/depthmapX/dialogs/ColumnPropertiesDlg.cpp new file mode 100644 index 00000000..d87aa5b6 --- /dev/null +++ b/depthmapX/dialogs/ColumnPropertiesDlg.cpp @@ -0,0 +1,231 @@ +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "ColumnPropertiesDlg.h" + +#include "genlib/stringutils.h" + +CColumnPropertiesDlg::CColumnPropertiesDlg(AttributeTable *table, LayerManagerImpl *layers, int col, QWidget *parent) + : QDialog(parent) { + setupUi(this); + m_formula = tr(""); + m_name = tr(""); + m_name_text = tr(""); + m_creator = tr(""); + m_formula_note = tr(""); + + m_table = table; + m_layers = layers; + m_col = col; + + AttributeColumn &column = m_table->getColumn(m_col); + m_name = column.getName().c_str(); + m_formula = column.getFormula().c_str(); + + if (!column.isLocked()) { + m_name_text = "Name"; + } else { + m_name_text = "Name (column locked and cannot be edited)"; + } + + if (m_formula.isEmpty()) { + // m_formula_note.Empty(); + } else { + m_formula_note = tr("Note: the formula may have been applied to a subset of objects"); + } + + UpdateData(false); +} + +void CColumnPropertiesDlg::OnOK() { + UpdateData(true); + accept(); +} + +void CColumnPropertiesDlg::UpdateData(bool value) { + std::vector rows; + std::vector summary_all; + std::vector summary_sel; + + rows.push_back(tr("Average")); + rows.push_back(tr("Minimum")); + rows.push_back(tr("Maximum")); + rows.push_back(tr("Std Dev")); + rows.push_back(tr("Count")); + + int i; + for (i = 0; i < 15; i++) { + if (i == 1 || i == 2) { + // minimum and maximum + summary_all.push_back(-1.0); + summary_sel.push_back(-1.0); + } else { + summary_all.push_back(0.0); + summary_sel.push_back(0.0); + } + } + + for (auto iter = m_table->begin(); iter != m_table->end(); iter++) { + auto &row = iter->getRow(); + double val = row.getValue(m_col); + if (val != -1.0 && isObjectVisible(*m_layers, iter->getRow())) { + summary_all[0] += val; + summary_all[4] += 1.0; + if (summary_all[1] == -1.0 || val < summary_all[1]) { + summary_all[1] = val; + } + if (summary_all[2] == -1.0 || val > summary_all[2]) { + summary_all[2] = val; + } + if (row.isSelected()) { + summary_sel[0] += val; + summary_sel[4] += 1.0; + if (summary_sel[1] == -1.0 || val < summary_sel[1]) { + summary_sel[1] = val; + } + if (summary_sel[2] == -1.0 || val > summary_sel[2]) { + summary_sel[2] = val; + } + } + } + } + + bool freqrows = false; + double unit; + if (summary_all[1] != -1.0 && summary_all[2] != -1.0 && summary_all[1] != summary_all[2]) { + freqrows = true; + unit = (summary_all[2] - summary_all[1]) / 10.0; + for (int i = 0; i < 10; i++) { + std::string name; + if (i == 0) { + name = dXstring::formatString(summary_all[1] + unit, "< %f"); + } else if (i == 9) { + name = dXstring::formatString(summary_all[2] - unit, "> %f"); + } else { + name = dXstring::formatString(summary_all[1] + unit * i, "%f") + " to " + + dXstring::formatString(summary_all[1] + unit * (i + 1), "%f"); + } + // Unicode conversion a bit of a mess here AT (01.02.11) + rows.push_back(QString(name.c_str())); + } + } + + if (summary_all[4] != 0) { + summary_all[0] /= summary_all[4]; + } + if (summary_sel[4] != 0) { + summary_sel[0] /= summary_sel[4]; + } + + // count of things rows: just for visible at the moment + + double var_all = 0.0; + double var_sel = 0.0; + for (auto iter = m_table->begin(); iter != m_table->end(); iter++) { + auto &row = iter->getRow(); + double val = row.getValue(m_col); + if (val != -1.0 && isObjectVisible(*m_layers, iter->getRow())) { + var_all += sqr(val - summary_all[0]); + if (freqrows) { + int pos = floor((val - summary_all[1]) / unit); + if (pos == 10) + pos = 9; // irritating exactly equal to max + summary_all[5 + pos] += 1; + } + if (row.isSelected()) { + var_sel += sqr(val - summary_sel[0]); + if (freqrows) { + // note: must use summary_all even on selected to make difference + int pos = floor((val - summary_all[1]) / unit); + if (pos == 10) + pos = 9; // irritating exactly equal to max + summary_sel[5 + pos] += 1; + } + } + } + } + + if (summary_all[4] != 0) { + summary_all[3] = sqrt(var_all / summary_all[4]); + } + if (summary_sel[4] != 0) { + summary_sel[3] = sqrt(var_sel / summary_sel[4]); + } + + c_summary->setSelectionBehavior(QAbstractItemView::SelectRows); + c_summary->setColumnCount(3); + + QTableWidgetItem *Item; + Item = new QTableWidgetItem("Value"); + c_summary->setColumnWidth(0, 100); + Item->setTextAlignment(Qt::AlignLeft); + c_summary->setHorizontalHeaderItem(0, Item); + + Item = new QTableWidgetItem("Attribute"); + c_summary->setColumnWidth(1, 100); + Item->setTextAlignment(Qt::AlignRight); + c_summary->setHorizontalHeaderItem(1, Item); + + Item = new QTableWidgetItem("Selection"); + c_summary->setColumnWidth(2, 100); + Item->setTextAlignment(Qt::AlignRight); + c_summary->setHorizontalHeaderItem(2, Item); + + c_summary->clearContents(); + + c_summary->setRowCount(15); + for (i = 0; i < 15; i++) { + if (i == 5 && !freqrows) { + break; + } + Item = new QTableWidgetItem(rows[i]); + Item->setFlags(Qt::NoItemFlags); + c_summary->setRowHeight(i, 20); + c_summary->setItem(i, 0, Item); + // + char text[64]; + // All + if (i == 4 || summary_all[4] != 0) { + sprintf(text, "%g", summary_all[i]); + } else { + strcpy(text, "No Value"); + } + Item = new QTableWidgetItem(QString(text)); + Item->setFlags(Qt::NoItemFlags); + c_summary->setItem(i, 1, Item); + // Sel + if (i == 4 || summary_sel[4] != 0) { + sprintf(text, "%g", summary_sel[i]); + } else { + strcpy(text, "No Value"); + } + Item = new QTableWidgetItem(QString(text)); + Item->setFlags(Qt::NoItemFlags); + c_summary->setItem(i, 2, Item); + } + if (value) { + m_formula = c_formula->toPlainText(); + m_name = c_name->text(); + m_name_text = c_name_text->text(); + m_formula_note = c_formula_note->text(); + } else { + c_formula->setPlainText(m_formula); + c_name->setText(m_name); + c_name_text->setText(m_name_text); + c_formula_note->setText(m_formula_note); + } +} + +void CColumnPropertiesDlg::showEvent(QShowEvent *event) { UpdateData(false); } diff --git a/depthmapX/ColumnPropertiesDlg.h b/depthmapX/dialogs/ColumnPropertiesDlg.h similarity index 62% rename from depthmapX/ColumnPropertiesDlg.h rename to depthmapX/dialogs/ColumnPropertiesDlg.h index 3f8d3c20..0ec3d53e 100644 --- a/depthmapX/ColumnPropertiesDlg.h +++ b/depthmapX/dialogs/ColumnPropertiesDlg.h @@ -14,26 +14,26 @@ // along with this program. If not, see . #include "ui_ColumnPropertiesDlg.h" +#include #include -#include #include -#include -class CColumnPropertiesDlg : public QDialog, public Ui::CColumnPropertiesDlg -{ - Q_OBJECT -public: - CColumnPropertiesDlg(AttributeTable *table = NULL, int col = -1, QWidget *parent = 0); - AttributeTable *m_table; - int m_col; - QString m_formula; - QString m_name; - QString m_name_text; - QString m_creator; - QString m_formula_note; - void UpdateData(bool value); - void showEvent(QShowEvent * event); +class CColumnPropertiesDlg : public QDialog, public Ui::CColumnPropertiesDlg { + Q_OBJECT + public: + CColumnPropertiesDlg(AttributeTable *table = NULL, LayerManagerImpl *layers = NULL, int col = -1, + QWidget *parent = 0); + AttributeTable *m_table; + LayerManagerImpl *m_layers; + int m_col; + QString m_formula; + QString m_name; + QString m_name_text; + QString m_creator; + QString m_formula_note; + void UpdateData(bool value); + void showEvent(QShowEvent *event); -private slots: - void OnOK(); + private slots: + void OnOK(); }; diff --git a/depthmapX/ConvertShapesDlg.cpp b/depthmapX/dialogs/ConvertShapesDlg.cpp similarity index 100% rename from depthmapX/ConvertShapesDlg.cpp rename to depthmapX/dialogs/ConvertShapesDlg.cpp diff --git a/depthmapX/ConvertShapesDlg.h b/depthmapX/dialogs/ConvertShapesDlg.h similarity index 100% rename from depthmapX/ConvertShapesDlg.h rename to depthmapX/dialogs/ConvertShapesDlg.h diff --git a/depthmapX/EditConnectionsDlg.cpp b/depthmapX/dialogs/EditConnectionsDlg.cpp similarity index 100% rename from depthmapX/EditConnectionsDlg.cpp rename to depthmapX/dialogs/EditConnectionsDlg.cpp diff --git a/depthmapX/EditConnectionsDlg.h b/depthmapX/dialogs/EditConnectionsDlg.h similarity index 100% rename from depthmapX/EditConnectionsDlg.h rename to depthmapX/dialogs/EditConnectionsDlg.h diff --git a/depthmapX/FewestLineOptionsDlg.cpp b/depthmapX/dialogs/FewestLineOptionsDlg.cpp similarity index 100% rename from depthmapX/FewestLineOptionsDlg.cpp rename to depthmapX/dialogs/FewestLineOptionsDlg.cpp diff --git a/depthmapX/FewestLineOptionsDlg.h b/depthmapX/dialogs/FewestLineOptionsDlg.h similarity index 100% rename from depthmapX/FewestLineOptionsDlg.h rename to depthmapX/dialogs/FewestLineOptionsDlg.h diff --git a/depthmapX/FilePropertiesDlg.cpp b/depthmapX/dialogs/FilePropertiesDlg.cpp similarity index 100% rename from depthmapX/FilePropertiesDlg.cpp rename to depthmapX/dialogs/FilePropertiesDlg.cpp diff --git a/depthmapX/FilePropertiesDlg.h b/depthmapX/dialogs/FilePropertiesDlg.h similarity index 100% rename from depthmapX/FilePropertiesDlg.h rename to depthmapX/dialogs/FilePropertiesDlg.h diff --git a/depthmapX/FindLocDlg.cpp b/depthmapX/dialogs/FindLocDlg.cpp similarity index 100% rename from depthmapX/FindLocDlg.cpp rename to depthmapX/dialogs/FindLocDlg.cpp diff --git a/depthmapX/FindLocDlg.h b/depthmapX/dialogs/FindLocDlg.h similarity index 100% rename from depthmapX/FindLocDlg.h rename to depthmapX/dialogs/FindLocDlg.h diff --git a/depthmapX/dialogs/GridDialog.cpp b/depthmapX/dialogs/GridDialog.cpp new file mode 100644 index 00000000..80f8d337 --- /dev/null +++ b/depthmapX/dialogs/GridDialog.cpp @@ -0,0 +1,71 @@ +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "GridDialog.h" +#include +#include + +CGridDialog::CGridDialog(double maxDimension, QWidget *parent) +: QDialog(parent), m_maxdimension(maxDimension) +{ + setupUi(this); + m_spacing = 0.01; +} + +void CGridDialog::showEvent(QShowEvent * event) +{ + GridProperties gp(m_maxdimension); + m_spacing = gp.getDefault(); + + c_spacing_ctrl->setRange(gp.getMin(), gp.getMax()); + + UpdateData(false); +} + +void CGridDialog::OnDeltaposSpinSpacing(double iDelta) +{ + // New slot for this ready userValue(double value) // slot link here though // TV + // m_spacing = c_spacing_ctrl->value(); // bug or not? + + if (int(iDelta / 1.0) > 1) c_spacing_ctrl->setSingleStep(1); + else if (int(iDelta / 0.1) > 1) c_spacing_ctrl->setSingleStep(0.1); + else if (int(iDelta / 0.01) > 1) c_spacing_ctrl->setSingleStep(0.01); + else c_spacing_ctrl->setSingleStep(0.001); + +} + +void CGridDialog::OnOK() +{ + UpdateData(true); + accept(); +} + +void CGridDialog::OnCancel() +{ + reject(); +} + +void CGridDialog::UpdateData(bool value) +{ + if (value) + { + m_spacing = c_spacing_ctrl->value(); + } + else + { + c_spacing_ctrl->setValue(m_spacing); + } +} diff --git a/depthmapX/GridDialog.h b/depthmapX/dialogs/GridDialog.h similarity index 71% rename from depthmapX/GridDialog.h rename to depthmapX/dialogs/GridDialog.h index 45d4cb48..afdbf059 100644 --- a/depthmapX/GridDialog.h +++ b/depthmapX/dialogs/GridDialog.h @@ -1,4 +1,5 @@ // Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017 Christian Sailer // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -14,30 +15,22 @@ // along with this program. If not, see . #include "ui_GridDialog.h" -#include -#include -#include -#include - class CGridDialog : public QDialog, public Ui::CGridDialog { Q_OBJECT public: - CGridDialog(QWidget *parent = 0); - double m_spacing; - double m_maxdimension; - int m_minexponent; - int m_maxexponent; - int m_basemantissa; - int m_mantissa; - int m_exponent; + CGridDialog(double maxDimension, QWidget *parent = 0); void UpdateData(bool value); void showEvent(QShowEvent * event); + double getSpacing() const { return m_spacing; } + +private: + double m_spacing; + double m_maxdimension; private slots: void OnDeltaposSpinSpacing(double); void OnOK(); void OnCancel(); - void userValue(double value); }; diff --git a/depthmapX/InsertColumnDlg.cpp b/depthmapX/dialogs/InsertColumnDlg.cpp similarity index 90% rename from depthmapX/InsertColumnDlg.cpp rename to depthmapX/dialogs/InsertColumnDlg.cpp index f0c2ff54..2b4833ab 100644 --- a/depthmapX/InsertColumnDlg.cpp +++ b/depthmapX/dialogs/InsertColumnDlg.cpp @@ -24,7 +24,7 @@ CInsertColumnDlg::CInsertColumnDlg(AttributeTable *table, int col, QWidget *pare m_col = col; m_col_names.push_back("Ref Number"); - for (int i = 0; i < table->getColumnCount(); i++) { + for (int i = 0; i < table->getNumColumns(); i++) { m_col_names.push_back(table->getColumnName(i)); } if (m_col == -1) { @@ -32,13 +32,13 @@ CInsertColumnDlg::CInsertColumnDlg(AttributeTable *table, int col, QWidget *pare MainWindow *mainWin = qobject_cast(widget); if (mainWin) { - m_formula_text = pstring(mainWin->m_formula_cache.toLatin1()); + m_formula_text = mainWin->m_formula_cache.toStdString(); break; } } } else { - m_formula_text = table->getColumnFormula(m_col); + m_formula_text = table->getColumn(m_col).getFormula(); } c_use_column->setEnabled(true); } @@ -82,7 +82,7 @@ void CInsertColumnDlg::OnOK() } } - m_formula_text = pstring(text.toLatin1()); + m_formula_text = text.toStdString(); // note formula text for column will have to be updated by calling function accept(); diff --git a/depthmapX/InsertColumnDlg.h b/depthmapX/dialogs/InsertColumnDlg.h similarity index 83% rename from depthmapX/InsertColumnDlg.h rename to depthmapX/dialogs/InsertColumnDlg.h index fcfb9080..ae582b8c 100644 --- a/depthmapX/InsertColumnDlg.h +++ b/depthmapX/dialogs/InsertColumnDlg.h @@ -15,19 +15,20 @@ #include "ui_InsertColumnDlg.h" #include -#include #include #include +#include +#include class CInsertColumnDlg : public QDialog, public Ui::CInsertColumnDlg { Q_OBJECT public: - CInsertColumnDlg(AttributeTable *table = NULL, int col = -1, QWidget *parent = 0); + CInsertColumnDlg(AttributeTable *table = NULL, int col = -1, QWidget *parent = 0); bool m_selection_only; int m_col; - pvecstring m_col_names; - pstring m_formula_text; + std::vector m_col_names; + std::string m_formula_text; void UpdateData(bool value); void showEvent(QShowEvent * event); diff --git a/depthmapX/IsovistPathDlg.cpp b/depthmapX/dialogs/IsovistPathDlg.cpp similarity index 100% rename from depthmapX/IsovistPathDlg.cpp rename to depthmapX/dialogs/IsovistPathDlg.cpp diff --git a/depthmapX/IsovistPathDlg.h b/depthmapX/dialogs/IsovistPathDlg.h similarity index 100% rename from depthmapX/IsovistPathDlg.h rename to depthmapX/dialogs/IsovistPathDlg.h diff --git a/depthmapX/LayerChooserDlg.cpp b/depthmapX/dialogs/LayerChooserDlg.cpp similarity index 87% rename from depthmapX/LayerChooserDlg.cpp rename to depthmapX/dialogs/LayerChooserDlg.cpp index 77f9ac2b..a58a72e8 100644 --- a/depthmapX/LayerChooserDlg.cpp +++ b/depthmapX/dialogs/LayerChooserDlg.cpp @@ -15,14 +15,12 @@ #include "LayerChooserDlg.h" -CLayerChooserDlg::CLayerChooserDlg(pvecstring names, QWidget *parent) -: QDialog(parent) +CLayerChooserDlg::CLayerChooserDlg(const std::vector& names, QWidget *parent) +: QDialog(parent), m_names(names) { setupUi(this); m_text = tr(""); m_layer = 0; - - m_names = names; } void CLayerChooserDlg::OnOK() diff --git a/depthmapX/LayerChooserDlg.h b/depthmapX/dialogs/LayerChooserDlg.h similarity index 84% rename from depthmapX/LayerChooserDlg.h rename to depthmapX/dialogs/LayerChooserDlg.h index 03325be0..df7aceac 100644 --- a/depthmapX/LayerChooserDlg.h +++ b/depthmapX/dialogs/LayerChooserDlg.h @@ -15,7 +15,6 @@ #include "ui_LayerChooserDlg.h" #include -#include #include #include @@ -24,13 +23,13 @@ class CLayerChooserDlg : public QDialog, public Ui::CLayerChooserDlg { Q_OBJECT public: - CLayerChooserDlg(pvecstring names = pvecstring(), QWidget *parent = 0); + CLayerChooserDlg(const std::vector& names = std::vector(), QWidget *parent = 0); QString m_text; int m_layer; void UpdateData(bool value); void showEvent(QShowEvent * event); - pvecstring m_names; + const std::vector& m_names; private slots: void OnOK(); diff --git a/depthmapX/LicenceDialog.cpp b/depthmapX/dialogs/LicenceDialog.cpp similarity index 100% rename from depthmapX/LicenceDialog.cpp rename to depthmapX/dialogs/LicenceDialog.cpp diff --git a/depthmapX/LicenceDialog.h b/depthmapX/dialogs/LicenceDialog.h similarity index 100% rename from depthmapX/LicenceDialog.h rename to depthmapX/dialogs/LicenceDialog.h diff --git a/depthmapX/MakeLayerDlg.cpp b/depthmapX/dialogs/MakeLayerDlg.cpp similarity index 100% rename from depthmapX/MakeLayerDlg.cpp rename to depthmapX/dialogs/MakeLayerDlg.cpp diff --git a/depthmapX/MakeLayerDlg.h b/depthmapX/dialogs/MakeLayerDlg.h similarity index 93% rename from depthmapX/MakeLayerDlg.h rename to depthmapX/dialogs/MakeLayerDlg.h index e903ba59..a379a819 100644 --- a/depthmapX/MakeLayerDlg.h +++ b/depthmapX/dialogs/MakeLayerDlg.h @@ -15,7 +15,6 @@ #include "ui_MakeLayerDlg.h" #include -#include #include #include @@ -41,7 +40,7 @@ class CMakeLayerDlg : public QDialog, public Ui::CMakeLayerDlg int m_mapin; int m_mapout; - pvecint m_lookup; + std::vector m_lookup; bool m_keeporiginal; void UpdateData(bool value); void showEvent(QShowEvent * event); diff --git a/depthmapX/MakeOptionsDlg.cpp b/depthmapX/dialogs/MakeOptionsDlg.cpp similarity index 100% rename from depthmapX/MakeOptionsDlg.cpp rename to depthmapX/dialogs/MakeOptionsDlg.cpp diff --git a/depthmapX/MakeOptionsDlg.h b/depthmapX/dialogs/MakeOptionsDlg.h similarity index 100% rename from depthmapX/MakeOptionsDlg.h rename to depthmapX/dialogs/MakeOptionsDlg.h diff --git a/depthmapX/NewLayerDlg.cpp b/depthmapX/dialogs/NewLayerDlg.cpp similarity index 100% rename from depthmapX/NewLayerDlg.cpp rename to depthmapX/dialogs/NewLayerDlg.cpp diff --git a/depthmapX/NewLayerDlg.h b/depthmapX/dialogs/NewLayerDlg.h similarity index 100% rename from depthmapX/NewLayerDlg.h rename to depthmapX/dialogs/NewLayerDlg.h diff --git a/depthmapX/OptionsDlg.cpp b/depthmapX/dialogs/OptionsDlg.cpp similarity index 100% rename from depthmapX/OptionsDlg.cpp rename to depthmapX/dialogs/OptionsDlg.cpp diff --git a/depthmapX/OptionsDlg.h b/depthmapX/dialogs/OptionsDlg.h similarity index 92% rename from depthmapX/OptionsDlg.h rename to depthmapX/dialogs/OptionsDlg.h index d01cb608..5e794902 100644 --- a/depthmapX/OptionsDlg.h +++ b/depthmapX/dialogs/OptionsDlg.h @@ -15,7 +15,6 @@ #include "ui_OptionsDlg.h" #include -#include #include #include @@ -33,7 +32,7 @@ class COptionsDlg : public QDialog, public Ui::COptionsDlg void UpdateData(bool value); void showEvent(QShowEvent * event); - pvecstring m_layer_names; + std::vector m_layer_names; private slots: void OnOutputType(bool); diff --git a/depthmapX/PromptReplace.cpp b/depthmapX/dialogs/PromptReplace.cpp similarity index 100% rename from depthmapX/PromptReplace.cpp rename to depthmapX/dialogs/PromptReplace.cpp diff --git a/depthmapX/PromptReplace.h b/depthmapX/dialogs/PromptReplace.h similarity index 100% rename from depthmapX/PromptReplace.h rename to depthmapX/dialogs/PromptReplace.h diff --git a/depthmapX/PushDialog.cpp b/depthmapX/dialogs/PushDialog.cpp similarity index 88% rename from depthmapX/PushDialog.cpp rename to depthmapX/dialogs/PushDialog.cpp index d351d151..95a5ec4d 100644 --- a/depthmapX/PushDialog.cpp +++ b/depthmapX/dialogs/PushDialog.cpp @@ -15,7 +15,7 @@ #include "PushDialog.h" -CPushDialog::CPushDialog(pqmap& names, QWidget *parent) +CPushDialog::CPushDialog(std::map, std::string> &names, QWidget *parent) : QDialog(parent) { setupUi(this); @@ -27,8 +27,8 @@ CPushDialog::CPushDialog(pqmap& names, QWidget *parent) m_function = 0; - for (size_t i = 0; i < names.size(); i++) { - m_names.push_back(names.value(i)); + for (auto name: names) { + m_names.push_back(name.second); } } diff --git a/depthmapX/PushDialog.h b/depthmapX/dialogs/PushDialog.h similarity index 87% rename from depthmapX/PushDialog.h rename to depthmapX/dialogs/PushDialog.h index 8a4960be..81b2fe36 100644 --- a/depthmapX/PushDialog.h +++ b/depthmapX/dialogs/PushDialog.h @@ -15,7 +15,6 @@ #include "ui_PushDialog.h" #include -#include #include #include @@ -23,7 +22,7 @@ class CPushDialog : public QDialog, public Ui::CPushDialog { Q_OBJECT public: - CPushDialog(pqmap& names, QWidget *parent = 0); + CPushDialog(std::map, std::string>& names, QWidget *parent = 0); int m_layer_selection; QString m_origin_attribute; QString m_origin_layer; @@ -32,7 +31,7 @@ class CPushDialog : public QDialog, public Ui::CPushDialog void UpdateData(bool value); void showEvent(QShowEvent * event); - pvecstring m_names; + std::vector m_names; private slots: void OnOK(); diff --git a/depthmapX/RenameObjectDlg.cpp b/depthmapX/dialogs/RenameObjectDlg.cpp similarity index 100% rename from depthmapX/RenameObjectDlg.cpp rename to depthmapX/dialogs/RenameObjectDlg.cpp diff --git a/depthmapX/RenameObjectDlg.h b/depthmapX/dialogs/RenameObjectDlg.h similarity index 100% rename from depthmapX/RenameObjectDlg.h rename to depthmapX/dialogs/RenameObjectDlg.h diff --git a/depthmapX/SegmentAnalysisDlg.cpp b/depthmapX/dialogs/SegmentAnalysisDlg.cpp similarity index 92% rename from depthmapX/SegmentAnalysisDlg.cpp rename to depthmapX/dialogs/SegmentAnalysisDlg.cpp index d93dbc00..f6188383 100644 --- a/depthmapX/SegmentAnalysisDlg.cpp +++ b/depthmapX/dialogs/SegmentAnalysisDlg.cpp @@ -142,7 +142,7 @@ void CSegmentAnalysisDlg::OnOK() MainWindow *mainWin = qobject_cast(widget); if (mainWin) { - mainWin->m_options.radius_list.clear(); + mainWin->m_options.radius_set.clear(); QString curr_radius; int curr_comma = -1, last_comma = 0; bool add_rn = false; @@ -179,13 +179,13 @@ void CSegmentAnalysisDlg::OnOK() return; } } - mainWin->m_options.radius_list.add((double) radius); + mainWin->m_options.radius_set.insert(double(radius)); } } } while (curr_comma != -1); - if (mainWin->m_options.radius_list.size() == 0 || add_rn) { - mainWin->m_options.radius_list.push_back(-1); + if (mainWin->m_options.radius_set.size() == 0 || add_rn) { + mainWin->m_options.radius_set.insert(-1); } if (m_tulip_bins % 2 != 0) { @@ -304,8 +304,8 @@ void CSegmentAnalysisDlg::UpdateData(bool value) void CSegmentAnalysisDlg::showEvent(QShowEvent * event) { const ShapeGraph& map = m_meta_graph->getDisplayedShapeGraph(); - const AttributeTable& table = map.getAttributeTable(); - for (int i = 0; i < table.getColumnCount(); i++) { + const AttributeTable& table = map.getAttributeTable(); + for (int i = 0; i < table.getNumColumns(); i++) { c_attribute->addItem(QString(table.getColumnName(i).c_str())); } diff --git a/depthmapX/SegmentAnalysisDlg.h b/depthmapX/dialogs/SegmentAnalysisDlg.h similarity index 94% rename from depthmapX/SegmentAnalysisDlg.h rename to depthmapX/dialogs/SegmentAnalysisDlg.h index 282e09c2..8539a7a4 100644 --- a/depthmapX/SegmentAnalysisDlg.h +++ b/depthmapX/dialogs/SegmentAnalysisDlg.h @@ -16,7 +16,6 @@ #include "ui_SegmentAnalysisDlg.h" #include -#include #include #include diff --git a/depthmapX/TopoMetDlg.cpp b/depthmapX/dialogs/TopoMetDlg.cpp similarity index 88% rename from depthmapX/TopoMetDlg.cpp rename to depthmapX/dialogs/TopoMetDlg.cpp index 624c0700..790f0c51 100644 --- a/depthmapX/TopoMetDlg.cpp +++ b/depthmapX/dialogs/TopoMetDlg.cpp @@ -20,7 +20,7 @@ CTopoMetDlg::CTopoMetDlg(QWidget *parent) : QDialog(parent) { setupUi(this); - m_topological = 0; + m_topological = TOPOMET_METHOD_TOPOLOGICAL; m_selected_only = false; m_radius = tr("n"); @@ -64,9 +64,9 @@ void CTopoMetDlg::UpdateData(bool value) if (value) { if (c_topological->isChecked()) - m_topological = 0; + m_topological = TOPOMET_METHOD_TOPOLOGICAL; else if (radioButton->isChecked()) - m_topological = 1; + m_topological = TOPOMET_METHOD_METRIC; else m_topological = -1; m_radius = c_radius->text(); @@ -79,10 +79,10 @@ void CTopoMetDlg::UpdateData(bool value) { switch(m_topological) { - case 0: + case TOPOMET_METHOD_TOPOLOGICAL: c_topological->setChecked(true); break; - case 1: + case TOPOMET_METHOD_METRIC: radioButton->setChecked(true); break; default: diff --git a/depthmapX/TopoMetDlg.h b/depthmapX/dialogs/TopoMetDlg.h similarity index 81% rename from depthmapX/TopoMetDlg.h rename to depthmapX/dialogs/TopoMetDlg.h index e170ff0f..a6de1cde 100644 --- a/depthmapX/TopoMetDlg.h +++ b/depthmapX/dialogs/TopoMetDlg.h @@ -17,7 +17,9 @@ class CTopoMetDlg : public QDialog, public Ui::CTopoMetDlg { - Q_OBJECT + Q_OBJECT +private: + enum {TOPOMET_METHOD_TOPOLOGICAL = 0, TOPOMET_METHOD_METRIC = 1}; public: CTopoMetDlg(QWidget *parent = 0); int m_topological; @@ -27,6 +29,10 @@ class CTopoMetDlg : public QDialog, public Ui::CTopoMetDlg void UpdateData(bool value); void showEvent(QShowEvent * event); + bool isAnalysisTopological() { + return m_topological == TOPOMET_METHOD_TOPOLOGICAL; + } + private slots: void OnOK(); }; diff --git a/depthmapX/licenseagreement.cpp b/depthmapX/dialogs/licenseagreement.cpp similarity index 100% rename from depthmapX/licenseagreement.cpp rename to depthmapX/dialogs/licenseagreement.cpp diff --git a/depthmapX/licenseagreement.h b/depthmapX/dialogs/licenseagreement.h similarity index 100% rename from depthmapX/licenseagreement.h rename to depthmapX/dialogs/licenseagreement.h diff --git a/depthmapX/dialogs/settings/generalpage.cpp b/depthmapX/dialogs/settings/generalpage.cpp new file mode 100644 index 00000000..f04abb21 --- /dev/null +++ b/depthmapX/dialogs/settings/generalpage.cpp @@ -0,0 +1,38 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "generalpage.h" +#include +#include "depthmapX/settings.h" + +GeneralPage::GeneralPage(Settings &settings, QWidget *parent) + : SettingsPage(settings, parent) +{ + readSettings(settings); + QGroupBox *configGroup = new QGroupBox(tr("General configuration")); + QCheckBox *simpleModeCheckBox = new QCheckBox(tr("Simple mode")); + simpleModeCheckBox->setToolTip(tr("If enabled, only Integration [HH] will be calulcated (or Visual Integration [HH] for VGA)")); + simpleModeCheckBox->setChecked(m_simpleVersion); + connect(simpleModeCheckBox, &QCheckBox::stateChanged, [=] () {m_simpleVersion = !m_simpleVersion;}); + + QVBoxLayout *configLayout = new QVBoxLayout; + configLayout->addWidget(simpleModeCheckBox); + configGroup->setLayout(configLayout); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(configGroup); + mainLayout->addStretch(1); + setLayout(mainLayout); +} diff --git a/depthmapX/dialogs/settings/generalpage.h b/depthmapX/dialogs/settings/generalpage.h new file mode 100644 index 00000000..47cebf6d --- /dev/null +++ b/depthmapX/dialogs/settings/generalpage.h @@ -0,0 +1,34 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include +#include "settingspage.h" +#include + +class GeneralPage : public SettingsPage +{ +private: + bool m_simpleVersion = false; + void readSettings(Settings &settings) { + m_simpleVersion = settings.readSetting(SettingTag::simpleVersion, true).toBool(); + } +public: + GeneralPage(Settings &settings, QWidget *parent = 0); + virtual void writeSettings(Settings &settings) override { + settings.writeSetting(SettingTag::simpleVersion, m_simpleVersion); + } +}; diff --git a/depthmapX/dialogs/settings/images/general.png b/depthmapX/dialogs/settings/images/general.png new file mode 100644 index 00000000..54638e93 Binary files /dev/null and b/depthmapX/dialogs/settings/images/general.png differ diff --git a/depthmapX/dialogs/settings/images/interface.png b/depthmapX/dialogs/settings/images/interface.png new file mode 100644 index 00000000..daba865f Binary files /dev/null and b/depthmapX/dialogs/settings/images/interface.png differ diff --git a/depthmapX/dialogs/settings/interfacepage.cpp b/depthmapX/dialogs/settings/interfacepage.cpp new file mode 100644 index 00000000..9428ae58 --- /dev/null +++ b/depthmapX/dialogs/settings/interfacepage.cpp @@ -0,0 +1,106 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "interfacepage.h" +#include +#include + +InterfacePage::InterfacePage(Settings &settings, QWidget *parent) + : SettingsPage(settings, parent) +{ + readSettings(settings); + + QGroupBox *generalGroup = new QGroupBox(tr("General")); + QCheckBox *legacyMapCheckBox = new QCheckBox(tr("Legacy map window as default")); + legacyMapCheckBox->setChecked(m_defaultMapWindowIsLegacy); + connect(legacyMapCheckBox, &QCheckBox::stateChanged, [=] () {m_defaultMapWindowIsLegacy = !m_defaultMapWindowIsLegacy;}); + + QVBoxLayout *generalLayout = new QVBoxLayout; + generalLayout->addWidget(legacyMapCheckBox); + generalGroup->setLayout(generalLayout); + + QGroupBox *interfaceColoursGroup = new QGroupBox(tr("Interface colours")); + QListWidget *interfaceColoursList = new QListWidget; + connect(interfaceColoursList, SIGNAL(itemDoubleClicked(QListWidgetItem*)), + this, SLOT(onInterfaceColourlItemClicked(QListWidgetItem*))); + + QListWidgetItem *bgItem = new QListWidgetItem(interfaceColoursList); + bgItem->setText(tr("Background")); + QPixmap pixmap(20,20); + pixmap.fill(m_background); + QIcon bgColourIcon(pixmap); + bgItem->setIcon(bgColourIcon); + colourMap.insert(std::pair(bgItem, &m_background)); + + QListWidgetItem *fgItem = new QListWidgetItem(interfaceColoursList); + fgItem->setText(tr("Foreground")); + pixmap.fill(m_foreground); + QIcon fgColourIcon(pixmap); + fgItem->setIcon(fgColourIcon); + colourMap.insert(std::pair(fgItem, &m_foreground)); + + QVBoxLayout *interfaceColoursLayout = new QVBoxLayout; + interfaceColoursLayout->addWidget(interfaceColoursList); + interfaceColoursGroup->setLayout(interfaceColoursLayout); + QGroupBox *glOptionsGroup = new QGroupBox(tr("OpenGL view options")); + + QLabel *samplesLabel = new QLabel(tr("Number of antialising samples:")); + QComboBox *samplesCombo = new QComboBox; + samplesCombo->addItem(tr("0 (fastest)"), 0); + samplesCombo->addItem(tr("2"), 2); + samplesCombo->addItem(tr("4"), 4); + samplesCombo->addItem(tr("8"), 8); + samplesCombo->addItem(tr("16 (prettiest)"), 16); + samplesCombo->setToolTip(tr("This will make lines smoother if higher, " + "but also the overall rendering slower. " + "To see the change close and reopen the file")); + + int index = samplesCombo->findData(m_antialiasingSamples); + if ( index != -1 ) { + samplesCombo->setCurrentIndex(index); + } + + connect(samplesCombo, static_cast(&QComboBox::activated), + [=](int index){ m_antialiasingSamples = samplesCombo->itemData(index).toInt();}); + + QHBoxLayout *samplesLayout = new QHBoxLayout; + samplesLayout->addWidget(samplesLabel); + samplesLayout->addWidget(samplesCombo); + + QVBoxLayout *configLayout = new QVBoxLayout; + configLayout->addLayout(samplesLayout); + glOptionsGroup->setLayout(configLayout); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(generalGroup); + mainLayout->addSpacing(1); + mainLayout->addWidget(interfaceColoursGroup); + mainLayout->addSpacing(1); + mainLayout->addWidget(glOptionsGroup); + mainLayout->addStretch(1); + setLayout(mainLayout); +} + +void InterfacePage::onInterfaceColourlItemClicked(QListWidgetItem* item) +{ + QColor colour = QColorDialog::getColor(); + colourMap[item]->setRed(colour.red()); + colourMap[item]->setGreen(colour.green()); + colourMap[item]->setBlue(colour.blue()); + QPixmap pixmap(100,100); + pixmap.fill(colour); + QIcon bgColourIcon(pixmap); + item->setIcon(bgColourIcon); +} diff --git a/depthmapX/dialogs/settings/interfacepage.h b/depthmapX/dialogs/settings/interfacepage.h new file mode 100644 index 00000000..e644a6d3 --- /dev/null +++ b/depthmapX/dialogs/settings/interfacepage.h @@ -0,0 +1,50 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include +#include +#include "settingspage.h" +#include +#include + +class InterfacePage : public SettingsPage +{ + Q_OBJECT + +private: + QColor m_background; + QColor m_foreground; + std::map colourMap; + int m_antialiasingSamples = 0; + bool m_defaultMapWindowIsLegacy = false; + void readSettings(Settings &settings) { + m_foreground = QColor(settings.readSetting(SettingTag::foregroundColour, qRgb(128,255,128)).toInt()); + m_background = QColor(settings.readSetting(SettingTag::backgroundColour, qRgb(0,0,0)).toInt()); + m_antialiasingSamples = settings.readSetting(SettingTag::antialiasingSamples, 0).toInt(); + m_defaultMapWindowIsLegacy = settings.readSetting(SettingTag::legacyMapWindow, false).toBool(); + } +private slots: + void onInterfaceColourlItemClicked(QListWidgetItem *item); +public: + InterfacePage(Settings &settings, QWidget *parent = 0); + virtual void writeSettings(Settings &settings) override { + settings.writeSetting(SettingTag::backgroundColour, m_background.rgb()); + settings.writeSetting(SettingTag::foregroundColour, m_foreground.rgb()); + settings.writeSetting(SettingTag::antialiasingSamples, m_antialiasingSamples); + settings.writeSetting(SettingTag::legacyMapWindow, m_defaultMapWindowIsLegacy); + } +}; diff --git a/depthmapX/dialogs/settings/settingsdialog.cpp b/depthmapX/dialogs/settings/settingsdialog.cpp new file mode 100644 index 00000000..8da4c4df --- /dev/null +++ b/depthmapX/dialogs/settings/settingsdialog.cpp @@ -0,0 +1,105 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include + +#include "settingsdialog.h" +#include "generalpage.h" +#include "interfacepage.h" + +SettingsDialog::SettingsDialog(Settings &settings) : m_settings(settings) +{ + contentsWidget = new QListWidget; + contentsWidget->setIconSize(QSize(96, 84)); + contentsWidget->setMovement(QListView::Static); + contentsWidget->setMaximumWidth(150); + contentsWidget->setSpacing(5); + + pagesWidget = new QStackedWidget; + settingsPages.push_back(std::unique_ptr(new GeneralPage(m_settings))); + settingsPages.push_back(std::unique_ptr(new InterfacePage(m_settings))); + + std::vector>::iterator iter = settingsPages.begin(), + end = settingsPages.end(); + for ( ; iter != end; ++iter ) + { + pagesWidget->addWidget((*iter).get()); + } + + QPushButton *saveButton = new QPushButton(tr("Save")); + connect(saveButton, &QAbstractButton::clicked, this, &SettingsDialog::saveChangesAndClose); + + QPushButton *cancelButton = new QPushButton(tr("Cancel")); + connect(cancelButton, &QAbstractButton::clicked, this, &QDialog::reject); + + createIcons(); + contentsWidget->setCurrentRow(0); + + + QHBoxLayout *horizontalLayout = new QHBoxLayout; + horizontalLayout->addWidget(contentsWidget); + horizontalLayout->addWidget(pagesWidget, 1); + + QHBoxLayout *buttonsLayout = new QHBoxLayout; + buttonsLayout->addStretch(1); + buttonsLayout->addWidget(saveButton); + buttonsLayout->addWidget(cancelButton); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addLayout(horizontalLayout); + mainLayout->addStretch(1); + mainLayout->addSpacing(12); + mainLayout->addLayout(buttonsLayout); + setLayout(mainLayout); + + setWindowTitle(tr("Settings")); +} + +void SettingsDialog::saveChanges() { + std::vector>::iterator iter = settingsPages.begin(), + end = settingsPages.end(); + for ( ; iter != end; ++iter ) + { + (*iter)->writeSettings(m_settings); + } +} + +void SettingsDialog::saveChangesAndClose() { + saveChanges(); + QDialog::accept(); +} + +void SettingsDialog::createIcons() +{ + QListWidgetItem *generalButton = new QListWidgetItem(contentsWidget); + generalButton->setIcon(QIcon(":/images/general.png")); + generalButton->setText(tr("General")); + generalButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + QListWidgetItem *interfaceButton = new QListWidgetItem(contentsWidget); + interfaceButton->setIcon(QIcon(":/images/interface.png")); + interfaceButton->setText(tr("Interface")); + interfaceButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + connect(contentsWidget, &QListWidget::currentItemChanged, this, &SettingsDialog::changePage); +} + +void SettingsDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous) +{ + if (!current) + current = previous; + + pagesWidget->setCurrentIndex(contentsWidget->row(current)); +} diff --git a/depthmapX/dialogs/settings/settingsdialog.h b/depthmapX/dialogs/settings/settingsdialog.h new file mode 100644 index 00000000..ab9456d2 --- /dev/null +++ b/depthmapX/dialogs/settings/settingsdialog.h @@ -0,0 +1,47 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "settingspage.h" + +#include +#include "depthmapX/settings.h" +#include +#include + +class QListWidget; +class QListWidgetItem; +class QStackedWidget; + +class SettingsDialog : public QDialog +{ + Q_OBJECT + +public: + SettingsDialog(Settings &settings); + +public slots: + void changePage(QListWidgetItem *current, QListWidgetItem *previous); + +private: + void createIcons(); + std::vector> settingsPages; + QListWidget *contentsWidget; + QStackedWidget *pagesWidget; + Settings &m_settings; + void saveChanges(); + void saveChangesAndClose(); +}; diff --git a/depthmapX/dialogs/settings/settingsdialog.qrc b/depthmapX/dialogs/settings/settingsdialog.qrc new file mode 100644 index 00000000..635fd561 --- /dev/null +++ b/depthmapX/dialogs/settings/settingsdialog.qrc @@ -0,0 +1,6 @@ + + + images/general.png + images/interface.png + + diff --git a/depthmapX/dialogs/settings/settingspage.h b/depthmapX/dialogs/settings/settingspage.h new file mode 100644 index 00000000..bf0221bc --- /dev/null +++ b/depthmapX/dialogs/settings/settingspage.h @@ -0,0 +1,27 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "depthmapX/settings.h" + +#include + +class SettingsPage : public QWidget +{ +public: + SettingsPage(Settings &settings, QWidget *parent = 0) : QWidget(parent) {} + virtual void writeSettings(Settings &settings) = 0; +}; diff --git a/depthmapX/icons.rc b/depthmapX/icons.rc new file mode 100644 index 00000000..6e2534c5 --- /dev/null +++ b/depthmapX/icons.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "icons\\depthmapX.ico" diff --git a/depthmapX/icons/depthmapX.icns b/depthmapX/icons/depthmapX.icns new file mode 100644 index 00000000..1c52d99c Binary files /dev/null and b/depthmapX/icons/depthmapX.icns differ diff --git a/depthmapX/icons/depthmapX.ico b/depthmapX/icons/depthmapX.ico new file mode 100644 index 00000000..c9344617 Binary files /dev/null and b/depthmapX/icons/depthmapX.ico differ diff --git a/depthmapX/icons/graph.icns b/depthmapX/icons/graph.icns new file mode 100644 index 00000000..23cd41f2 Binary files /dev/null and b/depthmapX/icons/graph.icns differ diff --git a/depthmapX/images/win/b-1-11.png b/depthmapX/images/win/b-1-11.png index 81a62855..78e6b9a7 100644 Binary files a/depthmapX/images/win/b-1-11.png and b/depthmapX/images/win/b-1-11.png differ diff --git a/depthmapX/images/win/b-1-19.png b/depthmapX/images/win/b-1-19.png index a578dea5..76f48a13 100644 Binary files a/depthmapX/images/win/b-1-19.png and b/depthmapX/images/win/b-1-19.png differ diff --git a/depthmapX/indexWidget.cpp b/depthmapX/indexWidget.cpp index 1de27e34..ad55834a 100644 --- a/depthmapX/indexWidget.cpp +++ b/depthmapX/indexWidget.cpp @@ -32,7 +32,7 @@ QT_BEGIN_NAMESPACE AttribWindow::AttribWindow(QWidget *parent, bool custom) : QListWidget(parent) { - custom = NULL; + custom = false; main_frm = parent; installEventFilter(this); diff --git a/depthmapX/DepthmapOptionsDlg.h b/depthmapX/main.cpp similarity index 64% rename from depthmapX/DepthmapOptionsDlg.h rename to depthmapX/main.cpp index 5d4f10b4..3b4d7cd4 100644 --- a/depthmapX/DepthmapOptionsDlg.h +++ b/depthmapX/main.cpp @@ -1,32 +1,36 @@ -// Copyright (C) 2011-2012, Tasos Varoudis -// Copyright (C) 2017 Christian Sailer - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#include "ui_DepthmapOptionsDlg.h" - -class CDepthmapOptionsDlg : public QDialog, public Ui::CDepthmapOptionsDlg -{ - Q_OBJECT -public: - CDepthmapOptionsDlg(QWidget *parent, bool simpleVersion); - bool m_show_research_toolbar; - bool m_show_simple_version; - void UpdateData(bool value); - void showEvent(QShowEvent * event); - -private slots: - void OnOK(); - void OnCancel(); -}; +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include +#include + +#include "coreapplication.h" + +#ifdef _WIN32 +#include +#endif + + +int main(int argc, char *argv[]) +{ + Q_INIT_RESOURCE(resource); + Q_INIT_RESOURCE(settingsdialog); + + CoreApplication app(argc, argv); + + return app.exec(); +} diff --git a/depthmapX/mainwindow.cpp b/depthmapX/mainwindow.cpp index 9e62a15b..f58ed73d 100644 --- a/depthmapX/mainwindow.cpp +++ b/depthmapX/mainwindow.cpp @@ -14,6 +14,16 @@ // along with this program. If not, see . + +#include "mainwindow.h" + +#include "depthmapX/views/depthmapview/depthmapview.h" +#include "depthmapX/views/3dview/3dview.h" +#include "depthmapX/views/plotview/plotview.h" +#include "depthmapX/views/tableview/tableview.h" +#include "dialogs/AboutDlg.h" +#include "dialogs/settings/settingsdialog.h" + #include #include #include @@ -26,38 +36,13 @@ #include #include #include - -#include "mainwindow.h" -#include "depthmapView.h" -#include "3DView.h" -#include "PlotView.h" -#include "tableView.h" -#include "DepthmapOptionsDlg.h" -#include "AboutDlg.h" +#include static int current_view_type = 0; -enum {VIEW_ALL = 0, VIEW_MAP = 1, VIEW_SCATTER = 2, VIEW_TABLE = 3, VIEW_3D = 4, VIEW_TYPES = 5}; const QString editstatetext[] = {"Not Editable", "Editable Off", "Editable On"}; -namespace SettingTag -{ - const QString position = "pos"; - const QString size = "size"; - const QString foregroundColour = "forColor"; - const QString backgroundColour = "backColor"; - const QString simpleVersion = "simple"; - const QString recentFileList = "recentFileList"; - const QString mwMaximised = "mainWindowMaximised"; - - template void saveSettings( const QString& settingsFilename, const QString& settingName, const ValueType& value ) - { - QSettings settings(settingsFilename, QSettings::Format::IniFormat ); - settings.setValue(settingName, value); - } -} - QmyEvent::QmyEvent(Type type, void* wp, int lp) : QEvent(type) { @@ -69,10 +54,8 @@ QmyEvent::QmyEvent(Type type, void* wp, int lp) void MainWindow::actionEvent ( QActionEvent * event ) { int id; - if(id = event->action()->data().toInt()) + if((id = event->action()->data().toInt())) { - int k = id; - } } @@ -86,7 +69,7 @@ bool MainWindow::eventFilter(QObject *object, QEvent *e) return QObject::eventFilter(object, e); } -MainWindow::MainWindow() +MainWindow::MainWindow(const QString &fileToLoad, Settings &settings) : mSettings(settings) { m_treeDoc = NULL; mdiArea = new QMdiArea; @@ -97,7 +80,7 @@ MainWindow::MainWindow() connect(windowMapper, SIGNAL(mapped(QWidget *)), this, SLOT(setActiveSubWindow(QWidget *))); - m_indexWidget = new indexWidget(this, false); + m_indexWidget = new IndexWidget(this); QDockWidget *indexDock = new QDockWidget(tr("Index"), this); indexDock->setObjectName(QLatin1String("IndexWindow")); indexDock->setWidget(m_indexWidget); @@ -108,8 +91,6 @@ MainWindow::MainWindow() AttributesListDock->setWidget(setupAttributesListWidget()); addDockWidget(Qt::LeftDockWidgetArea, AttributesListDock); - m_settingsFile = QStandardPaths::standardLocations(QStandardPaths::AppConfigLocation).first() + "/depthmapXsettings.ini"; - readSettings(); // read setting or generate default setWindowTitle(TITLE_BASE); @@ -119,9 +100,15 @@ MainWindow::MainWindow() createStatusBar(); updateToolbar(); updateActiveWindows(); + updateGLWindows(true, true); installEventFilter(this); // setWindowIcon(QIcon(tr(":/images/cur/icon-1-1.png"))); + + if (fileToLoad.length()>0) + { + loadFile(fileToLoad); + } } QWidget * MainWindow::setupAttributesListWidget() @@ -159,7 +146,7 @@ QWidget * MainWindow::setupAttributesListWidget() void MainWindow::closeEvent(QCloseEvent *event) { mdiArea->closeAllSubWindows(); - if (activeQDepthmapView()) { + if (activeMapView()) { event->ignore(); } else { QApplication::postEvent((QObject*)&m_wndColourScale, new QEvent(QEvent::Close)); @@ -170,10 +157,35 @@ void MainWindow::closeEvent(QCloseEvent *event) void MainWindow::OnFileNew() { - QDepthmapView *child = createQDepthmapView(); - child->newFile(); + MapView *child = createMapView(); + child->getGraphDoc()->OnNewDocument(); + child->setCurrentFile(""); + child->postLoadFile(); child->show(); - OnFocusGraph(child->pDoc, QGraphDoc::CONTROLS_LOADALL); + OnFocusGraph(child->getGraphDoc(), QGraphDoc::CONTROLS_LOADALL); +} + +void MainWindow::loadFile(QString fileName) { + QMdiSubWindow *existing = findMapView(fileName); + if (existing) { + mdiArea->setActiveSubWindow(existing); + return; + } + MapView *child = createMapView(); + QByteArray ba = fileName.toUtf8(); // quick fix for weird chars (russian filename bug report) + char *file = ba.data(); // quick fix for weird chars (russian filename bug report) + if(child->getGraphDoc()->OnOpenDocument(file)) // quick fix for weird chars (russian filename bug report) + { + child->setCurrentFile(fileName); + child->postLoadFile(); + statusBar()->showMessage(tr("File loaded"), 2000); + child->show(); + OnFocusGraph(child->getGraphDoc(), QGraphDoc::CONTROLS_LOADALL); + setCurrentFile(fileName); + } else { + child->close(); + QMessageBox::warning(this, "Failed to load", QString("Failed to load file ")+fileName, QMessageBox::Ok, QMessageBox::Ok ); + } } void MainWindow::OnFileOpen() @@ -190,21 +202,7 @@ void MainWindow::OnFileOpen() &selectedFilter, options); if (!fileName.isEmpty()) { - QMdiSubWindow *existing = findQDepthmapView(fileName); - if (existing) { - mdiArea->setActiveSubWindow(existing); - return; - } - QDepthmapView *child = createQDepthmapView(); - if (child->loadFile(fileName)) - { - statusBar()->showMessage(tr("File loaded"), 2000); - child->show(); - OnFocusGraph(child->pDoc, QGraphDoc::CONTROLS_LOADALL); - setCurrentFile(fileName); - } else { - child->close(); - } + loadFile(fileName); } } @@ -235,14 +233,9 @@ void MainWindow::OnFilePrintSetup() } -void MainWindow::OnFileExit() -{ - -} - void MainWindow::OnEditUndo() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnEditUndo(); @@ -255,13 +248,13 @@ void MainWindow::OnEditCopyData() void MainWindow::OnEditCopy() { - QDepthmapView* m_p = activeQDepthmapView(); + MapView* m_p = activeMapView(); if(m_p) m_p->OnEditCopy(); } void MainWindow::OnEditSave() { - QDepthmapView* m_p = activeQDepthmapView(); + MapView* m_p = activeMapView(); if(m_p) { m_p->OnEditSave(); @@ -270,7 +263,7 @@ void MainWindow::OnEditSave() void MainWindow::OnEditClear() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnEditClear(); @@ -279,7 +272,7 @@ void MainWindow::OnEditClear() void MainWindow::OnEditQuery() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnEditQuery(); @@ -288,13 +281,13 @@ void MainWindow::OnEditQuery() void MainWindow::OnViewZoomsel() { - QDepthmapView* m_p = activeQDepthmapView(); + MapView* m_p = activeMapView(); if(m_p) m_p->OnViewZoomsel(); } void MainWindow::OnEditSelectToLayer() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnEditSelectToLayer(); @@ -303,7 +296,7 @@ void MainWindow::OnEditSelectToLayer() void MainWindow::OnFileImport() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnFileImport(); @@ -312,7 +305,7 @@ void MainWindow::OnFileImport() void MainWindow::OnLayerNew() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnLayerNew(); @@ -321,7 +314,7 @@ void MainWindow::OnLayerNew() void MainWindow::OnLayerDelete() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnLayerDelete(); @@ -330,7 +323,7 @@ void MainWindow::OnLayerDelete() void MainWindow::OnLayerConvert() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnLayerConvert(); @@ -339,7 +332,7 @@ void MainWindow::OnLayerConvert() void MainWindow::OnLayerConvertDrawing() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnLayerConvertDrawing(); @@ -348,7 +341,7 @@ void MainWindow::OnLayerConvertDrawing() void MainWindow::OnConvertMapShapes() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnConvertMapShapes(); @@ -357,16 +350,71 @@ void MainWindow::OnConvertMapShapes() void MainWindow::OnFileExport() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnFileExport(); } } + +void MainWindow::OnFileExportMapGeometry() +{ + QGraphDoc* m_p = activeMapDoc(); + if(m_p) + { + m_p->OnFileExportMapGeometry(); + } +} + +void MainWindow::OnFileExportLinks() +{ + QGraphDoc* m_p = activeMapDoc(); + if(m_p) + { + m_p->OnFileExportLinks(); + } +} + +void MainWindow::OnAxialConnectionsExportAsDot() +{ + QGraphDoc* m_p = activeMapDoc(); + if(m_p) + { + m_p->OnAxialConnectionsExportAsDot(); + } +} + +void MainWindow::OnAxialConnectionsExportAsPairCSV() +{ + QGraphDoc* m_p = activeMapDoc(); + if(m_p) + { + m_p->OnAxialConnectionsExportAsPairCSV(); + } +} + +void MainWindow::OnSegmentConnectionsExportAsPairCSV() +{ + QGraphDoc* m_p = activeMapDoc(); + if(m_p) + { + m_p->OnSegmentConnectionsExportAsPairCSV(); + } +} + +void MainWindow::OnPointmapExportConnectionsAsCSV() +{ + QGraphDoc* m_p = activeMapDoc(); + if(m_p) + { + m_p->OnPointmapExportConnectionsAsCSV(); + } +} + void MainWindow::OnAddColumn() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnAddColumn(); @@ -375,7 +423,7 @@ void MainWindow::OnAddColumn() void MainWindow::OnRenameColumn() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnRenameColumn(); @@ -384,7 +432,7 @@ void MainWindow::OnRenameColumn() void MainWindow::OnUpdateColumn() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnUpdateColumn(); @@ -393,7 +441,7 @@ void MainWindow::OnUpdateColumn() void MainWindow::OnRemoveColumn() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnRemoveColumn(); @@ -402,7 +450,7 @@ void MainWindow::OnRemoveColumn() void MainWindow::OnColumnProperties() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnColumnProperties(); @@ -411,7 +459,7 @@ void MainWindow::OnColumnProperties() void MainWindow::OnPushToLayer() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnPushToLayer(); @@ -420,7 +468,7 @@ void MainWindow::OnPushToLayer() void MainWindow::OnEditGrid() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnEditGrid(); @@ -429,16 +477,34 @@ void MainWindow::OnEditGrid() void MainWindow::OnToolsMakeGraph() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnToolsMakeGraph(); } } +void MainWindow::OnToolsUnmakeGraph() +{ + QGraphDoc* m_p = activeMapDoc(); + if(m_p) + { + m_p->OnToolsUnmakeGraph(); + } +} + +void MainWindow::OnToolsImportVGALinks() +{ + QGraphDoc* m_p = activeMapDoc(); + if(m_p) + { + m_p->OnVGALinksFileImport(); + } +} + void MainWindow::OnToolsRun() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnToolsRun(); @@ -447,7 +513,7 @@ void MainWindow::OnToolsRun() void MainWindow::OnToolsAgentRun() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnToolsAgentRun(); @@ -456,7 +522,7 @@ void MainWindow::OnToolsAgentRun() void MainWindow::OnToolsIsovistpath() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnToolsIsovistpath(); @@ -465,7 +531,7 @@ void MainWindow::OnToolsIsovistpath() void MainWindow::OnToolsAgentLoadProgram() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { if(m_p->m_view[QGraphDoc::VIEW_3D]) @@ -475,7 +541,7 @@ void MainWindow::OnToolsAgentLoadProgram() void MainWindow::OnToolsRunAxa() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnToolsRunAxa(); @@ -484,7 +550,7 @@ void MainWindow::OnToolsRunAxa() void MainWindow::OnToolsPD() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnToolsPD(); @@ -493,7 +559,7 @@ void MainWindow::OnToolsPD() void MainWindow::OnToolsMakeFewestLineMap() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnToolsMakeFewestLineMap(); @@ -502,7 +568,7 @@ void MainWindow::OnToolsMakeFewestLineMap() void MainWindow::OnToolsAxialConvShapeMap() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnToolsAxialConvShapeMap(); @@ -511,7 +577,7 @@ void MainWindow::OnToolsAxialConvShapeMap() void MainWindow::OnToolsLineLoadUnlinks() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnToolsLineLoadUnlinks(); @@ -520,7 +586,7 @@ void MainWindow::OnToolsLineLoadUnlinks() void MainWindow::OnToolsRunSeg() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnToolsRunSeg(); @@ -529,7 +595,7 @@ void MainWindow::OnToolsRunSeg() void MainWindow::OnToolsTopomet() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnToolsTopomet(); @@ -538,7 +604,7 @@ void MainWindow::OnToolsTopomet() void MainWindow::OnToolsTPD() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnToolsTPD(); @@ -547,7 +613,7 @@ void MainWindow::OnToolsTPD() void MainWindow::OnToolsMPD() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnToolsMPD(); @@ -556,7 +622,7 @@ void MainWindow::OnToolsMPD() void MainWindow::OnToolsPointConvShapeMap() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnToolsPointConvShapeMap(); @@ -565,7 +631,7 @@ void MainWindow::OnToolsPointConvShapeMap() void MainWindow::OnToolsAPD() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnToolsAPD(); @@ -574,49 +640,20 @@ void MainWindow::OnToolsAPD() void MainWindow::OnToolsOptions() { - CDepthmapOptionsDlg dlg(this, m_simpleVersion); - - if (QDialog::Accepted == dlg.exec()) { - - m_simpleVersion = dlg.c_show_simple_version->checkState(); - SettingTag::saveSettings(m_settingsFile, SettingTag::simpleVersion, m_simpleVersion); - if(m_simpleVersion) - qWarning("SV = True"); - else - qWarning("SV = False"); + SettingsDialog dialog(mSettings); + if(QDialog::Accepted == dialog.exec()) { + readSettings(); } } -void MainWindow::OnWindowBackground() -{ - m_background = QColorDialog::getColor(m_background).rgb(); - SettingTag::saveSettings(m_settingsFile, SettingTag::backgroundColour, m_background); -} - -void MainWindow::OnWindowForeground() -{ - m_foreground = QColorDialog::getColor(m_foreground).rgb(); - SettingTag::saveSettings(m_settingsFile, SettingTag::foregroundColour, m_foreground); -} - -void MainWindow::OnShowResearchtoolbar() -{ - //if (GetApp()->m_show_researchtoolbar) { - // m_wndResearchToolBar.show(); - //} - //else { - // m_wndResearchToolBar.hide(); - //} -} - void MainWindow::OnViewCentreView() { - activeQDepthmapDoc()->SetRedrawFlag(QGraphDoc::VIEW_MAP, QGraphDoc::REDRAW_TOTAL, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP, this); + activeMapDoc()->SetRedrawFlag(QGraphDoc::VIEW_MAP, QGraphDoc::REDRAW_TOTAL, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP, this); } void MainWindow::OnViewShowGrid() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnViewShowGrid(); @@ -625,7 +662,7 @@ void MainWindow::OnViewShowGrid() void MainWindow::OnViewSummary() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { m_p->OnViewSummary(); @@ -669,30 +706,61 @@ void MainWindow::OnHelpSalaManual() void MainWindow::OnFileClose() { - QDepthmapView* m_p = activeQDepthmapView(); + MapView* m_p = activeMapView(); if(m_p) QApplication::postEvent((QObject*)m_p, new QEvent(QEvent::Close)); } void MainWindow::OnFileSave() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { - m_p->OnFileSave(); - statusBar()->showMessage(tr("File saved"), 2000); - setCurrentFile(m_p->m_opened_name); + bool saved = m_p->OnFileSave(); + if(saved) { + statusBar()->showMessage(tr("File saved"), 2000); + setCurrentFile(m_p->m_opened_name); + updateSubWindowTitles(m_p->m_base_title); + } else { + statusBar()->showMessage(tr("File not saved"), 2000); + } } } void MainWindow::OnFileSaveAs() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(m_p) { - m_p->OnFileSaveAs(); - statusBar()->showMessage(tr("File saved"), 2000); - setCurrentFile(m_p->m_opened_name); + bool saved = m_p->OnFileSaveAs(); + if(saved) { + statusBar()->showMessage(tr("File saved"), 2000); + setCurrentFile(m_p->m_opened_name); + updateSubWindowTitles(m_p->m_base_title); + } else { + statusBar()->showMessage(tr("File not saved"), 2000); + } + } +} +void MainWindow::updateSubWindowTitles(QString newTitle) { + QList windowList = mdiArea->subWindowList(); + QList::iterator iter = windowList.begin(), end = + windowList.end(); + for ( ; iter != end; ++iter ) + { + QWidget *p = 0; + if (QMdiSubWindow *subWindow = *iter) + { + p = qobject_cast(subWindow->widget()); + if(p) subWindow->setWindowTitle(newTitle +":Map View"); + p = qobject_cast(subWindow->widget()); + if(p) subWindow->setWindowTitle(newTitle +":Scatter Plot"); + p = qobject_cast(subWindow->widget()); + if(p) subWindow->setWindowTitle(newTitle +":Table View"); + p = qobject_cast(subWindow->widget()); + if(p) subWindow->setWindowTitle(newTitle +":3D View"); + } } + } void MainWindow::OnAppAbout() @@ -701,87 +769,103 @@ void MainWindow::OnAppAbout() aboutDlg.exec(); } -QDepthmapView *MainWindow::createQDepthmapView() +MapView *MainWindow::createMapView() { QGraphDoc* doc = new QGraphDoc("", ""); doc->m_mainFrame = this; - QDepthmapView *child = new QDepthmapView(m_settingsFile); - child->pDoc = doc; + if(m_defaultMapWindowIsLegacy) + { + QDepthmapView *child = new QDepthmapView(*doc, mSettings); + mdiArea->addSubWindow(child); + return child; + } + else + { + GLView *child = new GLView(*doc, mSettings); + mdiArea->addSubWindow(child); + return child; + } - mdiArea->addSubWindow(child); - return child; } -QDepthmapView *MainWindow::activeQDepthmapView() +MapView *MainWindow::activeMapView() { QWidget *p = 0; if (QMdiSubWindow *activeSubWindow = mdiArea->activeSubWindow()) { - p = qobject_cast(activeSubWindow->widget()); - if(p) return (QDepthmapView *)p; + p = qobject_cast(activeSubWindow->widget()); + if(p) return (MapView *)p; if(!p) { p = qobject_cast(activeSubWindow->widget()); - if(p) return (QDepthmapView *)(((QPlotView*)p)->pDoc->m_view[1]); + if(p) return (MapView *)(((QPlotView*)p)->pDoc->m_view[1]); } if(!p) { - p = qobject_cast(activeSubWindow->widget()); - if(p) return (QDepthmapView *)(((tableView*)p)->pDoc->m_view[1]); + p = qobject_cast(activeSubWindow->widget()); + if(p) return (MapView *)(((TableView*)p)->pDoc->m_view[1]); } if(!p) { p = qobject_cast(activeSubWindow->widget()); - if(p) return (QDepthmapView *)(((Q3DView*)p)->pDoc->m_view[1]); + if(p) return (MapView *)(((Q3DView*)p)->pDoc->m_view[1]); } } current_view_type = 0; return 0; } -QGraphDoc *MainWindow::activeQDepthmapDoc() +QGraphDoc *MainWindow::activeMapDoc() { QWidget *p = 0; if (QMdiSubWindow *activeSubWindow = mdiArea->activeSubWindow()) { - p = qobject_cast(activeSubWindow->widget()); - if(p) return ((QDepthmapView *)p)->pDoc; + p = qobject_cast(activeSubWindow->widget()); + if(p) return ((MapView *)p)->getGraphDoc(); p = qobject_cast(activeSubWindow->widget()); if(p) return ((QPlotView *)p)->pDoc; - p = qobject_cast(activeSubWindow->widget()); - if(p) return ((tableView *)p)->pDoc; + p = qobject_cast(activeSubWindow->widget()); + if(p) return ((TableView *)p)->pDoc; p = qobject_cast(activeSubWindow->widget()); if(p) return ((Q3DView *)p)->pDoc; } return 0; } -QMdiSubWindow *MainWindow::findQDepthmapView(const QString &fileName) +QMdiSubWindow *MainWindow::findMapView(const QString &fileName) { QString canonicalFilePath = QFileInfo(fileName).canonicalFilePath(); foreach (QMdiSubWindow *window, mdiArea->subWindowList()) { - QDepthmapView *mdiChild = qobject_cast(window->widget()); - if (mdiChild && mdiChild->currentFile() == canonicalFilePath) return window; + MapView *mdiChild = qobject_cast(window->widget()); + if (mdiChild && mdiChild->getCurrentFile() == canonicalFilePath) return window; } return 0; } void MainWindow::OnWindowMap() { - return setActiveSubWindow(activeQDepthmapView()); + MapView* m_p = activeMapView(); + if(m_p) + { + if(m_p->getGraphDoc()->m_view[QGraphDoc::VIEW_MAP]) + return setActiveSubWindow(m_p->getGraphDoc()->m_view[QGraphDoc::VIEW_MAP]); + QDepthmapView *child = new QDepthmapView(*m_p->getGraphDoc(), mSettings); + mdiArea->addSubWindow(child); + child->show(); + } } void MainWindow::OnViewTable() { - QDepthmapView* m_p = activeQDepthmapView(); + MapView* m_p = activeMapView(); if(m_p) { - if(m_p->pDoc->m_view[QGraphDoc::VIEW_TABLE]) - return setActiveSubWindow(m_p->pDoc->m_view[QGraphDoc::VIEW_TABLE]); - tableView *child = new tableView(this, m_p->pDoc); - child->pDoc = m_p->pDoc; + if(m_p->getGraphDoc()->m_view[QGraphDoc::VIEW_TABLE]) + return setActiveSubWindow(m_p->getGraphDoc()->m_view[QGraphDoc::VIEW_TABLE]); + TableView *child = new TableView(mSettings, this, m_p->getGraphDoc()); + child->pDoc = m_p->getGraphDoc(); mdiArea->addSubWindow(child); child->show(); } @@ -789,13 +873,26 @@ void MainWindow::OnViewTable() void MainWindow::OnWindow3dView() { - QDepthmapView* m_p = activeQDepthmapView(); + MapView* m_p = activeMapView(); + if(m_p) + { + if(m_p->getGraphDoc()->m_view[QGraphDoc::VIEW_3D]) + return setActiveSubWindow(m_p->getGraphDoc()->m_view[QGraphDoc::VIEW_3D]); + Q3DView *child = new Q3DView(this, m_p->getGraphDoc()); + child->pDoc = m_p->getGraphDoc(); + mdiArea->addSubWindow(child); + child->show(); + } +} + +void MainWindow::OnWindowGLView() +{ + MapView* m_p = activeMapView(); if(m_p) { - if(m_p->pDoc->m_view[QGraphDoc::VIEW_3D]) - return setActiveSubWindow(m_p->pDoc->m_view[QGraphDoc::VIEW_3D]); - Q3DView *child = new Q3DView(this, m_p->pDoc); - child->pDoc = m_p->pDoc; + if(m_p->getGraphDoc()->m_view[QGraphDoc::VIEW_MAP_GL]) + return setActiveSubWindow(m_p->getGraphDoc()->m_view[QGraphDoc::VIEW_MAP_GL]); + GLView *child = new GLView(*m_p->getGraphDoc(), mSettings); mdiArea->addSubWindow(child); child->show(); } @@ -803,13 +900,13 @@ void MainWindow::OnWindow3dView() void MainWindow::OnViewScatterplot() { - QDepthmapView* m_p = activeQDepthmapView(); + MapView* m_p = activeMapView(); if(m_p) { - if(m_p->pDoc->m_view[QGraphDoc::VIEW_SCATTER]) - return setActiveSubWindow(m_p->pDoc->m_view[QGraphDoc::VIEW_SCATTER]); + if(m_p->getGraphDoc()->m_view[QGraphDoc::VIEW_SCATTER]) + return setActiveSubWindow(m_p->getGraphDoc()->m_view[QGraphDoc::VIEW_SCATTER]); QPlotView *child = new QPlotView; - child->pDoc = m_p->pDoc; + child->pDoc = m_p->getGraphDoc(); child->m_parent = this; mdiArea->addSubWindow(child); child->show(); @@ -839,7 +936,7 @@ void MainWindow::updateActiveWindows() editToolBar->hide(); thirdViewToolBar->hide(); plotToolBar->show(); - current_view_type = VIEW_SCATTER; + current_view_type = QGraphDoc::VIEW_SCATTER; OnFocusGraph(((QPlotView*)p)->pDoc, QGraphDoc::CONTROLS_LOADALL); RedoPlotViewMenu(((QPlotView*)p)->pDoc); @@ -854,20 +951,23 @@ void MainWindow::updateActiveWindows() if(((QPlotView*)p)->m_view_rsquared) Rtwo->setChecked(true); else Rtwo->setChecked(false); } - else if(qobject_cast(activeSubWindow->widget())) + else if(qobject_cast(activeSubWindow->widget())) { editToolBar->hide(); thirdViewToolBar->hide(); plotToolBar->hide(); - current_view_type = VIEW_TABLE; + current_view_type = QGraphDoc::VIEW_TABLE; + QGraphDoc* m_p = activeMapDoc(); + OnFocusGraph(m_p, QGraphDoc::CONTROLS_LOADALL); + m_p->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_FOCUS ); return; } - else if(p = qobject_cast(activeSubWindow->widget())) + else if((p = qobject_cast(activeSubWindow->widget()))) { editToolBar->hide(); plotToolBar->hide(); thirdViewToolBar->show(); - QGraphDoc* pDoc = activeQDepthmapDoc(); + QGraphDoc* pDoc = activeMapDoc(); Q3DView *ptr = (Q3DView *)p; if(ptr->m_animating) toolsAgentsPlayAct->setChecked(true); @@ -954,16 +1054,18 @@ void MainWindow::updateActiveWindows() else { thirdFilledAct->setChecked(0); } - current_view_type = VIEW_3D; + current_view_type = QGraphDoc::VIEW_3D; return; } - else if(p = qobject_cast(activeSubWindow->widget())) + else if((p = qobject_cast(activeSubWindow->widget()))) { editToolBar->show(); thirdViewToolBar->hide(); plotToolBar->hide(); - current_view_type = VIEW_MAP; - switch(((QDepthmapView*)p)->m_curr_seleted) + current_view_type = QGraphDoc::VIEW_MAP; + QWidget* v = qobject_cast(activeSubWindow->widget()); + if(v) current_view_type = QGraphDoc::VIEW_MAP_GL; + switch(m_selected_mapbar_item) { case ID_MAPBAR_ITEM_SELECT: SelectButton->setChecked(true); @@ -1031,18 +1133,20 @@ void MainWindow::updateActiveWindows() SelectButton->setChecked(false); break; } - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); OnFocusGraph(m_p, QGraphDoc::CONTROLS_LOADALL); - m_p->SetRedrawFlag(VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_FOCUS ); + m_p->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_FOCUS ); } } -void MainWindow::switchLayoutDirection() -{ - if (layoutDirection() == Qt::LeftToRight) - qApp->setLayoutDirection(Qt::RightToLeft); - else - qApp->setLayoutDirection(Qt::LeftToRight); +void MainWindow::updateGLWindows(bool datasetChanged, bool recentreView) { + QList windows = mdiArea->subWindowList(); + for (int i = 0; i < windows.size(); ++i) { + GLView *child = qobject_cast(windows.at(i)->widget()); + if(!child) continue; + if(datasetChanged) child->notifyDatasetChanged(); + if(recentreView) child->matchViewToCurrentMetaGraph(); + } } void MainWindow::setActiveSubWindow(QWidget *win) @@ -1102,9 +1206,13 @@ int MainWindow::OnFocusGraph(QGraphDoc* pDoc, int lParam) m_indexWidget->clear(); ClearGraphTree(); MakeTree(); - MakeGraphTree(); } else if (lParam == QGraphDoc::CONTROLS_LOADDRAWING && pDoc == m_treeDoc) { // Force update if match current window + m_backgraph = NULL; + m_attrWindow->clear(); + m_indexWidget->clear(); + ClearGraphTree(); + MakeGraphTree(); MakeDrawingTree(); } else if (lParam == QGraphDoc::CONTROLS_LOADATTRIBUTES && pDoc == m_treeDoc) { // Force update if match current window @@ -1162,16 +1270,16 @@ void MainWindow::OnSelchangingList() { if(in_FocusGraph) return; - int row = 0; + int row = -1; row = m_attrWindow->currentRow(); - if(row && m_treeDoc){ + if(row > -1 && m_treeDoc){ MetaGraph *graph = m_treeDoc->m_meta_graph; if (graph->viewingProcessed()) { graph->setDisplayedAttribute(row - 1); } m_treeDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_FOCUS ); SetAttributeChecks(); - OnFocusGraph(m_treeDoc, QGraphDoc::CONTROLS_CHANGEATTRIBUTE); // Bug Test TV + OnFocusGraph(m_treeDoc, QGraphDoc::CONTROLS_CHANGEATTRIBUTE); // Bug Test TV } // this *does* work here (but only if they click on a valid attribute): @@ -1185,12 +1293,12 @@ void MainWindow::OnSelchangingTree(QTreeWidgetItem* hItem, int col) bool update = false; // look it up in the table to see what to do: - size_t n = m_treegraphmap.searchindex(hItem); - if (n != paftl::npos) { - ItemTreeEntry entry = m_treegraphmap.value(n); + auto iter = m_treegraphmap.find(hItem); + if (iter != m_treegraphmap.end()) { + ItemTreeEntry entry = iter->second; bool remenu = false; if (entry.m_cat != -1) { - if (entry.m_subcat == -1) { + if (entry.m_subcat == -1 && m_indexWidget->isMapColumn(col)) { switch (entry.m_type) { case 0: if (graph->getViewClass() & MetaGraph::VIEWVGA) { @@ -1209,30 +1317,30 @@ void MainWindow::OnSelchangingTree(QTreeWidgetItem* hItem, int col) break; case 1: if (graph->getViewClass() & MetaGraph::VIEWAXIAL) { - if (graph->getShapeGraphs().getDisplayedMapRef() == entry.m_cat) { + if (graph->getDisplayedShapeGraphRef() == entry.m_cat) { graph->setViewClass(MetaGraph::SHOWHIDEAXIAL); } else { - graph->getShapeGraphs().setDisplayedMapRef(entry.m_cat); + graph->setDisplayedShapeGraphRef(entry.m_cat); } } else { - graph->getShapeGraphs().setDisplayedMapRef(entry.m_cat); + graph->setDisplayedShapeGraphRef(entry.m_cat); graph->setViewClass(MetaGraph::SHOWAXIALTOP); } remenu = true; break; case 2: if (graph->getViewClass() & MetaGraph::VIEWDATA) { - if (graph->getDataMaps().getDisplayedMapRef() == entry.m_cat) { + if (graph->getDisplayedDataMapRef() == entry.m_cat) { graph->setViewClass(MetaGraph::SHOWHIDESHAPE); } else { - graph->getDataMaps().setDisplayedMapRef(entry.m_cat); + graph->setDisplayedDataMapRef(entry.m_cat); } } else { - graph->getDataMaps().setDisplayedMapRef(entry.m_cat); + graph->setDisplayedDataMapRef(entry.m_cat); graph->setViewClass(MetaGraph::SHOWSHAPETOP); } remenu = true; @@ -1248,17 +1356,17 @@ void MainWindow::OnSelchangingTree(QTreeWidgetItem* hItem, int col) } m_treeDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_TABLE ); } - else if (entry.m_subcat == -2) { + else if (entry.m_subcat == -1 && m_indexWidget->isEditableColumn(col)) { // hit editable box if (entry.m_type == 1) { - int type = graph->getShapeGraphs().getMap(entry.m_cat).getMapType(); + int type = graph->getShapeGraphs()[entry.m_cat]->getMapType(); if (type != ShapeMap::SEGMENTMAP && type != ShapeMap::ALLLINEMAP) { - graph->getShapeGraphs().getMap(entry.m_cat).setEditable(hItem->checkState(0)); + graph->getShapeGraphs()[entry.m_cat]->setEditable(m_indexWidget->isItemSetEditable(hItem)); update = true; } } if (entry.m_type == 2) { - graph->getDataMaps().getMap(entry.m_cat).setEditable(hItem->checkState(0)); + graph->getDataMaps()[entry.m_cat].setEditable(m_indexWidget->isItemSetEditable(hItem)); update = true; } if (update) { @@ -1271,11 +1379,11 @@ void MainWindow::OnSelchangingTree(QTreeWidgetItem* hItem, int col) // They've clicked on the displayed layers if (entry.m_type == 1) { update = true; - graph->getShapeGraphs().getMap(entry.m_cat).setLayerVisible(entry.m_subcat, hItem->checkState(0)); + graph->getShapeGraphs()[entry.m_cat]->setLayerVisible(entry.m_subcat, m_indexWidget->isItemSetVisible(hItem)); } else if (entry.m_type == 2) { update = true; - graph->getDataMaps().getMap(entry.m_cat).setLayerVisible(entry.m_subcat, hItem->checkState(0)); + graph->getDataMaps()[entry.m_cat].setLayerVisible(entry.m_subcat, m_indexWidget->isItemSetVisible(hItem)); } if (update) { m_treeDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_TABLE ); @@ -1285,18 +1393,18 @@ void MainWindow::OnSelchangingTree(QTreeWidgetItem* hItem, int col) } } else { - size_t n = m_treedrawingmap.searchindex(hItem); - if (n != paftl::npos) { - ItemTreeEntry entry = m_treedrawingmap.value(n); + auto iter = m_treedrawingmap.find(hItem); + if (iter != m_treedrawingmap.end()) { + ItemTreeEntry entry = iter->second; if (entry.m_subcat != -1) { if (graph->getLineLayer(entry.m_cat,entry.m_subcat).isShown()) { graph->getLineLayer(entry.m_cat,entry.m_subcat).setShow(false); - graph->PointMaps::redoBlockLines(); + graph->redoPointMapBlockLines(); graph->resetBSPtree(); } else { graph->getLineLayer(entry.m_cat,entry.m_subcat).setShow(true); - graph->PointMaps::redoBlockLines(); + graph->redoPointMapBlockLines(); graph->resetBSPtree(); } } @@ -1310,9 +1418,9 @@ void MainWindow::SetGraphTreeChecks() in_FocusGraph = true; MetaGraph *graph = m_treeDoc->m_meta_graph; int viewclass = graph->getViewClass(); - for (size_t i = 0; i < m_treegraphmap.size(); i++) { - QTreeWidgetItem* key = m_treegraphmap.key(i); - ItemTreeEntry entry = m_treegraphmap[i]; + for (auto item: m_treegraphmap) { + QTreeWidgetItem* key = item.first; + ItemTreeEntry entry = item.second; int checkstyle = 7; if (entry.m_cat != -1) { if (entry.m_subcat == -1) { @@ -1329,36 +1437,39 @@ void MainWindow::SetGraphTreeChecks() } break; case 1: - if (viewclass & MetaGraph::VIEWAXIAL && graph->getShapeGraphs().getDisplayedMapRef() == entry.m_cat) { + if (viewclass & MetaGraph::VIEWAXIAL && graph->getDisplayedShapeGraphRef() == entry.m_cat) { checkstyle = 5; m_topgraph = key; } - else if (viewclass & MetaGraph::VIEWBACKAXIAL && graph->getShapeGraphs().getDisplayedMapRef() == entry.m_cat) { + else if (viewclass & MetaGraph::VIEWBACKAXIAL && graph->getDisplayedShapeGraphRef() == entry.m_cat) { checkstyle = 6; m_backgraph = key; } break; case 2: - if (viewclass & MetaGraph::VIEWDATA && graph->getDataMaps().getDisplayedMapRef() == entry.m_cat) { + if (viewclass & MetaGraph::VIEWDATA && graph->getDisplayedDataMapRef() == entry.m_cat) { checkstyle = 5; m_topgraph = key; } - else if (viewclass & MetaGraph::VIEWBACKDATA && graph->getDataMaps().getDisplayedMapRef() == entry.m_cat) { + else if (viewclass & MetaGraph::VIEWBACKDATA && graph->getDisplayedDataMapRef() == entry.m_cat) { checkstyle = 6; m_backgraph = key; } break; } - if(checkstyle == 5) key->setCheckState(0, Qt::Checked); - else if(checkstyle == 6) key->setCheckState(0, Qt::PartiallyChecked); - else if(checkstyle == 7) key->setCheckState(0, Qt::Unchecked); - } - else if (entry.m_subcat == -2) { + + if(checkstyle == 5) + m_indexWidget->setItemVisibility(key, Qt::Checked); + else if(checkstyle == 6) + m_indexWidget->setItemVisibility(key, Qt::PartiallyChecked); + else if(checkstyle == 7) + m_indexWidget->setItemVisibility(key, Qt::Unchecked); + // the editable box int editable = MetaGraph::NOT_EDITABLE; switch (entry.m_type) { case 0: - if (graph->PointMaps::at(entry.m_cat).isProcessed()) { + if (graph->getPointMaps()[entry.m_cat].isProcessed()) { editable = MetaGraph::NOT_EDITABLE; } else { @@ -1367,30 +1478,28 @@ void MainWindow::SetGraphTreeChecks() break; case 1: { - int type = graph->getShapeGraphs().getMap(entry.m_cat).getMapType(); + int type = graph->getShapeGraphs()[entry.m_cat]->getMapType(); if (type == ShapeMap::SEGMENTMAP || type == ShapeMap::ALLLINEMAP) { editable = MetaGraph::NOT_EDITABLE; } else { - editable = graph->getShapeGraphs().getMap(entry.m_cat).isEditable() ? MetaGraph::EDITABLE_ON : MetaGraph::EDITABLE_OFF; + editable = graph->getShapeGraphs()[entry.m_cat]->isEditable() ? MetaGraph::EDITABLE_ON : MetaGraph::EDITABLE_OFF; } } break; case 2: - editable = graph->getDataMaps().getMap(entry.m_cat).isEditable() ? MetaGraph::EDITABLE_ON : MetaGraph::EDITABLE_OFF; + editable = graph->getDataMaps()[entry.m_cat].isEditable() ? MetaGraph::EDITABLE_ON : MetaGraph::EDITABLE_OFF; break; } switch (editable) { case MetaGraph::NOT_EDITABLE: - key->setFlags(0); + m_indexWidget->setItemReadOnly(key); break; case MetaGraph::EDITABLE_OFF: - key->setCheckState(0, Qt::Unchecked); - key->setText(0, editstatetext[2]); + m_indexWidget->setItemEditability(key, Qt::Unchecked); break; case MetaGraph::EDITABLE_ON: - key->setCheckState(0, Qt::Checked); - key->setText(0, editstatetext[2]); + m_indexWidget->setItemEditability(key, Qt::Checked); break; } } @@ -1399,16 +1508,16 @@ void MainWindow::SetGraphTreeChecks() // do not currently have layers supported bool show = false; if (entry.m_type == 1) { - show = graph->getShapeGraphs().getMap(entry.m_cat).isLayerVisible(entry.m_subcat); + show = graph->getShapeGraphs()[entry.m_cat]->isLayerVisible(entry.m_subcat); } else if (entry.m_type == 2) { - show = graph->getDataMaps().getMap(entry.m_cat).isLayerVisible(entry.m_subcat); + show = graph->getDataMaps()[entry.m_cat].isLayerVisible(entry.m_subcat); } if (show) { - key->setCheckState(0, Qt::Checked); + m_indexWidget->setItemVisibility(key, Qt::Checked); } else { - key->setCheckState(0, Qt::Unchecked); + m_indexWidget->setItemVisibility(key, Qt::Unchecked); } } } @@ -1421,14 +1530,14 @@ void MainWindow::SetDrawingTreeChecks() { MetaGraph *graph = m_treeDoc->m_meta_graph; int viewclass = graph->getViewClass(); - for (size_t i = 0; i < m_treedrawingmap.size(); i++) { - ItemTreeEntry entry = m_treedrawingmap[i]; + for (auto iter: m_treedrawingmap) { + ItemTreeEntry entry = iter.second; if (entry.m_subcat != -1) { if (graph->getLineLayer(entry.m_cat,entry.m_subcat).isShown()) { - m_treedrawingmap.key(i)->setIcon(0, m_tree_icon[12]); + iter.first->setIcon(0, m_tree_icon[12]); } else { - m_treedrawingmap.key(i)->setIcon(0, m_tree_icon[13]); + iter.first->setIcon(0, m_tree_icon[13]); } } } @@ -1453,149 +1562,104 @@ void MainWindow::MakeGraphTree() MetaGraph *graph = m_treeDoc->m_meta_graph; int state = graph->getState(); - int viewclass = graph->getViewClass(); if (state & MetaGraph::POINTMAPS) { if (!m_treeroots[0]) { - QTreeWidgetItem* hItem = m_indexWidget->addNewRootFolder(tr("Visibility Graphs")); + QTreeWidgetItem* hItem = m_indexWidget->addNewItem(tr("Visibility Graphs")); hItem->setIcon(0, m_tree_icon[0]); ItemTreeEntry entry(0,-1,-1); - m_treegraphmap.add(hItem, entry); + m_treegraphmap[hItem] = entry; m_treeroots[0] = hItem; } - QTreeWidgetItem* hItem = m_treeroots[0]->child(0); - for (size_t i = 0; i < m_treeDoc->m_meta_graph->PointMaps::size(); i++) { - QString name = QString(m_treeDoc->m_meta_graph->PointMaps::at(i).getName().c_str()); - if (hItem == NULL) { - hItem = m_indexWidget->addNewFolder(name, m_treeroots[0]); - hItem->setCheckState(0, Qt::Unchecked); - ItemTreeEntry entry(0,(short)i,-1); - m_treegraphmap.add(hItem,entry); - { - QTreeWidgetItem* hNewItem = m_indexWidget->addNewItem("Editable", 0); - hNewItem->setCheckState(0, Qt::Unchecked); - ItemTreeEntry newentry = ItemTreeEntry(0,(short)i,-2); - m_treegraphmap.add(hNewItem, newentry); - } - } - else if (hItem->text(0) != name) hItem->setText(0, name); - hItem = hItem->child(1); - } - while (hItem != NULL) - { - QTreeWidgetItem* hItemDestroy = hItem; - hItem = hItemDestroy->child(0); - hItemDestroy->removeChild(hItemDestroy); + int i = 0; + for (auto& pointmap: m_treeDoc->m_meta_graph->getPointMaps()) { + QString name = QString(pointmap.getName().c_str()); + QTreeWidgetItem* hItem = m_indexWidget->addNewItem(name, m_treeroots[0]); + m_indexWidget->setItemVisibility(hItem, Qt::Unchecked); + m_indexWidget->setItemEditability(hItem, Qt::Unchecked); + ItemTreeEntry entry(0,(short)i,-1); + m_treegraphmap.insert(std::make_pair(hItem,entry)); + i++; } } else if (m_treeroots[0]) { m_treeroots[0]->removeChild(m_treeroots[0]); - m_treegraphmap.remove(m_treeroots[0]); + auto iter = m_treegraphmap.find(m_treeroots[0]); + if(iter != m_treegraphmap.end()) { + m_treegraphmap.erase(iter); + } m_treeroots[0] = NULL; } if (state & MetaGraph::SHAPEGRAPHS) { if (!m_treeroots[1]) { - QTreeWidgetItem* hItem = m_indexWidget->addNewRootFolder(tr("Shape Graphs")); + QTreeWidgetItem* hItem = m_indexWidget->addNewItem(tr("Shape Graphs")); hItem->setIcon(0, m_tree_icon[1]); ItemTreeEntry entry(1,-1,-1); - m_treegraphmap.add(hItem, entry); + m_treegraphmap[hItem] = entry; m_treeroots[1] = hItem; } - QTreeWidgetItem* hItem = m_treeroots[1]->child(0); - for (size_t i = 0; i < m_treeDoc->m_meta_graph->getShapeGraphs().getMapCount(); i++) { - QString name = QString(m_treeDoc->m_meta_graph->getShapeGraphs().getMap(i).getName().c_str()); - if (hItem == NULL) { - hItem = m_indexWidget->addNewFolder(name, m_treeroots[1]); - hItem->setCheckState(0, Qt::Unchecked); - ItemTreeEntry entry(1,(short)i,-1); - m_treegraphmap.add(hItem,entry); - { - QTreeWidgetItem* hNewItem = m_indexWidget->addNewItem("Editable", 0); - hNewItem->setCheckState(0, Qt::Unchecked); - ItemTreeEntry newentry = ItemTreeEntry(1,(short)i,-2); - m_treegraphmap.add(hNewItem, newentry); - } - } - else if (hItem->text(0) != name) hItem->setText(0, name); - QTreeWidgetItem* hNewItem = hItem->child(0); - AttributeTable& table = m_treeDoc->m_meta_graph->getShapeGraphs().getMap(i).getAttributeTable(); - for (int j = 0; j < table.getLayerCount(); j++) { - QString name = QString(table.getLayerName(j).c_str()); - if (hNewItem == NULL) { - hNewItem = m_indexWidget->addNewItem(name, 0); + for (size_t i = 0; i < m_treeDoc->m_meta_graph->getShapeGraphs().size(); i++) { + QString name = QString(m_treeDoc->m_meta_graph->getShapeGraphs()[i]->getName().c_str()); + QTreeWidgetItem* hItem = m_indexWidget->addNewItem(name, m_treeroots[1]); + m_indexWidget->setItemVisibility(hItem, Qt::Unchecked); + m_indexWidget->setItemEditability(hItem, Qt::Unchecked); + ItemTreeEntry entry(1,(short)i,-1); + m_treegraphmap.insert(std::make_pair(hItem,entry)); + LayerManagerImpl& layers = m_treeDoc->m_meta_graph->getShapeGraphs()[i]->getLayers(); + if(layers.getNumLayers() > 1) { + for (int j = 0; j < layers.getNumLayers(); j++) { + QString name = QString(layers.getLayerName(j).c_str()); + QTreeWidgetItem* hNewItem = m_indexWidget->addNewItem(name, hItem); ItemTreeEntry entry(1,(short)i,j); - m_treegraphmap.add(hNewItem,entry); + m_treegraphmap[hNewItem] = entry; } - else if (hNewItem->text(0) != name) hNewItem->setText(0, name); - hNewItem = hNewItem->child(1); } - hItem = hNewItem; - } - while (hItem != NULL) - { - QTreeWidgetItem* hItemDestroy = hItem; - hItem = hItemDestroy->child(0); - hItemDestroy->removeChild(hItemDestroy); } } else if (m_treeroots[1]) { m_treeroots[1]->removeChild(m_treeroots[1]); - m_treegraphmap.remove(m_treeroots[1]); + auto iter = m_treegraphmap.find(m_treeroots[1]); + if(iter != m_treegraphmap.end()) { + m_treegraphmap.erase(iter); + } m_treeroots[1] = NULL; } if (state & MetaGraph::DATAMAPS) { if (!m_treeroots[2]) { - QTreeWidgetItem* hItem = m_indexWidget->addNewRootFolder(tr("Data Maps")); + QTreeWidgetItem* hItem = m_indexWidget->addNewItem(tr("Data Maps")); hItem->setIcon(0, m_tree_icon[2]); ItemTreeEntry entry(2,-1,-1); - m_treegraphmap.add(hItem, entry); + m_treegraphmap[hItem] = entry; m_treeroots[2] = hItem; } - QTreeWidgetItem* hItem = m_treeroots[2]->child(0); - for (size_t i = 0; i < m_treeDoc->m_meta_graph->getDataMaps().getMapCount(); i++) { - QString name = QString(m_treeDoc->m_meta_graph->getDataMaps().getMap(i).getName().c_str()); - if (hItem == NULL) - { - hItem = m_indexWidget->addNewFolder(name, m_treeroots[2]); - hItem->setCheckState(0, Qt::Unchecked); - ItemTreeEntry entry(2,(short)i,-1); - m_treegraphmap.add(hItem, entry); - { - hItem = m_indexWidget->addNewItem(tr("Editable"), 0); - hItem->setCheckState(0, Qt::Unchecked); - ItemTreeEntry newentry = ItemTreeEntry(2,(short)i,-2); - m_treegraphmap.add(hItem, newentry); - } - } - else if (hItem->text(0) != name) hItem->setText(0, name); - - QTreeWidgetItem* hNewItem = hItem->child(0); - AttributeTable& table = m_treeDoc->m_meta_graph->getDataMaps().getMap(i).getAttributeTable(); - for (int j = 0; j < table.getLayerCount(); j++) { - QString name = QString(table.getLayerName(j).c_str()); - if (hNewItem == NULL) { - hNewItem = m_indexWidget->addNewItem(name, 0); - hNewItem->setCheckState(0, Qt::Unchecked); + for (size_t i = 0; i < m_treeDoc->m_meta_graph->getDataMaps().size(); i++) { + QString name = QString(m_treeDoc->m_meta_graph->getDataMaps()[i].getName().c_str()); + QTreeWidgetItem* hItem = m_indexWidget->addNewItem(name, m_treeroots[2]); + m_indexWidget->setItemVisibility(hItem, Qt::Unchecked); + m_indexWidget->setItemEditability(hItem, Qt::Unchecked); + ItemTreeEntry entry(2,(short)i,-1); + m_treegraphmap[hItem] = entry; + + LayerManagerImpl layers = m_treeDoc->m_meta_graph->getDataMaps()[i].getLayers(); + if(layers.getNumLayers() > 1) { + for (int j = 0; j < layers.getNumLayers(); j++) { + QString name = QString(layers.getLayerName(j).c_str()); + QTreeWidgetItem* hNewItem = m_indexWidget->addNewItem(name, hItem); + m_indexWidget->setItemVisibility(hNewItem, Qt::Unchecked); ItemTreeEntry entry(2,(short)i,j); - m_treegraphmap.add(hNewItem,entry); + m_treegraphmap.insert(std::make_pair(hNewItem,entry)); } - else if (hNewItem->text(0) != name) hNewItem->setText(0, name); - hNewItem = hNewItem->child(0); } - hItem = hNewItem; - } - while (hItem != NULL) - { - QTreeWidgetItem* hItemDestroy = hItem; - hItem = hItemDestroy->child(0); - hItemDestroy->removeChild(hItemDestroy); } } else if (m_treeroots[2]) { m_treeroots[2]->removeChild(m_treeroots[2]); - m_treegraphmap.remove(m_treeroots[2]); + auto iter = m_treegraphmap.find(m_treeroots[2]); + if(iter != m_treegraphmap.end()) { + m_treegraphmap.erase(iter); + } m_treeroots[2] = NULL; } @@ -1614,29 +1678,29 @@ void MainWindow::MakeDrawingTree() m_treedrawingmap.clear(); } // we'll do all of these if it works... - QTreeWidgetItem* root = m_indexWidget->addNewRootFolder(tr("Drawing Layers")); + QTreeWidgetItem* root = m_indexWidget->addNewItem(tr("Drawing Layers")); root->setIcon(0, m_tree_icon[4]); ItemTreeEntry entry(4,0,-1); - m_treedrawingmap.add(root,entry); + m_treedrawingmap.insert(std::make_pair(root,entry)); m_treeroots[4] = root; for (int i = 0; i < m_treeDoc->m_meta_graph->getLineFileCount(); i++) { - QTreeWidgetItem* subroot = m_indexWidget->addNewFolder(QString(m_treeDoc->m_meta_graph->getLineFileName(i).c_str())); + QTreeWidgetItem* subroot = m_indexWidget->addNewItem(QString(m_treeDoc->m_meta_graph->getLineFileName(i).c_str()), m_treeroots[4]); subroot->setIcon(0, m_tree_icon[8]); ItemTreeEntry entry(4,i,-1); - m_treedrawingmap.add(subroot,entry); + m_treedrawingmap.insert(std::make_pair(subroot,entry)); for (int j = 0; j < m_treeDoc->m_meta_graph->getLineLayerCount(i); j++) { QString name(m_treeDoc->m_meta_graph->getLineLayer(i,j).getName().c_str()); - QTreeWidgetItem* hItem = m_indexWidget->addNewItem(name, 0); + QTreeWidgetItem* hItem = m_indexWidget->addNewItem(name, subroot); if (m_treeDoc->m_meta_graph->getLineLayer(i,j).isShown()) { - hItem->setCheckState(0, Qt::Checked); + m_indexWidget->setItemVisibility(hItem, Qt::Checked); } else { - hItem->setCheckState(0, Qt::Unchecked); + m_indexWidget->setItemVisibility(hItem, Qt::Unchecked); } ItemTreeEntry entry(4,i,j); - m_treedrawingmap.add(hItem,entry); + m_treedrawingmap.insert(std::make_pair(hItem,entry)); } } } @@ -1648,7 +1712,8 @@ void MainWindow::MakeAttributeList() if (graph == NULL) { return; } - if (graph->setLock(this)) { + auto lock = graph->getLockDeferred(); + if (lock.try_lock()) { // just doing this the simple way to start off with // (when you add new attributes, list is cleared and re @@ -1662,14 +1727,13 @@ void MainWindow::MakeAttributeList() m_attrWindow->addItem(tr("Ref Number")); m_attribute_locked.push_back(true); - for (int i = 0; i < table.getColumnCount(); i++) { + for (int i = 0; i < table.getNumColumns(); i++) { name = QString(table.getColumnName(i).c_str()); m_attrWindow->addItem(name); - m_attribute_locked.push_back(table.isColumnLocked(i)); + m_attribute_locked.push_back(table.getColumn(i).isLocked()); //} } } - graph->releaseLock(this); } SetAttributeChecks(); @@ -1707,48 +1771,63 @@ void MainWindow::SetAttributeChecks() } } +void MainWindow::chooseAttributeOnIndex(int attributeIdx) { + SetAttributeChecks(); + m_attrWindow->setCurrentRow(attributeIdx); +} + void MainWindow::OninvertColor() { - activeQDepthmapDoc()->OnSwapColours(); + activeMapDoc()->OnSwapColours(); } void MainWindow::OnzoomTo() { - activeQDepthmapView()->OnViewZoomsel(); + activeMapView()->OnViewZoomsel(); } void MainWindow::SelectButtonTriggered() { - activeQDepthmapView()->OnEditSelect(); + m_selected_mapbar_item = ID_MAPBAR_ITEM_SELECT; + activeMapView()->OnEditSelect(); } void MainWindow::DragButtonTriggered() { - activeQDepthmapView()->OnViewMove(); + m_selected_mapbar_item = ID_MAPBAR_ITEM_MOVE; + activeMapView()->OnViewPan(); } void MainWindow::SelectPenTriggered() { - activeQDepthmapView()->OnEditPencil(); + m_selected_mapbar_item = ID_MAPBAR_ITEM_PENCIL; + activeMapView()->OnEditPencil(); } void MainWindow::AxialMapTriggered() { - activeQDepthmapView()->OnToolsAxialMap(); + m_selected_mapbar_item = ID_MAPBAR_ITEM_AL2; + activeMapView()->OnModeSeedAxial(); } void MainWindow::StepDepthTriggered() { - activeQDepthmapDoc()->OnToolsPD(); + activeMapDoc()->OnToolsPD(); } void MainWindow::zoomButtonTriggered() { int id = zoomInAct->data().value(); if(id == ID_MAPBAR_ITEM_ZOOM_IN) - activeQDepthmapView()->OnViewZoomIn(); + { + m_selected_mapbar_item = ID_MAPBAR_ITEM_ZOOM_IN; + activeMapView()->OnViewZoomIn(); + } else - activeQDepthmapView()->OnViewZoomOut(); + { + m_selected_mapbar_item = ID_MAPBAR_ITEM_ZOOM_OUT; + activeMapView()->OnViewZoomOut(); + } } void MainWindow::FillButtonTriggered() @@ -1763,38 +1842,65 @@ void MainWindow::FillButtonTriggered() } if(id == ID_MAPBAR_ITEM_FILL) - activeQDepthmapView()->OnEditFill(); + { + m_selected_mapbar_item = ID_MAPBAR_ITEM_FILL; + activeMapView()->OnEditFill(); + } else if (id == ID_MAPBAR_ITEM_SEMIFILL) // AV TV - activeQDepthmapView()->OnEditSemiFill(); + { + m_selected_mapbar_item = ID_MAPBAR_ITEM_SEMIFILL; + activeMapView()->OnEditSemiFill(); + } else - activeQDepthmapView()->OnEditAugmentFill(); // AV TV + { + m_selected_mapbar_item = ID_MAPBAR_ITEM_AUGMENT_FILL; + activeMapView()->OnEditAugmentFill(); // AV TV + } } void MainWindow::LineButtonTriggered() { int id = SelectLineAct->data().value(); if(id == ID_MAPBAR_ITEM_LINETOOL) - activeQDepthmapView()->OnEditLineTool(); + { + m_selected_mapbar_item = ID_MAPBAR_ITEM_LINETOOL; + activeMapView()->OnEditLineTool(); + } else - activeQDepthmapView()->OnEditPolygon(); + { + m_selected_mapbar_item = ID_MAPBAR_ITEM_POLYGON; + activeMapView()->OnEditPolygonTool(); + } } void MainWindow::isoButtonTriggered() { int id = MakeIosAct->data().value(); if(id == ID_MAPBAR_ITEM_ISOVIST) - activeQDepthmapView()->OnModeIsovist(); + { + m_selected_mapbar_item = ID_MAPBAR_ITEM_ISOVIST; + activeMapView()->OnModeIsovist(); + } else - activeQDepthmapView()->OnModeHalfovist(); + { + m_selected_mapbar_item = ID_MAPBAR_ITEM_HALFISOVIST; + activeMapView()->OnModeTargetedIsovist(); + } } void MainWindow::joinButtonTriggered() { int id = JoinAct->data().value(); if(id == ID_MAPBAR_ITEM_JOIN) - activeQDepthmapView()->OnModeJoin(); + { + m_selected_mapbar_item = ID_MAPBAR_ITEM_JOIN; + activeMapView()->OnModeJoin(); + } else - activeQDepthmapView()->OnModeUnjoin(); + { + m_selected_mapbar_item = ID_MAPBAR_ITEM_UNJOIN; + activeMapView()->OnModeUnjoin(); + } } void MainWindow::zoomModeTriggered() @@ -1852,77 +1958,77 @@ void MainWindow::joinTriggered() void MainWindow::OnFileProperties() { - QGraphDoc* gd = activeQDepthmapView()->pDoc; + QGraphDoc* gd = activeMapView()->getGraphDoc(); gd->OnFileProperties(); } // PlotView message void MainWindow::OntoggleColor() { - QGraphDoc* gd = activeQDepthmapDoc(); + QGraphDoc* gd = activeMapDoc(); if(((QPlotView*)gd->m_view[QGraphDoc::VIEW_SCATTER])) ((QPlotView*)gd->m_view[QGraphDoc::VIEW_SCATTER])->OnViewColor(); } void MainWindow::OntoggleOrg() { - QGraphDoc* gd = activeQDepthmapDoc(); + QGraphDoc* gd = activeMapDoc(); if(((QPlotView*)gd->m_view[QGraphDoc::VIEW_SCATTER])) ((QPlotView*)gd->m_view[QGraphDoc::VIEW_SCATTER])->OnViewOrigin(); } void MainWindow::OnviewTrend() { - QGraphDoc* gd = activeQDepthmapDoc(); + QGraphDoc* gd = activeMapDoc(); if(((QPlotView*)gd->m_view[QGraphDoc::VIEW_SCATTER])) ((QPlotView*)gd->m_view[QGraphDoc::VIEW_SCATTER])->OnViewTrendLine(); } void MainWindow::OnYX() { - QGraphDoc* gd = activeQDepthmapDoc(); + QGraphDoc* gd = activeMapDoc(); if(((QPlotView*)gd->m_view[QGraphDoc::VIEW_SCATTER])) ((QPlotView*)gd->m_view[QGraphDoc::VIEW_SCATTER])->OnViewEquation(); } void MainWindow::OnRtwo() { - QGraphDoc* gd = activeQDepthmapDoc(); + QGraphDoc* gd = activeMapDoc(); if(((QPlotView*)gd->m_view[QGraphDoc::VIEW_SCATTER])) ((QPlotView*)gd->m_view[QGraphDoc::VIEW_SCATTER])->OnViewRsquared(); } void MainWindow::OnToolsImportTraces() { - QGraphDoc* gd = activeQDepthmapDoc(); + QGraphDoc* gd = activeMapDoc(); if(((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])) ((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])->OnToolsImportTraces(); } void MainWindow::OnAddAgent() { - QGraphDoc* gd = activeQDepthmapDoc(); + QGraphDoc* gd = activeMapDoc(); if(((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])) ((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])->OnAddAgent(); } void MainWindow::OnToolsAgentsPlay() { - QGraphDoc* gd = activeQDepthmapDoc(); + QGraphDoc* gd = activeMapDoc(); if(((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])) ((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])->OnToolsAgentsPlay(); } void MainWindow::OnToolsAgentsPause() { - QGraphDoc* gd = activeQDepthmapDoc(); + QGraphDoc* gd = activeMapDoc(); if(((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])) ((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])->OnToolsAgentsPause(); } void MainWindow::OnToolsAgentsStop() { - QGraphDoc* gd = activeQDepthmapDoc(); + QGraphDoc* gd = activeMapDoc(); if(((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])) ((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])->OnToolsAgentsStop(); updateActiveWindows(); @@ -1930,42 +2036,42 @@ void MainWindow::OnToolsAgentsStop() void MainWindow::OnAgentTrails() { - QGraphDoc* gd = activeQDepthmapDoc(); + QGraphDoc* gd = activeMapDoc(); if(((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])) ((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])->OnAgentTrails(); } void MainWindow::On3dRot() { - QGraphDoc* gd = activeQDepthmapDoc(); + QGraphDoc* gd = activeMapDoc(); if(((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])) ((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])->On3dRot(); } void MainWindow::On3dPan() { - QGraphDoc* gd = activeQDepthmapDoc(); + QGraphDoc* gd = activeMapDoc(); if(((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])) ((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])->On3dPan(); } void MainWindow::On3dZoom() { - QGraphDoc* gd = activeQDepthmapDoc(); + QGraphDoc* gd = activeMapDoc(); if(((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])) ((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])->On3dZoom(); } void MainWindow::OnPlayLoop() { - QGraphDoc* gd = activeQDepthmapDoc(); + QGraphDoc* gd = activeMapDoc(); if(((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])) ((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])->OnPlayLoop(); } void MainWindow::On3dFilled() { - QGraphDoc* gd = activeQDepthmapDoc(); + QGraphDoc* gd = activeMapDoc(); if(((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])) ((Q3DView*)gd->m_view[QGraphDoc::VIEW_3D])->On3dFilled(); } @@ -1987,17 +2093,14 @@ void MainWindow::createStatusBar() void MainWindow::readSettings() { - QCoreApplication::setOrganizationName("Tasos Varoudis"); - QCoreApplication::setOrganizationDomain("depthmap.org"); - QCoreApplication::setApplicationName("depthmapX"); - - QSettings settings(m_settingsFile, QSettings::IniFormat); - QPoint pos = settings.value(SettingTag::position, QPoint(200, 200)).toPoint(); - QSize size = settings.value(SettingTag::size, QSize(400, 400)).toSize(); - m_foreground = settings.value(SettingTag::foregroundColour, qRgb(128,255,128)).toInt(); - m_background = settings.value(SettingTag::backgroundColour, qRgb(0,0,0)).toInt(); - m_simpleVersion = settings.value(SettingTag::simpleVersion, true).toBool(); - if (settings.value(SettingTag::mwMaximised, true).toBool()) + auto settings = mSettings.getTransaction(); + QPoint pos = settings->readSetting(SettingTag::position, QPoint(200, 200)).toPoint(); + QSize size = settings->readSetting(SettingTag::size, QSize(400, 400)).toSize(); + m_foreground = settings->readSetting(SettingTag::foregroundColour, qRgb(128,255,128)).toInt(); + m_background = settings->readSetting(SettingTag::backgroundColour, qRgb(0,0,0)).toInt(); + m_simpleVersion = settings->readSetting(SettingTag::simpleVersion, true).toBool(); + m_defaultMapWindowIsLegacy = settings->readSetting(SettingTag::legacyMapWindow, false).toBool(); + if (settings->readSetting(SettingTag::mwMaximised, true).toBool()) { setWindowState(Qt::WindowMaximized); } @@ -2009,38 +2112,30 @@ void MainWindow::readSettings() void MainWindow::writeSettings() { - QCoreApplication::setOrganizationName("Tasos Varoudis"); - QCoreApplication::setOrganizationDomain("depthmap.org"); - QCoreApplication::setApplicationName("depthmapX"); - - QSettings settings(m_settingsFile, QSettings::IniFormat); - - settings.setValue(SettingTag::position, pos()); - settings.setValue(SettingTag::size, size()); - settings.setValue(SettingTag::mwMaximised, windowState() == Qt::WindowMaximized); + auto settings = mSettings.getTransaction(); + settings->writeSetting(SettingTag::position, pos()); + settings->writeSetting(SettingTag::size, size()); + settings->writeSetting(SettingTag::mwMaximised, windowState() == Qt::WindowMaximized); } void MainWindow::setCurrentFile(const QString &fileName) { - QSettings settings(m_settingsFile, QSettings::IniFormat); - QStringList files = settings.value(SettingTag::recentFileList).toStringList(); + auto settings = mSettings.getTransaction(); + + QStringList files = settings->readSetting(SettingTag::recentFileList).toStringList(); files.removeAll(fileName); files.prepend(fileName); while (files.size() > MaxRecentFiles) files.removeLast(); - settings.setValue(SettingTag::recentFileList, files); + settings->writeSetting(SettingTag::recentFileList, files); - updateRecentFileActions(); + updateRecentFileActions(files); } -void MainWindow::updateRecentFileActions() +void MainWindow::updateRecentFileActions(const QStringList &files) { - QSettings settings(m_settingsFile, QSettings::IniFormat); - - QStringList files = settings.value(SettingTag::recentFileList).toStringList(); - int numRecentFiles = qMin(files.size(), MaxRecentFiles); for (int i = 0; i < numRecentFiles; ++i) { @@ -2065,18 +2160,22 @@ void MainWindow::openRecentFile() QAction *action = qobject_cast(sender()); if (action) { - QMdiSubWindow *existing = findQDepthmapView(action->data().toString()); + QMdiSubWindow *existing = findMapView(action->data().toString()); if (existing) { mdiArea->setActiveSubWindow(existing); return; } - QDepthmapView *child = createQDepthmapView(); - if (child->loadFile(action->data().toString())) + MapView *child = createMapView(); + QByteArray ba = action->data().toString().toUtf8(); // quick fix for weird chars (russian filename bug report) + char *file = ba.data(); // quick fix for weird chars (russian filename bug report) + if(child->getGraphDoc()->OnOpenDocument(file)) // quick fix for weird chars (russian filename bug report) { + child->setCurrentFile(action->data().toString()); + child->postLoadFile(); setCurrentFile(action->data().toString()); statusBar()->showMessage(tr("File loaded"), 2000); child->show(); - OnFocusGraph(child->pDoc, QGraphDoc::CONTROLS_LOADALL); + OnFocusGraph(child->getGraphDoc(), QGraphDoc::CONTROLS_LOADALL); } else child->close(); } @@ -2091,58 +2190,61 @@ void MainWindow::RedoPlotViewMenu(QGraphDoc* pDoc) int view_class = pDoc->m_meta_graph->getViewClass() & (MetaGraph::VIEWVGA | MetaGraph::VIEWAXIAL | MetaGraph::VIEWDATA); int curr_j = 0; - if (pDoc->m_meta_graph->setLock(this)) { - m_view_map_entries.clear(); - if (view_class == MetaGraph::VIEWVGA) { - PointMap& map = pDoc->m_meta_graph->getDisplayedPointMap(); - int displayed_ref = map.getDisplayedAttribute(); - - const AttributeTable& table = map.getAttributeTable(); - m_view_map_entries.add(0, "Ref Number"); - for (int i = 0; i < table.getColumnCount(); i++) { - m_view_map_entries.add(i+1, table.getColumnName(i)); - if (map.getDisplayedAttribute() == i) { - curr_j = i + 1; - } - } - } - else if (view_class == MetaGraph::VIEWAXIAL) { - // using attribute tables is very, very simple... - const ShapeGraph& map = pDoc->m_meta_graph->getDisplayedShapeGraph(); - const AttributeTable& table = map.getAttributeTable(); - m_view_map_entries.add(0, "Ref Number"); - curr_j = 0; - for (int i = 0; i < table.getColumnCount(); i++) { - m_view_map_entries.add(i+1, table.getColumnName(i)); - if (map.getDisplayedAttribute() == i) { - curr_j = i + 1; - } - } - } - else if (view_class == MetaGraph::VIEWDATA) { - // using attribute tables is very, very simple... - const ShapeMap& map = pDoc->m_meta_graph->getDisplayedDataMap(); - const AttributeTable& table = map.getAttributeTable(); - m_view_map_entries.add(0, "Ref Number"); - curr_j = 0; - for (int i = 0; i < table.getColumnCount(); i++) { - m_view_map_entries.add(i+1, table.getColumnName(i)); - if (map.getDisplayedAttribute() == i) { - curr_j = i + 1; - } - } - } - pDoc->m_meta_graph->releaseLock(this); - } + { + auto lock = pDoc->m_meta_graph->getLockDeferred(); + if (lock.try_lock()) { + m_view_map_entries.clear(); + if (view_class == MetaGraph::VIEWVGA) { + PointMap& map = pDoc->m_meta_graph->getDisplayedPointMap(); + + const AttributeTable& table = map.getAttributeTable(); + m_view_map_entries.insert(std::make_pair(0, "Ref Number")); + for (int i = 0; i < table.getNumColumns(); i++) { + m_view_map_entries.insert(std::make_pair(i+1, table.getColumnName(i))); + if (map.getDisplayedAttribute() == i) { + curr_j = i + 1; + } + } + } + else if (view_class == MetaGraph::VIEWAXIAL) { + // using attribute tables is very, very simple... + const ShapeGraph& map = pDoc->m_meta_graph->getDisplayedShapeGraph(); + const AttributeTable& table = map.getAttributeTable(); + m_view_map_entries.insert(std::make_pair(0, "Ref Number")); + curr_j = 0; + for (int i = 0; i < table.getNumColumns(); i++) { + m_view_map_entries.insert(std::make_pair(i+1, table.getColumnName(i))); + if (map.getDisplayedAttribute() == i) { + curr_j = i + 1; + } + } + } + else if (view_class == MetaGraph::VIEWDATA) { + // using attribute tables is very, very simple... + const ShapeMap& map = pDoc->m_meta_graph->getDisplayedDataMap(); + const AttributeTable& table = map.getAttributeTable(); + m_view_map_entries.insert(std::make_pair(0, "Ref Number")); + curr_j = 0; + for (int i = 0; i < table.getNumColumns(); i++) { + m_view_map_entries.insert(std::make_pair(i+1, table.getColumnName(i))); + if (map.getDisplayedAttribute() == i) { + curr_j = i + 1; + } + } + } + } + } int t, cur_sel = 0; x_coord->clear(); y_coord->clear(); - for (size_t i = 0; i < m_view_map_entries.size(); i++) { - if (curr_j == m_view_map_entries.key(i)) cur_sel = (int) i; - x_coord->addItem( QString(m_view_map_entries.value(i).c_str()) ); - y_coord->addItem( QString(m_view_map_entries.value(i).c_str()) ); + int i = 0; + for (auto view_map_entry: m_view_map_entries) { + if (curr_j == view_map_entry.first) cur_sel = i; + x_coord->addItem( QString(view_map_entry.second.c_str()) ); + y_coord->addItem( QString(view_map_entry.second.c_str()) ); + i++; } t = ((QPlotView*)pDoc->m_view[QGraphDoc::VIEW_SCATTER])->curr_y; @@ -2164,7 +2266,7 @@ void MainWindow::OnSelchangeViewSelector_X(const QString &string) int i = x_coord->currentIndex(); - QGraphDoc* gd = activeQDepthmapDoc(); + QGraphDoc* gd = activeMapDoc(); ((QPlotView*)gd->m_view[QGraphDoc::VIEW_SCATTER])->SetAxis(0, /*m_view_selection*/i - 1, true); ((QPlotView*)gd->m_view[QGraphDoc::VIEW_SCATTER])->curr_x = i; @@ -2178,7 +2280,7 @@ void MainWindow::OnSelchangeViewSelector_Y(const QString &string) if(in_FocusGraph) return; int i = y_coord->currentIndex(); - QGraphDoc* gd = activeQDepthmapDoc(); + QGraphDoc* gd = activeMapDoc(); ((QPlotView*)gd->m_view[QGraphDoc::VIEW_SCATTER])->SetAxis(1, i - 1, true); ((QPlotView*)gd->m_view[QGraphDoc::VIEW_SCATTER])->curr_y = i; @@ -2190,9 +2292,7 @@ void MainWindow::OnSelchangeViewSelector_Y(const QString &string) void MainWindow::updateViewMenu() { - BackgroundAct->setEnabled(true); - foregroundAct->setEnabled(true); - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(!m_p) { RecentAct->setEnabled(0); @@ -2214,11 +2314,13 @@ void MainWindow::updateViewMenu() void MainWindow::updateVisibilitySubMenu() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(!m_p) { SetGridAct->setEnabled(0); makeVisibilityGraphAct->setEnabled(0); + unmakeVisibilityGraphAct->setEnabled(0); + importVGALinksAct->setEnabled(0); makeIsovistPathAct->setEnabled(0); runVisibilityGraphAnalysisAct->setEnabled(0); convertDataMapLinesAct->setEnabled(0); @@ -2228,18 +2330,28 @@ void MainWindow::updateVisibilitySubMenu() SetGridAct->setEnabled(true); else SetGridAct->setEnabled(0); - if(m_p->m_meta_graph->viewingUnprocessedPoints()) + if (m_p->m_meta_graph->viewingUnprocessedPoints()) { makeVisibilityGraphAct->setEnabled(true); - else makeVisibilityGraphAct->setEnabled(0); + unmakeVisibilityGraphAct->setEnabled(false); + } else { + makeVisibilityGraphAct->setEnabled(false); + unmakeVisibilityGraphAct->setEnabled(true); + } int state = m_p->m_meta_graph->getState(); if (state & MetaGraph::LINEDATA) makeIsovistPathAct->setEnabled(true); else makeIsovistPathAct->setEnabled(0); - if (m_p->m_meta_graph->viewingProcessedPoints()) + if (m_p->m_meta_graph->viewingProcessedPoints()) { + importVGALinksAct->setEnabled(true); runVisibilityGraphAnalysisAct->setEnabled(true); - else runVisibilityGraphAnalysisAct->setEnabled(0); + } + else + { + importVGALinksAct->setEnabled(0); + runVisibilityGraphAnalysisAct->setEnabled(0); + } if ( !m_p->m_communicator && m_p->m_meta_graph->viewingProcessedShapes() && @@ -2251,7 +2363,7 @@ void MainWindow::updateVisibilitySubMenu() void MainWindow::updateStepDepthSubMenu() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(!m_p) { visibilityStepAct->setEnabled(0); @@ -2274,7 +2386,7 @@ void MainWindow::updateStepDepthSubMenu() void MainWindow::updateAgentToolsSubMenu() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(!m_p) { runAgentAnalysisAct->setEnabled(0); @@ -2284,13 +2396,13 @@ void MainWindow::updateAgentToolsSubMenu() if (m_p->m_meta_graph && m_p->m_meta_graph->viewingProcessedPoints() && !m_p->m_communicator) runAgentAnalysisAct->setEnabled(true); else runAgentAnalysisAct->setEnabled(0); - if(current_view_type == VIEW_3D) loadAgentProgramAct->setEnabled(true); + if(current_view_type == QGraphDoc::VIEW_3D) loadAgentProgramAct->setEnabled(true); else loadAgentProgramAct->setEnabled(0); } void MainWindow::updateSegmentSubMenu() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(!m_p) { runAngularSegmentAnalysisAct->setEnabled(0); @@ -2308,7 +2420,7 @@ void MainWindow::updateSegmentSubMenu() void MainWindow::updateSegmentStepDepthSubMenu() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(!m_p) { segmentAngularStepAct->setEnabled(0); @@ -2332,7 +2444,7 @@ void MainWindow::updateSegmentStepDepthSubMenu() void MainWindow::updateAxialSubMenu() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(!m_p) { runGraphAnaysisAct->setEnabled(0); @@ -2374,7 +2486,7 @@ void MainWindow::updateAxialSubMenu() void MainWindow::updateAttributesMenu() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(!m_p) { addColumAct->setEnabled(0); @@ -2417,7 +2529,7 @@ void MainWindow::updateAttributesMenu() void MainWindow::updateMapMenu() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(!m_p) { mapNewAct->setEnabled(0); @@ -2427,6 +2539,11 @@ void MainWindow::updateMapMenu() convertMapShapesAct->setEnabled(0); importAct->setEnabled(0); exportAct->setEnabled(0); + exportGeometryAct->setEnabled(false); + exportLinksAct->setEnabled(0); + exportAxialConnectionsDotAct->setEnabled(0); + exportAxialConnectionsPairAct->setEnabled(0); + exportSegmentConnectionsPairAct->setEnabled(0); return; } mapNewAct->setEnabled(true); @@ -2448,14 +2565,29 @@ void MainWindow::updateMapMenu() else convertMapShapesAct->setEnabled(0); if (!m_p->m_meta_graph->viewingNone() && !m_p->m_communicator) + { exportAct->setEnabled(true); - else exportAct->setEnabled(0); + exportGeometryAct->setEnabled(true); + exportLinksAct->setEnabled(true); + exportAxialConnectionsDotAct->setEnabled(true); + exportAxialConnectionsPairAct->setEnabled(true); + exportSegmentConnectionsPairAct->setEnabled(true); + } + else + { + exportAct->setEnabled(0); + exportGeometryAct->setEnabled(false); + exportLinksAct->setEnabled(0); + exportAxialConnectionsDotAct->setEnabled(0); + exportAxialConnectionsPairAct->setEnabled(0); + exportSegmentConnectionsPairAct->setEnabled(0); + } } void MainWindow::updateEditMenu() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); if(!m_p) { copyDataAct->setEnabled(0); @@ -2500,7 +2632,7 @@ void MainWindow::updateFileMenu() saveAct->setEnabled( true ); saveAsAct->setEnabled( true ); propertiesAct->setEnabled( true ); - if(current_view_type == VIEW_3D) + if(current_view_type == QGraphDoc::VIEW_3D) { printAct->setEnabled( 0 ); printPreviewAct->setEnabled( 0 ); @@ -2524,7 +2656,7 @@ void MainWindow::updateFileMenu() void MainWindow::updateWindowMenu() { - QGraphDoc* m_p = activeQDepthmapDoc(); + QGraphDoc* m_p = activeMapDoc(); windowMenu->clear(); windowMenu->addAction(mapAct); @@ -2543,6 +2675,10 @@ void MainWindow::updateWindowMenu() if(m_p && m_p->m_view[QGraphDoc::VIEW_3D]) thirdDViewAct->setChecked(true); else thirdDViewAct->setChecked(false); + windowMenu->addAction(glViewAct); + if(m_p && m_p->m_view[QGraphDoc::VIEW_MAP_GL]) glViewAct->setChecked(true); + else glViewAct->setChecked(false); + windowMenu->addSeparator(); windowMenu->addAction(colourRangeAct); windowMenu->addSeparator(); @@ -2557,11 +2693,13 @@ void MainWindow::updateWindowMenu() scatterPlotAct->setEnabled(0); tableAct->setEnabled(0); thirdDViewAct->setEnabled(0); + glViewAct->setEnabled(0); } else { thirdDViewAct->setEnabled(true); mapAct->setEnabled(true); + glViewAct->setEnabled(true); if (m_p->m_meta_graph && m_p->m_meta_graph->viewingProcessed()) { tableAct->setEnabled(true); @@ -2576,14 +2714,14 @@ void MainWindow::updateWindowMenu() QList windows = mdiArea->subWindowList(); int find_count = 1; for (int i = 0; i < windows.size(); ++i) { - QDepthmapView *child = qobject_cast(windows.at(i)->widget()); + MapView *child = qobject_cast(windows.at(i)->widget()); if(!child) continue; QString text; text = tr("&%1 %2").arg(find_count++).arg(child->windowTitle()); QAction *action = windowMenu->addAction(text); action->setCheckable(true); - action ->setChecked(child == activeQDepthmapView()); + action ->setChecked(child == activeMapView()); connect(action, SIGNAL(triggered()), windowMapper, SLOT(map())); windowMapper->setMapping(action, windows.at(i)->widget()); } @@ -2624,13 +2762,14 @@ void MainWindow::updateToolbar() attr_del_button->setEnabled(0); attr_add_button->setEnabled(0); - QGraphDoc* m_p = activeQDepthmapDoc(); - QDepthmapView* tmpView = activeQDepthmapView(); + QGraphDoc* m_p = activeMapDoc(); + MapView* tmpView = activeMapView(); if(m_p) { importAct->setEnabled(true); saveAct->setEnabled(true); - addColumAct->setEnabled(true); + if(m_p->m_meta_graph->getDisplayedMapRef() != -1) + addColumAct->setEnabled(true); SelectButton->setEnabled(true); DragButton->setEnabled(true); RecentAct->setEnabled(true); @@ -2655,7 +2794,9 @@ void MainWindow::updateToolbar() { if (tmpView) { - if (tmpView->m_curr_seleted == ID_MAPBAR_ITEM_FILL || tmpView->m_curr_seleted == ID_MAPBAR_ITEM_SEMIFILL || tmpView->m_curr_seleted == ID_MAPBAR_ITEM_PENCIL) + if (m_selected_mapbar_item == ID_MAPBAR_ITEM_FILL + || m_selected_mapbar_item == ID_MAPBAR_ITEM_SEMIFILL + || m_selected_mapbar_item == ID_MAPBAR_ITEM_PENCIL) { tmpView->OnEditSelect(); SelectButton->setChecked(true); @@ -2672,7 +2813,8 @@ void MainWindow::updateToolbar() { if (tmpView) { - if (tmpView->m_curr_seleted == ID_MAPBAR_ITEM_LINETOOL || tmpView->m_curr_seleted == ID_MAPBAR_ITEM_POLYGON) + if (m_selected_mapbar_item == ID_MAPBAR_ITEM_LINETOOL + || m_selected_mapbar_item == ID_MAPBAR_ITEM_POLYGON) { tmpView->OnEditSelect(); SelectButton->setChecked(true); @@ -2687,7 +2829,7 @@ void MainWindow::updateToolbar() { if (tmpView) { - if (tmpView->m_curr_seleted == ID_MAPBAR_ITEM_ISOVIST || tmpView->m_curr_seleted == ID_MAPBAR_ITEM_HALFISOVIST) + if (m_selected_mapbar_item == ID_MAPBAR_ITEM_ISOVIST || m_selected_mapbar_item == ID_MAPBAR_ITEM_HALFISOVIST) { tmpView->OnEditSelect(); SelectButton->setChecked(true); @@ -2696,16 +2838,16 @@ void MainWindow::updateToolbar() } if (( ( (m_p->m_meta_graph->getViewClass() & MetaGraph::VIEWVGA) && - (m_p->m_meta_graph->getDisplayedPointMap().isProcessed())) || - ( (m_p->m_meta_graph->getViewClass() & MetaGraph::VIEWAXIAL) && + (m_p->m_meta_graph->getDisplayedPointMap().getFilledPointCount() > 1)) || + (((m_p->m_meta_graph->getViewClass() & MetaGraph::VIEWAXIAL) && (m_p->m_meta_graph->getState() & MetaGraph::SHAPEGRAPHS)) && - (!m_p->m_meta_graph->getDisplayedShapeGraph().isSegmentMap()) ) ) + (!m_p->m_meta_graph->getDisplayedShapeGraph().isSegmentMap()) ) )) JoinToolButton->setEnabled(true); else { if (tmpView) { - if (tmpView->m_curr_seleted == ID_MAPBAR_ITEM_JOIN || tmpView->m_curr_seleted == ID_MAPBAR_ITEM_UNJOIN) + if (m_selected_mapbar_item == ID_MAPBAR_ITEM_JOIN || m_selected_mapbar_item == ID_MAPBAR_ITEM_UNJOIN) { tmpView->OnEditSelect(); SelectButton->setChecked(true); @@ -2719,7 +2861,7 @@ void MainWindow::updateToolbar() { if (tmpView) { - if (tmpView->m_curr_seleted == ID_MAPBAR_ITEM_AL2) + if (m_selected_mapbar_item == ID_MAPBAR_ITEM_AL2) { tmpView->OnEditSelect(); SelectButton->setChecked(true); @@ -2799,7 +2941,7 @@ void MainWindow::createActions() exitAct = new QAction(tr("E&xit"), this); exitAct->setStatusTip(tr("Quit the application; prompts to save documents\nExit")); - connect(exitAct, SIGNAL(triggered()), this, SLOT(OnFileExit())); + connect(exitAct, SIGNAL(triggered()), this, SLOT(close())); //Edit Menu Actions undoAct = new QAction(tr("&Undo"), this); @@ -2821,6 +2963,7 @@ void MainWindow::createActions() clearAct = new QAction(tr("&Clear"), this); clearAct->setShortcut(tr("Del")); + clearAct->setShortcutContext(Qt::ApplicationShortcut); clearAct->setStatusTip(tr("Erase the selection\nErase")); connect(clearAct, SIGNAL(triggered()), this, SLOT(OnEditClear())); @@ -2862,11 +3005,35 @@ void MainWindow::createActions() importAct->setStatusTip(tr("Import a DXF or points file\nImport Map")); connect(importAct, SIGNAL(triggered()), this, SLOT(OnFileImport())); - exportAct = new QAction(tr("&Export..."), this); + exportAct = new QAction(tr("&Export map..."), this); exportAct->setShortcut(tr("Ctrl+E")); - exportAct->setStatusTip(tr("Export the active map\nExport Map")); + exportAct->setStatusTip(tr("Export the active map")); connect(exportAct, SIGNAL(triggered()), this, SLOT(OnFileExport())); + exportGeometryAct = new QAction(tr("&Export map geometry..."), this); + exportGeometryAct->setStatusTip(tr("Export the geometry of the active map")); + connect(exportGeometryAct, SIGNAL(triggered()), this, SLOT(OnFileExportMapGeometry())); + + exportLinksAct = new QAction(tr("&Export links..."), this); + exportLinksAct->setStatusTip(tr("Export the links of the active map")); + connect(exportLinksAct, SIGNAL(triggered()), this, SLOT(OnFileExportLinks())); + + exportAxialConnectionsPairAct = new QAction(tr("&Axial Connections as CSV..."), this); + exportAxialConnectionsPairAct->setStatusTip(tr("Export a list of line-line intersections")); + connect(exportAxialConnectionsPairAct, SIGNAL(triggered()), this, SLOT(OnAxialConnectionsExportAsPairCSV())); + + exportAxialConnectionsDotAct = new QAction(tr("&Axial Connections as Dot..."), this); + exportAxialConnectionsDotAct->setStatusTip(tr("Export a list of line-line intersections")); + connect(exportAxialConnectionsDotAct, SIGNAL(triggered()), this, SLOT(OnAxialConnectionsExportAsDot())); + + exportSegmentConnectionsPairAct = new QAction(tr("&Segment Connections as CSV..."), this); + exportSegmentConnectionsPairAct->setStatusTip(tr("Export a list of line-line intersections and weights")); + connect(exportSegmentConnectionsPairAct, SIGNAL(triggered()), this, SLOT(OnSegmentConnectionsExportAsPairCSV())); + + exportPointmapConnectionsPairAct = new QAction(tr("Visibility Graph Connections as CSV..."), this); + exportPointmapConnectionsPairAct->setStatusTip(tr("Export connections between cells in a visibility graph as an adjacency list")); + connect(exportPointmapConnectionsPairAct, SIGNAL(triggered()), this, SLOT(OnPointmapExportConnectionsAsCSV())); + //Attributes Menu Actions renameColumnAct = new QAction(tr("&Rename Column..."), this); renameColumnAct->setStatusTip(tr("Rename the currently displayed attribute")); @@ -2880,6 +3047,12 @@ void MainWindow::createActions() makeVisibilityGraphAct = new QAction(tr("Make &Visibility Graph..."), this); connect(makeVisibilityGraphAct, SIGNAL(triggered()), this, SLOT(OnToolsMakeGraph())); + unmakeVisibilityGraphAct = new QAction(tr("Unmake &Visibility Graph..."), this); + connect(unmakeVisibilityGraphAct, SIGNAL(triggered()), this, SLOT(OnToolsUnmakeGraph())); + + importVGALinksAct = new QAction(tr("Import VGA links from file..."), this); + connect(importVGALinksAct, SIGNAL(triggered()), this, SLOT(OnToolsImportVGALinks())); + makeIsovistPathAct = new QAction(tr("Make &Isovist Path..."), this); connect(makeIsovistPathAct, SIGNAL(triggered()), this, SLOT(OnToolsIsovistpath())); @@ -2948,14 +3121,6 @@ void MainWindow::createActions() connect(optionsAct, SIGNAL(triggered()), this, SLOT(OnToolsOptions())); //View Menu Actions - BackgroundAct = new QAction(tr("&Background..."), this); - BackgroundAct->setStatusTip(tr("Turns the current selection into a layer object [Ctrl+G]\nAdd Layer Object")); - connect(BackgroundAct, SIGNAL(triggered()), this, SLOT(OnWindowBackground())); - - foregroundAct = new QAction(tr("&Foreground..."), this); - foregroundAct->setStatusTip(tr("Clear agent trails")); - connect(foregroundAct, SIGNAL(triggered()), this, SLOT(OnWindowForeground())); - showGridAct = new QAction(tr("Show &Grid"), this); showGridAct->setStatusTip(tr("Display grid")); showGridAct->setCheckable(true); @@ -2982,6 +3147,10 @@ void MainWindow::createActions() thirdDViewAct->setCheckable(true); connect(thirdDViewAct, SIGNAL(triggered()), this, SLOT(OnWindow3dView())); + glViewAct = new QAction(tr("Map (Open&GL)"), this); + glViewAct->setCheckable(true); + connect(glViewAct, SIGNAL(triggered()), this, SLOT(OnWindowGLView())); + colourRangeAct = new QAction(tr("&Colour Range"), this); connect(colourRangeAct, SIGNAL(triggered()), this, SLOT(OnViewColourRange())); @@ -3345,7 +3514,7 @@ void MainWindow::createMenus() fileMenu->addAction(recentFileActs[i]); fileMenu->addSeparator(); fileMenu->addAction(exitAct); - updateRecentFileActions(); + updateRecentFileActions(mSettings.readSetting(SettingTag::recentFileList).toStringList()); editMenu = menuBar()->addMenu(tr("&Edit")); editMenu->addAction(undoAct); @@ -3369,7 +3538,14 @@ void MainWindow::createMenus() mapMenu->addAction(convertMapShapesAct); mapMenu->addSeparator(); mapMenu->addAction(importAct); - mapMenu->addAction(exportAct); + exportSubMenu = mapMenu->addMenu(tr("&Export")); + exportSubMenu->addAction(exportAct); + exportSubMenu->addAction(exportGeometryAct); + exportSubMenu->addAction(exportLinksAct); + exportSubMenu->addAction(exportAxialConnectionsDotAct); + exportSubMenu->addAction(exportAxialConnectionsPairAct); + exportSubMenu->addAction(exportSegmentConnectionsPairAct); + exportSubMenu->addAction(exportPointmapConnectionsPairAct); attributesMenu = menuBar()->addMenu(tr("&Attributes")); attributesMenu->addAction(addColumAct); @@ -3385,6 +3561,8 @@ void MainWindow::createMenus() visibilitySubMenu = toolsMenu->addMenu(tr("&Visibility")); visibilitySubMenu->addAction(SetGridAct); visibilitySubMenu->addAction(makeVisibilityGraphAct); + visibilitySubMenu->addAction(unmakeVisibilityGraphAct); + visibilitySubMenu->addAction(importVGALinksAct); visibilitySubMenu->addAction(makeIsovistPathAct); visibilitySubMenu->addSeparator(); visibilitySubMenu->addAction(runVisibilityGraphAnalysisAct); @@ -3419,9 +3597,6 @@ void MainWindow::createMenus() toolsMenu->addAction(optionsAct); viewMenu = menuBar()->addMenu(tr("&View")); - viewMenu->addAction(BackgroundAct); - viewMenu->addAction(foregroundAct); - viewMenu->addSeparator(); viewMenu->addAction(RecentAct); viewMenu->addAction(showGridAct); viewMenu->addAction(attributeSummaryAct); @@ -3431,6 +3606,7 @@ void MainWindow::createMenus() windowMenu->addAction(scatterPlotAct); windowMenu->addAction(tableAct); windowMenu->addAction(thirdDViewAct); + windowMenu->addAction(glViewAct); windowMenu->addSeparator(); windowMenu->addAction(colourRangeAct); windowMenu->addSeparator(); diff --git a/depthmapX/mainwindow.h b/depthmapX/mainwindow.h index 722b784d..dde4c205 100644 --- a/depthmapX/mainwindow.h +++ b/depthmapX/mainwindow.h @@ -17,16 +17,20 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H +#include "depthmapX/indexWidget.h" +#include "depthmapX/treeWindow.h" +#include "depthmapX/GraphDoc.h" +#include "depthmapX/compatibilitydefines.h" +#include "depthmapX/settings.h" + +#include "depthmapX/dialogs/ColourScaleDlg.h" +#include "depthmapX/views/glview/glview.h" + +#include "version.h" + #include #include #include -#include "indexWidget.h" -#include "treeWindow.h" -#include "GraphDoc.h" -#include "ColourScaleDlg.h" -#include "compatibilitydefines.h" - -#include "version.h" class ItemTreeEntry { @@ -51,36 +55,6 @@ class QSignalMapper; class QToolButton; QT_END_NAMESPACE -enum { - ID_MAPBAR_ZOOM_ITEMS = 2, - ID_MAPBAR_FILL_ITEMS = 8, - ID_MAPBAR_DRAW_ITEMS = 10, - ID_MAPBAR_ISOVIST_ITEMS = 12, - ID_MAPBAR_JOIN_ITEMS = 15 -}; - -enum { - ID_MAPBAR_ITEM_SELECT = 0, - ID_MAPBAR_ITEM_MOVE = 1, - ID_MAPBAR_ITEM_ZOOM_IN = 2, - ID_MAPBAR_ITEM_ZOOM_OUT = 3, - ID_MAPBAR_ITEM_FINDLOC = 4, - ID_MAPBAR_ITEM_CENTREVIEW = 5, - ID_MAPBAR_ITEM_GRID = 6, - ID_MAPBAR_ITEM_FILL = 7, - ID_MAPBAR_ITEM_SEMIFILL = 8, - ID_MAPBAR_ITEM_PENCIL = 9, - ID_MAPBAR_ITEM_LINETOOL = 10, - ID_MAPBAR_ITEM_POLYGON = 11, - ID_MAPBAR_ITEM_ISOVIST = 12, - ID_MAPBAR_ITEM_HALFISOVIST = 13, - ID_MAPBAR_ITEM_AL2 = 14, - ID_MAPBAR_ITEM_PD = 15, - ID_MAPBAR_ITEM_JOIN = 16, - ID_MAPBAR_ITEM_UNJOIN = 17, - ID_MAPBAR_ITEM_AUGMENT_FILL = 18 // AV test - TV -}; - const int MaxRecentFiles = 5; enum { FOCUSGRAPH = 1001, AllTransactionsDone = 1002 }; @@ -99,7 +73,7 @@ class MainWindow : public QMainWindow Q_OBJECT public: - MainWindow(); + MainWindow(const QString &fileToLoad, Settings &settings); // Graph analysis options QString m_formula_cache; Options m_options; @@ -113,6 +87,10 @@ class MainWindow : public QMainWindow void update3DToolbar(); void showContextMenu(QPoint &point); void UpdateStatus(QString s1, QString s2, QString s3); + void updateGLWindows(bool datasetChanged, bool recentreView); + void loadFile(QString fileName); + + void chooseAttributeOnIndex(int attributeIdx); protected: QGraphDoc* m_treeDoc; @@ -122,6 +100,7 @@ class MainWindow : public QMainWindow private slots: void updateActiveWindows(); + void updateSubWindowTitles(QString newTitle); void updateWindowMenu(); void setActiveSubWindow(QWidget *window); void OnSelchangingTree(QTreeWidgetItem* item, int col); @@ -136,7 +115,6 @@ private slots: void OnFilePrint(); void OnFilePrintPreview(); void OnFilePrintSetup(); - void OnFileExit(); void OnEditUndo(); void OnEditCopyData(); void OnEditCopy(); @@ -152,6 +130,12 @@ private slots: void OnLayerConvertDrawing(); void OnConvertMapShapes(); void OnFileExport(); + void OnFileExportMapGeometry(); + void OnFileExportLinks(); + void OnAxialConnectionsExportAsDot(); + void OnAxialConnectionsExportAsPairCSV(); + void OnSegmentConnectionsExportAsPairCSV(); + void OnPointmapExportConnectionsAsCSV(); void OnAddColumn(); void OnRenameColumn(); void OnUpdateColumn(); @@ -159,6 +143,8 @@ private slots: void OnColumnProperties(); void OnPushToLayer(); void OnToolsMakeGraph(); + void OnToolsUnmakeGraph(); + void OnToolsImportVGALinks(); void OnToolsIsovistpath(); void OnToolsAgentLoadProgram(); void OnToolsRunAxa(); @@ -173,9 +159,6 @@ private slots: void OnToolsMPD(); void OnToolsPointConvShapeMap(); void OnToolsOptions(); - void OnShowResearchtoolbar(); - void OnWindowBackground(); - void OnWindowForeground(); void OnViewCentreView(); void OnViewShowGrid(); void OnViewSummary(); @@ -188,6 +171,7 @@ private slots: void OnWindowMap(); void OnViewTable(); void OnWindow3dView(); + void OnWindowGLView(); void OnViewScatterplot(); void OnToolsRun(); void OnToolsAgentRun(); @@ -245,7 +229,7 @@ private slots: private: int OnFocusGraph(QGraphDoc* pDoc, int lParam); void setCurrentFile(const QString &fileName); - void updateRecentFileActions(); + void updateRecentFileActions(const QStringList &files); QString strippedName(const QString &fullFileName); void createActions(); @@ -254,24 +238,25 @@ private slots: void createStatusBar(); // Settings Files - QString m_settingsFile; + Settings &mSettings; void readSettings(); void writeSettings(); - void switchLayoutDirection(); + bool m_defaultMapWindowIsLegacy; + QWidget * setupAttributesListWidget(); - QDepthmapView *createQDepthmapView(); - QDepthmapView *activeQDepthmapView(); - QGraphDoc *activeQDepthmapDoc(); - QMdiSubWindow *findQDepthmapView(const QString &fileName); + MapView *createMapView(); + MapView *activeMapView(); + QGraphDoc *activeMapDoc(); + QMdiSubWindow *findMapView(const QString &fileName); ////////////////////////////////////////////////////// // treeContorl QVector m_tree_icon; - pqmap m_view_map_entries; + std::map m_view_map_entries; - pvector m_attribute_locked; - pmap m_treegraphmap; - pmap m_treedrawingmap; + std::vector m_attribute_locked; + std::map m_treegraphmap; + std::map m_treedrawingmap; QTreeWidgetItem* m_topgraph; QTreeWidgetItem* m_backgraph; QTreeWidgetItem* m_treeroots[5]; @@ -284,19 +269,12 @@ private slots: void SetAttributeChecks(); void SetDrawingTreeChecks(); void SetGraphTreeChecks(); - int SetDisplayedAttribute(QTreeWidgetItem* hItem, ItemTreeEntry entry); - // popup stuff - ItemTreeEntry m_popup_entry; - int m_popup_attribute; - void GetItemMap(MetaGraph *graph, PointMap* &pointmap, ShapeMap* &shapemap); - // misc - void SwitchFocusBack(); //////////////////////////////////////////////////////////// QMdiArea *mdiArea; QSignalMapper *windowMapper; - indexWidget* m_indexWidget; + IndexWidget* m_indexWidget; AttribWindow* m_attrWindow; CColourScaleDlg m_wndColourScale; @@ -307,6 +285,7 @@ private slots: QMenu *fileMenu; QMenu *editMenu; QMenu *mapMenu; + QMenu *exportSubMenu; QMenu *attributesMenu; QMenu *toolsMenu; QMenu *visibilitySubMenu; @@ -314,7 +293,6 @@ private slots: QMenu *agentToolsSubMenu; QMenu *axialSubMenu; QMenu *segmentSubMenu; - pvector plugInSubMenu; QMenu *segmentStepDepthSubMenu; QMenu *viewMenu; QMenu *windowMenu; @@ -323,7 +301,6 @@ private slots: QToolBar *fileToolBar; QToolBar *editToolBar; QToolBar *plotToolBar; - QToolBar *ResearchToolBar; QToolBar *thirdViewToolBar; QToolButton *fillColorToolButton; QToolButton *zoomToolButton; @@ -360,7 +337,6 @@ private slots: QAction *exportScreenAct; QAction *clearAct; QAction *selectByQueryAct; - QAction *zoomToSelectionAct; QAction *selectionToLayerAct; //Map Menu Actions @@ -371,6 +347,12 @@ private slots: QAction *convertMapShapesAct; QAction *importAct; QAction *exportAct; + QAction *exportGeometryAct; + QAction *exportLinksAct; + QAction *exportAxialConnectionsDotAct; + QAction *exportAxialConnectionsPairAct; + QAction *exportSegmentConnectionsPairAct; + QAction *exportPointmapConnectionsPairAct; //Attributes Menu Actions QAction *renameColumnAct; @@ -378,6 +360,8 @@ private slots: //Tools Menu Actions QAction *makeVisibilityGraphAct; + QAction *unmakeVisibilityGraphAct; + QAction *importVGALinksAct; QAction *makeIsovistPathAct; QAction *runVisibilityGraphAnalysisAct; QAction *visibilityStepAct; @@ -399,8 +383,6 @@ private slots: QAction *optionsAct; //View Menu Actions - QAction *BackgroundAct; - QAction *foregroundAct; QAction *showGridAct; QAction *attributeSummaryAct; @@ -409,6 +391,7 @@ private slots: QAction *scatterPlotAct; QAction *tableAct; QAction *thirdDViewAct; + QAction *glViewAct; QAction *colourRangeAct; QAction *cascadeAct; QAction *tileAct; @@ -462,17 +445,36 @@ private slots: QAction *thirdZoomAct; QAction *playLoopAct; QAction *thirdFilledAct; -//depthmapX Test - QAction *FillLineAct; - QAction *ShowBinsAct; - QAction *EvolutionAct; - QAction *Test1Act; - QAction *Test2Act; - QAction *Test3Act; - QAction *Test4Act; - QAction *ExportPolyAct; - QAction *Bindistance1Act; - QAction *Bindistance2Act; + + int m_selected_mapbar_item = -1; + + + enum { + ID_MAPBAR_ZOOM_ITEMS = 2, + ID_MAPBAR_FILL_ITEMS = 8, + ID_MAPBAR_DRAW_ITEMS = 10, + ID_MAPBAR_ISOVIST_ITEMS = 12, + ID_MAPBAR_JOIN_ITEMS = 15 + }; + + enum { + ID_MAPBAR_ITEM_SELECT = 0, + ID_MAPBAR_ITEM_MOVE = 1, + ID_MAPBAR_ITEM_ZOOM_IN = 2, + ID_MAPBAR_ITEM_ZOOM_OUT = 3, + ID_MAPBAR_ITEM_FILL = 7, + ID_MAPBAR_ITEM_SEMIFILL = 8, + ID_MAPBAR_ITEM_PENCIL = 9, + ID_MAPBAR_ITEM_LINETOOL = 10, + ID_MAPBAR_ITEM_POLYGON = 11, + ID_MAPBAR_ITEM_ISOVIST = 12, + ID_MAPBAR_ITEM_HALFISOVIST = 13, + ID_MAPBAR_ITEM_AL2 = 14, + ID_MAPBAR_ITEM_PD = 15, + ID_MAPBAR_ITEM_JOIN = 16, + ID_MAPBAR_ITEM_UNJOIN = 17, + ID_MAPBAR_ITEM_AUGMENT_FILL = 18 // AV test - TV + }; }; #endif diff --git a/depthmapX/mainwindowfactory.cpp b/depthmapX/mainwindowfactory.cpp index 550c827a..2aa27aad 100644 --- a/depthmapX/mainwindowfactory.cpp +++ b/depthmapX/mainwindowfactory.cpp @@ -15,35 +15,17 @@ #include "mainwindowfactory.h" #include "mainwindow.h" -#include "licenseagreement.h" - -MainWindowHolder::MainWindowHolder() -{ - m_window = dynamic_cast(new MainWindow()); -} - -MainWindowHolder::~MainWindowHolder() -{ - delete m_window; -} - -QMainWindow& MainWindowHolder::get() -{ - return *m_window; -} - - -LicenseAgreementHolder::LicenseAgreementHolder() -{ - m_licenseDialog = dynamic_cast(new LicenseAgreement()); -} - -LicenseAgreementHolder::~LicenseAgreementHolder() -{ - delete m_licenseDialog; -} - -QDialog& LicenseAgreementHolder::get() -{ - return *m_licenseDialog; +#include "dialogs/licenseagreement.h" +#include + +namespace MainWindowFactory{ + std::unique_ptr getMainWindow(const QString& fileToLoad, Settings &settings) + { + return std::unique_ptr(new MainWindow(fileToLoad, settings)); + } + + std::unique_ptr getLicenseDialog() + { + return std::unique_ptr(new LicenseAgreement); + } } diff --git a/depthmapX/mainwindowfactory.h b/depthmapX/mainwindowfactory.h index 125bee8e..364b87fe 100644 --- a/depthmapX/mainwindowfactory.h +++ b/depthmapX/mainwindowfactory.h @@ -16,32 +16,14 @@ #ifndef MAINWINDOWFACTORY_H #define MAINWINDOWFACTORY_H -#include +#include #include +#include -class MainWindowHolder -{ -public: - MainWindowHolder(); - ~MainWindowHolder(); - QMainWindow& get(); - -private: - QMainWindow* m_window; - MainWindowHolder(const MainWindowHolder& ); - MainWindowHolder& operator=(const MainWindowHolder& ); -}; - -class LicenseAgreementHolder -{ -public: - LicenseAgreementHolder(); - ~LicenseAgreementHolder(); - QDialog& get(); -private: - QDialog* m_licenseDialog; - LicenseAgreementHolder(const LicenseAgreementHolder& ); - LicenseAgreementHolder& operator=(const LicenseAgreementHolder&); -}; +class Settings; +namespace MainWindowFactory{ + std::unique_ptr getMainWindow(const QString &fileToLoad, Settings &settings); + std::unique_ptr getLicenseDialog(); +} #endif // MAINWINDOWFACTORY_H diff --git a/depthmapX/make_version_header.bat b/depthmapX/make_version_header.bat new file mode 100644 index 00000000..a0fa05d8 --- /dev/null +++ b/depthmapX/make_version_header.bat @@ -0,0 +1,43 @@ +@echo off +del version_defs.h +echo // Copyright (C) 2018 Christian Sailer >> version_defs.h + +echo // This program is free software: you can redistribute it and/or modify >> version_defs.h +echo // it under the terms of the GNU General Public License as published by >> version_defs.h +echo // the Free Software Foundation, either version 3 of the License, or >> version_defs.h +echo // (at your option) any later version. >> version_defs.h +echo. >> version_defs.h +echo // This program is distributed in the hope that it will be useful, >> version_defs.h +echo // but WITHOUT ANY WARRANTY; without even the implied warranty of >> version_defs.h +echo // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> version_defs.h +echo // GNU General Public License for more details. >> version_defs.h +echo. >> version_defs.h +echo // You should have received a copy of the GNU General Public License >> version_defs.h +echo|set /p="// along with this program. If not, see ." >> version_defs.h +echo. >> version_defs.h +echo. >> version_defs.h +echo // This file is autogenerated - do not modify it directly! >> version_defs.h +echo. >> version_defs.h +echo #pragma once >> version_defs.h +echo. >> version_defs.h + +:: Get date in correct form (YYYY/MM/DD). +for /f "skip=1" %%x in ('wmic os get localdatetime') do if not defined MyDate set MyDate=%%x +for /f %%x in ('wmic path win32_localtime get /format:list ^| findstr "="') do set %%x +set fmonth=00%Month% +set fday=00%Day% +set today=%Year%/%fmonth:~-2%/%fday:~-2% + +echo #ifndef APP_DATE >> version_defs.h +echo #define APP_DATE "%today%" >> version_defs.h +echo #endif >> version_defs.h +echo. >> version_defs.h +for /f "delims=" %%A in ('git rev-parse --abbrev-ref HEAD') do set "mybranch=%%A" +echo #ifndef APP_GIT_BRANCH >> version_defs.h +echo #define APP_GIT_BRANCH "%mybranch%" >> version_defs.h +echo #endif >> version_defs.h +echo. >> version_defs.h +for /f "delims=" %%A in ('git log "--pretty=format:%%h" -n 1') do set "mycommit=%%A" +echo #ifndef APP_GIT_COMMIT >> version_defs.h +echo #define APP_GIT_COMMIT "%mycommit%" >> version_defs.h +echo #endif >> version_defs.h diff --git a/depthmapX/make_version_header.sh b/depthmapX/make_version_header.sh new file mode 100644 index 00000000..6a42e93d --- /dev/null +++ b/depthmapX/make_version_header.sh @@ -0,0 +1,30 @@ +rm version_defs.h +printf "// Copyright (C) 2018 Christian Sailer\n" >> version_defs.h + +printf "// This program is free software: you can redistribute it and/or modify\n" >> version_defs.h +printf "// it under the terms of the GNU General Public License as published by\n" >> version_defs.h +printf "// the Free Software Foundation, either version 3 of the License, or\n" >> version_defs.h +printf "// (at your option) any later version.\n\n" >> version_defs.h +printf "// This program is distributed in the hope that it will be useful,\n" >> version_defs.h +printf "// but WITHOUT ANY WARRANTY\; without even the implied warranty of\n" >> version_defs.h +printf "// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" >> version_defs.h +printf "// GNU General Public License for more details.\n\n" >> version_defs.h +printf "// You should have received a copy of the GNU General Public License\n" >> version_defs.h +printf "// along with this program. If not, see .\n\n" >> version_defs.h + +printf "// This file is autogenerated - do not modify it directly!\n\n" >> version_defs.h + +printf "#pragma once\n\n" >> version_defs.h + +printf "#ifndef APP_DATE\n" >> version_defs.h +printf "#define APP_DATE \"`date +%Y/%m/%d`\"\n" >> version_defs.h +printf "#endif\n\n" >> version_defs.h + +printf "#ifndef APP_GIT_BRANCH\n" >> version_defs.h +printf "#define APP_GIT_BRANCH \"`git rev-parse --abbrev-ref HEAD`\"\n" >> version_defs.h +printf "#endif\n\n" >> version_defs.h + +printf "#ifndef APP_GIT_COMMIT\n" >> version_defs.h +printf "#define APP_GIT_COMMIT \"`git log --pretty=format:'%h' -n 1`\"\n" >> version_defs.h +printf "#endif\n" >> version_defs.h + diff --git a/depthmapX/renderthread.cpp b/depthmapX/renderthread.cpp index adc78636..f536d059 100644 --- a/depthmapX/renderthread.cpp +++ b/depthmapX/renderthread.cpp @@ -15,7 +15,6 @@ #include -#include #include #include "mainwindow.h" @@ -32,10 +31,10 @@ CMSCommunicator::~CMSCommunicator() { } -inline void CMSCommunicator::CommPostMessage(int m, int x, int y) const +inline void CMSCommunicator::CommPostMessage(int m, int x) const { QGraphDoc *pDoc = (QGraphDoc *)parent_doc; - pDoc->ProcPostMessage(m, x, y); + pDoc->ProcPostMessage(m, x); } //! [0] @@ -93,7 +92,7 @@ void RenderThread::run() pDoc->modifiedFlag = true; } else if (ok == -1) { - QMessageBox::warning(0, tr("Warning"), tr("An error was found in the import file"), QMessageBox::Yes, QMessageBox::Yes); + emit showWarningMessage(tr("Warning"), tr("An error was found in the import file")); } // This might change the line layers available, alert the layer chooser: QApplication::postEvent(pMain, new QmyEvent((enum QEvent::Type)FOCUSGRAPH, (void*)pDoc, QGraphDoc::CONTROLS_LOADDRAWING)); @@ -105,26 +104,24 @@ void RenderThread::run() switch (ok) { case MINFO_MULTIPLE: //BUG - //QMessageBox::warning(0, tr("Warning"), tr("The imported MIF file contains multiple shapes per object.\n Please note that depthmapX has broken these up, so each shape has one row of attribute data.\n Please consult your MapInfo provider for details."), QMessageBox::Yes, QMessageBox::Yes); + //QMessageBox::warning(0, tr("Warning"), tr("The imported MIF file contains multiple shapes per object.\n Please note that depthmapX has broken these up, so each shape has one row of attribute data.\n Please consult your MapInfo provider for details."), QMessageBox::Ok, QMessageBox::Ok); case MINFO_OK: pDoc->SetUpdateFlag(QGraphDoc::NEW_TABLE); break; case MINFO_HEADER: - QMessageBox::warning(0, tr("Warning"), tr("depthmapX had a problem reading the header information in your MIF file."), QMessageBox::Yes, QMessageBox::Yes); + emit showWarningMessage(tr("Warning"), tr("depthmapX had a problem reading the header information in your MIF file.")); break; case MINFO_TABLE: - QMessageBox::warning(0, tr("Warning"), tr("depthmapX had a problem reading the table data in your MID file."), QMessageBox::Yes, QMessageBox::Yes); + emit showWarningMessage(tr("Warning"), tr("depthmapX had a problem reading the table data in your MID file.")); break; case MINFO_MIFPARSE: - QMessageBox::warning(0, tr("Warning"), tr("depthmapX had a problem reading the shape data in your MIF file.\n\ - Please ensure that your shape data contains only points, lines, polylines or regions."), - QMessageBox::Yes, QMessageBox::Yes); + emit showWarningMessage(tr("Warning"), tr("depthmapX had a problem reading the shape data in your MIF file.\n\ + Please ensure that your shape data contains only points, lines, polylines or regions.")); break; case MINFO_OBJROWS: - QMessageBox::warning(0, tr("Warning"), tr("depthmapX had a problem reading the shape data in your MIF file.\n\ + emit showWarningMessage(tr("Warning"), tr("depthmapX had a problem reading the shape data in your MIF file.\n\ It seems as though there are a different number of shapes to rows in the associated table.\n\ - This may be due to the existance of unsupported shape types in the file."), - QMessageBox::Yes, QMessageBox::Yes); + This may be due to the existance of unsupported shape types in the file.")); break; } pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_TOTAL, QGraphDoc::NEW_DATA ); @@ -153,17 +150,9 @@ void RenderThread::run() pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); break; - case CMSCommunicator::ANALYSEANGULAR: - ok = pDoc->m_meta_graph->analyseAngular( comm, pMain->m_options.process_in_memory ); - if (ok) { - pDoc->SetUpdateFlag(QGraphDoc::NEW_DATA); - } - pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); - break; - case CMSCommunicator::MAKEISOVIST: if (comm->GetSeedAngle() == -1.0) { - ok = pDoc->m_meta_graph->makeIsovist( comm, comm->GetSeedPoint() ); + ok = pDoc->m_meta_graph->makeIsovist( comm, comm->GetSeedPoint(), 0, 0, comm->simple_version ); } else { double ang1 = comm->GetSeedAngle() - comm->GetSeedFoV() * 0.5; @@ -172,7 +161,7 @@ void RenderThread::run() ang1 += 2.0 * M_PI; if (ang2 > 2.0 * M_PI) ang2 -= 2.0 * M_PI; - ok = pDoc->m_meta_graph->makeIsovist( comm, comm->GetSeedPoint(), ang1, ang2 ); + ok = pDoc->m_meta_graph->makeIsovist( comm, comm->GetSeedPoint(), ang1, ang2, comm->simple_version ); } if (ok) { pDoc->SetUpdateFlag(QGraphDoc::NEW_DATA); @@ -211,33 +200,33 @@ void RenderThread::run() pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); break; - case CMSCommunicator::MAKEDRAWING: + case CMSCommunicator::MAKEDRAWING: { // option 1 is: 0 a data map, 1 an axial map - ok = pDoc->m_meta_graph->convertToDrawing( comm, pstring(comm->GetString().toLatin1()), comm->GetOption(1) ); + ok = pDoc->m_meta_graph->convertToDrawing( comm, comm->GetString().toStdString(), (comm->GetOption(1) == 0)); if (ok) { pDoc->modifiedFlag = true; } else { - QMessageBox::warning(0, tr("Warning"), tr("No objects currently visible in drawing layers"), QMessageBox::Yes, QMessageBox::Yes); + emit showWarningMessage(tr("Warning"), tr("No objects currently visible in drawing layers")); } // Tell the sidebar about the new map: QApplication::postEvent(pMain, new QmyEvent((enum QEvent::Type)FOCUSGRAPH, (void*)pDoc, QGraphDoc::CONTROLS_LOADDRAWING)); pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_TOTAL, QGraphDoc::NEW_DATA ); break; - + } case CMSCommunicator::MAKEUSERMAP: - ok = pDoc->m_meta_graph->convertDrawingToAxial( comm, pstring(comm->GetString().toLatin1()) ); + ok = pDoc->m_meta_graph->convertDrawingToAxial( comm, comm->GetString().toStdString()); if (ok) { pDoc->SetUpdateFlag(QGraphDoc::NEW_TABLE); } else { - QMessageBox::warning(0, tr("Warning"), tr("No objects currently visible in drawing layers"), QMessageBox::Yes, QMessageBox::Yes); + emit showWarningMessage(tr("Warning"), tr("No objects currently visible in drawing layers")); } pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); break; case CMSCommunicator::MAKEUSERMAPSHAPE: - ok = pDoc->m_meta_graph->convertDataToAxial( comm, pstring(comm->GetString().toLatin1()), (comm->GetOption(0) == 1), (comm->GetOption(1) == 1) ); + ok = pDoc->m_meta_graph->convertDataToAxial( comm, comm->GetString().toStdString(), (comm->GetOption(0) == 1), (comm->GetOption(1) == 1) ); if (ok) { if (comm->GetOption(0) == 0) { // note: there is both a new table and a deleted table, but deleted table leads to a greater redraw: @@ -248,24 +237,24 @@ void RenderThread::run() } } else { - QMessageBox::warning(0, tr("Warning"), tr("No lines available in current layer to convert to axial lines"), QMessageBox::Yes, QMessageBox::Yes); + emit showWarningMessage(tr("Warning"), tr("No lines available in current layer to convert to axial lines")); } pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); break; case CMSCommunicator::MAKEUSERSEGMAP: - ok = pDoc->m_meta_graph->convertDrawingToSegment( comm, pstring(comm->GetString().toLatin1()) ); + ok = pDoc->m_meta_graph->convertDrawingToSegment( comm, comm->GetString().toStdString() ); if (ok) { pDoc->SetUpdateFlag(QGraphDoc::NEW_TABLE); } else { - QMessageBox::warning(0, tr("Warning"), tr("No objects currently visible in drawing layers"), QMessageBox::Yes, QMessageBox::Yes); + emit showWarningMessage(tr("Warning"), tr("No objects currently visible in drawing layers")); } pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); break; case CMSCommunicator::MAKEUSERSEGMAPSHAPE: - ok = pDoc->m_meta_graph->convertDataToSegment( comm, pstring(comm->GetString().toLatin1()), (comm->GetOption(0) == 1), (comm->GetOption(1) == 1) ); + ok = pDoc->m_meta_graph->convertDataToSegment( comm, comm->GetString().toStdString(), (comm->GetOption(0) == 1), (comm->GetOption(1) == 1) ); if (ok) { if (comm->GetOption(0) == 0) { // note: there is both a new table and a deleted table, but deleted table leads to a greater redraw: @@ -276,14 +265,20 @@ void RenderThread::run() } } else { - QMessageBox::warning(0, tr("Warning"), tr("No lines available in current layer to convert to segments"), QMessageBox::Yes, QMessageBox::Yes); + emit showWarningMessage(tr("Warning"), tr("No lines available in current layer to convert to segments")); } pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); break; - case CMSCommunicator::MAKEGATESMAP: + case CMSCommunicator::MAKEGATESMAP: { // note: relies on the fact that make data map from drawing sets option 1 to -1, whereas make data layer from graph it to either 0 or 1 - ok = pDoc->m_meta_graph->convertToData( comm, pstring(comm->GetString().toLatin1()), (comm->GetOption(0) == 1), comm->GetOption(1) ); + int shapeMapType = ShapeMap::DRAWINGMAP; + bool copydata = false; + if(comm->GetOption(1) != -1) { + shapeMapType = ShapeMap::DATAMAP; + copydata = (comm->GetOption(1) != 0); + } + ok = pDoc->m_meta_graph->convertToData( comm, comm->GetString().toStdString(), (comm->GetOption(0) == 1), shapeMapType, copydata ); if (ok) { if (comm->GetOption(0) == 0) { // note: there is both a new table and a deleted table, but deleted table leads to a greater redraw: @@ -294,14 +289,20 @@ void RenderThread::run() } } else { - QMessageBox::warning(0, tr("Warning"), tr("No objects currently visible in drawing layers"), QMessageBox::Yes, QMessageBox::Yes); + emit showWarningMessage(tr("Warning"), tr("No objects currently visible in drawing layers")); } pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); break; - - case CMSCommunicator::MAKECONVEXMAP: + } + case CMSCommunicator::MAKECONVEXMAP: { // note: relies on the fact that make convex map from drawing sets option 1 to -1, whereas make convex map from data sets it to either 0 or 1 - ok = pDoc->m_meta_graph->convertToConvex( comm, pstring(comm->GetString().toLatin1()), (comm->GetOption(0) == 1), comm->GetOption(1) ); + int shapeMapType = ShapeMap::DRAWINGMAP; + bool copydata = false; + if(comm->GetOption(1) != -1) { + shapeMapType = ShapeMap::DATAMAP; + copydata = (comm->GetOption(1) != 0); + } + ok = pDoc->m_meta_graph->convertToConvex( comm, comm->GetString().toStdString(), (comm->GetOption(0) == 1), shapeMapType, copydata); if (ok) { if (comm->GetOption(0) == 0) { // note: there is both a new table and a deleted table, but deleted table leads to a greater redraw: @@ -312,17 +313,17 @@ void RenderThread::run() } } else { - QMessageBox::warning(0, tr("Warning"), tr("No polygons currently visible in drawing layers"), QMessageBox::Yes, QMessageBox::Yes); + emit showWarningMessage(tr("Warning"), tr("No polygons currently visible in drawing layers")); } pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); break; - + } case CMSCommunicator::MAKEBOUNDARYMAP: break; case CMSCommunicator::MAKESEGMENTMAP: // convert percentage to fraction, and pass to metagraph - ok = pDoc->m_meta_graph->convertAxialToSegment( comm, pstring(comm->GetString().toLatin1()), (comm->GetOption(0) == 1), (comm->GetOption(1) == 1), double(comm->GetOption(2)) / 100.0); + ok = pDoc->m_meta_graph->convertAxialToSegment( comm, comm->GetString().toStdString(), (comm->GetOption(0) == 1), (comm->GetOption(1) == 1), double(comm->GetOption(2)) / 100.0); if (ok) { if (comm->GetOption(0) == 0) { // note: there is both a new table and a deleted table, but deleted table leads to a greater redraw: @@ -333,7 +334,7 @@ void RenderThread::run() } } else { - QMessageBox::warning(0, tr("Warning"), tr("No lines exist in map to convert to segments"), QMessageBox::Yes, QMessageBox::Yes); + emit showWarningMessage(tr("Warning"), tr("No lines exist in map to convert to segments")); } pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); break; @@ -346,24 +347,24 @@ void RenderThread::run() pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); break; - case CMSCommunicator::SEGMENTANALYSIS: - ok = pDoc->m_meta_graph->analyseSegments( comm, pMain->m_options ); + case CMSCommunicator::SEGMENTANALYSISTULIP: + ok = pDoc->m_meta_graph->analyseSegmentsTulip( comm, pMain->m_options ); if (ok) { pDoc->SetUpdateFlag(QGraphDoc::NEW_DATA); } pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); break; - case CMSCommunicator::TOPOMETANALYSIS: - ok = pDoc->m_meta_graph->analyseTopoMet( comm, pMain->m_options ); + case CMSCommunicator::SEGMENTANALYSISANGULAR: + ok = pDoc->m_meta_graph->analyseSegmentsAngular( comm, pMain->m_options ); if (ok) { pDoc->SetUpdateFlag(QGraphDoc::NEW_DATA); } pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); break; - case CMSCommunicator::MAKEAXIALLINES: - ok = pDoc->m_meta_graph->makeAxialLines( comm, pMain->m_options.process_in_memory ); + case CMSCommunicator::TOPOMETANALYSIS: + ok = pDoc->m_meta_graph->analyseTopoMet( comm, pMain->m_options ); if (ok) { pDoc->SetUpdateFlag(QGraphDoc::NEW_DATA); } @@ -432,114 +433,18 @@ void RenderThread::run() case CMSCommunicator::AGENTANALYSIS: { - pDoc->m_meta_graph->runAgentEngine( comm ); - pDoc->SetUpdateFlag(QGraphDoc::NEW_DATA); - pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DATA ); - } - break; - - case CMSCommunicator::BINDISPLAY: - { - // Set up for options metric point depth selection - Options options; - options.global = 0; - options.point_depth_selection = 4; - - ok = pDoc->m_meta_graph->analyseGraph( comm, options, comm->simple_version ); - if (ok) { - pDoc->SetUpdateFlag(QGraphDoc::NEW_DATA); - } - pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DATA ); - } - break; - - case CMSCommunicator::IMPORTEDANALYSIS: - { -/* int analysis_type = comm->GetModule().m_analysis_type[ comm->GetOption() ]; - - // temporarily disable VGA from the metagraph to avoid redraw problems: - int state = pDoc->m_meta_graph->getState(); - if (analysis_type & DLL_GRAPH_FILE_ANALYSIS) { - state &= ~(MetaGraph::POINTMAPS | MetaGraph::SHAPEGRAPHS | MetaGraph::DATAMAPS); - } - else if (analysis_type & DLL_VGA_ANALYSIS) { - state &= ~MetaGraph::POINTMAPS; - } - else if (analysis_type & (DLL_AXIAL_ANALYSIS | DLL_SEGMENT_ANALYSIS)) { - state &= ~MetaGraph::SHAPEGRAPHS; - } - else if (analysis_type & DLL_DATA_ANALYSIS) { - state &= ~MetaGraph::DATAMAPS; - } - pDoc->m_meta_graph->setState(state); - // - FUNC_PROCESSVGA processVGA = (FUNC_PROCESSVGA)GetProcAddress(comm->GetModule().m_inst,"processVGA"); - FUNC_PROCESSSHAPE processShape = (FUNC_PROCESSSHAPE)GetProcAddress(comm->GetModule().m_inst,"processShape"); - FUNC_PROCESSATTRIBUTES processAttributes = (FUNC_PROCESSATTRIBUTES)GetProcAddress(comm->GetModule().m_inst,"processAttributes"); - FUNC_PROCESSGRAPHFILE processGraphFile = (FUNC_PROCESSGRAPHFILE)GetProcAddress(comm->GetModule().m_inst,"processGraphFile"); - FUNC_POSTPROCESS postprocess = (FUNC_POSTPROCESS)GetProcAddress(comm->GetModule().m_inst,"postprocess"); - // - IComm dllcomm; - dllcomm.setData( (void *) comm ); - IVGAMap dllvga; - IShapeMap dllshape; - IGraphFile dllgraph; - if (analysis_type & DLL_GRAPH_FILE_ANALYSIS) { - dllgraph.setData( (void *) pDoc->m_meta_graph ); - } - if (analysis_type & DLL_VGA_ANALYSIS) { - dllvga.setData( (void *) &(pDoc->m_meta_graph->getDisplayedPointMap()) ); - } - if (analysis_type & (DLL_AXIAL_ANALYSIS | DLL_SEGMENT_ANALYSIS)) { - dllshape.setData( (void *) &(pDoc->m_meta_graph->getDisplayedShapeGraph()) ); - } - else if (analysis_type & DLL_DATA_ANALYSIS) { - dllshape.setData( (void *) &(pDoc->m_meta_graph->getDisplayedDataMap()) ); - } - IAttributes dllattr; - dllattr.setData( (void *) &(pDoc->m_meta_graph->getAttributeTable()), analysis_type ); - // - ok = false; - if ((analysis_type & DLL_GRAPH_FILE_ANALYSIS) && processGraphFile != NULL) { - ok = processGraphFile( comm->GetOption(), &dllcomm, &dllgraph ); - } - else if ((analysis_type & DLL_VGA_ANALYSIS) && processVGA != NULL) { - ok = processVGA( comm->GetOption(), &dllcomm, &dllvga, &dllattr ); - } - else if ((analysis_type & (DLL_AXIAL_ANALYSIS | DLL_SEGMENT_ANALYSIS | DLL_DATA_ANALYSIS)) && processShape != NULL) { - ok = processShape( comm->GetOption(), &dllcomm, &dllshape, &dllattr ); - } - else if ((analysis_type & DLL_ATTRIBUTE_ANALYSIS) && processAttributes != NULL) { - ok = processAttributes( comm->GetOption(), &dllcomm, &dllattr ); - } - // - // Now, the new file stuff could have added new layers or deleted them... we'll need to just explicitly check what's in the file and set the state accordingly: - if (pDoc->m_meta_graph->PointMaps::size() > 0) { - state |= MetaGraph::POINTMAPS; - } - if (pDoc->m_meta_graph->m_data_maps.getMapCount() > 0) { - state |= MetaGraph::DATAMAPS; - } - if (pDoc->m_meta_graph->m_shape_graphs.getMapCount() > 0) { - state |= MetaGraph::SHAPEGRAPHS; - } - // at this stage, before redraw, it is time to set the old state back on: - pDoc->m_meta_graph->setState(state); - // - // - if (ok) { - pDoc->SetUpdateFlag(QGraphDoc::NEW_TABLE); // includes set modified flag (note: 10.04.08 NEW_TABLE required because analysis may create a new table) - if (postprocess != NULL) { - postprocess( comm->GetOption() ); - } - } - // note: a total redraw is required in case new geometry has been added (new to Dmap 8) - pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_TOTAL, QGraphDoc::NEW_DATA );*/ + try { + pDoc->m_meta_graph->runAgentEngine( comm ); + pDoc->SetUpdateFlag(QGraphDoc::NEW_TABLE); + pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DATA ); + } catch (depthmapX::PointMapException const & e) { + emit runtimeExceptionThrown(e.getErrorType(), e.what()); + } } break; } - pDoc->DestroyWaitDialog(); + emit closeWaitDialog(); msleep(100); delete pDoc->m_communicator; // Ensure we delete *the* communicator pDoc->m_communicator = NULL; diff --git a/depthmapX/resources/Info.plist b/depthmapX/resources/Info.plist new file mode 100644 index 00000000..ce67a420 --- /dev/null +++ b/depthmapX/resources/Info.plist @@ -0,0 +1,33 @@ + + + + + NSPrincipalClass + NSApplication + CFBundleIconFile + depthmapX.icns + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleExecutable + depthmapX + CFBundleIdentifier + com.spacegroupucl.depthmapX + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + graph + + CFBundleTypeName + Graph File + CFBundleTypeRole + Editor + CFBundleTypeIconFile + graph.icns + + + + diff --git a/depthmapX/settings.h b/depthmapX/settings.h new file mode 100644 index 00000000..cccb1e6e --- /dev/null +++ b/depthmapX/settings.h @@ -0,0 +1,63 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once +#include +#include +#include + + +/** + * Tags for settings to be used when reading writing settings. Don't just use + * string literals + */ +namespace SettingTag +{ + const QString position = "pos"; + const QString size = "size"; + const QString foregroundColour = "forColor"; + const QString backgroundColour = "backColor"; + const QString antialiasingSamples = "antialisingSamples"; + const QString simpleVersion = "simple"; + const QString recentFileList = "recentFileList"; + const QString mwMaximised = "mainWindowMaximised"; + const QString licenseAccepted = "licenseAccepted"; + const QString depthmapViewSize = "depthmapViewSize"; + const QString legacyMapWindow = "legacyMapWindow"; +} + +/** + * @brief Class encapsulating one settings transaction + * This is supposed to use one underlying QSettings object for several reads/writes + */ +class SettingsTransaction +{ +public: + virtual const QVariant readSetting( const QString& tag, const QVariant& defaultValue = QVariant()) const = 0; + virtual void writeSetting( const QString& tag, const QVariant& value) = 0; + virtual ~SettingsTransaction(){} +}; + +/** + * @brief The Settings class + * Encapsulates reading/writing settings so we don't have to faff around with constructing QSettings in + * 7 different location. The read/write methods on this class create a temporary QSettings object, so + * if you want to read/write more than one setting in one go, use a transaction. + */ +class Settings : public SettingsTransaction +{ +public: + virtual std::unique_ptr getTransaction() = 0; +}; diff --git a/depthmapX/settingsimpl.cpp b/depthmapX/settingsimpl.cpp new file mode 100644 index 00000000..a1769c8e --- /dev/null +++ b/depthmapX/settingsimpl.cpp @@ -0,0 +1,58 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#include "settingsimpl.h" + +SettingsImpl::SettingsImpl(QSettingsFactory* factory) : mSettingsFactory(factory) +{ + +} + + +const QVariant SettingsImpl::readSetting(const QString &tag, const QVariant &defaultValue) const +{ + auto settings = mSettingsFactory->getSettings(); + return settings->value(tag, defaultValue); +} + +void SettingsImpl::writeSetting(const QString &tag, const QVariant &value) +{ + auto settings = mSettingsFactory->getSettings(); + settings->setValue(tag, value); +} + +class SettingsTransactionImpl : public SettingsTransaction +{ +public: + SettingsTransactionImpl(std::unique_ptr &&settings) : mSettings(std::move(settings)) + {} + virtual const QVariant readSetting(const QString &tag, const QVariant &defaultValue) const + { + return mSettings->value(tag, defaultValue); + } + virtual void writeSetting(const QString &tag, const QVariant &value) + { + mSettings->setValue(tag, value); + } + +private: + std::unique_ptr mSettings; +}; + +std::unique_ptr SettingsImpl::getTransaction() +{ + return std::unique_ptr(new SettingsTransactionImpl(mSettingsFactory->getSettings())); +} diff --git a/depthmapX/settingsimpl.h b/depthmapX/settingsimpl.h new file mode 100644 index 00000000..0ef97fa4 --- /dev/null +++ b/depthmapX/settingsimpl.h @@ -0,0 +1,65 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#pragma once +#include "settings.h" +#include +#include +#include + +class QSettingsFactory +{ +public: + virtual std::unique_ptr getSettings() const = 0; + virtual ~QSettingsFactory() {} +}; + +class DefaultSettingsFactory : public QSettingsFactory +{ +public: + DefaultSettingsFactory() + { + m_settingsFile = QStandardPaths::standardLocations(QStandardPaths::AppConfigLocation).first() + "/depthmapXsettings.ini"; + } + + // QSettingsFactory interface +public: + virtual std::unique_ptr getSettings() const + { + return std::unique_ptr(new QSettings(m_settingsFile, QSettings::IniFormat)); + } + +private: + QString m_settingsFile; +}; + +class SettingsImpl : public Settings +{ +public: + SettingsImpl(QSettingsFactory *settingsFactory); + + // SettingsTransaction interface +public: + virtual const QVariant readSetting(const QString &tag, const QVariant &defaultValue) const; + virtual void writeSetting(const QString &tag, const QVariant &value); + + // Settings interface + virtual std::unique_ptr getTransaction(); + +private: + std::unique_ptr mSettingsFactory; + +}; diff --git a/depthmapX/tableView.cpp b/depthmapX/tableView.cpp deleted file mode 100644 index d8ea2795..00000000 --- a/depthmapX/tableView.cpp +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "mainwindow.h" -#include "tableView.h" - -#define ROW_HEIGHT 20 -#define PG_COUNT 40 - -static bool in_update = 0; - -tableView::tableView(QWidget *parent, QGraphDoc* p) - : QTableWidget(parent) -{ - pDoc = p; - m_from = m_curr_row = 0; - - connect(this, SIGNAL(itemChanged(QTableWidgetItem*)), this, - SLOT(itemChanged(QTableWidgetItem*))); - - connect(this, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, - SLOT(itemEditChanged(QTableWidgetItem*))); - - RedoTable(); - setWindowIcon(QIcon(tr(":/images/cur/icon-1-5.png"))); - setWindowTitle(pDoc->m_base_title+":Table View"); - - m_protect_edit = false; -} - -tableView::~tableView() -{ - // nothing todo -} - -void tableView::RedoTable() -{ - clear(); - - if (pDoc->m_meta_graph->viewingProcessed()) { - const AttributeTable& table = pDoc->m_meta_graph->getAttributeTable(); - const AttributeIndex& index = table.m_display_index; - int col = pDoc->m_meta_graph->getDisplayedAttribute(); - int i; - - m_column_count = table.getColumnCount(); - setColumnCount(m_column_count+1); - connect(horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(colum_Sort(int))); - verticalHeader()->hide(); - - QTableWidgetItem *Item = new QTableWidgetItem("Ref Number"); - Item->setTextAlignment(Qt::AlignLeft); - setHorizontalHeaderItem(0, Item); - - for (i = 0; i < m_column_count; i++) { - QTableWidgetItem *Item = new QTableWidgetItem(QString("%1").arg(table.getColumnName(i).c_str())); - Item->setTextAlignment(Qt::AlignLeft); - setHorizontalHeaderItem(i+1, Item); - } - - m_row_count = table.getRowCount(); - setRowCount(m_row_count); - PrepareCache(0, m_curr_row); - } -} - -void tableView::scrollContentsBy(int dx, int dy) -{ - if(!dy){ - QTableWidget::scrollContentsBy(dx, 0); - return; - } - PrepareCache(m_curr_row, m_curr_row - dy); - m_curr_row -= dy; - QTableWidget::scrollContentsBy(dx, dy); -} - -QSize tableView::sizeHint() const -{ - return QSize(2000, 2000); -} - -void tableView::PrepareCache(int from, int to) -{ - in_update = 1; - QTableWidgetItem *Item; - const AttributeTable& table = pDoc->m_meta_graph->getAttributeTable(); - AttributeIndex& index = table.m_display_index; - - if(to+PG_COUNT >= m_row_count) return; - for (int i = 0; i < PG_COUNT; i++) - { - for (int j = 0; j < m_column_count+1; j++) - { - if(!j) - { - if(Item = item(to+i, j)) - { - if(table.isSelected(to+i)) Item->setCheckState(Qt::Checked); - else Item->setCheckState(Qt::Unchecked); - } - else - { - Item = new QTableWidgetItem(QString("%1").arg(table.getRowKey(index[to+i].index))); - if(table.isSelected(to+i)) Item->setCheckState(Qt::Checked); - else Item->setCheckState(Qt::Unchecked); - setItem(to+i, 0, Item); - continue; - } - } - if(!item(to+i, j)) - { - Item = new QTableWidgetItem(QString("%1").arg(table.getValue(index[to+i].index, j-1))); - setRowHeight(to+i, ROW_HEIGHT); - setItem(to+i, j, Item); - } - } - } - in_update = 0; -} - -void tableView::itemChanged(QTableWidgetItem * item) -{ - if(in_update) return; - int row = item->row(); - int col = item->column(); - if(col == 0) - { - pvecint x; - AttributeTable& table = pDoc->m_meta_graph->getAttributeTable(); - AttributeIndex& index = table.m_display_index; - x.push_back(table.getRowKey(index[row].index)); - pDoc->m_meta_graph->setSelSet(x); - pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_SELECTION, this); - PrepareCache(0, m_curr_row); - } - else - { - wchar_t *endptr; - // first reset contents: - double value = wcstod((wchar_t*)item->text().utf16(), &endptr); // AT: Unicode conversion -- this doesn't look safe -- edittext is a CString! - if (endptr == (wchar_t*)item->text().utf16()) { - QMessageBox::warning(this, tr("Warning"), tr("Cannot convert text to number"), QMessageBox::Ok, QMessageBox::Ok); - return; - } - - MetaGraph *graph = pDoc->m_meta_graph; - if (graph && graph->viewingProcessed()) { - // go for the change: - AttributeTable &table = graph->getAttributeTable(); - double value2 = table.getValue(table.m_display_index[row].index, col-1); - if (value2 == 0 || fabs((value / value2) - 1.0) > 1e-5) { - table.changeValue(table.m_display_index[row].index, col-1, value); - pDoc->modifiedFlag = true; - } - - RedoTable(); - // note: this as caller will prevent us from redrawing ourself: - // could be either new data or new selection, just go for a big redraw: - pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA,this); - } - } -} - -void tableView::colum_Sort(int col_id) -{ - if (col_id - 1 != pDoc->m_meta_graph->getDisplayedAttribute()) - { - pDoc->m_meta_graph->setDisplayedAttribute(col_id - 1); - clearContents(); - PrepareCache(0, m_curr_row); - return; - - RedoTable(); - } -} - -int tableView::OnRedraw(int wParam, int lParam) -{ - bool done = false; - if (pDoc->GetRemenuFlag(QGraphDoc::VIEW_TABLE)) { - pDoc->SetRemenuFlag(QGraphDoc::VIEW_TABLE,false); - // this is big: start from scratch... - RedoTable(); - done = true; - } - int flag = pDoc->GetRedrawFlag(QGraphDoc::VIEW_TABLE); - if (flag != QGraphDoc::REDRAW_DONE) { - // - while (!pDoc->SetRedrawFlag(QGraphDoc::VIEW_TABLE,QGraphDoc::REDRAW_DONE)) { - // prefer waitformultipleobjects here - } - // - if (!done && lParam != (long) this) { - if (wParam == QGraphDoc::NEW_TABLE) { - // this is big start from scratch... - RedoTable(); - done = true; - } - else { - // redo the cache and redisplay - PrepareCache(0, m_curr_row); - } - } - } - - return 0; -} - -void tableView::itemEditChanged(QTableWidgetItem* item) -{ - int row = item->row(); - int col = item->column(); - - if (col > 0 && col < pDoc->m_meta_graph->getAttributeTable().getColumnCount() + 1) { - // don't let them edit a locked attribute - if (pDoc->m_meta_graph->getAttributeTable().isColumnLocked(col-1)) { - QMessageBox::warning(this, tr("Warning"), tr("This column is locked and cannot be edited"), QMessageBox::Ok, QMessageBox::Ok); - } - } -} - -void tableView::closeEvent(QCloseEvent *event) -{ - pDoc->m_view[QGraphDoc::VIEW_TABLE] = NULL; - if (!pDoc->OnCloseDocument(QGraphDoc::VIEW_TABLE)) - { - pDoc->m_view[QGraphDoc::VIEW_TABLE] = this; - event->ignore(); - } -} - -void tableView::resizeEvent(QResizeEvent *event) -{ - pDoc->m_view[QGraphDoc::VIEW_TABLE] = this; -} diff --git a/depthmapX/treeWindow.cpp b/depthmapX/treeWindow.cpp index 311e209e..40070639 100644 --- a/depthmapX/treeWindow.cpp +++ b/depthmapX/treeWindow.cpp @@ -29,17 +29,15 @@ QT_BEGIN_NAMESPACE -indexWidget::indexWidget(QWidget *parent, bool custom) +IndexWidget::IndexWidget(QWidget *parent) : QTreeWidget(parent) - , m_custom(custom) { - if (m_custom) { - setColumnCount(2); - hideColumn(1); - setHeaderLabel(tr("Bookmarks")); - } else { - header()->hide(); - } + setColumnCount(2); + setHeaderLabels(columnNames); + header()->setSectionResizeMode(Column::MAP, QHeaderView::Stretch); + header()->setSectionResizeMode(Column::EDITABLE, QHeaderView::ResizeToContents); + header()->resizeSection(Column::EDITABLE, 10); + header()->setStretchLastSection(false); installEventFilter(this); setContextMenuPolicy(Qt::CustomContextMenu); @@ -48,16 +46,11 @@ indexWidget::indexWidget(QWidget *parent, bool custom) SLOT(OnSelchangingTree(QTreeWidgetItem*, int))); } -indexWidget::~indexWidget() -{ - // nothing todo -} - -void indexWidget::removeAllItem(QTreeWidgetItem *start) +void IndexWidget::removeAllItem(QTreeWidgetItem *start) { int index; QTreeWidgetItem *currentItem = start; - if(currentItem) //while (currentItem) + if(currentItem) { QTreeWidgetItem *parent = currentItem->parent(); if (parent) { @@ -70,76 +63,20 @@ void indexWidget::removeAllItem(QTreeWidgetItem *start) } } -QTreeWidgetItem* indexWidget::addNewRootFolder(const QString &title) -{ - QString folderName = title; - QTreeWidgetItem *newItem = 0; - - QStringList columnStrings(folderName); - columnStrings << QLatin1String("Folder"); - newItem = new QTreeWidgetItem(this, columnStrings); - - setCurrentItem(newItem); - return newItem; -} - -QTreeWidgetItem* indexWidget::addNewFolder(const QString &title, QTreeWidgetItem *parent) -{ - QString folderName = title; - - QTreeWidgetItem *newItem = 0; - QTreeWidgetItem *treeItem = itemIfNotDirectory(); - - QStringList columnStrings(folderName); - columnStrings << QLatin1String("Folder"); - if(parent) - { - newItem = new QTreeWidgetItem(parent, columnStrings); - } - else if (treeItem) { - newItem = new QTreeWidgetItem(columnStrings); - treeItem->addChild(newItem); - } - else { - newItem = new QTreeWidgetItem(this, columnStrings); - } - - setCurrentItem(newItem); - newItem->setFlags(newItem->flags() &~ (Qt::ItemIsEditable | Qt::ItemIsSelectable)); - return newItem; -} - -QTreeWidgetItem * indexWidget::addNewItem(const QString &title, const QString &url) +QTreeWidgetItem * IndexWidget::addNewItem(const QString &title, QTreeWidgetItem* parent) { QTreeWidgetItem *newItem = 0; - QTreeWidgetItem *treeItem = itemIfNotDirectory(); QStringList columnStrings(title); - if (treeItem) { - newItem = new QTreeWidgetItem(columnStrings);// << url); - treeItem->insertChild(0, newItem); + if (parent != NULL) { + newItem = new QTreeWidgetItem(parent, columnStrings); } else { - newItem = new QTreeWidgetItem(this, columnStrings);// << url); + newItem = new QTreeWidgetItem(this, columnStrings); } setCurrentItem(newItem); newItem->setFlags(newItem->flags() &~ (Qt::ItemIsEditable | Qt::ItemIsSelectable)); return newItem; - - if(url == "") return NULL; -} - - -QTreeWidgetItem* indexWidget::itemIfNotDirectory() -{ - QTreeWidgetItem *currentItem = this->currentItem(); - - if (currentItem) { - QString data = currentItem->data(1, Qt::DisplayRole).toString(); - if (data != QLatin1String("Folder")) - currentItem = currentItem->parent(); - } - return currentItem; } diff --git a/depthmapX/treeWindow.h b/depthmapX/treeWindow.h index 165238cc..5341a2bc 100644 --- a/depthmapX/treeWindow.h +++ b/depthmapX/treeWindow.h @@ -24,28 +24,51 @@ QT_BEGIN_NAMESPACE class QEvent; class QTreeWidgetItem; -class indexWidget : public QTreeWidget +class IndexWidget : public QTreeWidget { Q_OBJECT +private: + enum Column {MAP = 0, EDITABLE = 1}; public: - indexWidget(QWidget *parent = 0, bool custom = true); - ~indexWidget(); + IndexWidget(QWidget *parent = 0); + + QString m_mapColumn = "Map"; + QString m_editableColumn = "Editable"; + + void setItemVisibility(QTreeWidgetItem* item, Qt::CheckState checkState) { + item->setCheckState(Column::MAP, checkState); + } + void setItemEditability(QTreeWidgetItem* item, Qt::CheckState checkState) { + item->setCheckState(Column::EDITABLE, checkState); + } + void setItemReadOnly(QTreeWidgetItem* item) { + item->setData(Column::EDITABLE, Qt::CheckStateRole, QVariant()); + } + bool isItemSetVisible(QTreeWidgetItem* item) { + return item->checkState(Column::MAP); + } + bool isItemSetEditable(QTreeWidgetItem* item) { + return item->checkState(Column::EDITABLE); + } + bool isMapColumn(int col) { + return col == Column::MAP; + } + bool isEditableColumn(int col) { + return col == Column::EDITABLE; + } signals: void requestShowLink(const QUrl& url); public slots: - void removeAllItem(QTreeWidgetItem *start); - QTreeWidgetItem* addNewRootFolder(const QString &title); - QTreeWidgetItem * addNewFolder(const QString &title, QTreeWidgetItem *parent = 0); - QTreeWidgetItem * addNewItem(const QString& title, const QString &url); - -private: - QTreeWidgetItem* itemIfNotDirectory(); + void removeAllItem(QTreeWidgetItem *start); + QTreeWidgetItem * addNewItem(const QString& title, QTreeWidgetItem *parent = NULL); private: - bool m_custom; + QStringList columnNames = (QStringList() + << m_mapColumn + << m_editableColumn); }; QT_END_NAMESPACE diff --git a/depthmapX/3DView.cpp b/depthmapX/views/3dview/3dview.cpp similarity index 85% rename from depthmapX/3DView.cpp rename to depthmapX/views/3dview/3dview.cpp index 4d747a6c..8acde114 100644 --- a/depthmapX/3DView.cpp +++ b/depthmapX/views/3dview/3dview.cpp @@ -14,17 +14,16 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#include "3dview.h" -// 3DView.cpp : implementation file -// +#include "depthmapX/mainwindow.h" + +#include "genlib/xmlparse.h" #include #include #include #include -#include -#include "mainwindow.h" -#include "3DView.h" #ifdef __APPLE__ #include @@ -34,6 +33,8 @@ #include #endif +#include "glureimpl.h" + #ifndef _WIN32 // Not working? #define LOBYTE(w) ((unsigned char)((w) & 0xff)) #define GetRValue(rgb) (LOBYTE(rgb)) @@ -55,11 +56,10 @@ // Q3DView Q3DView::Q3DView(QWidget *parent, QGraphDoc* doc) - : QGLWidget(QGLFormat(QGL::SampleBuffers), parent) + : QOpenGLWidget(parent) { m_points = NULL; m_pointcount = 0; - m_lock_draw = false; m_mouse_mode = ID_3D_ROT;//resouce m_mouse_mode_on = 0; m_key_mode_on = 0; @@ -137,7 +137,7 @@ void Q3DView::timerEvent(QTimerEvent *event) if (!m_animating) { // if animating will redraw below DrawScene(); } - updateGL(); + update(); } else if (m_key_mode_on) { QSize diff(0,0); @@ -186,10 +186,10 @@ void Q3DView::timerEvent(QTimerEvent *event) PixelRef pix = pointmap.pixelate(p); // note, take the pix before you scale! p.normalScale(m_region); m_mannequins[i].advance(p); - size_t x = m_pixels.searchindex(pix); - if (x != paftl::npos) { - if (m_pixels[x].m_value < 10) { - m_pixels[x].m_value += 1; + auto iter = m_pixels.find(pix); + if (iter != m_pixels.end()) { + if (iter->second.m_value < 10) { + iter->second.m_value += 1; } } } @@ -207,10 +207,10 @@ void Q3DView::timerEvent(QTimerEvent *event) // // pretty coloured pixels PixelRef pix = m_agents[j].getNode(); - size_t x = m_pixels.searchindex(pix); - if (x != paftl::npos) { - if (m_pixels[x].m_value < 10) { - m_pixels[x].m_value += 1; + auto iter = m_pixels.find(pix); + if (iter != m_pixels.end()) { + if (iter->second.m_value < 10) { + iter->second.m_value += 1; } } } @@ -235,10 +235,10 @@ void Q3DView::initializeGL() void Q3DView::DrawScene() { - if (m_lock_draw) { - return; - } - m_lock_draw = true; + std::unique_lock lock(m_draw_mutex, std::try_to_lock); + if (!lock.owns_lock()){ + return; + } makeCurrent(); @@ -247,7 +247,7 @@ void Q3DView::DrawScene() QRgb bg = qRgb(0,0,0); QRgb fg = qRgb(128,128,128); - glClearColor((GLfloat)GetRValue(bg)/255.0f,(GLfloat)GetGValue(bg)/255.0f,(GLfloat)GetBValue(bg)/255.0f, 0.0f); + glClearColor((GLfloat)GetRValue(bg)/255.0f,(GLfloat)GetGValue(bg)/255.0f,(GLfloat)GetBValue(bg)/255.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(1.0f,0.0f,0.0f); @@ -270,11 +270,12 @@ void Q3DView::DrawScene() // okay, you can go for it and draw all the squares in cutesy 3d: PointMap& pointmap = pDoc->m_meta_graph->getDisplayedPointMap(); AttributeTable& table = pointmap.getAttributeTable(); - for (int i = 0; i < table.getRowCount(); i++) { - PixelRef pix = table.getRowKey(i); + + for (auto iter = table.begin(); iter != table.end(); iter++) { + PixelRef pix = iter->getKey().value; PafColor color; int col = pointmap.getDisplayedAttribute(); - float value = table.getNormValue(i,col); + float value = iter->getRow().getNormalisedValue(col); if (value != -1.0f) { color.makeAxmanesque(value); glColor3f(color.redf(),color.greenf(),color.bluef()); @@ -290,8 +291,8 @@ void Q3DView::DrawScene() } } else { - for (size_t i = 0; i < m_pixels.size(); i++) { - int& value = m_pixels[i].m_value; + for (auto pixel: m_pixels) { + int& value = pixel.second.m_value; if (value != -1) { if (pafrand() % 10000 == 0) { value--; @@ -299,7 +300,7 @@ void Q3DView::DrawScene() PafColor color; color.makeAxmanesque(float(value)/10.0f); glColor3f(color.redf(),color.greenf(),color.bluef()); - Point2f& p = m_pixels[i].m_point; + Point2f& p = pixel.second.m_point; glPushMatrix(); glTranslatef(p.x,p.y,0.0f); glVertexPointer(3, GL_FLOAT, 0, m_rect); @@ -318,20 +319,20 @@ void Q3DView::DrawScene() glFlush(); -#if defined(_WIN32) +#if defined(_MSC_VER) SwapBuffers(wglGetCurrentDC()); #else ; #endif - - m_lock_draw = false; } void Q3DView::Reshape(int x, int y) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); - gluPerspective(45.0f, (GLfloat) x / (GLfloat) y, 0.1f, 3.0f); + + gluReimpl::gluPerspective(45.0f, (GLfloat) x / (GLfloat) y, 0.1f, 3.0f); + // leave matrix mode in model view: glMatrixMode(GL_MODELVIEW); } @@ -362,35 +363,32 @@ void Q3DView::ReloadLineData() if (pDoc->m_meta_graph && pDoc->m_meta_graph->getState() & MetaGraph::LINEDATA) { // should really check communicator is not open... - pDoc->m_meta_graph->setLock(this); - while (m_lock_draw) { - //sleep(1); - } - m_lock_draw = true; - - SuperSpacePixel& superspacepix = *(pDoc->m_meta_graph); - - prefvec lines; - for (int i = 0; i < superspacepix.size(); i++) { - for (int j = 0; j < superspacepix.at(i).size(); j++) { - if (superspacepix.at(i).at(j).isShown()) { - if (m_region.isNull()) { - m_region = superspacepix.at(i).at(j).getRegion(); + auto mgraphLock = pDoc->m_meta_graph->getLock(); + std::unique_lock drawLock(m_draw_mutex); + + std::vector lines; + for (const auto& pixelGroup: pDoc->m_meta_graph->m_drawingFiles) { + for (const auto& pixel: pixelGroup.m_spacePixels) { + if (pixel.isShown()) { + if (m_region.atZero()) { + m_region = pixel.getRegion(); } else { - m_region = runion(m_region,superspacepix.at(i).at(j).getRegion()); + m_region = runion(m_region, pixel.getRegion()); } - for (int k = 0; k < superspacepix.at(i).at(j).getAllShapes().size(); k++) { - SalaShape& shape = superspacepix.at(i).at(j).getAllShapes().at(k); + + auto refShapes = pixel.getAllShapes(); + for (const auto& refShape: refShapes) { + const SalaShape& shape = refShape.second; if (shape.isLine()) { lines.push_back(shape.getLine()); } else if (shape.isPolyLine() || shape.isPolygon()) { - for (int n = 0; n < shape.size() - 1; n++) { - lines.push_back(Line(shape[n],shape[n+1])); + for (int n = 0; n < shape.m_points.size() - 1; n++) { + lines.push_back(Line(shape.m_points[n],shape.m_points[n+1])); } if (shape.isPolygon()) { - lines.push_back(Line(shape.tail(),shape.head())); + lines.push_back(Line(shape.m_points.back(),shape.m_points.front())); } } } @@ -427,9 +425,6 @@ void Q3DView::ReloadLineData() m_points[i*3+2] = 0.0; } } - - m_lock_draw = false; - pDoc->m_meta_graph->releaseLock(this); } // note: as affects region, will also affect point data: @@ -452,7 +447,7 @@ void Q3DView::ReloadPointData() if (pDoc->m_meta_graph && pDoc->m_meta_graph->viewingProcessedPoints()) { // - if (!m_region.isNull()) { + if (!m_region.atZero()) { GLfloat unit = pDoc->m_meta_graph->getDisplayedPointMap().getSpacing() / m_region.width(); m_male_template.Init(unit, true); m_female_template.Init(unit, false); @@ -470,11 +465,11 @@ void Q3DView::ReloadPointData() m_pixels.clear(); PointMap& map = pDoc->m_meta_graph->getDisplayedPointMap(); AttributeTable& table = map.getAttributeTable(); - for (int i = 0; i < table.getRowCount(); i++) { - PixelRef pix = table.getRowKey(i); + for (const auto& iter: table) { + PixelRef pix = iter.getKey().value; Point2f p = map.depixelate(pix); p.normalScale(m_region); - m_pixels.add(pix,C3DPixelData(p)); + m_pixels[pix] = C3DPixelData(p); } } else { @@ -527,17 +522,14 @@ void Q3DView::OnToolsAgentLoadProgram() return; } - pstring filename = pstring(infiles[0].toLatin1()); + std::string filename = infiles[0].toStdString(); if (!filename.empty()) { m_animating = false; - while (m_lock_draw) { - //sleep(1); - } - m_lock_draw = true; + std::unique_lock lock(m_draw_mutex); + m_agents.clear(); m_mannequins.clear(); - m_lock_draw = false; if (!m_agent_program.open(filename)) { QMessageBox::warning(this, tr("depthmapX"), tr("Unable to understand agent program"), QMessageBox::Ok, QMessageBox::Ok); } @@ -573,10 +565,6 @@ void Q3DView::OnLButtonDown(unsigned int nFlags, QPoint point) { m_right_mouse = false; - while (m_lock_draw) { -// Sleep(1); - } - switch (m_mouse_mode) { case ID_3D_PAN: case ID_3D_ROT: case ID_3D_ZOOM: m_mouse_mode_on = m_mouse_mode; @@ -610,9 +598,7 @@ void Q3DView::OnRButtonDown(unsigned int nFlags, QPoint point) { m_right_mouse = true; - while (m_lock_draw) { -// Sleep(1); - } + std::unique_lock lock(m_draw_mutex); m_mouse_origin = point; } @@ -743,11 +729,7 @@ void Q3DView::CreateAgent(QPoint point) return; } - while (m_lock_draw) { - //sleep(1); - } - m_lock_draw = true; - + std::unique_lock lock(m_draw_mutex); bool animating = m_animating; m_animating = false; @@ -755,20 +737,25 @@ void Q3DView::CreateAgent(QPoint point) GLint viewport[4]; GLdouble mvmatrix[16], projmatrix[16]; + glViewport(0, 0, width(), height()); glGetIntegerv(GL_VIEWPORT, viewport); + Reshape(viewport[2], viewport[3]); + SetModelMat(); + glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix); glGetDoublev(GL_PROJECTION_MATRIX, projmatrix); GLint realy = viewport[3] - point.y(); GLdouble wx1, wy1, wz1, wx2, wy2, wz2; - gluUnProject((GLdouble) point.x(), (GLdouble) realy, 0.0, + + gluReimpl::gluUnProject((GLdouble) point.x(), (GLdouble) realy, 0.0, mvmatrix, projmatrix, viewport, &wx1, &wy1, &wz1); - gluUnProject((GLdouble) point.x(), (GLdouble) realy, 1.0, + gluReimpl::gluUnProject((GLdouble) point.x(), (GLdouble) realy, 1.0, mvmatrix, projmatrix, viewport, &wx2, &wy2, &wz2); // 0 plane has to lie between wz1 and wz2: - if (finite(wz1) && finite(wz2) && wz1 > 0 && wz2 < 0) { + if (std::isfinite(wz1) && std::isfinite(wz2) && wz1 > 0 && wz2 < 0) { double scaling = wz1/(wz2-wz1); Point2f p(wx1-scaling*(wx2-wx1),wy1-scaling*(wy2-wy1)); @@ -779,14 +766,14 @@ void Q3DView::CreateAgent(QPoint point) PixelRef pix = pointmap.pixelate(p); if (pointmap.getPoint(pix).filled()) { m_agents.push_back( Agent(&m_agent_program, &pointmap) ); - m_agents.tail().onInit(pix); - Point2f p2 = m_agents.tail().getLocation(); + m_agents.back().onInit(pix); + Point2f p2 = m_agents.back().getLocation(); p2.normalScale(m_region); m_mannequins.push_back( QMannequin(p2, m_agents.size()-1) ); - m_agents.tail().onMove(); - p2 = m_agents.tail().getLocation(); + m_agents.back().onMove(); + p2 = m_agents.back().getLocation(); p2.normalScale(m_region); - m_mannequins.tail().advance(p2); + m_mannequins.back().advance(p2); m_animating = true; } @@ -794,7 +781,6 @@ void Q3DView::CreateAgent(QPoint point) } m_animating |= animating; - m_lock_draw = false; } ////////////////////////////////////////////////////////////////////////////////////// @@ -1148,20 +1134,16 @@ void Q3DView::OnToolsImportTraces() return; } - pstring filename = pstring(infiles[0].toLatin1()); + std::string filename = infiles[0].toStdString(); if (!filename.empty()) { m_animating = false; - while (m_lock_draw) { - //sleep(1); - } - m_lock_draw = true; + std::unique_lock lock(m_draw_mutex); m_agents.clear(); m_traces.clear(); m_mannequins.clear(); - m_lock_draw = false; - // - ifstream file(filename.c_str()); + // + std::ifstream file(filename.c_str()); // Eva's XMLs do not have the header yet: xmlelement traceset; QString elementname; @@ -1183,19 +1165,19 @@ void Q3DView::OnToolsImportTraces() double x = QString(traceevent.attributes["x"].c_str()).toDouble(); double y = QString(traceevent.attributes["y"].c_str()).toDouble(); double t = QString(traceevent.attributes["t"].c_str()).toDouble(); - m_traces.tail().events.push_back(Event2f(x,y,t)); + m_traces.back().events.push_back(Event2f(x,y,t)); if (firstevent) { - m_traces.tail().starttime = t; + m_traces.back().starttime = t; firstevent = false; } } } - if (m_traces.tail().events.size() >= 1) { - m_traces.tail().endtime = m_traces.tail().events.tail().t; - Point2f p = m_traces.tail().events[0]; + if (m_traces.back().events.size() >= 1) { + m_traces.back().endtime = m_traces.back().events.back().t; + Point2f p = m_traces.back().events[0]; p.normalScale(m_region); m_mannequins.push_back( QMannequin(p,m_traces.size()-1,true) ); - m_mannequins.tail().m_active = false; + m_mannequins.back().m_active = false; } } } @@ -1220,8 +1202,8 @@ void Q3DView::OnToolsAgentsStop() m_mannequins[i].m_nextloc = m_mannequins[i].m_startloc; } } - for (int j = 0; j < m_pixels.size(); j++) { - m_pixels[j].m_value = -1; + for (auto pixel: m_pixels) { + pixel.second.m_value = -1; } } @@ -1276,6 +1258,8 @@ void Q3DView::mousePressEvent(QMouseEvent *event) case Qt::RightButton: OnRButtonDown(0, event->pos()); break; + default: + break; } } @@ -1290,6 +1274,8 @@ void Q3DView::mouseReleaseEvent(QMouseEvent *event) case Qt::RightButton: OnRButtonUp(0, event->pos()); break; + default: + break; } } diff --git a/depthmapX/3DView.h b/depthmapX/views/3dview/3dview.h similarity index 89% rename from depthmapX/3DView.h rename to depthmapX/views/3dview/3dview.h index 0937563b..e7408d53 100644 --- a/depthmapX/3DView.h +++ b/depthmapX/views/3dview/3dview.h @@ -14,16 +14,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#include "depthmapX/GraphDoc.h" +#include "salalib/agents/agentprogram.h" - -///////////////////////////////////////////////////////////////////////////// -// Q3DView view -#include +#include #include #include #include -#include "GraphDoc.h" -#include #define ID_ADD_AGENT 32947 #define ID_3D_PAN 32948 @@ -78,6 +75,14 @@ struct QMannequin int m_pointcount; }; + +struct Trace +{ + double starttime; + double endtime; + std::vector events; +}; + struct C3DPixelData { Point2f m_point; @@ -88,7 +93,7 @@ struct C3DPixelData ///////////////////////////////////////////////////////////////////////////// -class Q3DView : public QGLWidget +class Q3DView : public QOpenGLWidget { Q_OBJECT @@ -106,7 +111,7 @@ class Q3DView : public QGLWidget QPainter *m_pDC; // bool m_quick_draw; - bool m_lock_draw; + std::mutex m_draw_mutex; bool m_animating; bool m_drawtrails; bool m_fill; @@ -116,7 +121,7 @@ class Q3DView : public QGLWidget QtRegion m_region; float *m_points; float m_rect[4][3]; - pqmap m_pixels; + std::map m_pixels; // int m_pointcount; // @@ -136,9 +141,9 @@ class Q3DView : public QGLWidget // use to initialise mannequintemplate: CMannequinTemplate m_male_template; CMannequinTemplate m_female_template; - prefvec m_mannequins; - prefvec m_agents; - prefvec m_traces; + std::vector m_mannequins; + std::vector m_agents; + std::vector m_traces; AgentProgram m_agent_program; // // used to keep track of internal time for all agents diff --git a/depthmapX/views/3dview/glureimpl.h b/depthmapX/views/3dview/glureimpl.h new file mode 100644 index 00000000..26818427 --- /dev/null +++ b/depthmapX/views/3dview/glureimpl.h @@ -0,0 +1,222 @@ +// Taken from https://github.com/Alexpux/superglu/blob/master/libutil/project.c +// Only provided here temporarily until the 3DView is converted to modern OpenGL + +/* +** License Applicability. Except to the extent portions of this file are +** made subject to an alternative license as permitted in the SGI Free +** Software License B, Version 1.1 (the "License"), the contents of this +** file are subject only to the provisions of the License. You may not use +** this file except in compliance with the License. You may obtain a copy +** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 +** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: +** +** http://oss.sgi.com/projects/FreeB +** +** Note that, as provided in the License, the Software is distributed on an +** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS +** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND +** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A +** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. +** +** Original Code. The Original Code is: OpenGL Sample Implementation, +** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, +** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. +** Copyright in any portions created by third parties is as indicated +** elsewhere herein. All Rights Reserved. +** +** Additional Notice Provisions: The application programming interfaces +** established by SGI in conjunction with the Original Code are The +** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released +** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version +** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X +** Window System(R) (Version 1.3), released October 19, 1998. This software +** was created using the OpenGL(R) version 1.2.1 Sample Implementation +** published by SGI, but has not been independently verified as being +** compliant with the OpenGL(R) version 1.2.1 Specification. +** +** $Date$ $Revision$ +** $Header$ +*/ +#pragma once + +#include + +#ifdef __APPLE__ +#include +#include +#else +#include +#include +#endif + +namespace gluReimpl { + /* + ** Make m an identity matrix + */ + static void __gluMakeIdentityd(GLdouble m[16]) { + m[0 + 4 * 0] = 1; + m[0 + 4 * 1] = 0; + m[0 + 4 * 2] = 0; + m[0 + 4 * 3] = 0; + m[1 + 4 * 0] = 0; + m[1 + 4 * 1] = 1; + m[1 + 4 * 2] = 0; + m[1 + 4 * 3] = 0; + m[2 + 4 * 0] = 0; + m[2 + 4 * 1] = 0; + m[2 + 4 * 2] = 1; + m[2 + 4 * 3] = 0; + m[3 + 4 * 0] = 0; + m[3 + 4 * 1] = 0; + m[3 + 4 * 2] = 0; + m[3 + 4 * 3] = 1; + } + +#define __glPi 3.14159265358979323846 + + void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar) { + GLdouble m[4][4]; + double sine, cotangent, deltaZ; + double radians = fovy / 2 * __glPi / 180; + + deltaZ = zFar - zNear; + sine = sin(radians); + if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) { + return; + } + cotangent = cos(radians) / sine; + + __gluMakeIdentityd(&m[0][0]); + m[0][0] = cotangent / aspect; + m[1][1] = cotangent; + m[2][2] = -(zFar + zNear) / deltaZ; + m[2][3] = -1; + m[3][2] = -2 * zNear * zFar / deltaZ; + m[3][3] = 0; + glMultMatrixd(&m[0][0]); + } + + static void __gluMultMatrixVecd(const GLdouble matrix[16], const GLdouble in[4], GLdouble out[4]) { + int i; + + for (i = 0; i < 4; i++) { + out[i] = in[0] * matrix[0 * 4 + i] + in[1] * matrix[1 * 4 + i] + in[2] * matrix[2 * 4 + i] + + in[3] * matrix[3 * 4 + i]; + } + } + + /* + ** inverse = invert(src) + */ + static int __gluInvertMatrixd(const GLdouble src[16], GLdouble inverse[16]) { + int i, j, k, swap; + double t; + GLdouble temp[4][4]; + + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + temp[i][j] = src[i * 4 + j]; + } + } + __gluMakeIdentityd(inverse); + + for (i = 0; i < 4; i++) { + /* + ** Look for largest element in column + */ + swap = i; + for (j = i + 1; j < 4; j++) { + if (fabs(temp[j][i]) > fabs(temp[i][i])) { + swap = j; + } + } + + if (swap != i) { + /* + ** Swap rows. + */ + for (k = 0; k < 4; k++) { + t = temp[i][k]; + temp[i][k] = temp[swap][k]; + temp[swap][k] = t; + + t = inverse[i * 4 + k]; + inverse[i * 4 + k] = inverse[swap * 4 + k]; + inverse[swap * 4 + k] = t; + } + } + + if (temp[i][i] == 0) { + /* + ** No non-zero pivot. The matrix is singular, which shouldn't + ** happen. This means the user gave us a bad matrix. + */ + return GL_FALSE; + } + + t = temp[i][i]; + for (k = 0; k < 4; k++) { + temp[i][k] /= t; + inverse[i * 4 + k] /= t; + } + for (j = 0; j < 4; j++) { + if (j != i) { + t = temp[j][i]; + for (k = 0; k < 4; k++) { + temp[j][k] -= temp[i][k] * t; + inverse[j * 4 + k] -= inverse[i * 4 + k] * t; + } + } + } + } + return GL_TRUE; + } + + static void __gluMultMatricesd(const GLdouble a[16], const GLdouble b[16], GLdouble r[16]) { + int i, j; + + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + r[i * 4 + j] = a[i * 4 + 0] * b[0 * 4 + j] + a[i * 4 + 1] * b[1 * 4 + j] + + a[i * 4 + 2] * b[2 * 4 + j] + a[i * 4 + 3] * b[3 * 4 + j]; + } + } + } + + GLint gluUnProject(GLdouble winx, GLdouble winy, GLdouble winz, const GLdouble modelMatrix[16], + const GLdouble projMatrix[16], const GLint viewport[4], GLdouble *objx, GLdouble *objy, + GLdouble *objz) { + double finalMatrix[16]; + double in[4]; + double out[4]; + + __gluMultMatricesd(modelMatrix, projMatrix, finalMatrix); + if (!__gluInvertMatrixd(finalMatrix, finalMatrix)) + return (GL_FALSE); + + in[0] = winx; + in[1] = winy; + in[2] = winz; + in[3] = 1.0; + + /* Map x and y from window coordinates */ + in[0] = (in[0] - viewport[0]) / viewport[2]; + in[1] = (in[1] - viewport[1]) / viewport[3]; + + /* Map to range -1 to 1 */ + in[0] = in[0] * 2 - 1; + in[1] = in[1] * 2 - 1; + in[2] = in[2] * 2 - 1; + + __gluMultMatrixVecd(finalMatrix, in, out); + if (out[3] == 0.0) + return (GL_FALSE); + out[0] /= out[3]; + out[1] /= out[3]; + out[2] /= out[3]; + *objx = out[0]; + *objy = out[1]; + *objz = out[2]; + return (GL_TRUE); + } +} // namespace glureimpl diff --git a/depthmapX/views/CMakeLists.txt b/depthmapX/views/CMakeLists.txt new file mode 100644 index 00000000..2c9f5421 --- /dev/null +++ b/depthmapX/views/CMakeLists.txt @@ -0,0 +1,44 @@ +target_sources(depthmapX + PRIVATE + mapview.cpp + viewhelpers.cpp + glview/gllinesuniform.cpp + glview/glview.cpp + glview/gllines.cpp + glview/glrastertexture.cpp + glview/glpolygons.cpp + glview/glutriangulator.cpp + glview/gltrianglesuniform.cpp + glview/glpointmap.cpp + glview/glshapegraph.cpp + glview/glshapemap.cpp + glview/gldynamicrect.cpp + glview/gldynamicline.cpp + plotview/plotview.cpp + tableview/tableview.cpp + depthmapview/depthmapview.cpp + 3dview/3dview.cpp + glview/glregularpolygons.cpp + glview/gltriangles.cpp + PUBLIC + mapview.h + viewhelpers.h + glview/gllinesuniform.h + glview/glview.h + glview/gllines.h + glview/glrastertexture.h + glview/glpolygons.h + glview/glutriangulator.h + glview/gltrianglesuniform.h + glview/glpointmap.h + glview/glshapegraph.h + glview/glshapemap.h + glview/gldynamicrect.h + glview/gldynamicline.h + plotview/plotview.h + tableview/tableview.h + depthmapview/depthmapview.h + glview/glregularpolygons.h + glview/gltriangles.h + 3dview/3dview.h) + diff --git a/depthmapX/depthmapView.cpp b/depthmapX/views/depthmapview/depthmapview.cpp similarity index 74% rename from depthmapX/depthmapView.cpp rename to depthmapX/views/depthmapview/depthmapview.cpp index f213de71..d2ba4604 100644 --- a/depthmapX/depthmapView.cpp +++ b/depthmapX/views/depthmapview/depthmapview.cpp @@ -33,8 +33,8 @@ #include #include "mainwindow.h" -#include "depthmapView.h" -#include "viewhelpers.h" +#include "depthmapview.h" +#include "depthmapX/views/viewhelpers.h" class QToolBar; @@ -46,10 +46,6 @@ class QToolBar; #define DMP_TIMER_3DVIEW 4 -// You don't want Depthmap to warn you about alerts way in the past, -// so this sets the earliest date Depthmap will pick up an alert from -const pstring g_earliest_alert_date = pstring("2010-11-01T00:00:01"); - // version 5.0 dll exports have split out the attribute table // functionality, so a single class operates with the VGA interface // and the Axial interface, this means previous DLLs will not work @@ -94,13 +90,12 @@ static QRgb colorMerge(QRgb color, QRgb mergecolor) return (color & 0x006f6f6f) | (mergecolor & 0x00a0a0a0); } -QDepthmapView::QDepthmapView(const QString &settingsFile ) - : QWidget(0), m_settingsFile(settingsFile) +QDepthmapView::QDepthmapView(QGraphDoc &pDoc, Settings &settings, QWidget *parent) + : MapView(pDoc, settings, parent) { m_drag_rect_a.setRect(0, 0, 0, 0); m_drag_rect_b.setRect(0, 0, 0, 0); - m_curr_seleted = -1; // Several screen drawing booleans: m_continue_drawing = false; m_drawing = false; @@ -133,8 +128,7 @@ QDepthmapView::QDepthmapView(const QString &settingsFile ) m_selected_color = qRgb(selcol.redb(),selcol.greenb(),selcol.blueb()); - QSettings settings(m_settingsFile, QSettings::IniFormat); - m_initialSize = settings.value(QLatin1String("depthmapViewSize"), QSize(2000, 2000)).toSize(); + m_initialSize = m_settings.readSetting(SettingTag::depthmapViewSize, QSize(2000, 2000)).toSize(); installEventFilter(this); @@ -145,23 +139,22 @@ QDepthmapView::QDepthmapView(const QString &settingsFile ) QDepthmapView::~QDepthmapView() { - QSettings settings(m_settingsFile, QSettings::IniFormat); - settings.setValue(QLatin1String("depthmapViewSize"), size()); + m_settings.writeSetting(SettingTag::depthmapViewSize, size()); } int QDepthmapView::OnRedraw(int wParam, int lParam) { - if (pDoc->GetRemenuFlag(QGraphDoc::VIEW_MAP)) { - pDoc->SetRemenuFlag(QGraphDoc::VIEW_MAP, false); + if (m_pDoc.GetRemenuFlag(QGraphDoc::VIEW_MAP)) { + m_pDoc.SetRemenuFlag(QGraphDoc::VIEW_MAP, false); // redo the menus for this *view* directly: - //((CChildFrame*) GetParentFrame())->m_view_selector.RedoMenu( *pDoc->m_meta_graph ); + //((CChildFrame*) GetParentFrame())->m_view_selector.RedoMenu( *m_pDoc.m_meta_graph ); } - if (pDoc->GetRedrawFlag(QGraphDoc::VIEW_MAP) != QGraphDoc::REDRAW_DONE) { - if (!pDoc->m_communicator) { + if (m_pDoc.GetRedrawFlag(QGraphDoc::VIEW_MAP) != QGraphDoc::REDRAW_DONE) { + if (!m_pDoc.m_communicator) { m_queued_redraw = false; - switch (pDoc->GetRedrawFlag(QGraphDoc::VIEW_MAP)) { + switch (m_pDoc.GetRedrawFlag(QGraphDoc::VIEW_MAP)) { case QGraphDoc::REDRAW_POINTS: - if (pDoc->m_meta_graph->viewingProcessedLines()) { + if (m_pDoc.m_meta_graph->viewingProcessedLines()) { // Axial lines are thicker on selection, so background needs clearing m_redraw_all = true; } @@ -177,7 +170,7 @@ int QDepthmapView::OnRedraw(int wParam, int lParam) m_redraw_all = true; break; } - pDoc->SetRedrawFlag(QGraphDoc::VIEW_MAP, QGraphDoc::REDRAW_DONE); + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_MAP, QGraphDoc::REDRAW_DONE); repaint(); } else { @@ -197,30 +190,34 @@ bool QDepthmapView::eventFilter(QObject *object, QEvent *e) case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: - case QEvent::MouseMove: + case QEvent::MouseMove: { Qt::KeyboardModifiers keyMods = QApplication::keyboardModifiers(); pressed_nFlags = ( keyMods & Qt::ShiftModifier ) ? pressed_nFlags |= MK_SHIFT : pressed_nFlags &= ~MK_SHIFT; pressed_nFlags = ( keyMods & Qt::ControlModifier ) ? pressed_nFlags |= MK_CONTROL : pressed_nFlags &= ~MK_CONTROL; + break; + } + default: + break; } if(e->type() == QEvent::ToolTip) { - if (!pDoc->m_communicator) + if (!m_pDoc.m_communicator) { - if(pDoc->m_meta_graph) + if(m_pDoc.m_meta_graph) { - if (pDoc->m_meta_graph->viewingProcessed() && pDoc->m_meta_graph->getSelCount() > 1) { - float val = pDoc->m_meta_graph->getSelAvg(); - int count = pDoc->m_meta_graph->getSelCount(); + if (m_pDoc.m_meta_graph->viewingProcessed() && m_pDoc.m_meta_graph->getSelCount() > 1) { + float val = m_pDoc.m_meta_graph->getSelAvg(); + int count = m_pDoc.m_meta_graph->getSelCount(); if (val == -1.0f) setToolTip("Null selection"); else if (val != -2.0f) setToolTip(QString("Selection\nAverage: %1\nCount: %2").arg(val).arg(count)); else setToolTip(""); } - else if (pDoc->m_meta_graph->viewingProcessed()) { + else if (m_pDoc.m_meta_graph->viewingProcessed()) { // and that it has an appropriate state to display a hover wnd - float val = pDoc->m_meta_graph->getLocationValue(LogicalUnits(hit_point)); + float val = m_pDoc.m_meta_graph->getLocationValue(LogicalUnits(hit_point)); if (val == -1.0f) setToolTip("No value"); else if (val != -2.0f) @@ -274,16 +271,16 @@ QtRegion QDepthmapView::LogicalViewport(const QRect& phys_bounds, QGraphDoc *pDo void QDepthmapView::SetRedrawflag() { - if (pDoc->GetRemenuFlag(QGraphDoc::VIEW_MAP)) - pDoc->SetRemenuFlag(QGraphDoc::VIEW_MAP, false); + if (m_pDoc.GetRemenuFlag(QGraphDoc::VIEW_MAP)) + m_pDoc.SetRemenuFlag(QGraphDoc::VIEW_MAP, false); - if (pDoc->GetRedrawFlag(QGraphDoc::VIEW_MAP) != QGraphDoc::REDRAW_DONE) + if (m_pDoc.GetRedrawFlag(QGraphDoc::VIEW_MAP) != QGraphDoc::REDRAW_DONE) { - if (pDoc->m_communicator) { + if (m_pDoc.m_communicator) { m_queued_redraw = false; - switch (pDoc->GetRedrawFlag(QGraphDoc::VIEW_MAP)) { + switch (m_pDoc.GetRedrawFlag(QGraphDoc::VIEW_MAP)) { case QGraphDoc::REDRAW_POINTS: - if (pDoc->m_meta_graph->viewingProcessedLines()) { + if (m_pDoc.m_meta_graph->viewingProcessedLines()) { // Axial lines are thicker on selection, so background needs clearing m_redraw_all = true; } @@ -301,7 +298,7 @@ void QDepthmapView::SetRedrawflag() m_redraw_all = true; break; } - pDoc->SetRedrawFlag(QGraphDoc::VIEW_MAP,QGraphDoc::REDRAW_DONE); + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_MAP,QGraphDoc::REDRAW_DONE); } else { killTimer(Tid_redraw); @@ -313,7 +310,7 @@ void QDepthmapView::SetRedrawflag() void QDepthmapView::paintEvent(QPaintEvent *) { - QPainter pDC(this); + QPainter pDC(m_pixmap); SetRedrawflag(); @@ -331,27 +328,28 @@ void QDepthmapView::paintEvent(QPaintEvent *) /* if (pDC->IsPrinting()) { - if (!pDoc->m_meta_graph->setLock(this)) + if (!m_pDoc.m_meta_graph->setLock(this)) { return; } - PrintBaby(pDC, pDoc); + PrintBaby(pDC, m_pDoc); - pDoc->m_meta_graph->releaseLock(this); + m_pDoc.m_meta_graph->releaseLock(this); return; }*/ - if (!pDoc->m_meta_graph->setLock(this)) { - return; + auto lock = m_pDoc.m_meta_graph->getLockDeferred(); + if (!lock.try_lock()){ + return; } m_drawing = true; QRect rect; - int state = pDoc->m_meta_graph->getState(); + int state = m_pDoc.m_meta_graph->getState(); if (m_invalidate) { @@ -403,7 +401,7 @@ void QDepthmapView::paintEvent(QPaintEvent *) m_redraw = true; if (!m_viewport_set && state & (MetaGraph::LINEDATA | MetaGraph::SHAPEGRAPHS | MetaGraph::DATAMAPS)) { - InitViewport(rect, pDoc); + InitViewport(rect, &m_pDoc); } if (m_redraw_all) { m_clear = true; @@ -427,21 +425,21 @@ void QDepthmapView::paintEvent(QPaintEvent *) // note that the redraw rect is dependent on the cleared portion above // note you *must* check *state* before drawing, you cannot rely on view_class as it can be set up before the layer is ready to draw: - if (state & MetaGraph::POINTMAPS && (!pDoc->m_meta_graph->getDisplayedPointMap().isProcessed() - || pDoc->m_meta_graph->getViewClass() & (MetaGraph::VIEWVGA | MetaGraph::VIEWBACKVGA)) - && !pDoc->m_communicator) // <- m_communicator because I'm having thread locking problems + if (state & MetaGraph::POINTMAPS && (!m_pDoc.m_meta_graph->getDisplayedPointMap().isProcessed() + || m_pDoc.m_meta_graph->getViewClass() & (MetaGraph::VIEWVGA | MetaGraph::VIEWBACKVGA)) + && !m_pDoc.m_communicator) // <- m_communicator because I'm having thread locking problems { - pDoc->m_meta_graph->getDisplayedPointMap().setScreenPixel( m_unit ); // only used by points (at the moment!) - pDoc->m_meta_graph->getDisplayedPointMap().makeViewportPoints( LogicalViewport(rect, pDoc) ); + m_pDoc.m_meta_graph->getDisplayedPointMap().setScreenPixel( m_unit ); // only used by points (at the moment!) + m_pDoc.m_meta_graph->getDisplayedPointMap().makeViewportPoints( LogicalViewport(rect, &m_pDoc) ); } - if (state & MetaGraph::SHAPEGRAPHS && (pDoc->m_meta_graph->getViewClass() & (MetaGraph::VIEWAXIAL | MetaGraph::VIEWBACKAXIAL))) { - pDoc->m_meta_graph->getDisplayedShapeGraph().makeViewportShapes( LogicalViewport(rect, pDoc) ); + if (state & MetaGraph::SHAPEGRAPHS && (m_pDoc.m_meta_graph->getViewClass() & (MetaGraph::VIEWAXIAL | MetaGraph::VIEWBACKAXIAL))) { + m_pDoc.m_meta_graph->getDisplayedShapeGraph().makeViewportShapes( LogicalViewport(rect, &m_pDoc) ); } - if (state & MetaGraph::DATAMAPS && (pDoc->m_meta_graph->getViewClass() & (MetaGraph::VIEWBACKDATA | MetaGraph::VIEWDATA))) { - pDoc->m_meta_graph->getDisplayedDataMap().makeViewportShapes( LogicalViewport(rect, pDoc) ); + if (state & MetaGraph::DATAMAPS && (m_pDoc.m_meta_graph->getViewClass() & (MetaGraph::VIEWBACKDATA | MetaGraph::VIEWDATA))) { + m_pDoc.m_meta_graph->getDisplayedDataMap().makeViewportShapes( LogicalViewport(rect, &m_pDoc) ); } if (state & MetaGraph::LINEDATA) { - pDoc->m_meta_graph->SuperSpacePixel::makeViewportShapes( LogicalViewport(rect, pDoc) ); + m_pDoc.m_meta_graph->makeViewportShapes( LogicalViewport(rect, &m_pDoc) ); } m_continue_drawing = true; @@ -457,7 +455,7 @@ void QDepthmapView::paintEvent(QPaintEvent *) // If the meta graph (at least) contains a DXF, draw it: if (m_continue_drawing && (state & (MetaGraph::LINEDATA | MetaGraph::SHAPEGRAPHS | MetaGraph::DATAMAPS)) && m_viewport_set) { - if (Output(&pDC, pDoc, true)) + if (Output(&pDC, &m_pDoc, true)) { Tid_redraw = startTimer(100); m_continue_drawing = true; @@ -475,15 +473,18 @@ void QDepthmapView::paintEvent(QPaintEvent *) } m_drawing = false; - pDoc->m_meta_graph->releaseLock(this); + QPainter screenPainter(this); + screenPainter.drawPixmap(0,0,width(),height(),*m_pixmap); } -void QDepthmapView::resizeEvent(QResizeEvent *) +void QDepthmapView::resizeGL(int w, int h) { // m_viewport_set = false; m_redraw_all = true; m_resize_viewport = true; - pDoc->m_view[QGraphDoc::VIEW_MAP] = this; + m_pDoc.m_view[QGraphDoc::VIEW_MAP] = this; + m_pixmap = new QPixmap(w, h); + update(); } void QDepthmapView::BeginDrag(QPoint point) @@ -524,7 +525,7 @@ void QDepthmapView::mouseMoveEvent(QMouseEvent *e) if (pressed_nFlags & MK_SHIFT) { // CTRL and SHIFT key down together, snap to displayed drawing layers // (note, don't use SHIFT on it's own, because that's already used for multiple select) - MetaGraph *graph = pDoc->m_meta_graph; + MetaGraph *graph = m_pDoc.m_meta_graph; Point2f p = LogicalUnits(point); double d = -1.0; for (int i = 0; i < graph->getLineFileCount(); i++) { @@ -532,7 +533,7 @@ void QDepthmapView::mouseMoveEvent(QMouseEvent *e) ShapeMap& map = graph->getLineLayer(i,j); if (map.isShown()) { Point2f px = map.getClosestVertex(p); - if (!px.isNull() && (d == -1 || dist(p,px) < d)) { + if (!px.atZero() && (d == -1 || dist(p,px) < d)) { d = dist(p,px); m_snap_point = px; } @@ -555,9 +556,9 @@ void QDepthmapView::mouseMoveEvent(QMouseEvent *e) } else { // If only CTRL key down, snap to grid - if (pDoc->m_meta_graph->getViewClass() & (MetaGraph::VIEWVGA | MetaGraph::VIEWBACKVGA)) { - PointMap& map = pDoc->m_meta_graph->getDisplayedPointMap(); - if (pDoc->m_meta_graph->getDisplayedPointMap().getSpacing() / m_unit > 20) { + if (m_pDoc.m_meta_graph->getViewClass() & (MetaGraph::VIEWVGA | MetaGraph::VIEWBACKVGA)) { + PointMap& map = m_pDoc.m_meta_graph->getDisplayedPointMap(); + if (m_pDoc.m_meta_graph->getDisplayedPointMap().getSpacing() / m_unit > 20) { // hi-res snap when zoomed in m_snap_point = map.depixelate(map.pixelate(LogicalUnits(point),false,2),0.5); } @@ -648,9 +649,9 @@ void QDepthmapView::mouseMoveEvent(QMouseEvent *e) } else if (m_current_mode == PENCIL) { if (m_mouse_point != point && - pDoc->m_meta_graph->getDisplayedPointMap().pixelate(LogicalUnits(point)) != - pDoc->m_meta_graph->getDisplayedPointMap().pixelate(LogicalUnits(m_mouse_point))) { - pDoc->m_meta_graph->getDisplayedPointMap().fillPoint(LogicalUnits(point),true); + m_pDoc.m_meta_graph->getDisplayedPointMap().pixelate(LogicalUnits(point)) != + m_pDoc.m_meta_graph->getDisplayedPointMap().pixelate(LogicalUnits(m_mouse_point))) { + m_pDoc.m_meta_graph->getDisplayedPointMap().fillPoint(LogicalUnits(point),true); m_redraw_no_clear = true; m_mouse_point = point; // Redraw scene @@ -659,9 +660,9 @@ void QDepthmapView::mouseMoveEvent(QMouseEvent *e) } else if (m_current_mode == ERASE) { if (m_mouse_point != point && - pDoc->m_meta_graph->getDisplayedPointMap().pixelate(LogicalUnits(point)) != - pDoc->m_meta_graph->getDisplayedPointMap().pixelate(LogicalUnits(m_mouse_point))) { - pDoc->m_meta_graph->getDisplayedPointMap().fillPoint(LogicalUnits(point),false); + m_pDoc.m_meta_graph->getDisplayedPointMap().pixelate(LogicalUnits(point)) != + m_pDoc.m_meta_graph->getDisplayedPointMap().pixelate(LogicalUnits(m_mouse_point))) { + m_pDoc.m_meta_graph->getDisplayedPointMap().fillPoint(LogicalUnits(point),false); m_redraw_no_clear = true; m_mouse_point = point; // Redraw scene @@ -737,8 +738,8 @@ void QDepthmapView::mouseMoveEvent(QMouseEvent *e) } } - pDoc->m_position = m_snap ? m_snap_point : LogicalUnits( point ); - pDoc->UpdateMainframestatus(); + m_pDoc.m_position = m_snap ? m_snap_point : LogicalUnits( point ); + m_pDoc.UpdateMainframestatus(); hit_point = point; } @@ -757,6 +758,8 @@ void QDepthmapView::mousePressEvent(QMouseEvent *e) case Qt::RightButton: pressed_nFlags = MK_RBUTTON; break; + default: + break; } QPoint point = e->pos(); if (pressed_nFlags & MK_RBUTTON) @@ -808,7 +811,7 @@ void QDepthmapView::mousePressEvent(QMouseEvent *e) { m_current_mode = PENCIL; // Fill the point - pDoc->m_meta_graph->getDisplayedPointMap().fillPoint(LogicalUnits(point),true); + m_pDoc.m_meta_graph->getDisplayedPointMap().fillPoint(LogicalUnits(point),true); m_mouse_point = point; // Redraw scene m_redraw_no_clear = true; @@ -828,10 +831,10 @@ void QDepthmapView::mousePressEvent(QMouseEvent *e) void QDepthmapView::BeginJoin() { - if (pDoc->m_meta_graph->getSelCount() > 1 && pDoc->m_meta_graph->viewingProcessedPoints()) { - QtRegion r = pDoc->m_meta_graph->getDisplayedPointMap().getSelBounds(); + if (m_pDoc.m_meta_graph->getSelCount() > 1 && m_pDoc.m_meta_graph->viewingProcessedPoints()) { + QtRegion r = m_pDoc.m_meta_graph->getDisplayedPointMap().getSelBounds(); QRect rect(PhysicalUnits(Point2f(r.bottom_left.x,r.top_right.y)),PhysicalUnits(Point2f(r.top_right.x,r.bottom_left.y))); - int spacer = int(ceil(5.0 * pDoc->m_meta_graph->getDisplayedPointMap().getSpacing() / (m_unit * 10.0) )); + int spacer = int(ceil(5.0 * m_pDoc.m_meta_graph->getDisplayedPointMap().getSpacing() / (m_unit * 10.0) )); m_mouse_point = this->rect().center(); m_drag_rect_a = QRect(-rect.width()-spacer/2,-rect.height()-spacer/2,spacer/2,spacer/2); m_drag_rect_a.translate(m_mouse_point); @@ -861,15 +864,15 @@ void QDepthmapView::mouseReleaseEvent(QMouseEvent *e) QRect rect = QRect(0,0,width(),height()); double ratio = __min( double(rect.height() / double(m_drag_rect_a.height()) ), double(rect.width()) / double(m_drag_rect_a.width()) ); - ZoomIn(ratio, LogicalUnits(m_drag_rect_a.center()) ); + ZoomTowards(1.0/ratio, LogicalUnits(m_drag_rect_a.center()) ); } else { - ZoomIn(2.0, m_centre); + ZoomTowards(0.75, m_centre); } break; case ZOOM_OUT: { - ZoomOut(); + ZoomTowards(1.5, m_centre); } break; case DRAG: @@ -903,17 +906,17 @@ void QDepthmapView::mouseReleaseEvent(QMouseEvent *e) m_invalidate = SELECT; update(); - if (!pDoc->m_communicator) { + if (!m_pDoc.m_communicator) { // After checking that processing isn't occurring... // Do the selection (might take a while if someone selects the lot...) if (pressed_nFlags & MK_SHIFT) { - pDoc->m_meta_graph->setCurSel( r, true ); // <- add to current sel + m_pDoc.m_meta_graph->setCurSel( r, true ); // <- add to current sel } else { - pDoc->m_meta_graph->setCurSel( r, false ); // <- reset current sel + m_pDoc.m_meta_graph->setCurSel( r, false ); // <- reset current sel } // Redraw scene - pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_SELECTION); + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_ALL,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_SELECTION); } } break; @@ -923,16 +926,16 @@ void QDepthmapView::mouseReleaseEvent(QMouseEvent *e) // now get on with join: bool ok = false; bool clearcursor = false; - if (pDoc->m_meta_graph->getViewClass() & MetaGraph::VIEWVGA) { - ok = pDoc->m_meta_graph->getDisplayedPointMap().mergePoints( LogicalUnits(point) ); + if (m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWVGA) { + ok = m_pDoc.m_meta_graph->getDisplayedPointMap().mergePoints( LogicalUnits(point) ); } - else if (pDoc->m_meta_graph->getViewClass() & MetaGraph::VIEWAXIAL) { - if (pDoc->m_meta_graph->getSelCount() == 1) { - ok = pDoc->m_meta_graph->getDisplayedShapeGraph().linkShapes( LogicalUnits(point) ); + else if (m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWAXIAL) { + if (m_pDoc.m_meta_graph->getSelCount() == 1) { + ok = m_pDoc.m_meta_graph->getDisplayedShapeGraph().linkShapes( LogicalUnits(point) ); } else { // oops: you are only allowed to join lines one to one: - pDoc->m_meta_graph->clearSel(); + m_pDoc.m_meta_graph->clearSel(); clearcursor = true; } } @@ -941,8 +944,8 @@ void QDepthmapView::mouseReleaseEvent(QMouseEvent *e) SetCursor(JOIN); m_drag_rect_a = QRect(0,0,0,0); if (ok) { - pDoc->modifiedFlag = true; - pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL,QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA); + m_pDoc.modifiedFlag = true; + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_ALL,QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA); } else { m_redraw_all = true; @@ -957,13 +960,13 @@ void QDepthmapView::mouseReleaseEvent(QMouseEvent *e) // now get on with unjoin: bool ok = false; bool clearcursor = false; - if (pDoc->m_meta_graph->getViewClass() & MetaGraph::VIEWAXIAL) { - if (pDoc->m_meta_graph->getSelCount() == 1) { - ok = pDoc->m_meta_graph->getDisplayedShapeGraph().unlinkShapes( LogicalUnits(point) ); + if (m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWAXIAL) { + if (m_pDoc.m_meta_graph->getSelCount() == 1) { + ok = m_pDoc.m_meta_graph->getDisplayedShapeGraph().unlinkShapes( LogicalUnits(point) ); } else { // oops: you are only allowed to join lines one to one: - pDoc->m_meta_graph->clearSel(); + m_pDoc.m_meta_graph->clearSel(); clearcursor = true; } } @@ -972,8 +975,8 @@ void QDepthmapView::mouseReleaseEvent(QMouseEvent *e) SetCursor(UNJOIN); m_drag_rect_a = QRect(0,0,0,0); if (ok) { - pDoc->modifiedFlag = true; - pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL,QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA); + m_pDoc.modifiedFlag = true; + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_ALL,QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA); } else { m_redraw_all = true; @@ -989,9 +992,9 @@ void QDepthmapView::mouseReleaseEvent(QMouseEvent *e) m_invalidate = LINEOFF; SetCursor(m_mouse_mode); update(); - if (pDoc->m_meta_graph->moveSelShape(Line(m_line.t_start(),location))) { - pDoc->modifiedFlag = true; - pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA); + if (m_pDoc.m_meta_graph->moveSelShape(Line(m_line.t_start(),location))) { + m_pDoc.modifiedFlag = true; + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA); } } break; @@ -1015,9 +1018,9 @@ void QDepthmapView::mouseReleaseEvent(QMouseEvent *e) m_mouse_mode &= ~DRAWLINE; m_invalidate = LINEOFF; update(); - if (pDoc->m_meta_graph->makeShape(Line(m_line.t_start(),location))) { - pDoc->modifiedFlag = true; - pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); + if (m_pDoc.m_meta_graph->makeShape(Line(m_line.t_start(),location))) { + m_pDoc.modifiedFlag = true; + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); } } break; @@ -1029,7 +1032,7 @@ void QDepthmapView::mouseReleaseEvent(QMouseEvent *e) update(); // if it's the first part, just make it a line: if (m_poly_points == 0) { - pDoc->m_meta_graph->polyBegin(Line(m_line.t_start(),location)); + m_currentlyEditingShapeRef = m_pDoc.m_meta_graph->polyBegin(Line(m_line.t_start(),location)); m_poly_start = m_line.t_start(); m_poly_points += 2; m_mouse_mode |= DRAWLINE; @@ -1039,27 +1042,28 @@ void QDepthmapView::mouseReleaseEvent(QMouseEvent *e) } else if (m_poly_points > 2 && PixelDist(point,PhysicalUnits(m_poly_start)) < 6) { // check to see if it's back to the original start point, if so, close off - pDoc->m_meta_graph->polyClose(); + m_pDoc.m_meta_graph->polyClose(m_currentlyEditingShapeRef); m_poly_points = 0; + m_currentlyEditingShapeRef = -1; } else { - pDoc->m_meta_graph->polyAppend(location); + m_pDoc.m_meta_graph->polyAppend(m_currentlyEditingShapeRef, location); m_poly_points += 1; m_mouse_mode |= DRAWLINE; m_line = Line(location, location); m_invalidate = LINEON; update(); } - pDoc->modifiedFlag = true; - pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); + m_pDoc.modifiedFlag = true; + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); } break; case FILL: - pDoc->OnFillPoints( location, m_fillmode ); + m_pDoc.OnFillPoints( location, m_fillmode ); break; case SEEDISOVIST: m_current_mode = NONE; - pDoc->OnMakeIsovist( location ); + m_pDoc.OnMakeIsovist( location ); break; case SEEDHALFOVIST: m_current_mode = NONE; @@ -1076,27 +1080,27 @@ void QDepthmapView::mouseReleaseEvent(QMouseEvent *e) update(); Point2f vec = m_line.vector(); vec.normalise(); - pDoc->OnMakeIsovist( m_line.t_start(), vec.angle() ); + m_pDoc.OnMakeIsovist( m_line.t_start(), vec.angle() ); } break; case SEEDAXIAL: - pDoc->OnToolsAxialMap( location ); + m_pDoc.OnToolsAxialMap( location ); // switch to select mode (stops you accidently pressing twice) OnEditSelect(); break; } if (m_mouse_mode == JOIN) { - if (pDoc->m_meta_graph->isSelected()) { + if (m_pDoc.m_meta_graph->isSelected()) { BeginJoin(); } } else if (m_mouse_mode == UNJOIN) { - if (pDoc->m_meta_graph->isSelected()) { - if (pDoc->m_meta_graph->viewingProcessedPoints()) { - if (pDoc->m_meta_graph->getDisplayedPointMap().unmergePoints()) { - pDoc->modifiedFlag = true; - pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL,QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA); + if (m_pDoc.m_meta_graph->isSelected()) { + if (m_pDoc.m_meta_graph->viewingProcessedPoints()) { + if (m_pDoc.m_meta_graph->getDisplayedPointMap().unmergePoints()) { + m_pDoc.modifiedFlag = true; + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_ALL,QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA); } } else { @@ -1121,8 +1125,9 @@ void QDepthmapView::mouseReleaseEvent(QMouseEvent *e) m_mouse_mode &= ~DRAWLINE; if (m_mouse_mode & POLYGONTOOL && m_poly_points > 0) { m_poly_points = 0; - pDoc->m_meta_graph->polyCancel(); - pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); + m_currentlyEditingShapeRef = -1; + m_pDoc.m_meta_graph->polyCancel(m_currentlyEditingShapeRef); + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); } else { m_invalidate = LINEOFF; @@ -1132,7 +1137,7 @@ void QDepthmapView::mouseReleaseEvent(QMouseEvent *e) // cancel other tools: switch (m_mouse_mode) { case ZOOM_IN: - ZoomOut(); + ZoomTowards(0.75, m_centre); break; case JOIN | JOINB: case UNJOIN | JOINB: @@ -1140,8 +1145,8 @@ void QDepthmapView::mouseReleaseEvent(QMouseEvent *e) SetCursor(m_mouse_mode); // drop through intentional case SELECT: - if (pDoc->m_meta_graph->isSelected()) { - pDoc->m_meta_graph->clearSel(); + if (m_pDoc.m_meta_graph->isSelected()) { + m_pDoc.m_meta_graph->clearSel(); // Redraw scene m_redraw_no_clear = true; update(); @@ -1149,7 +1154,7 @@ void QDepthmapView::mouseReleaseEvent(QMouseEvent *e) break; case PENCIL: { - pDoc->m_meta_graph->getDisplayedPointMap().fillPoint(LogicalUnits(point),false); + m_pDoc.m_meta_graph->getDisplayedPointMap().fillPoint(LogicalUnits(point),false); m_redraw_all = true; update(); } @@ -1175,31 +1180,43 @@ void QDepthmapView::mouseReleaseEvent(QMouseEvent *e) pressed_nFlags &= ~MK_RBUTTON; } -void QDepthmapView::keyPressEvent(QKeyEvent *e) -{ - char key = e->key(); -} - void QDepthmapView::wheelEvent(QWheelEvent *e) { short zDelta = e->delta(); - QPoint centre = this->rect().center(); QPoint position = e->pos(); - if (zDelta < 0) { - ZoomOut(LogicalUnits(ViewHelpers::calculateCenter(position,centre,2.0))); - } - else { - QPoint centre = this->rect().center(); - QPoint position = e->pos(); - auto zoomFactor = 1.0 + double(zDelta) / 120.0; - ZoomIn(zoomFactor, LogicalUnits(ViewHelpers::calculateCenter(position, centre, 1.0/zoomFactor))); + QPoint centre(m_physical_centre.width(),m_physical_centre.height()); + auto zoomFactor = 1.0 + std::abs(double(zDelta)) / 120.0; + if (zDelta > 0) { + zoomFactor = 1.0/zoomFactor; } + Point2f newCentre = ViewHelpers::calculateCenter(position, centre, zoomFactor); + + // Same as LogicalUnits() with non-discreet input + newCentre.x = m_centre.x + m_unit * double(newCentre.x - m_physical_centre.width()); + newCentre.y = m_centre.y + m_unit * double(m_physical_centre.height() - newCentre.y); + + if(!IsAtZoomLimits(zoomFactor, 10)) { + ZoomTowards(zoomFactor, newCentre); + } +} + +// provides a way to limit how much can we zoom out in relation to the window +// and graph bounding box size to avoid problems when zooming out too far +bool QDepthmapView::IsAtZoomLimits(double ratio, double maxZoomOutRatio) { + if ( ratio < 1 ) + { + return false; + } + // for zoom out + QtRegion bounds = m_pDoc.m_meta_graph->getBoundingBox(); + double maxUnit = __max(bounds.width() / width(), bounds.height() / height()); + return m_unit * ratio > maxZoomOutRatio * maxUnit; } -void QDepthmapView::ZoomIn(double ratio, const Point2f& point) +void QDepthmapView::ZoomTowards(double ratio, const Point2f& point) { m_centre = point; - m_unit /= ratio; + m_unit *= ratio; m_invalidate = 0; @@ -1208,22 +1225,6 @@ void QDepthmapView::ZoomIn(double ratio, const Point2f& point) update(); } -void QDepthmapView::ZoomOut() -{ - m_unit *= 2; - m_invalidate = 0; - - // Redraw scene - m_redraw_all = true; - update(); -} - -void QDepthmapView::ZoomOut(Point2f centre) -{ - m_centre = centre; - ZoomOut(); -} - QSize QDepthmapView::sizeHint() const { return m_initialSize; @@ -1233,30 +1234,13 @@ void QDepthmapView::saveToFile() { } -bool QDepthmapView::loadFile(const QString &fileName) -{ - m_open_file_name = fileName; - m_redraw_all = 1; - QByteArray ba = fileName.toUtf8(); // quick fix for weird chars (russian filename bug report) - char *file = ba.data(); // quick fix for weird chars (russian filename bug report) - if(pDoc->OnOpenDocument(file)) // quick fix for weird chars (russian filename bug report) - { - setWindowTitle(pDoc->m_base_title+":Map View"); - return true; - } - return false; -} - -bool QDepthmapView::newFile() +void QDepthmapView::postLoadFile() { - m_open_file_name = ""; - m_redraw_all = 1; - pDoc->OnNewDocument(); - setWindowTitle(pDoc->m_base_title+":Map View"); - return true; + m_redraw_all = 1; + setWindowTitle(m_pDoc.m_base_title+":Map View"); } -bool QDepthmapView::Output(QPainter *pDC, QGraphDoc *pDoc, bool screendraw) +bool QDepthmapView::Output(QPainter *pDC, QGraphDoc *pDoc, bool screendraw) { unsigned long ticks = 0;//GetTickCount(); @@ -1308,7 +1292,7 @@ bool QDepthmapView::Output(QPainter *pDC, QGraphDoc *pDoc, bool screendraw) { bool nextlayer = false, first = true; pDC->setPen(QPen(QBrush(QColor(m_foreground)), spacer/20+1, Qt::SolidLine, Qt::RoundCap)); - while ( (b_continue = pDoc->m_meta_graph->SuperSpacePixel::findNextShape(nextlayer)) ) + while ( (b_continue = pDoc->m_meta_graph->findNextShape(nextlayer)) ) { /* Line l = pDoc->m_meta_graph->SuperSpacePixel::getNextLine(); if (nextlayer || first) { @@ -1327,7 +1311,7 @@ bool QDepthmapView::Output(QPainter *pDC, QGraphDoc *pDoc, bool screendraw) nextlayer = false; }*/ - const SalaShape& shape = pDoc->m_meta_graph->SuperSpacePixel::getNextShape(); + const SalaShape& shape = pDoc->m_meta_graph->getNextShape(); spacer = GetSpacer(pDoc); if (shape.isPoint()) { @@ -1342,12 +1326,12 @@ bool QDepthmapView::Output(QPainter *pDC, QGraphDoc *pDoc, bool screendraw) } else { size_t i; - for (i = 1; i < shape.size(); i++) + for (i = 1; i < shape.m_points.size(); i++) { - pDC->drawLine(PhysicalUnits(shape[i-1]), PhysicalUnits(shape[i])); + pDC->drawLine(PhysicalUnits(shape.m_points[i-1]), PhysicalUnits(shape.m_points[i])); } if (shape.isClosed()) { - pDC->drawLine(PhysicalUnits(shape[i-1]), PhysicalUnits(shape[0])); + pDC->drawLine(PhysicalUnits(shape.m_points[i-1]), PhysicalUnits(shape.m_points[0])); } } } @@ -1362,7 +1346,7 @@ bool QDepthmapView::Output(QPainter *pDC, QGraphDoc *pDoc, bool screendraw) ShapeMap& map = pDoc->m_meta_graph->getDisplayedDataMap(); for (int i = 0; i < map.getObjectCount(); i++) { if (map.getDisplayedAttributeValue(i) > 0) { - pstring text = map.getDisplayedAttributeText(i); + std::string text = map.getDisplayedAttributeText(i); QPoint p = PhysicalUnits(map.getCentroid(i)); QSize sz = pDC->GetTextExtent(text.c_str()); pDC->drawText(p.x(), p.y()-(sz.height()/2), text.c_str()); @@ -1373,7 +1357,7 @@ bool QDepthmapView::Output(QPainter *pDC, QGraphDoc *pDoc, bool screendraw) if (!b_continue && m_showlinks) { pDC->setBrush(QBrush( QColor(m_foreground), Qt::SolidPattern)); - if (pDoc->m_meta_graph->getViewClass() & MetaGraph::VIEWVGA && pDoc->m_meta_graph->getDisplayedPointMap().isProcessed()) + if (pDoc->m_meta_graph->getViewClass() & MetaGraph::VIEWVGA && pDoc->m_meta_graph->getDisplayedPointMap().isProcessed()) { PointMap& map = pDoc->m_meta_graph->getDisplayedPointMap(); // merge lines @@ -1438,7 +1422,7 @@ bool QDepthmapView::DrawPoints(QPainter *pDC, QGraphDoc *pDoc, int spacer, unsig Point2f logical = map.getNextPointLocation(); PafColor color; - color = map.getPointColor(); + color = map.getCurrentPointColor(); if (color.alphab() != 0) { // alpha == 0 is transparent @@ -1539,11 +1523,12 @@ bool QDepthmapView::DrawShapes(QPainter *pDC, ShapeMap& map, bool muted, int spa const SalaShape& poly = map.getNextShape(); QPoint *points = NULL; int drawable = 0; - if (!poly.isPoint() && !poly.isLine()) { - points = new QPoint [poly.size()]; - for (size_t i = 0; i < poly.size(); i++) { - points[drawable] = PhysicalUnits(poly[i]); - if (i == 0 || points[drawable] != points[drawable-1]) { + if (!poly.isPoint() && !poly.isLine() && !poly.m_points.empty()) { + points = new QPoint [poly.m_points.size()]; + if (poly.m_points.size() > 0) drawable++; + for (auto& point: poly.m_points) { + points[drawable] = PhysicalUnits(point); + if (points[drawable] != points[drawable-1]) { drawable++; } } @@ -1694,7 +1679,7 @@ void QDepthmapView::DrawPointHandle(QPainter *pDC, QPoint pt) pDC->drawRect(rect); } -void QDepthmapView::OutputEPS( ofstream& stream, QGraphDoc *pDoc ) +void QDepthmapView::OutputEPS( std::ofstream& stream, QGraphDoc *pDoc, bool includeScale ) { // This output EPS is a copy of the standard output... obviously, if you change // standard output, remember to change this one too! @@ -1702,7 +1687,7 @@ void QDepthmapView::OutputEPS( ofstream& stream, QGraphDoc *pDoc ) // now the two are a little out of synch if (!m_viewport_set) { - QMessageBox::warning(this, tr("Warning"), tr("Can't save screen as the Depthmap window is not initialised"), QMessageBox::Yes, QMessageBox::Yes); + QMessageBox::warning(this, tr("Warning"), tr("Can't save screen as the Depthmap window is not initialised"), QMessageBox::Ok, QMessageBox::Ok); return; } @@ -1711,7 +1696,7 @@ void QDepthmapView::OutputEPS( ofstream& stream, QGraphDoc *pDoc ) stream << "%!PS-Adobe-3.0 EPSF-3.0\n" << "%%BoundingBox: 0 0 " << clrect.width() << " " << clrect.height() << "\n" - << "%%Creator: depthmapX " << DEPTHMAPX_VERSION << "." << DEPTHMAPX_MINOR_VERSION << endl; + << "%%Creator: " << TITLE_BASE << std::endl; // temporarily inflate resolution for EPS draw rect = QRect(clrect.left() * 10, clrect.top() * 10, clrect.width() * 10, clrect.height() * 10); @@ -1730,11 +1715,11 @@ void QDepthmapView::OutputEPS( ofstream& stream, QGraphDoc *pDoc ) float fgg = float(GetGValue(fg))/255.0f; float fgb = float(GetBValue(fg))/255.0f; - stream << "/M {moveto} def" << endl; - stream << "/L {lineto} def" << endl; - stream << "/R {rlineto} def" << endl; - stream << "/C {setrgbcolor} def" << endl; - stream << "/W {setlinewidth} def" << endl; + stream << "/M {moveto} def" << std::endl; + stream << "/L {lineto} def" << std::endl; + stream << "/R {rlineto} def" << std::endl; + stream << "/C {setrgbcolor} def" << std::endl; + stream << "/W {setlinewidth} def" << std::endl; stream << "newpath\n" << 0 << " " << 0 << " M\n" @@ -1743,7 +1728,7 @@ void QDepthmapView::OutputEPS( ofstream& stream, QGraphDoc *pDoc ) << -clrect.width() << " " << 0 << " R\n" << "closepath\n" << bgr << " " << bgg << " " << bgb << " C\n" - << "fill" << endl; + << "fill" << std::endl; int state = pDoc->m_meta_graph->getState(); @@ -1760,7 +1745,7 @@ void QDepthmapView::OutputEPS( ofstream& stream, QGraphDoc *pDoc ) pDoc->m_meta_graph->getDisplayedDataMap().makeViewportShapes( logicalviewport ); } if (state & MetaGraph::LINEDATA) { - pDoc->m_meta_graph->SuperSpacePixel::makeViewportShapes( logicalviewport ); + pDoc->m_meta_graph->makeViewportShapes( logicalviewport ); } double spacer = GetSpacer(pDoc) / 10.0; @@ -1776,9 +1761,9 @@ void QDepthmapView::OutputEPS( ofstream& stream, QGraphDoc *pDoc ) << " " << 2 * spacer << " " << 0 << " R\n" << " " << 0 << " " << 2 * spacer << " R\n" << " " << 2 * -spacer << " " << 0 << " R\n" - << " closepath } def" << endl; + << " closepath } def" << std::endl; stream << "/fbx\n" - << " { C fill } def" << endl; + << " { C fill } def" << std::endl; PointMap& map = pDoc->m_meta_graph->getDisplayedPointMap(); @@ -1786,15 +1771,15 @@ void QDepthmapView::OutputEPS( ofstream& stream, QGraphDoc *pDoc ) Point2f logical = map.getNextPointLocation(); - PafColor color = map.getPointColor(); + PafColor color = map.getCurrentPointColor(); if (color.alphab() != 0) { // alpha == 0 is transparent QPoint p = PhysicalUnits(logical); // Now do EPS box... remember the coordinate system is the right way up! - stream << p.x() / 10.0 - spacer << " " << (rect.height() - p.y()) / 10.0 - spacer << " bx" << endl; - stream << color.redf() << " " << color.greenf() << " " << color.bluef() << " fbx" << endl; + stream << p.x() / 10.0 - spacer << " " << (rect.height() - p.y()) / 10.0 - spacer << " bx" << std::endl; + stream << color.redf() << " " << color.greenf() << " " << color.bluef() << " fbx" << std::endl; } } } @@ -1815,14 +1800,14 @@ void QDepthmapView::OutputEPS( ofstream& stream, QGraphDoc *pDoc ) if (state & MetaGraph::LINEDATA) { - stream << "newpath" << endl; + stream << "newpath" << std::endl; bool nextlayer = false; bool first = true; int style = 0; - while ( pDoc->m_meta_graph->SuperSpacePixel::findNextShape(nextlayer) ) { + while ( pDoc->m_meta_graph->findNextShape(nextlayer) ) { - const SalaShape& shape = pDoc->m_meta_graph->SuperSpacePixel::getNextShape(); + const SalaShape& shape = pDoc->m_meta_graph->getNextShape(); Line l; if (shape.isPoint()) { @@ -1846,35 +1831,35 @@ void QDepthmapView::OutputEPS( ofstream& stream, QGraphDoc *pDoc ) else { stream << "[]"; } - stream << " 0 setdash" << endl; - stream << fgr << " " << fgg << " " << fgb << " C" << endl; - stream << spacer/10+1 << " W" << endl; - stream << "stroke" << endl; + stream << " 0 setdash" << std::endl; + stream << fgr << " " << fgg << " " << fgb << " C" << std::endl; + stream << spacer/10+1 << " W" << std::endl; + stream << "stroke" << std::endl; } // loaded paths if (pDoc->m_evolved_paths.size()) { - stream << "newpath" << endl; + stream << "newpath" << std::endl; for (size_t i = 0; i < pDoc->m_evolved_paths.size(); i++) { - const prefvec& path = pDoc->m_evolved_paths[i]; + const std::vector& path = pDoc->m_evolved_paths[i]; if (path.size() > 1) { QPoint last = PhysicalUnits(path[0]); - stream << (last.x() - spacer/40) / 10.0 << " " << (rect.height() - last.y() + spacer/40) / 10.0 << " M\n" << endl; + stream << (last.x() - spacer/40) / 10.0 << " " << (rect.height() - last.y() + spacer/40) / 10.0 << " M\n" << std::endl; for (size_t j = 1; j < path.size(); j++) { QPoint next = PhysicalUnits(path[j]); - stream << (next.x() - last.x() - spacer/40) / 10.0 << " " << (last.y() - next.y() - spacer/40) / 10.0 << " L" << endl; + stream << (next.x() - last.x() - spacer/40) / 10.0 << " " << (last.y() - next.y() - spacer/40) / 10.0 << " L" << std::endl; last = next; } - stream << fgr << " " << fgg << " " << fgb << " C" << endl; - stream << spacer/20+1 << " W" << endl; - stream << "stroke" << endl; + stream << fgr << " " << fgg << " " << fgb << " C" << std::endl; + stream << spacer/20+1 << " W" << std::endl; + stream << "stroke" << std::endl; } } } @@ -1892,61 +1877,63 @@ void QDepthmapView::OutputEPS( ofstream& stream, QGraphDoc *pDoc ) QPoint p = PhysicalUnits(Point2f(logical.x, logical.y)); QPoint bottomleft = PhysicalUnits(Point2f(logical.x - 0.5, logical.y - 0.5)); // Now do EPS box... remember the coordinate system is the right way up! - stream << (p.x - spacer) / 10.0 << " " << (rect.Height() - p.y - spacer) / 10.0 << " bx" << endl; - stream << bgr << " " << bgg << " " << bgb << " fbx" << endl; + stream << (p.x - spacer) / 10.0 << " " << (rect.Height() - p.y - spacer) / 10.0 << " bx" << std::endl; + stream << bgr << " " << bgg << " " << bgb << " fbx" << std::endl; // And cover with line: stream << (bottomleft.x - spacer/20) / 10.0 << " " << (rect.Height() - bottomleft.y + spacer/20) / 10.0 << " M\n" << (spacer * 2 - spacer/20) / 10.0 << " " << 0 << " L\n" << 0 << " " << (spacer * 2 - spacer/20) / 10.0 << " L\n" << (-spacer * 2 + spacer/20) / 10.0 << " " << 0 << " L\n" - << 0 << " " << (-spacer * 2 + spacer/20) / 10.0 << " L" << endl; - stream << fgr << " " << fgg << " " << fgb << " setrgbcolor" << endl; - stream << spacer/10+1 << " setlinewidth" << endl; - stream << "stroke" << endl; + << 0 << " " << (-spacer * 2 + spacer/20) / 10.0 << " L" << std::endl; + stream << fgr << " " << fgg << " " << fgb << " setrgbcolor" << std::endl; + stream << spacer/10+1 << " setlinewidth" << std::endl; + stream << "stroke" << std::endl; } } } */ - // add the scale to the bottom lefthand corner - double logicalwidth = m_unit * rect.width(); - if (logicalwidth > 10) { - int workingwidth = floor(log10(logicalwidth/2)*2.0); - int barwidth = (int) pow(10.0,(double)(workingwidth/2)) * ((workingwidth%2 == 0) ? 1 : 5); - double physicalbar = double(barwidth) / m_unit; - stream << "newpath" << endl; - stream << "0 0 M 0 18 R" << endl; - stream << physicalbar / 10.0 << " 0 R 0 -18 R closepath" << endl; - stream << bgr << " " << bgg << " " << bgb << " C" << endl; - stream << "fill newpath" << endl; - stream << fgr << " " << fgg << " " << fgb << " C" << endl; - stream << "0 12 M" << endl; - stream << physicalbar / 10.0 << " 0 R" << endl; - stream << "3 W stroke" << endl; - stream << "0 6 M 0 7.5 R" << endl; - stream << physicalbar / 10.0 << " 6 M 0 7.5 R" << endl; - stream << "1.5 W stroke" << endl; - stream << "/Arial findfont 12 scalefont setfont" << endl; - // assume metres! - if (barwidth > 1000) { - stream << "(" << (barwidth / 1000) << "km) stringwidth pop 2 div" << endl; - } - else { - stream << "(" << barwidth << "m) stringwidth pop 2 div" << endl; - } - stream << physicalbar / 20.0 << " exch sub" << endl; - stream << "0 M" << endl; - stream << "(" << barwidth << "m) show" << endl; - } - - stream << "showpage" << endl; + if(includeScale) { + // add the scale to the bottom lefthand corner + double logicalwidth = m_unit * rect.width(); + if (logicalwidth > 10) { + int workingwidth = floor(log10(logicalwidth/2)*2.0); + int barwidth = (int) pow(10.0,(double)(workingwidth/2)) * ((workingwidth%2 == 0) ? 1 : 5); + double physicalbar = double(barwidth) / m_unit; + stream << "newpath" << std::endl; + stream << "0 0 M 0 18 R" << std::endl; + stream << physicalbar / 10.0 << " 0 R 0 -18 R closepath" << std::endl; + stream << bgr << " " << bgg << " " << bgb << " C" << std::endl; + stream << "fill newpath" << std::endl; + stream << fgr << " " << fgg << " " << fgb << " C" << std::endl; + stream << "0 12 M" << std::endl; + stream << physicalbar / 10.0 << " 0 R" << std::endl; + stream << "3 W stroke" << std::endl; + stream << "0 6 M 0 7.5 R" << std::endl; + stream << physicalbar / 10.0 << " 6 M 0 7.5 R" << std::endl; + stream << "1.5 W stroke" << std::endl; + stream << "/Arial findfont 12 scalefont setfont" << std::endl; + // assume metres! + if (barwidth > 1000) { + stream << "(" << (barwidth / 1000) << "km) stringwidth pop 2 div" << std::endl; + } + else { + stream << "(" << barwidth << "m) stringwidth pop 2 div" << std::endl; + } + stream << physicalbar / 20.0 << " exch sub" << std::endl; + stream << "0 M" << std::endl; + stream << "(" << barwidth << "m) show" << std::endl; + } + } + + stream << "showpage" << std::endl; // undo temporary unit setting m_unit = oldunit; m_physical_centre = QSize(oldcentre.x(), oldcentre.y()) ; } -void QDepthmapView::OutputEPSMap(ofstream& stream, ShapeMap& map, QtRegion& logicalviewport, QRect& rect, float spacer) +void QDepthmapView::OutputEPSMap(std::ofstream& stream, ShapeMap& map, QtRegion& logicalviewport, QRect& rect, float spacer) { bool monochrome = (map.getDisplayParams().colorscale == DisplayParams::MONOCHROME); double thickness = 1.0, oldthickness = 1.0; @@ -1958,8 +1945,8 @@ void QDepthmapView::OutputEPSMap(ofstream& stream, ShapeMap& map, QtRegion& logi float fgg = float(GetGValue(fg))/255.0f; float fgb = float(GetBValue(fg))/255.0f; - stream << "newpath" << endl; - stream << fgr << " " << fgg << " " << fgb << " C" << endl; + stream << "newpath" << std::endl; + stream << fgr << " " << fgg << " " << fgb << " C" << std::endl; bool dummy; while ( map.findNextShape(dummy) ) { @@ -1975,15 +1962,15 @@ void QDepthmapView::OutputEPSMap(ofstream& stream, ShapeMap& map, QtRegion& logi continue; } if (thickness != oldthickness || closed != oldclosed) { - stream << oldthickness << " W" << endl; - stream << (oldclosed ? "fill" : "stroke") << endl; + stream << oldthickness << " W" << std::endl; + stream << (oldclosed ? "fill" : "stroke") << std::endl; oldthickness = thickness; oldclosed = closed; } } else if (color != oldcolor || closed != oldclosed) { - stream << oldcolor.redf() << " " << oldcolor.greenf() << " " << oldcolor.bluef() << " C" << endl; - stream << (oldclosed ? "fill" : "stroke") << endl; + stream << oldcolor.redf() << " " << oldcolor.greenf() << " " << oldcolor.bluef() << " C" << std::endl; + stream << (oldclosed ? "fill" : "stroke") << std::endl; oldcolor = color; oldclosed = closed; } @@ -1999,14 +1986,14 @@ void QDepthmapView::OutputEPSMap(ofstream& stream, ShapeMap& map, QtRegion& logi OutputEPSPoly(stream, shape, spacer, logicalviewport, rect); } } - stream << thickness << " W" << endl; + stream << thickness << " W" << std::endl; if (!monochrome) { - stream << color.redf() << " " << color.greenf() << " " << color.bluef() << " C" << endl; + stream << color.redf() << " " << color.greenf() << " " << color.bluef() << " C" << std::endl; } - stream << (closed ? "fill" : "stroke") << endl; + stream << (closed ? "fill" : "stroke") << std::endl; } -void QDepthmapView::OutputEPSLine(ofstream& stream, Line& line, int spacer, QtRegion& logicalviewport, QRect& rect) +void QDepthmapView::OutputEPSLine(std::ofstream& stream, Line& line, int spacer, QtRegion& logicalviewport, QRect& rect) { bool drewit = false; if (line.crop(logicalviewport)) { @@ -2016,19 +2003,19 @@ void QDepthmapView::OutputEPSLine(ofstream& stream, Line& line, int spacer, QtRe if (sqrt(sqr(start.x() - end.x()) + sqr(start.y() - end.y())) > 5.0) { stream << (start.x() / 10.0) << " " << (rect.height() - start.y()) / 10.0 << " M "; - stream << (end.x() / 10.0) << " " << (rect.height() - end.y()) / 10.0 << " L" << endl; + stream << (end.x() / 10.0) << " " << (rect.height() - end.y()) / 10.0 << " L" << std::endl; } } } -void QDepthmapView::OutputEPSPoly(ofstream& stream, const SalaShape& shape, int spacer, QtRegion& logicalviewport, QRect& rect) +void QDepthmapView::OutputEPSPoly(std::ofstream& stream, const SalaShape& shape, int spacer, QtRegion& logicalviewport, QRect& rect) { bool starter = true; - Point2f lastpoint = shape[0]; - int count = shape.isClosed() ? shape.size() + 1 : shape.size(); - int size = shape.size(); + Point2f lastpoint = shape.m_points[0]; + int count = shape.isClosed() ? shape.m_points.size() + 1 : shape.m_points.size(); + int size = shape.m_points.size(); for (int i = 1; i < count; i++) { - Line line(lastpoint,shape[i%size]); + Line line(lastpoint,shape.m_points[i%size]); if (line.crop(logicalviewport)) { // note: use t_start and t_end so that this line moves in the correct direction QPoint start = PhysicalUnits(line.t_start()); @@ -2039,14 +2026,14 @@ void QDepthmapView::OutputEPSPoly(ofstream& stream, const SalaShape& shape, int if (starter) { stream << start.x() / 10.0 << " " << (rect.height() - start.y()) / 10.0 << " M "; } - stream << end.x() / 10.0 << " " << (rect.height() - end.y()) / 10.0 << " L" << endl; + stream << end.x() / 10.0 << " " << (rect.height() - end.y()) / 10.0 << " L" << std::endl; // note: you must use t_end (true end) so that it takes the end point from the shape[i] end: lastpoint = line.t_end(); starter = false; } } else { - lastpoint = shape[i]; + lastpoint = shape.m_points[i]; starter = true; } } @@ -2205,8 +2192,8 @@ void QDepthmapView::SetCursor(int mode) // Zoom to Selection void QDepthmapView::OnViewZoomsel() { - if (pDoc->m_meta_graph && pDoc->m_meta_graph->isSelected()) { - QtRegion sel_bounds = pDoc->m_meta_graph->getSelBounds(); + if (m_pDoc.m_meta_graph && m_pDoc.m_meta_graph->isSelected()) { + QtRegion sel_bounds = m_pDoc.m_meta_graph->getSelBounds(); // select a suitable zoom factor based on bounding box dimensions: m_centre = sel_bounds.getCentre(); QRect phys_bounds = this->rect(); @@ -2217,7 +2204,7 @@ void QDepthmapView::OnViewZoomsel() } else { // base area on some arbitrary zoom into the map - QtRegion map_bounds = pDoc->m_meta_graph->getBoundingBox(); + QtRegion map_bounds = m_pDoc.m_meta_graph->getBoundingBox(); m_unit = 0.01 * __max( map_bounds.width() / double(phys_bounds.width()), map_bounds.height() / double(phys_bounds.height()) ); } @@ -2227,74 +2214,66 @@ void QDepthmapView::OnViewZoomsel() } } -void QDepthmapView::OnViewMove() +void QDepthmapView::OnViewPan() { - m_curr_seleted = ID_MAPBAR_ITEM_MOVE; m_mouse_mode = DRAG; SetCursor(DRAG); } void QDepthmapView::OnViewZoomIn() { - m_curr_seleted = ID_MAPBAR_ITEM_ZOOM_IN; m_mouse_mode = ZOOM_IN; SetCursor(ZOOM_IN); } void QDepthmapView::OnViewZoomOut() { - m_curr_seleted = ID_MAPBAR_ITEM_ZOOM_OUT; m_mouse_mode = ZOOM_OUT; SetCursor(ZOOM_OUT); } void QDepthmapView::OnEditSelect() { - m_curr_seleted = ID_MAPBAR_ITEM_SELECT; m_mouse_mode = SELECT; SetCursor(SELECT); if (m_showlinks) { m_showlinks = false; - pDoc->SetRedrawFlag(QGraphDoc::VIEW_MAP, QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP, this); + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_MAP, QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP, this); } } void QDepthmapView::OnModeIsovist() { - m_curr_seleted = ID_MAPBAR_ITEM_ISOVIST; m_mouse_mode = SEEDISOVIST; SetCursor(SEEDISOVIST); if (m_showlinks) { m_showlinks = false; - pDoc->SetRedrawFlag(QGraphDoc::VIEW_MAP,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP, this); + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_MAP,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP, this); } } -void QDepthmapView::OnModeHalfovist() +void QDepthmapView::OnModeTargetedIsovist() { - m_curr_seleted = ID_MAPBAR_ITEM_HALFISOVIST; m_mouse_mode = SEEDHALFOVIST; SetCursor(SEEDHALFOVIST); if (m_showlinks) { m_showlinks = false; - pDoc->SetRedrawFlag(QGraphDoc::VIEW_MAP,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP, this); + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_MAP,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP, this); } } -void QDepthmapView::OnToolsAxialMap() +void QDepthmapView::OnModeSeedAxial() { - m_curr_seleted = ID_MAPBAR_ITEM_AL2; m_mouse_mode = SEEDAXIAL; SetCursor(SEEDAXIAL); if (m_showlinks) { m_showlinks = false; - pDoc->SetRedrawFlag(QGraphDoc::VIEW_MAP,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP, this); + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_MAP,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP, this); } } void QDepthmapView::OnEditFill() { - m_curr_seleted = ID_MAPBAR_ITEM_FILL; m_mouse_mode = FILL; m_fillmode = FULLFILL; SetCursor(FILL); @@ -2302,7 +2281,6 @@ void QDepthmapView::OnEditFill() void QDepthmapView::OnEditSemiFill() { - m_curr_seleted = ID_MAPBAR_ITEM_SEMIFILL; m_mouse_mode = FILL; m_fillmode = SEMIFILL; SetCursor(FILL); @@ -2311,7 +2289,6 @@ void QDepthmapView::OnEditSemiFill() // AV TV void QDepthmapView::OnEditAugmentFill() { - m_curr_seleted = ID_MAPBAR_ITEM_AUGMENT_FILL; m_mouse_mode = FILL; m_fillmode = AUGMENT; SetCursor(FILL); @@ -2319,7 +2296,6 @@ void QDepthmapView::OnEditAugmentFill() void QDepthmapView::OnEditPencil() { - m_curr_seleted = ID_MAPBAR_ITEM_PENCIL; m_mouse_mode = PENCIL; SetCursor(PENCIL); } @@ -2332,32 +2308,29 @@ void QDepthmapView::OnEditEraser() void QDepthmapView::OnEditLineTool() { - m_curr_seleted = ID_MAPBAR_ITEM_LINETOOL; m_mouse_mode = LINETOOL; SetCursor(LINETOOL); if (m_showlinks) { m_showlinks = false; - pDoc->SetRedrawFlag(QGraphDoc::VIEW_MAP,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP, this); + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_MAP,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP, this); } } -void QDepthmapView::OnEditPolygon() +void QDepthmapView::OnEditPolygonTool() { - m_curr_seleted = ID_MAPBAR_ITEM_POLYGON; m_mouse_mode = POLYGONTOOL; SetCursor(POLYGONTOOL); if (m_showlinks) { m_showlinks = false; - pDoc->SetRedrawFlag(QGraphDoc::VIEW_MAP,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP, this); + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_MAP,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP, this); } } void QDepthmapView::OnModeJoin() { - m_curr_seleted = ID_MAPBAR_ITEM_JOIN; - if (pDoc->m_meta_graph->getState() & (MetaGraph::POINTMAPS | MetaGraph::SHAPEGRAPHS)) { + if (m_pDoc.m_meta_graph->getState() & (MetaGraph::POINTMAPS | MetaGraph::SHAPEGRAPHS)) { m_mouse_mode = JOIN; - if (!pDoc->m_meta_graph->isSelected()) { + if (!m_pDoc.m_meta_graph->isSelected()) { SetCursor(m_mouse_mode); } else { @@ -2365,21 +2338,20 @@ void QDepthmapView::OnModeJoin() } // Redraw scene m_showlinks = true; - pDoc->SetRedrawFlag(QGraphDoc::VIEW_MAP,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP, this); + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_MAP,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP, this); } } void QDepthmapView::OnModeUnjoin() { - m_curr_seleted = ID_MAPBAR_ITEM_UNJOIN; - if (pDoc->m_meta_graph->getState() & (MetaGraph::POINTMAPS | MetaGraph::SHAPEGRAPHS)) { + if (m_pDoc.m_meta_graph->getState() & (MetaGraph::POINTMAPS | MetaGraph::SHAPEGRAPHS)) { m_mouse_mode = UNJOIN; - if (!pDoc->m_meta_graph->isSelected()) { + if (!m_pDoc.m_meta_graph->isSelected()) { SetCursor(m_mouse_mode); } else { - if (pDoc->m_meta_graph->viewingProcessedPoints()) { - pDoc->m_meta_graph->clearSel(); + if (m_pDoc.m_meta_graph->viewingProcessedPoints()) { + m_pDoc.m_meta_graph->clearSel(); } else { m_mouse_mode |= JOINB; @@ -2388,49 +2360,47 @@ void QDepthmapView::OnModeUnjoin() } // Redraw scene m_showlinks = true; - pDoc->SetRedrawFlag(QGraphDoc::VIEW_MAP,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP, this); + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_MAP,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_DEPTHMAPVIEW_SETUP, this); } } -void QDepthmapView::OnEditCopy() +void QDepthmapView::OnEditCopy() { - QRect rectin = QRect(0,0,width(),height()); - int state = pDoc->m_meta_graph->getState(); + QRect rectin = QRect(0,0,width(),height()); + int state = m_pDoc.m_meta_graph->getState(); - if (state & MetaGraph::POINTMAPS && (!pDoc->m_meta_graph->getDisplayedPointMap().isProcessed() || pDoc->m_meta_graph->getViewClass() & (MetaGraph::VIEWVGA | MetaGraph::VIEWBACKVGA))) { - pDoc->m_meta_graph->getDisplayedPointMap().setScreenPixel( m_unit ); // only used by points (at the moment!) - pDoc->m_meta_graph->getDisplayedPointMap().makeViewportPoints( LogicalViewport(rectin, pDoc) ); - } - if (state & MetaGraph::SHAPEGRAPHS && (pDoc->m_meta_graph->getViewClass() & (MetaGraph::VIEWBACKAXIAL | MetaGraph::VIEWAXIAL))) { - pDoc->m_meta_graph->getDisplayedShapeGraph().makeViewportShapes( LogicalViewport(rectin, pDoc) ); - } - if (state & MetaGraph::DATAMAPS && (pDoc->m_meta_graph->getViewClass() & (MetaGraph::VIEWBACKDATA | MetaGraph::VIEWDATA))) { - pDoc->m_meta_graph->getDisplayedDataMap().makeViewportShapes( LogicalViewport(rectin, pDoc) ); - } - if (state & MetaGraph::LINEDATA) { - pDoc->m_meta_graph->SuperSpacePixel::makeViewportShapes( LogicalViewport(rectin, pDoc) ); - } + if (state & MetaGraph::POINTMAPS && (!m_pDoc.m_meta_graph->getDisplayedPointMap().isProcessed() || m_pDoc.m_meta_graph->getViewClass() & (MetaGraph::VIEWVGA | MetaGraph::VIEWBACKVGA))) { + m_pDoc.m_meta_graph->getDisplayedPointMap().setScreenPixel( m_unit ); // only used by points (at the moment!) + m_pDoc.m_meta_graph->getDisplayedPointMap().makeViewportPoints( LogicalViewport(rectin, &m_pDoc) ); + } + if (state & MetaGraph::SHAPEGRAPHS && (m_pDoc.m_meta_graph->getViewClass() & (MetaGraph::VIEWBACKAXIAL | MetaGraph::VIEWAXIAL))) { + m_pDoc.m_meta_graph->getDisplayedShapeGraph().makeViewportShapes( LogicalViewport(rectin, &m_pDoc) ); + } + if (state & MetaGraph::DATAMAPS && (m_pDoc.m_meta_graph->getViewClass() & (MetaGraph::VIEWBACKDATA | MetaGraph::VIEWDATA))) { + m_pDoc.m_meta_graph->getDisplayedDataMap().makeViewportShapes( LogicalViewport(rectin, &m_pDoc) ); + } + if (state & MetaGraph::LINEDATA) { + m_pDoc.m_meta_graph->makeViewportShapes( LogicalViewport(rectin, &m_pDoc) ); + } // Copy to Clipboard - QPixmap image(0, 0); - QPainter painter; - painter.begin(&image); // paint in picture + QPixmap image(width(), height()); + QPainter painter; + painter.begin(&image); // paint in picture - Output(&painter, pDoc, false); - painter.end(); // painting done + Output(&painter, &m_pDoc, false); + painter.end(); // painting done - QImage img = image.toImage(); - QClipboard *clipboard = QApplication::clipboard(); -// clipboard->setImage(img); - clipboard->setPixmap(image); + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setPixmap(image); } -void QDepthmapView::OnEditSave() +void QDepthmapView::OnEditSave() { // Very similar to copy to clipboard, only writes an EPS instead of a WMF - if (pDoc->m_communicator) { - QMessageBox::warning(this, tr("Warning"), tr("Another Depthmap process is running, please wait until it completes"), QMessageBox::Ok, QMessageBox::Ok); + if (m_pDoc.m_communicator) { + QMessageBox::warning(this, tr("Warning"), tr("Another Depthmap process is running, please wait until it completes"), QMessageBox::Ok, QMessageBox::Ok); return; } @@ -2444,54 +2414,58 @@ void QDepthmapView::OnEditSave() QFileDialog::Options options = 0; QString selectedFilter; QString outfile = QFileDialog::getSaveFileName( - 0, tr("Save Screen As"), - saveas, - template_string, - &selectedFilter, - options); - + 0, tr("Save Screen As"), + saveas, + template_string, + &selectedFilter, + options); + if(outfile.isEmpty()) return; FILE* fp = fopen(outfile.toLatin1(), "wb"); fclose(fp); - ofstream stream( outfile.toLatin1() ); + std::ofstream stream( outfile.toLatin1() ); if (stream.fail()) { QMessageBox::warning(this, tr("Warning"), tr("Sorry, unable to open ") + outfile + tr(" for writing"), QMessageBox::Ok, QMessageBox::Ok ); - return; + return; } - QFilePath newpath(outfile); + QFilePath newpath(outfile); QString ext = newpath.m_ext.toLower(); if (ext == "svg") { - OutputSVG( stream, pDoc ); + OutputSVG( stream, &m_pDoc ); } else { + QMessageBox::StandardButton reply; + reply = QMessageBox::question(this, "", "Would you like to include a scale?", + QMessageBox::Yes|QMessageBox::No); + bool includeScale = (reply == QMessageBox::Yes); // Set up complete... run the .eps outputter (copied from standard output!) - OutputEPS( stream, pDoc ); + OutputEPS( stream, &m_pDoc, includeScale ); } - stream.close(); + stream.close(); } void QDepthmapView::closeEvent(QCloseEvent *event) { - pDoc->m_view[QGraphDoc::VIEW_MAP] = NULL; - if (!pDoc->OnCloseDocument(QGraphDoc::VIEW_MAP)) + m_pDoc.m_view[QGraphDoc::VIEW_MAP] = NULL; + if (!m_pDoc.OnCloseDocument(QGraphDoc::VIEW_MAP)) { - pDoc->m_view[QGraphDoc::VIEW_MAP] = this; + m_pDoc.m_view[QGraphDoc::VIEW_MAP] = this; event->ignore(); } } -static string SVGColor(PafColor color) +static std::string SVGColor(PafColor color) { - stringstream text; + std::stringstream text; int r = color.redb(); int g = color.greenb(); int b = color.blueb(); - text << setfill('0') << "#" << setw(2) << std::hex << r << setw(2) << std::hex << g<< setw(2) << std::hex << b; + text << std::setfill('0') << "#" << std::setw(2) << std::hex << r << std::setw(2) << std::hex << g<< std::setw(2) << std::hex << b; return text.str(); } @@ -2503,7 +2477,7 @@ static QPoint SVGPhysicalUnits(const Point2f& p, const QtRegion& r, int h) ); } -void QDepthmapView::OutputSVG( ofstream& stream, QGraphDoc *pDoc ) +void QDepthmapView::OutputSVG( std::ofstream& stream, QGraphDoc *pDoc ) { // This output SVG is a copy of the standard output... obviously, if you change // standard output, remember to change this one too! @@ -2522,19 +2496,19 @@ void QDepthmapView::OutputSVG( ofstream& stream, QGraphDoc *pDoc ) // we'll make this 24cm wide whatever, and base the height on it: int h = (4800 * rect.height()) / rect.width(); - stream << "" << endl; - stream << "" << endl; - stream << "" << endl; - stream << "depthmapX " << DEPTHMAPX_VERSION << "." << DEPTHMAPX_MINOR_VERSION << "" << endl; + stream << "" << std::endl; + stream << "" << std::endl; + stream << "" << std::endl; + stream << "" << TITLE_BASE << "" << std::endl; // note, SVG draw completely overrides standard draw physical units to achieve hi-res output // (EPS should probably follow this model too) QtRegion logicalviewport = LogicalViewport(rect, pDoc); stream << "" << endl; + << "fill=\"" << SVGColor(m_background) << "\" stroke=\"none\" stroke-width=\"0\" />" << std::endl; int state = pDoc->m_meta_graph->getState(); @@ -2549,7 +2523,7 @@ void QDepthmapView::OutputSVG( ofstream& stream, QGraphDoc *pDoc ) pDoc->m_meta_graph->getDisplayedDataMap().makeViewportShapes( logicalviewport ); } if (state & MetaGraph::LINEDATA) { - pDoc->m_meta_graph->SuperSpacePixel::makeViewportShapes( logicalviewport ); + pDoc->m_meta_graph->makeViewportShapes( logicalviewport ); } if (state & MetaGraph::POINTMAPS && pDoc->m_meta_graph->getViewClass() & MetaGraph::VIEWVGA) { @@ -2559,23 +2533,23 @@ void QDepthmapView::OutputSVG( ofstream& stream, QGraphDoc *pDoc ) double spacing = map.getSpacing(); double spacer = 4800.0 * (spacing/logicalviewport.width()) / 2.0; - stream << "" << endl; + stream << "" << std::endl; - stream << "" << endl; + stream << "" << std::endl; while ( map.findNextPoint() ) { Point2f logical = map.getNextPointLocation(); - PafColor color = map.getPointColor(); + PafColor color = map.getCurrentPointColor(); if (color.alphab() != 0) { // alpha == 0 is transparent QPoint p = SVGPhysicalUnits(logical,logicalviewport,h); - stream << "" << endl; + stream << "" << std::endl; } } - stream << "" << endl; + stream << "" << std::endl; } if (state & MetaGraph::SHAPEGRAPHS && pDoc->m_meta_graph->getViewClass() & MetaGraph::VIEWAXIAL) { @@ -2594,10 +2568,10 @@ void QDepthmapView::OutputSVG( ofstream& stream, QGraphDoc *pDoc ) if (state & MetaGraph::LINEDATA) { // arbitrary stroke width for now - stream << "" << endl; + stream << "" << std::endl; bool nextlayer = false; - while ( pDoc->m_meta_graph->SuperSpacePixel::findNextShape(nextlayer) ) { - const SalaShape& shape = pDoc->m_meta_graph->SuperSpacePixel::getNextShape(); + while ( pDoc->m_meta_graph->findNextShape(nextlayer) ) { + const SalaShape& shape = pDoc->m_meta_graph->getNextShape(); Line l; if (shape.isPoint()) { } @@ -2609,14 +2583,14 @@ void QDepthmapView::OutputSVG( ofstream& stream, QGraphDoc *pDoc ) OutputSVGPoly(stream, shape, logicalviewport, h); } } - stream << "" << endl; + stream << "" << std::endl; } - stream << "" << endl; + stream << "" << std::endl; } -void QDepthmapView::OutputSVGMap(ofstream& stream, ShapeMap& map, QtRegion& logicalviewport, int h) +void QDepthmapView::OutputSVGMap(std::ofstream& stream, ShapeMap& map, QtRegion& logicalviewport, int h) { bool monochrome = (map.getDisplayParams().colorscale == DisplayParams::MONOCHROME); // monochrome not implemented yet! @@ -2630,7 +2604,7 @@ void QDepthmapView::OutputSVGMap(ofstream& stream, ShapeMap& map, QtRegion& logi map.getPolygonDisplay(showlines,showfill,showcentroids); // arbitrary stroke width for now - stream << "" << endl; + stream << "" << std::endl; PafColor color, oldcolor; bool closed, oldclosed; @@ -2646,21 +2620,21 @@ void QDepthmapView::OutputSVGMap(ofstream& stream, ShapeMap& map, QtRegion& logi if (first || color != oldcolor || closed != oldclosed) { if (!first) { - stream << "" << endl; + stream << "" << std::endl; } else { first = false; } if (closed) { if (showlines) { - stream << "" << endl; + stream << "" << std::endl; } else { - stream << "" << endl; + stream << "" << std::endl; } } else { - stream << "" << endl; + stream << "" << std::endl; } oldcolor = color; oldclosed = closed; @@ -2678,13 +2652,13 @@ void QDepthmapView::OutputSVGMap(ofstream& stream, ShapeMap& map, QtRegion& logi } } if (!first) { - stream << "" << endl; + stream << "" << std::endl; } - stream << "" << endl; + stream << "" << std::endl; } -void QDepthmapView::OutputSVGLine(ofstream& stream, Line& line, QtRegion& logicalviewport, int h) +void QDepthmapView::OutputSVGLine(std::ofstream& stream, Line& line, QtRegion& logicalviewport, int h) { bool drewit = false; if (line.crop(logicalviewport)) { @@ -2693,12 +2667,12 @@ void QDepthmapView::OutputSVGLine(ofstream& stream, Line& line, QtRegion& logica // 2.0 is about 0.1mm in a standard SVG output size if (dist(Point2f(start.x(), start.y()), Point2f(end.x(), end.y())) >= 2.4f) { stream << "" << endl; + << " x2=\"" << end.x() << "\" y2=\"" << end.y() << "\" />" << std::endl; } } } -void QDepthmapView::OutputSVGPoly(ofstream& stream, const SalaShape& shape, QtRegion& logicalviewport, int h) +void QDepthmapView::OutputSVGPoly(std::ofstream& stream, const SalaShape& shape, QtRegion& logicalviewport, int h) { QPoint bl = SVGPhysicalUnits(shape.getBoundingBox().bottom_left,logicalviewport,h); QPoint tr = SVGPhysicalUnits(shape.getBoundingBox().top_right,logicalviewport,h); @@ -2710,9 +2684,11 @@ void QDepthmapView::OutputSVGPoly(ofstream& stream, const SalaShape& shape, QtRe // open lines are fairly easy: simply chop lines as they enter and exit stream << "= 2.0f || i == shape.size() - 1) { + if (dist(Point2f(start.x(), start.y()), Point2f(end.x(), end.y())) >= 2.0f || iter == shape.m_points.end() - 1) { // also, always draw the very last point regardless of distance stream << end.x() << "," << end.y() << " "; drawn = true; @@ -2734,23 +2710,25 @@ void QDepthmapView::OutputSVGPoly(ofstream& stream, const SalaShape& shape, QtRe drawn = true; } if (drawn) { - lastpoint = shape[i]; + lastpoint = *iter; drawn = false; } } - stream << "\" />" << endl; + stream << "\" />" << std::endl; } else { // polygons are hard... have to work out entry and exit points to the clipping frame // and wind according to their direction stream << " eus = shape.getClippingSet(logicalviewport); + std::vector eus = shape.getClippingSet(logicalviewport); if (eus.size() == 0) { // this should be a shape that is entirely within the viewport: - QPoint last = SVGPhysicalUnits(shape[0],logicalviewport,h); + QPoint last = SVGPhysicalUnits(shape.m_points[0],logicalviewport,h); stream << last.x() << "," << last.y() << " "; - for (size_t i = 1; i < shape.size(); i++) { - QPoint next = SVGPhysicalUnits(shape[i],logicalviewport,h); + auto iter = shape.m_points.begin(); + iter++; + for (; iter != shape.m_points.end(); iter++) { + QPoint next = SVGPhysicalUnits(*iter,logicalviewport,h); if (dist(Point2f(last.x(), last.y()), Point2f(next.x(), next.y())) >= 2.0f) { stream << next.x() << "," << next.y() << " "; last = next; @@ -2771,10 +2749,10 @@ void QDepthmapView::OutputSVGPoly(ofstream& stream, const SalaShape& shape, QtRe QPoint next; stream << last.x() << "," << last.y() << " "; for (size_t i = eus[entry].index + 1; i != eus[exit].index; i++) { - if (i >= shape.size()) { + if (i >= shape.m_points.size()) { i = 0; } - next = SVGPhysicalUnits(shape[i],logicalviewport,h); + next = SVGPhysicalUnits(shape.m_points[i],logicalviewport,h); if (dist(Point2f(last.x(), last.y()), Point2f(next.x(), next.y())) >= 2.0f) { stream << next.x() << "," << next.y() << " "; last = next; @@ -2818,13 +2796,20 @@ void QDepthmapView::OutputSVGPoly(ofstream& stream, const SalaShape& shape, QtRe } if (breakup) { //if (entry + 2 < eus.size() && ccwEdgeU(eus[entry],eus[entry+1],eus[entry+2]) != shape.isCCW()) { - stream << "\" />" << endl; + stream << "\" />" << std::endl; stream << "" << endl; + stream << "\" />" << std::endl; } } +void QDepthmapView::OnViewZoomToRegion(QtRegion regionToZoomAt) { + + m_centre = regionToZoomAt.getCentre(); + QRect phys_bounds = this->rect(); + m_unit = 1.0 * __max( regionToZoomAt.width() / double(phys_bounds.width()), + regionToZoomAt.height() / double(phys_bounds.height()) ); +} diff --git a/depthmapX/depthmapView.h b/depthmapX/views/depthmapview/depthmapview.h similarity index 60% rename from depthmapX/depthmapView.h rename to depthmapX/views/depthmapview/depthmapview.h index 7bd84fd1..0924b698 100644 --- a/depthmapX/depthmapView.h +++ b/depthmapX/views/depthmapview/depthmapview.h @@ -14,13 +14,12 @@ // along with this program. If not, see . -#include +#include "depthmapX/views/mapview.h" #include #include #include #include -#include "GraphDoc.h" #define MK_LBUTTON 0x0001 #define MK_RBUTTON 0x0002 @@ -28,26 +27,19 @@ #define MK_CONTROL 0x0008 #define MK_MBUTTON 0x0010 -class QDepthmapView : public QWidget +class QDepthmapView : public MapView { Q_OBJECT public: - QGraphDoc* pDoc; - - QDepthmapView(const QString &settingFilename); + QDepthmapView(QGraphDoc &pDoc, + Settings &settings, + QWidget *parent = Q_NULLPTR); ~QDepthmapView(); - QSize sizeHint() const; - void SetRedrawflag(); - bool loadFile(const QString &fileName); - bool newFile(); + QSize sizeHint() const override; + void SetRedrawflag(); void saveToFile(); - QString m_open_file_name; - QString currentFile() {return m_open_file_name;} - - const QString &m_settingsFile; - int m_curr_seleted; bool m_showgrid; bool m_showtext; bool m_showlinks; @@ -67,41 +59,42 @@ class QDepthmapView : public QWidget GENERICJOIN = 0x20000, JOINB = 0x00400, JOIN = 0x20001, UNJOIN = 0x20002 }; enum {FULLFILL = 0, SEMIFILL = 1, AUGMENT = 2}; // AV TV + virtual void OnModeJoin() override; + virtual void OnModeUnjoin() override; + virtual void OnModeSeedAxial() override; + virtual void OnModeIsovist() override; + virtual void OnModeTargetedIsovist() override; + virtual void OnEditLineTool() override; + virtual void OnEditPolygonTool() override; + virtual void OnEditFill() override; + virtual void OnEditSemiFill() override; + virtual void OnEditAugmentFill() override; // AV TV + virtual void OnViewZoomIn() override; + virtual void OnViewZoomOut() override; + virtual void OnViewPan() override; + virtual void OnViewZoomsel() override; + virtual void OnEditSelect() override; + virtual void OnEditPencil() override; + virtual void postLoadFile() override; + virtual void OnEditCopy() override; + virtual void OnEditSave() override; + virtual void OnViewZoomToRegion(QtRegion regionToZoomAt) override; protected: - virtual void timerEvent(QTimerEvent *event); - virtual void paintEvent(QPaintEvent *event); - virtual void resizeEvent(QResizeEvent *event); - virtual void mouseMoveEvent(QMouseEvent *event); - virtual void mousePressEvent(QMouseEvent *event); - virtual void mouseReleaseEvent(QMouseEvent *event); - virtual void closeEvent(QCloseEvent *event); - virtual void mouseDoubleClickEvent(QMouseEvent *e); - virtual void wheelEvent(QWheelEvent *e); - virtual void keyPressEvent(QKeyEvent *event); - virtual bool eventFilter(QObject *object, QEvent *e); + virtual void timerEvent(QTimerEvent *event) override; + virtual void paintEvent(QPaintEvent *event) override; + virtual void resizeGL(int w, int h) override; + virtual void mouseMoveEvent(QMouseEvent *event) override; + virtual void mousePressEvent(QMouseEvent *event) override; + virtual void mouseReleaseEvent(QMouseEvent *event) override; + virtual void closeEvent(QCloseEvent *event) override; + virtual void mouseDoubleClickEvent(QMouseEvent *e) override; + virtual void wheelEvent(QWheelEvent *e) override; + virtual bool eventFilter(QObject *object, QEvent *e) override; public slots: - int OnRedraw(int wParam, int lParam); - void OnEditEraser(); - void OnEditFill(); - void OnEditSemiFill(); - void OnEditAugmentFill(); // AV TV - void OnViewZoomIn(); - void OnViewZoomOut(); - void OnViewMove(); - void OnEditSelect(); - void OnEditPencil(); - void OnEditCopy(); - void OnEditSave(); - void OnModeJoin(); - void OnModeUnjoin(); - void OnToolsAxialMap(); - void OnModeIsovist(); - void OnModeHalfovist(); - void OnEditLineTool(); - void OnEditPolygon(); - void OnViewZoomsel(); + int OnRedraw(int wParam, int lParam); + void OnEditEraser(); private: int m_mouse_mode; @@ -158,10 +151,12 @@ public slots: // Line start and end (must be in map units in case you zoom out / pan while you're drawing! Line m_line; Line m_old_line; - pvector m_line_pixels; - prefvec m_point_handles; + std::vector m_line_pixels; + std::vector m_point_handles; int m_active_point_handle; + int m_currentlyEditingShapeRef = -1; + // polygon drawing utilities Point2f m_poly_start; int m_poly_points; @@ -178,9 +173,8 @@ public slots: void ResetHoverWnd(const QPoint& p = QPoint(-1,-1)); void CreateHoverWnd(); - void ZoomIn(double ratio, const Point2f& point); - void ZoomOut(); - void ZoomOut(Point2f centre); + bool IsAtZoomLimits(double ratio, double maxZoomOutRatio); + void ZoomTowards(double ratio, const Point2f& point); void InitViewport(const QRect& phys_bounds, QGraphDoc *pDoc); QtRegion LogicalViewport(const QRect& phys_bounds, QGraphDoc *pDoc); @@ -196,15 +190,15 @@ public slots: void DrawPointHandle(QPainter *pDC, QPoint pt); // - void OutputEPS( ofstream& stream, QGraphDoc *pDoc ); - void OutputEPSMap(ofstream& stream, ShapeMap& map, QtRegion& logicalviewport, QRect& rect, float spacer); - void OutputEPSLine(ofstream& stream, Line& line, int spacer, QtRegion& logicalviewport, QRect& rect); - void OutputEPSPoly(ofstream& stream, const SalaShape& shape, int spacer, QtRegion& logicalviewport, QRect& rect); + void OutputEPS(std::ofstream& stream, QGraphDoc *pDoc , bool includeScale = true); + void OutputEPSMap(std::ofstream& stream, ShapeMap& map, QtRegion& logicalviewport, QRect& rect, float spacer); + void OutputEPSLine(std::ofstream& stream, Line& line, int spacer, QtRegion& logicalviewport, QRect& rect); + void OutputEPSPoly(std::ofstream& stream, const SalaShape& shape, int spacer, QtRegion& logicalviewport, QRect& rect); - void OutputSVG( ofstream& stream, QGraphDoc *pDoc ); - void OutputSVGMap(ofstream& stream, ShapeMap& map, QtRegion& logicalviewport, int h); - void OutputSVGLine(ofstream& stream, Line& line, QtRegion& logicalviewport, int h); - void OutputSVGPoly(ofstream& stream, const SalaShape& shape, QtRegion& logicalviewport, int h); + void OutputSVG( std::ofstream& stream, QGraphDoc *pDoc ); + void OutputSVGMap(std::ofstream& stream, ShapeMap& map, QtRegion& logicalviewport, int h); + void OutputSVGLine(std::ofstream& stream, Line& line, QtRegion& logicalviewport, int h); + void OutputSVGPoly(std::ofstream& stream, const SalaShape& shape, QtRegion& logicalviewport, int h); void FillLocation(QPainter *pDC, QPoint& p, int spacer, unsigned int blocked, QRgb color); void DrawLine(QPainter *pDC, QRect& line, bool drawit); @@ -214,7 +208,9 @@ public slots: void AltMode(); void BeginJoin(); void BeginDrag(QPoint point); - + + QPixmap *m_pixmap; + }; diff --git a/depthmapX/views/glview/gldynamicline.cpp b/depthmapX/views/glview/gldynamicline.cpp new file mode 100644 index 00000000..be69e899 --- /dev/null +++ b/depthmapX/views/glview/gldynamicline.cpp @@ -0,0 +1,49 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "gldynamicline.h" +/** + * @brief GLDynamicLine::GLDynamicLine + * This class is an OpenGL representation of a dynamic line. See GLDynamicRect + * to understand the details of the implementation. This class only uses the + * diagonal points of the GLDynamicRect to make a line + */ + +GLDynamicLine::GLDynamicLine() +{ + m_count = 0; + m_program = 0; + m_data.resize(2); + + add(0); + add(3); +} + +void GLDynamicLine::paintGL(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel, const QMatrix2x2 &m_selectionBounds) +{ + if(!m_built) return; + QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); + m_program->bind(); + m_program->setUniformValue(m_projMatrixLoc, m_mProj); + m_program->setUniformValue(m_mvMatrixLoc, m_mView * m_mModel); + m_program->setUniformValue(m_diagVertices2DLoc, m_selectionBounds); + + m_program->setUniformValue(m_colourVectorLoc, m_colour_stroke); + glDrawArrays(GL_LINE_LOOP, 0, vertexCount()); + + m_program->release(); +} + diff --git a/depthmapX/views/glview/gldynamicline.h b/depthmapX/views/glview/gldynamicline.h new file mode 100644 index 00000000..ffc45f60 --- /dev/null +++ b/depthmapX/views/glview/gldynamicline.h @@ -0,0 +1,26 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "depthmapX/views/glview/gldynamicrect.h" + +class GLDynamicLine : public GLDynamicRect +{ +public: + GLDynamicLine(); + void paintGL(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel, const QMatrix2x2 &m_selectionBounds); +}; diff --git a/depthmapX/views/glview/gldynamicrect.cpp b/depthmapX/views/glview/gldynamicrect.cpp new file mode 100644 index 00000000..21a672fa --- /dev/null +++ b/depthmapX/views/glview/gldynamicrect.cpp @@ -0,0 +1,169 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "gldynamicrect.h" + +static const char *vertexShaderSourceCore = + "#version 150\n" + "in float vertexIndex;\n" + "int idxx = int(mod(vertexIndex,2.0));\n" + "int idxy = int(vertexIndex/2.0);\n" + "uniform mat2 diagVertices2D;\n" + "uniform mat4 projMatrix;\n" + "uniform mat4 mvMatrix;\n" + "void main() {\n" + " gl_Position = projMatrix * mvMatrix * vec4(diagVertices2D[0][idxx],diagVertices2D[1][idxy],0,1);\n" + "}\n"; + +static const char *fragmentShaderSourceCore = + "#version 150\n" + "uniform vec4 colourVector;\n" + "out highp vec4 fragColor;\n" + "void main() {\n" + " fragColor = colourVector;\n" + "}\n"; + +static const char *vertexShaderSource = + "attribute float vertexIndex;\n" + "int idxx = int(mod(vertexIndex,2.0));\n" + "int idxy = int(vertexIndex/2.0);\n" + "uniform mat2 diagVertices2D;\n" + "uniform mat4 projMatrix;\n" + "uniform mat4 mvMatrix;\n" + "void main() {\n" + " gl_Position = projMatrix * mvMatrix * vec4(diagVertices2D[0][idxx],diagVertices2D[1][idxy],0,1);\n" + "}\n"; + +static const char *fragmentShaderSource = + "uniform vec4 colourVector;\n" + "void main() {\n" + " gl_FragColor = colourVector;\n" + "}\n"; + +/** + * @brief GLDynamicRect::GLDynamicRect + * This class is an OpenGL representation of a dynamic rectangle. The only attribute + * sent to the shader is the index of 4 vertices, and the actual position of the + * vertices is sent as a uniform 2x2 matrix (bottom-left-x, bottom-left-y, top-right-x, + * top-right-y) + */ + +GLDynamicRect::GLDynamicRect() + : m_count(0), + m_program(0) +{ + m_count = 0; + m_data.resize(4); + + add(0); + add(1); + add(3); + add(2); +} + +void GLDynamicRect::setupVertexAttribs() +{ + m_vbo.bind(); + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + f->glEnableVertexAttribArray(0); + f->glVertexAttribPointer(0, DATA_DIMENSIONS, GL_FLOAT, GL_FALSE, DATA_DIMENSIONS * sizeof(GLfloat), 0); + m_vbo.release(); +} + +void GLDynamicRect::initializeGL(bool m_core) +{ + if(m_data.size() == 0) return; + m_program = new QOpenGLShaderProgram; + m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, m_core ? vertexShaderSourceCore : vertexShaderSource); + m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, m_core ? fragmentShaderSourceCore : fragmentShaderSource); + m_program->bindAttributeLocation("vertexIndex", 0); + m_program->link(); + + m_program->bind(); + m_diagVertices2DLoc = m_program->uniformLocation("diagVertices2D"); + m_projMatrixLoc = m_program->uniformLocation("projMatrix"); + m_mvMatrixLoc = m_program->uniformLocation("mvMatrix"); + m_colourVectorLoc = m_program->uniformLocation("colourVector"); + + m_vao.create(); + QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); + + m_vbo.create(); + m_vbo.bind(); + m_vbo.allocate(constData(), m_count * sizeof(GLfloat)); + + setupVertexAttribs(); + m_program->setUniformValue(m_colourVectorLoc, m_colour_fill); + m_program->release(); + m_built = true; +} + +void GLDynamicRect::updateGL(bool m_core) { + if(m_program == 0) { + // has not been initialised yet, do that instead + initializeGL(m_core); + } else { + m_vbo.bind(); + m_vbo.allocate(constData(), m_count * sizeof(GLfloat)); + m_vbo.release(); + } +} + +void GLDynamicRect::setFillColour(const QRgb &fillColour) +{ + m_colour_fill.setX(qRed(fillColour)/255.0); + m_colour_fill.setY(qGreen(fillColour)/255.0); + m_colour_fill.setZ(qBlue(fillColour)/255.0); +} + +void GLDynamicRect::setStrokeColour(const QRgb &strokeColour) +{ + m_colour_stroke.setX(qRed(strokeColour)/255.0); + m_colour_stroke.setY(qGreen(strokeColour)/255.0); + m_colour_stroke.setZ(qBlue(strokeColour)/255.0); +} + +void GLDynamicRect::cleanup() +{ + m_vbo.destroy(); + delete m_program; + m_program = 0; +} + +void GLDynamicRect::paintGL(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel, const QMatrix2x2 &m_selectionBounds) +{ + if(!m_built) return; + QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); + m_program->bind(); + m_program->setUniformValue(m_projMatrixLoc, m_mProj); + m_program->setUniformValue(m_mvMatrixLoc, m_mView * m_mModel); + m_program->setUniformValue(m_diagVertices2DLoc, m_selectionBounds); + + m_program->setUniformValue(m_colourVectorLoc, m_colour_fill); + glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount()); + + m_program->setUniformValue(m_colourVectorLoc, m_colour_stroke); + glDrawArrays(GL_LINE_LOOP, 0, vertexCount()); + + m_program->release(); +} + +void GLDynamicRect::add(const GLfloat v) +{ + GLfloat *p = m_data.data() + m_count; + *p++ = v; + m_count += DATA_DIMENSIONS; +} diff --git a/depthmapX/views/glview/gldynamicrect.h b/depthmapX/views/glview/gldynamicrect.h new file mode 100644 index 00000000..9797e286 --- /dev/null +++ b/depthmapX/views/glview/gldynamicrect.h @@ -0,0 +1,67 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +class GLDynamicRect +{ +public: + GLDynamicRect(); + void paintGL(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel, const QMatrix2x2 &m_selectionBounds); + void initializeGL(bool m_core); + void updateGL(bool m_core); + void cleanup(); + void setFillColour(const QRgb &fillColour); + void setStrokeColour(const QRgb &strokeColour); + int vertexCount() const { return m_count / DATA_DIMENSIONS; } + + GLDynamicRect( const GLDynamicRect& ) = delete; + GLDynamicRect& operator=(const GLDynamicRect& ) = delete; + +protected: + void add(const GLfloat v); + + int m_count; + bool m_built = false; + QVector m_data; + + QOpenGLBuffer m_vbo; + QOpenGLVertexArrayObject m_vao; + QOpenGLShaderProgram *m_program; + + int m_diagVertices2DLoc; + int m_projMatrixLoc; + int m_mvMatrixLoc; + int m_colourVectorLoc; + + QVector4D m_colour_fill = QVector4D(0.0f, 1.0f, 0.0f, 0.3f); + QVector4D m_colour_stroke = QVector4D(1.0f, 1.0f, 1.0f, 1.0f); + +private: + const int DATA_DIMENSIONS = 1; + void setupVertexAttribs(); + int count() const { return m_count; } + const GLfloat *constData() const { return m_data.constData(); } +}; diff --git a/depthmapX/views/glview/gllines.cpp b/depthmapX/views/glview/gllines.cpp new file mode 100644 index 00000000..ff2d6f86 --- /dev/null +++ b/depthmapX/views/glview/gllines.cpp @@ -0,0 +1,176 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "gllines.h" +#include +#include + +static const char *vertexShaderSourceCore = + "#version 150\n" + "in vec4 vertex;\n" + "in vec3 colour;\n" + "out vec3 col;\n" + "uniform mat4 projMatrix;\n" + "uniform mat4 mvMatrix;\n" + "void main() {\n" + " col = colour.xyz;\n" + " gl_Position = projMatrix * mvMatrix * vertex;\n" + "}\n"; + +static const char *fragmentShaderSourceCore = + "#version 150\n" + "in vec3 col;\n" + "out highp vec3 fragColor;\n" + "void main() {\n" + " fragColor = col;\n" + "}\n"; + +static const char *vertexShaderSource = + "attribute vec4 vertex;\n" + "attribute vec3 colour;\n" + "varying vec3 col;\n" + "uniform mat4 projMatrix;\n" + "uniform mat4 mvMatrix;\n" + "void main() {\n" + " col = colour.xyz;\n" + " gl_Position = projMatrix * mvMatrix * vertex;\n" + "}\n"; + +static const char *fragmentShaderSource = + "varying vec3 col;\n" + "void main() {\n" + " gl_FragColor = vec4(col, 1.0);\n" + "}\n"; + +/** + * @brief GLLines::GLLines + * This class is an OpenGL representation of multiple lines of uniform colour + */ + +GLLines::GLLines() + : m_count(0), + m_program(0) +{ + +} + +void GLLines::loadLineData(const std::vector> &colouredLines) +{ + m_built = false; + + m_count = 0; + m_data.resize(colouredLines.size() * 2 * DATA_DIMENSIONS); + + for (auto& colouredLine: colouredLines) + { + const SimpleLine &line = colouredLine.first; + const PafColor &colour = colouredLine.second; + + QVector3D colourVector(colour.redf(), colour.greenf(), colour.bluef()); + add(QVector3D(line.start().x, line.start().y, 0.0f), colourVector); + add(QVector3D(line.end().x, line.end().y, 0.0f), colourVector); + } +} + +void GLLines::setupVertexAttribs() +{ + m_vbo.bind(); + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + f->glEnableVertexAttribArray(0); + f->glEnableVertexAttribArray(1); + f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, DATA_DIMENSIONS * sizeof(GLfloat), + 0); + f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, DATA_DIMENSIONS * sizeof(GLfloat), + reinterpret_cast(3 * sizeof(GLfloat))); + m_vbo.release(); +} + +void GLLines::initializeGL(bool coreProfile) +{ + if(m_data.size() == 0) return; + m_program = new QOpenGLShaderProgram; + m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, coreProfile ? vertexShaderSourceCore : vertexShaderSource); + m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, coreProfile ? fragmentShaderSourceCore : fragmentShaderSource); + m_program->bindAttributeLocation("vertex", 0); + m_program->bindAttributeLocation("colour", 1); + m_program->link(); + + m_program->bind(); + m_projMatrixLoc = m_program->uniformLocation("projMatrix"); + m_mvMatrixLoc = m_program->uniformLocation("mvMatrix"); + + // Create a vertex array object. In OpenGL ES 2.0 and OpenGL 2.x + // implementations this is optional and support may not be present + // at all. Nonetheless the below code works in all cases and makes + // sure there is a VAO when one is needed. + m_vao.create(); + QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); + + // Setup our vertex buffer object. + m_vbo.create(); + m_vbo.bind(); + m_vbo.allocate(constData(), m_count * sizeof(GLfloat)); + + // Store the vertex attribute bindings for the program. + setupVertexAttribs(); + m_program->release(); + m_built = true; +} + +void GLLines::updateGL(bool coreProfile) { + if(m_program == 0) { + // has not been initialised yet, do that instead + initializeGL(coreProfile); + } else { + m_vbo.bind(); + m_vbo.allocate(constData(), m_count * sizeof(GLfloat)); + m_vbo.release(); + m_built = true; + } +} + +void GLLines::cleanup() +{ + if(!m_built) return; + m_vbo.destroy(); + delete m_program; + m_program = 0; +} + +void GLLines::paintGL(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel) +{ + if(!m_built) return; + QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); + m_program->bind(); + m_program->setUniformValue(m_projMatrixLoc, m_mProj); + m_program->setUniformValue(m_mvMatrixLoc, m_mView * m_mModel); + + glDrawArrays(GL_LINES, 0, vertexCount()); + + m_program->release(); +} + +void GLLines::add(const QVector3D &v, const QVector3D &c) +{ + GLfloat *p = m_data.data() + m_count; + *p++ = v.x(); + *p++ = v.y(); + *p++ = v.z(); + *p++ = c.x(); + *p++ = c.y(); + *p++ = c.z(); + m_count += DATA_DIMENSIONS; +} diff --git a/depthmapX/views/glview/gllines.h b/depthmapX/views/glview/gllines.h new file mode 100644 index 00000000..b4ed94ba --- /dev/null +++ b/depthmapX/views/glview/gllines.h @@ -0,0 +1,60 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "genlib/p2dpoly.h" +#include "salalib/pafcolor.h" +#include +#include +#include +#include +#include +#include +#include +#include + +class GLLines +{ + friend class testgllines; + +public: + GLLines(); + void loadLineData(const std::vector > &colouredLines); + void paintGL(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel); + void initializeGL(bool coreProfile); + void updateGL(bool coreProfile); + void cleanup(); + int vertexCount() const { return m_count / DATA_DIMENSIONS; } + GLLines( const GLLines& ) = delete; + GLLines& operator=(const GLLines& ) = delete; + +private: + const int DATA_DIMENSIONS = 6; + void setupVertexAttribs(); + const GLfloat *constData() const { return m_data.constData(); } + void add(const QVector3D &v, const QVector3D &c); + + QVector m_data; + int m_count; + bool m_built = false; + + QOpenGLVertexArrayObject m_vao; + QOpenGLBuffer m_vbo; + QOpenGLShaderProgram *m_program; + int m_projMatrixLoc; + int m_mvMatrixLoc; +}; diff --git a/depthmapX/views/glview/gllinesuniform.cpp b/depthmapX/views/glview/gllinesuniform.cpp new file mode 100644 index 00000000..3c836df9 --- /dev/null +++ b/depthmapX/views/glview/gllinesuniform.cpp @@ -0,0 +1,172 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "gllinesuniform.h" +#include + +static const char *vertexShaderSourceCore = + "#version 150\n" + "in vec4 vertex;\n" + "uniform mat4 projMatrix;\n" + "uniform mat4 mvMatrix;\n" + "void main() {\n" + " gl_Position = projMatrix * mvMatrix * vertex;\n" + "}\n"; + +static const char *fragmentShaderSourceCore = + "#version 150\n" + "uniform vec4 colourVector;\n" + "out highp vec4 fragColor;\n" + "void main() {\n" + " fragColor = colourVector;\n" + "}\n"; + +static const char *vertexShaderSource = + "attribute vec4 vertex;\n" + "uniform mat4 projMatrix;\n" + "uniform mat4 mvMatrix;\n" + "void main() {\n" + " gl_Position = projMatrix * mvMatrix * vertex;\n" + "}\n"; + +static const char *fragmentShaderSource = + "uniform vec4 colourVector;\n" + "void main() {\n" + " gl_FragColor = colourVector;\n" + "}\n"; + +/** + * @brief GLLinesUniform::GLLinesUniform + * This class is an OpenGL representation of multiple lines of uniform colour + */ + +GLLinesUniform::GLLinesUniform() + : m_count(0), + m_program(0) +{ + +} + +void GLLinesUniform::loadLineData(const std::vector& lines, const QRgb &lineColour) +{ + m_built = false; + + m_count = 0; + m_data.resize(lines.size() * 2 * DATA_DIMENSIONS); + + for (auto& line: lines) + { + add(QVector3D(line.start().x, line.start().y, 0.0f)); + add(QVector3D(line.end().x, line.end().y, 0.0f)); + } + m_colour.setX(qRed(lineColour)/255.0f); + m_colour.setY(qGreen(lineColour)/255.0f); + m_colour.setZ(qBlue(lineColour)/255.0f); +} + +void GLLinesUniform::setupVertexAttribs() +{ + m_vbo.bind(); + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + f->glEnableVertexAttribArray(0); + f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, DATA_DIMENSIONS * sizeof(GLfloat), 0); + m_vbo.release(); +} + +void GLLinesUniform::initializeGL(bool coreProfile) +{ + if(m_data.size() == 0) return; + m_program = new QOpenGLShaderProgram; + m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, coreProfile ? vertexShaderSourceCore : vertexShaderSource); + m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, coreProfile ? fragmentShaderSourceCore : fragmentShaderSource); + m_program->bindAttributeLocation("vertex", 0); + m_program->link(); + + m_program->bind(); + m_projMatrixLoc = m_program->uniformLocation("projMatrix"); + m_mvMatrixLoc = m_program->uniformLocation("mvMatrix"); + m_colourVectorLoc = m_program->uniformLocation("colourVector"); + + // Create a vertex array object. In OpenGL ES 2.0 and OpenGL 2.x + // implementations this is optional and support may not be present + // at all. Nonetheless the below code works in all cases and makes + // sure there is a VAO when one is needed. + m_vao.create(); + QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); + + // Setup our vertex buffer object. + m_vbo.create(); + m_vbo.bind(); + m_vbo.allocate(constData(), m_count * sizeof(GLfloat)); + + // Store the vertex attribute bindings for the program. + setupVertexAttribs(); + m_program->setUniformValue(m_colourVectorLoc, m_colour); + m_program->release(); + m_built = true; +} + +void GLLinesUniform::updateGL(bool coreProfile) { + if(m_program == 0) { + // has not been initialised yet, do that instead + initializeGL(coreProfile); + } else { + m_vbo.bind(); + m_vbo.allocate(constData(), m_count * sizeof(GLfloat)); + m_vbo.release(); + m_built = true; + } +} + +void GLLinesUniform::updateColour(const QRgb &lineColour) +{ + m_colour.setX(qRed(lineColour)/255.0f); + m_colour.setY(qGreen(lineColour)/255.0f); + m_colour.setZ(qBlue(lineColour)/255.0f); + m_program->bind(); + m_program->setUniformValue(m_colourVectorLoc, m_colour); + m_program->release(); +} + +void GLLinesUniform::cleanup() +{ + if(!m_built) return; + m_vbo.destroy(); + delete m_program; + m_program = 0; +} + +void GLLinesUniform::paintGL(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel) +{ + if(!m_built) return; + QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); + m_program->bind(); + m_program->setUniformValue(m_projMatrixLoc, m_mProj); + m_program->setUniformValue(m_mvMatrixLoc, m_mView * m_mModel); + + glDrawArrays(GL_LINES, 0, vertexCount()); + + m_program->release(); +} + +void GLLinesUniform::add(const QVector3D &v) +{ + GLfloat *p = m_data.data() + m_count; + *p++ = v.x(); + *p++ = v.y(); + *p++ = v.z(); + m_count += DATA_DIMENSIONS; +} diff --git a/depthmapX/views/glview/gllinesuniform.h b/depthmapX/views/glview/gllinesuniform.h new file mode 100644 index 00000000..dea6c040 --- /dev/null +++ b/depthmapX/views/glview/gllinesuniform.h @@ -0,0 +1,60 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "genlib/p2dpoly.h" +#include +#include +#include +#include +#include +#include +#include +#include + +class GLLinesUniform +{ +public: + GLLinesUniform(); + void loadLineData(const std::vector& lines, const QRgb& lineColour); + void paintGL(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel); + void initializeGL(bool coreProfile); + void updateGL(bool coreProfile); + void cleanup(); + void updateColour(const QRgb& lineColour); + int vertexCount() const { return m_count / DATA_DIMENSIONS; } + GLLinesUniform( const GLLinesUniform& ) = delete; + GLLinesUniform& operator=(const GLLinesUniform& ) = delete; + +private: + const int DATA_DIMENSIONS = 3; + void setupVertexAttribs(); + const GLfloat *constData() const { return m_data.constData(); } + void add(const QVector3D &v); + + QVector m_data; + int m_count; + bool m_built = false; + QVector4D m_colour = QVector4D(1.0f, 1.0f, 1.0f, 1.0f); + + QOpenGLVertexArrayObject m_vao; + QOpenGLBuffer m_vbo; + QOpenGLShaderProgram *m_program; + int m_projMatrixLoc; + int m_mvMatrixLoc; + int m_colourVectorLoc; +}; diff --git a/depthmapX/views/glview/glpointmap.cpp b/depthmapX/views/glview/glpointmap.cpp new file mode 100644 index 00000000..0ad138ea --- /dev/null +++ b/depthmapX/views/glview/glpointmap.cpp @@ -0,0 +1,72 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "glpointmap.h" +#include "salalib/linkutils.h" +#include "salalib/geometrygenerators.h" + +void GLPointMap::loadGLObjects(PointMap& pointMap) { + QtRegion region = pointMap.getRegion(); + m_pointMap.loadRegionData(region.bottom_left.x, region.bottom_left.y, region.top_right.x, region.top_right.y); + + if(m_showGrid) { + std::vector gridData; + double spacing = pointMap.getSpacing(); + double offsetX = region.bottom_left.x; + double offsetY = region.bottom_left.y; + for(int x = 1; x < pointMap.getCols(); x++) { + gridData.push_back(SimpleLine(offsetX + x*spacing, region.bottom_left.y, offsetX + x*spacing, region.top_right.y)); + } + for(int y = 1; y < pointMap.getRows(); y++) { + gridData.push_back(SimpleLine(region.bottom_left.x, offsetY + y*spacing, region.top_right.x, offsetY + y*spacing)); + } + m_grid.loadLineData(gridData, m_gridColour); + } + if(m_showLinks) { + const std::vector &mergedPixelLines = depthmapX::getMergedPixelsAsLines(pointMap); + std::vector mergedPixelLocations; + for (auto& mergeLine: mergedPixelLines) + { + mergedPixelLocations.push_back(mergeLine.start()); + mergedPixelLocations.push_back(mergeLine.end()); + } + + const std::vector &linkFillTriangles = + GeometryGenerators::generateMultipleDiskTriangles(32, pointMap.getSpacing()*0.25, mergedPixelLocations); + m_linkFills.loadTriangleData(linkFillTriangles, qRgb(0,0,0)); + + std::vector linkFillPerimeters = + GeometryGenerators::generateMultipleCircleLines(32, pointMap.getSpacing()*0.25, mergedPixelLocations); + linkFillPerimeters.insert( linkFillPerimeters.end(), mergedPixelLines.begin(), mergedPixelLines.end() ); + m_linkLines.loadLineData(linkFillPerimeters, qRgb(0,255,0)); + } +} +void GLPointMap::loadGLObjectsRequiringGLContext(const PointMap& currentPointMap) { + QImage data(currentPointMap.getCols(),currentPointMap.getRows(), QImage::Format_RGBA8888); + data.fill(Qt::transparent); + + for (int y = 0; y < currentPointMap.getRows(); y++) { + for (int x = 0; x < currentPointMap.getCols(); x++) { + PixelRef pix(x, y); + PafColor colour = currentPointMap.getPointColor( pix ); + if (colour.alphab() != 0) + { // alpha == 0 is transparent + data.setPixelColor(x, y, qRgb(colour.redb(),colour.greenb(),colour.blueb())); + } + } + } + m_pointMap.loadPixelData(data); +} diff --git a/depthmapX/views/glview/glpointmap.h b/depthmapX/views/glview/glpointmap.h new file mode 100644 index 00000000..a1977a9e --- /dev/null +++ b/depthmapX/views/glview/glpointmap.h @@ -0,0 +1,84 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/mgraph.h" +#include "depthmapX/views/glview/gllinesuniform.h" +#include "depthmapX/views/glview/glrastertexture.h" +#include "depthmapX/views/glview/gltrianglesuniform.h" + +class GLPointMap +{ +public: + void initializeGL(bool m_core) + { + m_grid.initializeGL(m_core); + m_pointMap.initializeGL(m_core); + m_linkLines.initializeGL(m_core); + m_linkFills.initializeGL(m_core); + } + void updateGL(bool m_core) + { + m_pointMap.updateGL(m_core); + m_grid.updateGL(m_core); + m_linkLines.updateGL(m_core); + m_linkFills.updateGL(m_core); + } + void cleanup() + { + m_grid.cleanup(); + m_pointMap.cleanup(); + m_linkLines.cleanup(); + m_linkFills.cleanup(); + } + void paintGLOverlay(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel) + { + if(m_showLinks) { + glLineWidth(3); + m_linkLines.paintGL(m_mProj, m_mView, m_mModel); + m_linkFills.paintGL(m_mProj, m_mView, m_mModel); + glLineWidth(1); + } + } + void paintGL(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel) + { + m_pointMap.paintGL(m_mProj, m_mView, m_mModel); + if(m_showGrid) + m_grid.paintGL(m_mProj, m_mView, m_mModel); + } + void setGridColour(QRgb gridColour) { + m_gridColour = gridColour; + } + void showLinks(bool showLinks) { + m_showLinks = showLinks; + } + void showGrid(bool showGrid) { + m_showGrid = showGrid; + } + void loadGLObjects(PointMap& pointMap); + void loadGLObjectsRequiringGLContext(const PointMap& currentPointMap); +private: + GLLinesUniform m_grid; + GLRasterTexture m_pointMap; + GLLinesUniform m_linkLines; + GLTrianglesUniform m_linkFills; + + QRgb m_gridColour = (qRgb(255, 255, 255) & 0x006f6f6f) | (qRgb(0, 0, 0) & 0x00a0a0a0); + + bool m_showGrid = true; + bool m_showLinks = false; +}; diff --git a/depthmapX/views/glview/glpolygons.cpp b/depthmapX/views/glview/glpolygons.cpp new file mode 100644 index 00000000..4851b72a --- /dev/null +++ b/depthmapX/views/glview/glpolygons.cpp @@ -0,0 +1,72 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "glpolygons.h" +#include "glutriangulator.h" + +/** + * @brief GLPolygons::GLPolygons + * This class is an OpenGL representation of multiple polygons of different colour + */ + +void GLPolygons::loadPolygonData(const std::map, PafColor>& colouredPolygons) +{ + m_polygons.clear(); + for (auto& colouredPolygon: colouredPolygons) + { + const std::vector & points = colouredPolygon.first; + QRgb colour = qRgb(colouredPolygon.second.redb(), + colouredPolygon.second.greenb(), + colouredPolygon.second.blueb()); + + m_polygons.push_back(std::unique_ptr(new GLTrianglesUniform)); + + std::vector triangulated = GLUTriangulator::triangulate(points); + m_polygons.back()->loadTriangleData(triangulated, colour); + } +} + +void GLPolygons::initializeGL(bool m_core) +{ + for (auto& polygon: m_polygons) + { + polygon->initializeGL(m_core); + } +} + +void GLPolygons::updateGL(bool m_core) +{ + for (auto& polygon: m_polygons) + { + polygon->updateGL(m_core); + } +} + +void GLPolygons::cleanup() +{ + for (auto& polygon: m_polygons) + { + polygon->cleanup(); + } +} + +void GLPolygons::paintGL(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel) +{ + for (auto& polygon: m_polygons) + { + polygon->paintGL(m_mProj, m_mView, m_mModel); + } +} diff --git a/depthmapX/views/glview/glpolygons.h b/depthmapX/views/glview/glpolygons.h new file mode 100644 index 00000000..9cbc33f1 --- /dev/null +++ b/depthmapX/views/glview/glpolygons.h @@ -0,0 +1,49 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/pafcolor.h" + +#include "depthmapX/views/glview/gltrianglesuniform.h" + +#include "genlib/p2dpoly.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief The GLPolygons class is a plain wrapper class for multiple GLPolygon + * that acts as if it's a single globject + */ +class GLPolygons +{ +public: + void loadPolygonData(const std::map, PafColor>& colouredPolygons); + void paintGL(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel); + void initializeGL(bool m_core); + void updateGL(bool m_core); + void cleanup(); + +private: + std::vector> m_polygons; +}; diff --git a/depthmapX/views/glview/glrastertexture.cpp b/depthmapX/views/glview/glrastertexture.cpp new file mode 100644 index 00000000..f3c06eab --- /dev/null +++ b/depthmapX/views/glview/glrastertexture.cpp @@ -0,0 +1,185 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "glrastertexture.h" +#include +#include + +static const char *vertexShaderSourceCore = + "#version 150\n" + "in vec4 vertex;\n" + "in vec4 texCoord;\n" + "out vec4 texc;\n" + "uniform mat4 projMatrix;\n" + "uniform mat4 mvMatrix;\n" + "void main() {\n" + " gl_Position = projMatrix * mvMatrix * vertex;\n" + " texc = texCoord;\n" + "}\n"; + +static const char *fragmentShaderSourceCore = + "#version 150\n" + "uniform sampler2D texture;\n" + "in mediump vec4 texc;\n" + "void main(void)\n" + "{\n" + " gl_FragColor = texture2D(texture, texc.st);\n" + "}\n"; + +static const char *vertexShaderSource = + "attribute highp vec4 vertex;\n" + "attribute mediump vec4 texCoord;\n" + "varying mediump vec4 texc;\n" + "uniform mat4 projMatrix;\n" + "uniform mat4 mvMatrix;\n" + "void main(void)\n" + "{\n" + " gl_Position = projMatrix * mvMatrix * vertex;\n" + " texc = texCoord;\n" + "}\n"; + +static const char *fragmentShaderSource = + "uniform sampler2D texture;\n" + "varying mediump vec4 texc;\n" + "void main(void)\n" + "{\n" + " gl_FragColor = texture2D(texture, texc.st);\n" + "}\n"; + +GLRasterTexture::GLRasterTexture() + : m_count(0), + m_program(0), + m_texture(QOpenGLTexture::Target2D) +{ + +} +void GLRasterTexture::loadRegionData(float minX, float minY, float maxX, float maxY) +{ + m_built = false; + + m_count = 0; + m_data.resize(4 * DATA_DIMENSIONS); + + add(QVector3D(minX,minY,0),QVector2D(0, 0)); + add(QVector3D(maxX,minY,0),QVector2D(1, 0)); + add(QVector3D(maxX,maxY,0),QVector2D(1, 1)); + add(QVector3D(minX,maxY,0),QVector2D(0, 1)); +} + +void GLRasterTexture::setupVertexAttribs() +{ + m_vbo.bind(); + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + f->glEnableVertexAttribArray(0); + f->glEnableVertexAttribArray(1); + f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, DATA_DIMENSIONS * sizeof(GLfloat), + 0); + f->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, DATA_DIMENSIONS * sizeof(GLfloat), + reinterpret_cast(3 * sizeof(GLfloat))); + m_vbo.release(); +} + +void GLRasterTexture::initializeGL(bool coreProfile) { + if(m_data.size() == 0) return; + m_program = new QOpenGLShaderProgram; + m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, coreProfile ? vertexShaderSourceCore : vertexShaderSource); + m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, coreProfile ? fragmentShaderSourceCore : fragmentShaderSource); + m_program->bindAttributeLocation("vertex", 0); + m_program->bindAttributeLocation("texCoord", 1); + m_program->link(); + + m_program->bind(); + m_projMatrixLoc = m_program->uniformLocation("projMatrix"); + m_mvMatrixLoc = m_program->uniformLocation("mvMatrix"); + m_textureSamplerLoc = m_program->uniformLocation("texture"); + + m_vao.create(); + QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); + + // Setup our vertex buffer object. + m_vbo.create(); + m_vbo.bind(); + m_vbo.allocate(constData(), m_count * sizeof(GLfloat)); + + // Store the vertex attribute bindings for the program. + setupVertexAttribs(); + + m_program->setUniformValue(m_textureSamplerLoc, 0); + + m_program->release(); + m_built = true; +} + +void GLRasterTexture::updateGL(bool coreProfile) { + if(m_program == 0) { + // has not been initialised yet, do that instead + initializeGL(coreProfile); + } else { + m_vbo.bind(); + m_vbo.allocate(constData(), m_count * sizeof(GLfloat)); + m_vbo.release(); + m_built = true; + } +} + +void GLRasterTexture::loadPixelData(QImage &data) +{ + if(!m_built) return; + m_program->bind(); + if(m_texture.isCreated()) + { + m_texture.destroy(); + } + m_texture.setData(data); + m_program->release(); +} + +void GLRasterTexture::cleanup() +{ + if(!m_built) return; + m_vbo.destroy(); + m_texture.destroy(); + delete m_program; + m_program = 0; +} + +void GLRasterTexture::paintGL(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel) +{ + if(!m_built) return; + QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); + m_program->bind(); + m_program->setUniformValue(m_projMatrixLoc, m_mProj); + m_program->setUniformValue(m_mvMatrixLoc, m_mView * m_mModel); + + m_texture.bind(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount()); + + m_program->release(); +} + +void GLRasterTexture::add(const QVector3D &v, const QVector2D &tc) +{ + GLfloat *p = m_data.data() + m_count; + *p++ = v.x(); + *p++ = v.y(); + *p++ = v.z(); + *p++ = tc.x(); + *p++ = tc.y(); + m_count += DATA_DIMENSIONS; +} diff --git a/depthmapX/views/glview/glrastertexture.h b/depthmapX/views/glview/glrastertexture.h new file mode 100644 index 00000000..7eb468cb --- /dev/null +++ b/depthmapX/views/glview/glrastertexture.h @@ -0,0 +1,60 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +class GLRasterTexture +{ +public: + GLRasterTexture(); + void loadRegionData(float minX, float minY, float maxX, float maxY); + void loadPixelData(QImage &data); + void paintGL(const QMatrix4x4 &m_proj, const QMatrix4x4 &m_camera, const QMatrix4x4 &m_mModel); + void initializeGL(bool coreProfile); + void updateGL(bool coreProfile); + void cleanup(); + int vertexCount() const { return m_count / DATA_DIMENSIONS; } + GLRasterTexture( const GLRasterTexture& ) = delete; + GLRasterTexture& operator=(const GLRasterTexture& ) = delete; + +private: + int DATA_DIMENSIONS = 5; + + void setupVertexAttribs(); + const GLfloat *constData() const { return m_data.constData(); } + void add(const QVector3D &v, const QVector2D &tc); + + QVector m_data; + int m_count; + bool m_built = false; + + QOpenGLVertexArrayObject m_vao; + QOpenGLBuffer m_vbo; + QOpenGLShaderProgram *m_program; + int m_projMatrixLoc; + int m_mvMatrixLoc; + int m_textureSamplerLoc; + + QOpenGLTexture m_texture; +}; diff --git a/depthmapX/views/glview/glregularpolygons.cpp b/depthmapX/views/glview/glregularpolygons.cpp new file mode 100644 index 00000000..809b202c --- /dev/null +++ b/depthmapX/views/glview/glregularpolygons.cpp @@ -0,0 +1,47 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "glregularpolygons.h" +#include + +void GLRegularPolygons::loadPolygonData(const std::vector> &colouredPoints, + const int sides, const float radius) { + init(colouredPoints.size() * sides * 3); + std::vector points(sides * 3); + float angle = 2 * M_PI / sides; + for (int i = 0; i < sides; i++) { + points[i * 3] = Point2f(cos((i)*angle) * radius, sin((i)*angle) * radius); + points[i * 3 + 1] = Point2f(cos((i + 1) * angle) * radius, sin((i + 1) * angle) * radius); + points[i * 3 + 2] = Point2f(0, 0); + } + + Point2f prevCentre(0, 0); + for (const auto &colouredPoint : colouredPoints) { + const Point2f ¢re = colouredPoint.first; + float r = colouredPoint.second.redf(); + float g = colouredPoint.second.greenf(); + float b = colouredPoint.second.bluef(); + + for (Point2f &point : points) { + point.x -= prevCentre.x; + point.y -= prevCentre.y; + point.x += centre.x; + point.y += centre.y; + add(QVector3D(point.x, point.y, 0.0f), QVector3D(r, g, b)); + } + prevCentre = centre; + } +} diff --git a/depthmapX/views/glview/glregularpolygons.h b/depthmapX/views/glview/glregularpolygons.h new file mode 100644 index 00000000..93ceaf7b --- /dev/null +++ b/depthmapX/views/glview/glregularpolygons.h @@ -0,0 +1,42 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/pafcolor.h" + +#include "depthmapX/views/glview/gltriangles.h" + +#include "genlib/p2dpoly.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief Meant to represent regular polygons i.e. those that are equiangular (all angles are equal in measure) and + * equilateral (all sides have the same length). Ideal for representing sets of disks/stars/squares etc. + */ +class GLRegularPolygons : public GLTriangles { + public: + void loadPolygonData(const std::vector> &colouredPoints, const int sides, + const float radius); +}; diff --git a/depthmapX/views/glview/glshapegraph.cpp b/depthmapX/views/glview/glshapegraph.cpp new file mode 100644 index 00000000..c5b3f550 --- /dev/null +++ b/depthmapX/views/glview/glshapegraph.cpp @@ -0,0 +1,49 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "glshapegraph.h" +#include "salalib/geometrygenerators.h" + +void GLShapeGraph::loadGLObjects(ShapeGraph &shapeGraph) { + m_shapeMap.loadGLObjects(shapeGraph); + const std::vector &linkLines = shapeGraph.getAllLinkLines(); + std::vector linkPointLocations; + for (auto& linkLine: linkLines) + { + linkPointLocations.push_back(linkLine.start()); + linkPointLocations.push_back(linkLine.end()); + } + + const std::vector &linkFillTriangles = + GeometryGenerators::generateMultipleDiskTriangles(32, shapeGraph.getSpacing()*0.1, linkPointLocations); + m_linkFills.loadTriangleData(linkFillTriangles, qRgb(0,0,0)); + + std::vector linkFillPerimeters = + GeometryGenerators::generateMultipleCircleLines(32, shapeGraph.getSpacing()*0.1, linkPointLocations); + linkFillPerimeters.insert( linkFillPerimeters.end(), linkLines.begin(), linkLines.end() ); + m_linkLines.loadLineData(linkFillPerimeters, qRgb(0,255,0)); + + + const std::vector &unlinkPoints = shapeGraph.getAllUnlinkPoints(); + + const std::vector &unlinkFillTriangles = + GeometryGenerators::generateMultipleDiskTriangles(32, shapeGraph.getSpacing()*0.1, unlinkPoints); + m_unlinkFills.loadTriangleData(unlinkFillTriangles, qRgb(255, 255, 255)); + + const std::vector &unlinkFillPerimeters = + GeometryGenerators::generateMultipleCircleLines(32, shapeGraph.getSpacing()*0.1, unlinkPoints); + m_unlinkLines.loadLineData(unlinkFillPerimeters, qRgb(255,0,0)); +} diff --git a/depthmapX/views/glview/glshapegraph.h b/depthmapX/views/glview/glshapegraph.h new file mode 100644 index 00000000..a9f2de29 --- /dev/null +++ b/depthmapX/views/glview/glshapegraph.h @@ -0,0 +1,78 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/mgraph.h" +#include "depthmapX/views/glview/glshapemap.h" +#include "depthmapX/views/glview/gllinesuniform.h" + +class GLShapeGraph +{ +public: + void initializeGL(bool m_core) + { + m_shapeMap.initializeGL(m_core); + m_linkLines.initializeGL(m_core); + m_linkFills.initializeGL(m_core); + m_unlinkFills.initializeGL(m_core); + m_unlinkLines.initializeGL(m_core); + } + void updateGL(bool m_core) + { + m_shapeMap.updateGL(m_core); + m_linkLines.updateGL(m_core); + m_linkFills.updateGL(m_core); + m_unlinkFills.updateGL(m_core); + m_unlinkLines.updateGL(m_core); + } + void cleanup() + { + m_shapeMap.cleanup(); + m_linkLines.cleanup(); + m_linkFills.cleanup(); + m_unlinkFills.cleanup(); + m_unlinkLines.cleanup(); + } + void paintGLOverlay(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel) + { + if(m_showLinks) + { + glLineWidth(3); + m_linkLines.paintGL(m_mProj, m_mView, m_mModel); + m_linkFills.paintGL(m_mProj, m_mView, m_mModel); + m_unlinkLines.paintGL(m_mProj, m_mView, m_mModel); + m_unlinkFills.paintGL(m_mProj, m_mView, m_mModel); + glLineWidth(1); + } + } + void paintGL(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel) + { + m_shapeMap.paintGL(m_mProj, m_mView, m_mModel); + } + void showLinks(bool showLinks) { + m_showLinks = showLinks; + } + void loadGLObjects(ShapeGraph &shapeGraph); +private: + GLShapeMap m_shapeMap; + GLLinesUniform m_linkLines; + GLTrianglesUniform m_linkFills; + GLLinesUniform m_unlinkLines; + GLTrianglesUniform m_unlinkFills; + + bool m_showLinks = false; +}; diff --git a/depthmapX/views/glview/glshapemap.cpp b/depthmapX/views/glview/glshapemap.cpp new file mode 100644 index 00000000..39227d27 --- /dev/null +++ b/depthmapX/views/glview/glshapemap.cpp @@ -0,0 +1,23 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "glshapemap.h" + +void GLShapeMap::loadGLObjects(ShapeMap &shapeMap) { + m_lines.loadLineData(shapeMap.getAllLinesWithColour()); + m_polygons.loadPolygonData(shapeMap.getAllPolygonsWithColour()); + m_points.loadPolygonData(shapeMap.getAllPointsWithColour(), 8, shapeMap.getSpacing()*0.1); +} diff --git a/depthmapX/views/glview/glshapemap.h b/depthmapX/views/glview/glshapemap.h new file mode 100644 index 00000000..78796c4c --- /dev/null +++ b/depthmapX/views/glview/glshapemap.h @@ -0,0 +1,56 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/mgraph.h" +#include "depthmapX/views/glview/gllines.h" +#include "depthmapX/views/glview/glpolygons.h" +#include "depthmapX/views/glview/glregularpolygons.h" + +class GLShapeMap +{ +public: + void initializeGL(bool m_core) + { + m_lines.initializeGL(m_core); + m_polygons.initializeGL(m_core); + m_points.initializeGL(m_core); + } + void updateGL(bool m_core) + { + m_lines.updateGL(m_core); + m_polygons.updateGL(m_core); + m_points.updateGL(m_core); + } + void cleanup() + { + m_lines.cleanup(); + m_polygons.cleanup(); + m_points.cleanup(); + } + void paintGL(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel) + { + m_lines.paintGL(m_mProj, m_mView, m_mModel); + m_polygons.paintGL(m_mProj, m_mView, m_mModel); + m_points.paintGL(m_mProj, m_mView, m_mModel); + } + void loadGLObjects(ShapeMap &shapeMap); +private: + GLLines m_lines; + GLPolygons m_polygons; + GLRegularPolygons m_points; +}; diff --git a/depthmapX/views/glview/gltriangles.cpp b/depthmapX/views/glview/gltriangles.cpp new file mode 100644 index 00000000..9126bfd2 --- /dev/null +++ b/depthmapX/views/glview/gltriangles.cpp @@ -0,0 +1,149 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "gltriangles.h" +#include + +// clang-format off +static const char *vertexShaderSourceCore = + "#version 150\n" + "in vec4 vertex;\n" + "uniform mat4 projMatrix;\n" + "uniform mat4 mvMatrix;\n" + "void main() {\n" + " gl_Position = projMatrix * mvMatrix * vertex;\n" + "}\n"; + +static const char *fragmentShaderSourceCore = + "#version 150\n" + "in vec4 colour;\n" + "out highp vec4 fragColor;\n" + "void main() {\n" + " fragColor = colour;\n" + "}\n"; + +static const char *vertexShaderSource = + "attribute vec4 vertex;\n" + "attribute vec4 colour;\n" + "varying vec4 fragColour;\n" + "uniform mat4 projMatrix;\n" + "uniform mat4 mvMatrix;\n" + "void main() {\n" + " gl_Position = projMatrix * mvMatrix * vertex;\n" + " fragColour = colour;\n" + "}\n"; + +static const char *fragmentShaderSource = + "varying vec4 fragColour;\n" + "void main() {\n" + " gl_FragColor = fragColour;\n" + "}\n"; +// clang-format on + +void GLTriangles::loadTriangleData(const std::vector, QRgb>> &triangleData) { + + init(triangleData.size()); + + for (auto &triangle : triangleData) { + float r = qRed(triangle.second) / 255.0; + float g = qGreen(triangle.second) / 255.0; + float b = qBlue(triangle.second) / 255.0; + for (auto &point : triangle.first) { + add(QVector3D(point.x, point.y, 0.0f), QVector3D(r, g, b)); + } + } +} + +void GLTriangles::setupVertexAttribs() { + m_vbo.bind(); + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + f->glEnableVertexAttribArray(0); + f->glEnableVertexAttribArray(1); + f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, DATA_DIMENSIONS * sizeof(GLfloat), 0); + f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, DATA_DIMENSIONS * sizeof(GLfloat), (void*)(3*sizeof(GLfloat))); + m_vbo.release(); +} + +void GLTriangles::initializeGL(bool m_core) { + if (m_data.size() == 0) + return; + m_program = new QOpenGLShaderProgram; + m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, m_core ? vertexShaderSourceCore : vertexShaderSource); + m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, + m_core ? fragmentShaderSourceCore : fragmentShaderSource); + m_program->bindAttributeLocation("vertex", 0); + m_program->bindAttributeLocation("colour", 1); + m_program->link(); + + m_program->bind(); + m_projMatrixLoc = m_program->uniformLocation("projMatrix"); + m_mvMatrixLoc = m_program->uniformLocation("mvMatrix"); + + m_vao.create(); + QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); + + m_vbo.create(); + m_vbo.bind(); + m_vbo.allocate(constData(), m_count * sizeof(GLfloat)); + + setupVertexAttribs(); + m_program->release(); + m_built = true; +} + +void GLTriangles::updateGL(bool m_core) { + if (m_program == 0) { + // has not been initialised yet, do that instead + initializeGL(m_core); + } else { + m_vbo.bind(); + m_vbo.allocate(constData(), m_count * sizeof(GLfloat)); + m_vbo.release(); + m_built = true; + } +} + +void GLTriangles::cleanup() { + if (!m_built) + return; + m_vbo.destroy(); + delete m_program; + m_program = 0; +} + +void GLTriangles::paintGL(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel) { + if (!m_built) + return; + QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); + m_program->bind(); + m_program->setUniformValue(m_projMatrixLoc, m_mProj); + m_program->setUniformValue(m_mvMatrixLoc, m_mView * m_mModel); + + glDrawArrays(GL_TRIANGLES, 0, vertexCount()); + + m_program->release(); +} + +void GLTriangles::add(const QVector3D &v, const QVector3D &c) { + GLfloat *p = m_data.data() + m_count; + *p++ = v.x(); + *p++ = v.y(); + *p++ = v.z(); + *p++ = c.x(); + *p++ = c.y(); + *p++ = c.z(); + m_count += DATA_DIMENSIONS; +} diff --git a/depthmapX/views/glview/gltriangles.h b/depthmapX/views/glview/gltriangles.h new file mode 100644 index 00000000..06286c0e --- /dev/null +++ b/depthmapX/views/glview/gltriangles.h @@ -0,0 +1,69 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "genlib/p2dpoly.h" +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief General triangles representation. Each triangle may have its own colour + */ + +class GLTriangles { + public: + GLTriangles() : m_count(0), m_program(0) {} + void loadTriangleData(const std::vector, QRgb>> &triangleData); + void paintGL(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel); + void initializeGL(bool m_core); + void updateGL(bool m_core); + void cleanup(); + void updateColour(const QRgb &polyColour); + int vertexCount() const { return m_count / DATA_DIMENSIONS; } + GLTriangles(const GLTriangles &) = delete; + GLTriangles &operator=(const GLTriangles &) = delete; + + protected: + void init(int numTriangles) { + m_built = false; + m_count = 0; + m_data.resize(numTriangles * 3 * DATA_DIMENSIONS); + } + void add(const QVector3D &v, const QVector3D &c); + + private: + const int DATA_DIMENSIONS = 6; + void setupVertexAttribs(); + const GLfloat *constData() const { return m_data.constData(); } + + QVector m_data; + int m_count; + bool m_built = false; + QVector4D m_colour = QVector4D(1.0f, 1.0f, 1.0f, 1.0f); + + QOpenGLVertexArrayObject m_vao; + QOpenGLBuffer m_vbo; + QOpenGLShaderProgram *m_program; + int m_projMatrixLoc; + int m_mvMatrixLoc; +}; diff --git a/depthmapX/views/glview/gltrianglesuniform.cpp b/depthmapX/views/glview/gltrianglesuniform.cpp new file mode 100644 index 00000000..2acb46c1 --- /dev/null +++ b/depthmapX/views/glview/gltrianglesuniform.cpp @@ -0,0 +1,165 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "gltrianglesuniform.h" +#include + +static const char *vertexShaderSourceCore = + "#version 150\n" + "in vec4 vertex;\n" + "uniform mat4 projMatrix;\n" + "uniform mat4 mvMatrix;\n" + "void main() {\n" + " gl_Position = projMatrix * mvMatrix * vertex;\n" + "}\n"; + +static const char *fragmentShaderSourceCore = + "#version 150\n" + "uniform vec4 colourVector;\n" + "out highp vec4 fragColor;\n" + "void main() {\n" + " fragColor = colourVector;\n" + "}\n"; + +static const char *vertexShaderSource = + "attribute vec4 vertex;\n" + "uniform mat4 projMatrix;\n" + "uniform mat4 mvMatrix;\n" + "void main() {\n" + " gl_Position = projMatrix * mvMatrix * vertex;\n" + "}\n"; + +static const char *fragmentShaderSource = + "uniform vec4 colourVector;\n" + "void main() {\n" + " gl_FragColor = colourVector;\n" + "}\n"; + +/** + * @brief GLTrianglesUniform::GLTrianglesUniform + * This class is an OpenGL representation of a set of triangles of uniform colour + */ + +GLTrianglesUniform::GLTrianglesUniform() + : m_count(0), + m_program(0) +{ + +} + +void GLTrianglesUniform::loadTriangleData(const std::vector& points, const QRgb &polyColour) +{ + m_built = false; + + m_count = 0; + m_data.resize(points.size() * DATA_DIMENSIONS); + + for (auto& point: points) + { + add(QVector3D(point.x, point.y, 0.0f)); + } + m_colour.setX(qRed(polyColour)/255.0); + m_colour.setY(qGreen(polyColour)/255.0); + m_colour.setZ(qBlue(polyColour)/255.0); +} + +void GLTrianglesUniform::setupVertexAttribs() +{ + m_vbo.bind(); + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + f->glEnableVertexAttribArray(0); + f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, DATA_DIMENSIONS * sizeof(GLfloat), 0); + m_vbo.release(); +} + +void GLTrianglesUniform::initializeGL(bool m_core) +{ + if(m_data.size() == 0) return; + m_program = new QOpenGLShaderProgram; + m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, m_core ? vertexShaderSourceCore : vertexShaderSource); + m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, m_core ? fragmentShaderSourceCore : fragmentShaderSource); + m_program->bindAttributeLocation("vertex", 0); + m_program->link(); + + m_program->bind(); + m_projMatrixLoc = m_program->uniformLocation("projMatrix"); + m_mvMatrixLoc = m_program->uniformLocation("mvMatrix"); + m_colourVectorLoc = m_program->uniformLocation("colourVector"); + + m_vao.create(); + QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); + + m_vbo.create(); + m_vbo.bind(); + m_vbo.allocate(constData(), m_count * sizeof(GLfloat)); + + setupVertexAttribs(); + m_program->setUniformValue(m_colourVectorLoc, m_colour); + m_program->release(); + m_built = true; +} + +void GLTrianglesUniform::updateGL(bool m_core) { + if(m_program == 0) { + // has not been initialised yet, do that instead + initializeGL(m_core); + } else { + m_vbo.bind(); + m_vbo.allocate(constData(), m_count * sizeof(GLfloat)); + m_vbo.release(); + m_built = true; + } +} + +void GLTrianglesUniform::updateColour(const QRgb &polyColour) +{ + m_colour.setX(qRed(polyColour)/255.0); + m_colour.setY(qGreen(polyColour)/255.0); + m_colour.setZ(qBlue(polyColour)/255.0); + m_program->bind(); + m_program->setUniformValue(m_colourVectorLoc, m_colour); + m_program->release(); +} + +void GLTrianglesUniform::cleanup() +{ + if(!m_built) return; + m_vbo.destroy(); + delete m_program; + m_program = 0; +} + +void GLTrianglesUniform::paintGL(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel) +{ + if(!m_built) return; + QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); + m_program->bind(); + m_program->setUniformValue(m_projMatrixLoc, m_mProj); + m_program->setUniformValue(m_mvMatrixLoc, m_mView * m_mModel); + + glDrawArrays(GL_TRIANGLES, 0, vertexCount()); + + m_program->release(); +} + +void GLTrianglesUniform::add(const QVector3D &v) +{ + GLfloat *p = m_data.data() + m_count; + *p++ = v.x(); + *p++ = v.y(); + *p++ = v.z(); + m_count += DATA_DIMENSIONS; +} diff --git a/depthmapX/views/glview/gltrianglesuniform.h b/depthmapX/views/glview/gltrianglesuniform.h new file mode 100644 index 00000000..e9e2e3f3 --- /dev/null +++ b/depthmapX/views/glview/gltrianglesuniform.h @@ -0,0 +1,64 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "genlib/p2dpoly.h" +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief General triangles representation. All same colour + */ + +class GLTrianglesUniform +{ +public: + GLTrianglesUniform(); + void loadTriangleData(const std::vector& points, const QRgb &polyColour); + void paintGL(const QMatrix4x4 &m_mProj, const QMatrix4x4 &m_mView, const QMatrix4x4 &m_mModel); + void initializeGL(bool m_core); + void updateGL(bool m_core); + void cleanup(); + void updateColour(const QRgb &polyColour); + int vertexCount() const { return m_count / DATA_DIMENSIONS; } + GLTrianglesUniform( const GLTrianglesUniform& ) = delete; + GLTrianglesUniform& operator=(const GLTrianglesUniform& ) = delete; + +private: + const int DATA_DIMENSIONS = 3; + void setupVertexAttribs(); + const GLfloat *constData() const { return m_data.constData(); } + void add(const QVector3D &v); + + QVector m_data; + int m_count; + bool m_built = false; + QVector4D m_colour = QVector4D(1.0f, 1.0f, 1.0f, 1.0f); + + QOpenGLVertexArrayObject m_vao; + QOpenGLBuffer m_vbo; + QOpenGLShaderProgram *m_program; + int m_projMatrixLoc; + int m_mvMatrixLoc; + int m_colourVectorLoc; +}; diff --git a/depthmapX/views/glview/glutriangulator.cpp b/depthmapX/views/glview/glutriangulator.cpp new file mode 100644 index 00000000..391668d3 --- /dev/null +++ b/depthmapX/views/glview/glutriangulator.cpp @@ -0,0 +1,118 @@ +// adapted from: https://stackoverflow.com/questions/12600325/force-glutesselator-to-generate-only-gl-triangles + +#include "glutriangulator.h" + +struct TessContext +{ + ~TessContext() + { + for( size_t i = 0; i < combined.size(); ++i ) + { + delete[] combined[i]; + } + } + + typedef std::pair< double, double > Point; + std::vector< Point > pts; + std::vector< GLdouble* > combined; +}; + +#ifdef _WIN32 +void __stdcall tess_begin( GLenum ) {} +void __stdcall tess_edgeFlag( GLboolean ) {} +void __stdcall tess_end() {} +#else +void tess_begin( GLenum ) {} +void tess_edgeFlag( GLboolean ) {} +void tess_end() {} +#endif + +#ifdef _WIN32 +void __stdcall tess_vertex +#else +void tess_vertex +#endif + ( + void* data, + TessContext* ctx + ) +{ + GLdouble* coord = (GLdouble*)data; + ctx->pts.push_back( TessContext::Point( coord[0], coord[1] ) ); +} + +#ifdef _WIN32 +void __stdcall tess_combine +#else +void tess_combine +#endif + ( + GLdouble coords[3], + void* vertex_data[4], + GLfloat weight[4], + void** outData, + TessContext* ctx + ) +{ + GLdouble* newVert = new GLdouble[3]; + ctx->combined.push_back( newVert ); + + newVert[0] = coords[0]; + newVert[1] = coords[1]; + newVert[2] = coords[2]; + *outData = newVert; +} + +std::vector< Point2f > GLUTriangulator::triangulate + ( + const std::vector< Point2f >& polygon + ) +{ + std::vector< GLdouble > coords; + for( size_t i = 0; i < polygon.size(); ++i ) + { + coords.push_back( polygon[i].x ); + coords.push_back( polygon[i].y ); + coords.push_back( 0 ); + } + + GLUtesselator* tess = gluNewTess(); +#ifdef _WIN32 + gluTessCallback( tess, GLU_TESS_BEGIN, (void (__stdcall *)()) tess_begin ); + gluTessCallback( tess, GLU_TESS_EDGE_FLAG, (void (__stdcall *)()) tess_edgeFlag ); + gluTessCallback( tess, GLU_TESS_VERTEX_DATA, (void (__stdcall *)()) tess_vertex ); + gluTessCallback( tess, GLU_TESS_END, (void (__stdcall *)()) tess_end ); + gluTessCallback( tess, GLU_TESS_COMBINE_DATA, (void (__stdcall *)()) tess_combine ); +#else + gluTessCallback( tess, GLU_TESS_BEGIN, (void (*)()) tess_begin ); + gluTessCallback( tess, GLU_TESS_EDGE_FLAG, (void (*)()) tess_edgeFlag ); + gluTessCallback( tess, GLU_TESS_VERTEX_DATA, (void (*)()) tess_vertex ); + gluTessCallback( tess, GLU_TESS_END, (void (*)()) tess_end ); + gluTessCallback( tess, GLU_TESS_COMBINE_DATA, (void (*)()) tess_combine ); +#endif + gluTessNormal( tess, 0.0, 0.0, 1.0 ); + + TessContext ctx; + + gluTessBeginPolygon( tess, &ctx ); + gluTessBeginContour( tess ); + + for( size_t i = 0; i < polygon.size(); ++i ) + { + gluTessVertex( tess, &coords[i*3], &coords[i*3] ); + } + + gluTessEndContour( tess ); + gluTessEndPolygon( tess ); + + gluDeleteTess(tess); + + std::vector< Point2f > ret( ctx.pts.size() ); + for( size_t i = 0; i < ret.size(); ++i ) + { + ret[i].x = ctx.pts[i].first; + ret[i].y = ctx.pts[i].second; + } + + return ret; +} diff --git a/depthmapX/views/glview/glutriangulator.h b/depthmapX/views/glview/glutriangulator.h new file mode 100644 index 00000000..8d9fc27d --- /dev/null +++ b/depthmapX/views/glview/glutriangulator.h @@ -0,0 +1,24 @@ +#pragma once + +#include "genlib/p2dpoly.h" +#include + +// This is required to silence the warnings for OpenGL deprecation in macOS +#ifndef GL_SILENCE_DEPRECATION +#define GL_SILENCE_DEPRECATION true +#endif + +#ifdef __linux__ +#include "GL/glu.h" +#elif _WIN32 +#include +#include "GL/glu.h" +#else +#include "glu.h" +#endif + +class GLUTriangulator +{ +public: + static std::vector< Point2f > triangulate(const std::vector< Point2f >& polygon); +}; diff --git a/depthmapX/views/glview/glview.cpp b/depthmapX/views/glview/glview.cpp new file mode 100644 index 00000000..b80bb1b0 --- /dev/null +++ b/depthmapX/views/glview/glview.cpp @@ -0,0 +1,788 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#include "glview.h" +#include "depthmapX/views/depthmapview/depthmapview.h" +#include "salalib/linkutils.h" +#include "salalib/geometrygenerators.h" +#include "mainwindow.h" +#include +#include + +static QRgb colorMerge(QRgb color, QRgb mergecolor) +{ + return (color & 0x006f6f6f) | (mergecolor & 0x00a0a0a0); +} + +GLView::GLView(QGraphDoc &pDoc, + Settings &settings, + QWidget *parent) + : MapView(pDoc, settings, parent), + m_eyePosX(0), + m_eyePosY(0) +{ + m_core = QCoreApplication::arguments().contains(QStringLiteral("--coreprofile")); + + m_foreground = settings.readSetting(SettingTag::foregroundColour, qRgb(128,255,128)).toInt(); + m_background = settings.readSetting(SettingTag::backgroundColour, qRgb(0,0,0)).toInt(); + m_initialSize = m_settings.readSetting(SettingTag::depthmapViewSize, QSize(2000, 2000)).toSize(); + m_antialiasingSamples = settings.readSetting(SettingTag::antialiasingSamples, 0).toInt(); + + if(m_antialiasingSamples) { + QSurfaceFormat format; + format.setSamples(m_antialiasingSamples); // Set the number of samples used for multisampling + setFormat(format); + } + + loadDrawingGLObjects(); + + loadAxes(); + + if(m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWAXIAL) { + m_visibleShapeGraph.loadGLObjects(m_pDoc.m_meta_graph->getDisplayedShapeGraph()); + } + m_visiblePointMap.setGridColour(colorMerge(m_foreground, m_background)); + if(m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWVGA) { + m_visiblePointMap.loadGLObjects(m_pDoc.m_meta_graph->getDisplayedPointMap()); + } + + if(m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWDATA) { + m_visibleDataMap.loadGLObjects(m_pDoc.m_meta_graph->getDisplayedDataMap()); + } + + m_dragLine.setStrokeColour(m_foreground); + m_selectionRect.setStrokeColour(m_background); + + matchViewToCurrentMetaGraph(); + + installEventFilter(this); + setMouseTracking(true); + m_pDoc.m_view[QGraphDoc::VIEW_MAP_GL] = this; +} + +GLView::~GLView() +{ + makeCurrent(); + m_selectionRect.cleanup(); + m_dragLine.cleanup(); + m_axes.cleanup(); + m_visibleDrawingLines.cleanup(); + m_visiblePointMap.cleanup(); + m_visibleShapeGraph.cleanup(); + m_visibleDataMap.cleanup(); + doneCurrent(); + m_settings.writeSetting(SettingTag::depthmapViewSize, size()); +} + +QSize GLView::minimumSizeHint() const +{ + return QSize(50, 50); +} + +QSize GLView::sizeHint() const +{ + return m_initialSize; +} + +void GLView::initializeGL() +{ + initializeOpenGLFunctions(); + glClearColor(qRed(m_background)/255.0f, qGreen(m_background)/255.0f, qBlue(m_background)/255.0f, 1); + + m_selectionRect.initializeGL(m_core); + m_dragLine.initializeGL(m_core); + m_axes.initializeGL(m_core); + m_visibleDrawingLines.initializeGL(m_core); + m_visiblePointMap.initializeGL(m_core); + m_visibleShapeGraph.initializeGL(m_core); + m_visibleDataMap.initializeGL(m_core); + + if(m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWVGA) { + m_visiblePointMap.loadGLObjectsRequiringGLContext(m_pDoc.m_meta_graph->getDisplayedPointMap()); + } + + m_mModel.setToIdentity(); + + m_mView.setToIdentity(); + m_mView.translate(0, 0, -1); +} + +void GLView::paintGL() +{ + glEnable(GL_MULTISAMPLE); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_CULL_FACE); + glEnable(GL_BLEND); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + + if(m_datasetChanged) { + + loadDrawingGLObjects(); + m_visibleDrawingLines.updateGL(m_core); + + if(m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWAXIAL + && m_pDoc.m_meta_graph->getDisplayedMapRef() != -1) { + m_visibleShapeGraph.loadGLObjects(m_pDoc.m_meta_graph->getDisplayedShapeGraph()); + m_visibleShapeGraph.updateGL(m_core); + } + + if(m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWDATA) { + m_visibleDataMap.loadGLObjects(m_pDoc.m_meta_graph->getDisplayedDataMap()); + m_visibleDataMap.updateGL(m_core); + } + + if(m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWVGA) { + m_visiblePointMap.loadGLObjects(m_pDoc.m_meta_graph->getDisplayedPointMap()); + m_visiblePointMap.updateGL(m_core); + m_visiblePointMap.loadGLObjectsRequiringGLContext(m_pDoc.m_meta_graph->getDisplayedPointMap()); + } + + m_datasetChanged = false; + } + + m_axes.paintGL(m_mProj, m_mView, m_mModel); + + if(m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWVGA) { + m_visiblePointMap.showGrid(m_pDoc.m_meta_graph->m_showgrid); + m_visiblePointMap.paintGL(m_mProj, m_mView, m_mModel); + } + + if(m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWAXIAL) { + m_visibleShapeGraph.paintGL(m_mProj, m_mView, m_mModel); + } + + if(m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWDATA) { + m_visibleDataMap.paintGL(m_mProj, m_mView, m_mModel); + } + + m_visibleDrawingLines.paintGL(m_mProj, m_mView, m_mModel); + + if(m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWVGA) { + m_visiblePointMap.paintGLOverlay(m_mProj, m_mView, m_mModel); + } + if(m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWAXIAL) { + m_visibleShapeGraph.paintGLOverlay(m_mProj, m_mView, m_mModel); + } + + + float pos [] = { + float(std::min(m_mouseDragRect.bottomRight().x(),m_mouseDragRect.topLeft().x())), + float(std::min(m_mouseDragRect.bottomRight().y(),m_mouseDragRect.topLeft().y())), + float(std::max(m_mouseDragRect.bottomRight().x(),m_mouseDragRect.topLeft().x())), + float(std::max(m_mouseDragRect.bottomRight().y(),m_mouseDragRect.topLeft().y())) + }; + m_selectionRect.paintGL(m_mProj, m_mView, m_mModel, QMatrix2x2(pos)); + + if((m_mouseMode & MOUSE_MODE_SECOND_POINT) == MOUSE_MODE_SECOND_POINT) { + float pos [] = { + float(m_tempFirstPoint.x), + float(m_tempFirstPoint.y), + float(m_tempSecondPoint.x), + float(m_tempSecondPoint.y) + }; + m_dragLine.paintGL(m_mProj, m_mView, m_mModel, QMatrix2x2(pos)); + } +} + +void GLView::loadAxes() { + std::vector> axesData; + axesData.push_back(std::pair (SimpleLine(0,0,1,0), PafColor(1,0,0))); + axesData.push_back(std::pair (SimpleLine(0,0,0,1), PafColor(0,1,0))); + m_axes.loadLineData(axesData); +} + +void GLView::loadDrawingGLObjects() { + auto lock = m_pDoc.m_meta_graph->getLock(); + m_visibleDrawingLines.loadLineData(m_pDoc.m_meta_graph->getVisibleDrawingLines(), m_foreground); +} + +void GLView::resizeGL(int w, int h) +{ + m_screenWidth = w; + m_screenHeight = h; + m_screenRatio = GLfloat(w) / h; + recalcView(); +} + +void GLView::mouseReleaseEvent(QMouseEvent *event) +{ + if(m_wasPanning) { + m_wasPanning = false; + return; + } + QPoint mousePoint = event->pos(); + Point2f worldPoint = getWorldPoint(mousePoint); + if (!m_pDoc.m_communicator) { + QtRegion r; + if(m_mouseDragRect.isNull()) + { + r.bottom_left = worldPoint; + r.top_right = worldPoint; + } + else + { + r.bottom_left.x = std::min(m_mouseDragRect.bottomRight().x(),m_mouseDragRect.topLeft().x()); + r.bottom_left.y = std::min(m_mouseDragRect.bottomRight().y(),m_mouseDragRect.topLeft().y()); + r.top_right.x = std::max(m_mouseDragRect.bottomRight().x(),m_mouseDragRect.topLeft().x()); + r.top_right.y = std::max(m_mouseDragRect.bottomRight().y(),m_mouseDragRect.topLeft().y()); + } + bool selected = false; + switch(m_mouseMode) + { + case MOUSE_MODE_NONE: + { + // nothing, deselect + m_pDoc.m_meta_graph->clearSel(); + break; + } + case MOUSE_MODE_SELECT: + { + // typical selection + Qt::KeyboardModifiers keyMods = QApplication::keyboardModifiers(); + m_pDoc.m_meta_graph->setCurSel( r, keyMods & Qt::ShiftModifier ); + ((MainWindow *) m_pDoc.m_mainFrame)->updateToolbar(); + break; + } + case MOUSE_MODE_ZOOM_IN: + { + if(r.width() > 0) + { + OnViewZoomToRegion(r); + recalcView(); + } + else + { + zoomBy(0.8, mousePoint.x(), mousePoint.y()); + } + break; + } + case MOUSE_MODE_ZOOM_OUT: + { + zoomBy(1.2, mousePoint.x(), mousePoint.y()); + break; + } + case MOUSE_MODE_FILL_FULL: + { + m_pDoc.OnFillPoints( worldPoint, 0 ); + break; + } + case MOUSE_MODE_PENCIL: + { + m_pDoc.m_meta_graph->getDisplayedPointMap().fillPoint(worldPoint, event->button() == Qt::LeftButton); + break; + } + case MOUSE_MODE_SEED_ISOVIST: + { + m_pDoc.OnMakeIsovist( worldPoint ); + break; + } + case MOUSE_MODE_SEED_TARGETED_ISOVIST: + { + m_tempFirstPoint = worldPoint; + m_tempSecondPoint = worldPoint; + m_mouseMode = MOUSE_MODE_SEED_TARGETED_ISOVIST | MOUSE_MODE_SECOND_POINT; + break; + } + case MOUSE_MODE_SEED_TARGETED_ISOVIST | MOUSE_MODE_SECOND_POINT: + { + Line directionLine(m_tempFirstPoint,worldPoint); + Point2f vec = directionLine.vector(); + vec.normalise(); + m_pDoc.OnMakeIsovist( m_tempFirstPoint, vec.angle() ); + m_mouseMode = MOUSE_MODE_SEED_TARGETED_ISOVIST; + break; + } + case MOUSE_MODE_SEED_AXIAL: + { + m_pDoc.OnToolsAxialMap( worldPoint ); + break; + } + case MOUSE_MODE_LINE_TOOL: + { + m_tempFirstPoint = worldPoint; + m_tempSecondPoint = worldPoint; + m_mouseMode = MOUSE_MODE_LINE_TOOL | MOUSE_MODE_SECOND_POINT; + break; + } + case MOUSE_MODE_LINE_TOOL | MOUSE_MODE_SECOND_POINT: + { + if (m_pDoc.m_meta_graph->makeShape(Line(m_tempFirstPoint,worldPoint))) { + m_pDoc.modifiedFlag = true; + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA ); + } + m_tempFirstPoint = worldPoint; + m_tempSecondPoint = worldPoint; + m_mouseMode = MOUSE_MODE_LINE_TOOL; + + break; + } + case MOUSE_MODE_POLYGON_TOOL: + { + m_tempFirstPoint = worldPoint; + m_tempSecondPoint = worldPoint; + m_polyPoints = 0; + m_mouseMode = MOUSE_MODE_POLYGON_TOOL | MOUSE_MODE_SECOND_POINT; + break; + } + case MOUSE_MODE_POLYGON_TOOL | MOUSE_MODE_SECOND_POINT: + { + if (m_polyPoints == 0) { + m_currentlyEditingShapeRef = m_pDoc.m_meta_graph->polyBegin(Line(m_tempFirstPoint,worldPoint)); + m_polyStart = m_tempFirstPoint; + m_tempFirstPoint = m_tempSecondPoint; + m_polyPoints += 2; + } + else if (m_polyPoints > 2 && PixelDist(mousePoint, getScreenPoint(m_polyStart)) < 6) { + // check to see if it's back to the original start point, if so, close off + m_pDoc.m_meta_graph->polyClose(m_currentlyEditingShapeRef); + m_polyPoints = 0; + m_currentlyEditingShapeRef = -1; + m_mouseMode = MOUSE_MODE_POLYGON_TOOL; + } + else { + m_pDoc.m_meta_graph->polyAppend(m_currentlyEditingShapeRef, worldPoint); + m_tempFirstPoint = m_tempSecondPoint; + m_polyPoints += 1; + } + break; + } + case MOUSE_MODE_POINT_STEP_DEPTH: + { + m_pDoc.m_meta_graph->setCurSel( r, false ); + m_pDoc.OnToolsPD(); + break; + } + case MOUSE_MODE_JOIN: + { + selected = m_pDoc.m_meta_graph->setCurSel( r, false ); + int selectedCount = m_pDoc.m_meta_graph->getSelCount(); + if(selectedCount > 0) { + Point2f selectionCentre; + if(selectedCount > 1) { + QtRegion selBounds = m_pDoc.m_meta_graph->getSelBounds(); + selectionCentre.x = (selBounds.bottom_left.x + selBounds.top_right.x)*0.5; + selectionCentre.y = (selBounds.bottom_left.y + selBounds.top_right.y)*0.5; + } else { + const std::set &selectedSet = m_pDoc.m_meta_graph->getSelSet(); + if (m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWVGA) { + selectionCentre = m_pDoc.m_meta_graph->getDisplayedPointMap().depixelate(*selectedSet.begin()); + } else if (m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWAXIAL) { + selectionCentre = m_pDoc.m_meta_graph->getDisplayedShapeGraph().getAllShapes()[*selectedSet.begin()].getCentroid(); + } + } + m_tempFirstPoint = selectionCentre; + m_tempSecondPoint = selectionCentre; + m_mouseMode = MOUSE_MODE_JOIN | MOUSE_MODE_SECOND_POINT; + } + break; + } + case MOUSE_MODE_JOIN | MOUSE_MODE_SECOND_POINT: + { + int selectedCount = m_pDoc.m_meta_graph->getSelCount(); + if (selectedCount > 0) { + if (m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWVGA) { + m_pDoc.m_meta_graph->getDisplayedPointMap().mergePoints( worldPoint ); + } else if (m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWAXIAL && selectedCount == 1) { + m_pDoc.m_meta_graph->setCurSel( r, true ); // add the new one to the selection set + const auto& selectedSet = m_pDoc.m_meta_graph->getSelSet(); + if (selectedSet.size() == 2) { + std::set::iterator it = selectedSet.begin(); + int axRef1 = *it; + it++; + int axRef2 = *it; + // axial is only joined one-by-one + m_pDoc.modifiedFlag = true; + m_pDoc.m_meta_graph->getDisplayedShapeGraph().linkShapes(axRef1, axRef2, true); + m_pDoc.m_meta_graph->clearSel(); + } + } + m_pDoc.m_meta_graph->clearSel(); + m_mouseMode = MOUSE_MODE_JOIN; + } + break; + } + case MOUSE_MODE_UNJOIN: + { + m_pDoc.m_meta_graph->setCurSel( r, false ); + int selectedCount = m_pDoc.m_meta_graph->getSelCount(); + if(selectedCount > 0) { + if (m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWVGA) { + if (m_pDoc.m_meta_graph->getDisplayedPointMap().unmergePoints()) { + m_pDoc.modifiedFlag = true; + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_ALL,QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA); + } + } else if (m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWAXIAL) { + const auto& selectedSet = m_pDoc.m_meta_graph->getSelSet(); + Point2f selectionCentre = m_pDoc.m_meta_graph->getDisplayedShapeGraph().getAllShapes()[*selectedSet.begin()].getCentroid(); + m_tempFirstPoint = selectionCentre; + m_tempSecondPoint = selectionCentre; + m_mouseMode = MOUSE_MODE_UNJOIN | MOUSE_MODE_SECOND_POINT; + } + } + break; + } + case MOUSE_MODE_UNJOIN | MOUSE_MODE_SECOND_POINT: + { + int selectedCount = m_pDoc.m_meta_graph->getSelCount(); + if (selectedCount > 0) { + if (m_pDoc.m_meta_graph->getViewClass() & MetaGraph::VIEWAXIAL && selectedCount == 1) { + m_pDoc.m_meta_graph->setCurSel( r, true ); // add the new one to the selection set + const auto& selectedSet = m_pDoc.m_meta_graph->getSelSet(); + if (selectedSet.size() == 2) { + std::set::iterator it = selectedSet.begin(); + int axRef1 = *it; + it++; + int axRef2 = *it; + // axial is only joined one-by-one + m_pDoc.modifiedFlag = true; + m_pDoc.m_meta_graph->getDisplayedShapeGraph().unlinkShapes(axRef1, axRef2, true); + m_pDoc.m_meta_graph->clearSel(); + } + } + m_pDoc.m_meta_graph->clearSel(); + m_mouseMode = MOUSE_MODE_UNJOIN; + } + break; + } + } + + m_pDoc.SetRedrawFlag(QGraphDoc::VIEW_ALL,QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_SELECTION); + } + m_mouseDragRect.setWidth(0); + m_mouseDragRect.setHeight(0); +} + +void GLView::mousePressEvent(QMouseEvent *event) +{ + m_mouseLastPos = event->pos(); +} + +void GLView::mouseMoveEvent(QMouseEvent *event) +{ + int dx = event->x() - m_mouseLastPos.x(); + int dy = event->y() - m_mouseLastPos.y(); + + Point2f worldPoint = getWorldPoint(event->pos()); + + if (event->buttons() & Qt::RightButton + || (event->buttons() & Qt::LeftButton && m_mouseMode == MOUSE_MODE_PAN)) { + panBy(dx, dy); + m_wasPanning = true; + } else if (event->buttons() & Qt::LeftButton) { + Point2f lastWorldPoint = getWorldPoint(m_mouseLastPos); + + if(m_mouseDragRect.isNull()) { + m_mouseDragRect.setX(lastWorldPoint.x); + m_mouseDragRect.setY(lastWorldPoint.y); + } + m_mouseDragRect.setWidth(worldPoint.x - m_mouseDragRect.x()); + m_mouseDragRect.setHeight(worldPoint.y - m_mouseDragRect.y()); + update(); + } + if((m_mouseMode & MOUSE_MODE_SECOND_POINT) == MOUSE_MODE_SECOND_POINT) + { + m_tempSecondPoint = worldPoint; + update(); + } + m_mouseLastPos = event->pos(); + m_pDoc.m_position = worldPoint; + m_pDoc.UpdateMainframestatus(); +} + +void GLView::wheelEvent(QWheelEvent *event) +{ + QPoint numDegrees = event->angleDelta() / 8; + + int x = event->x(); + int y = event->y(); + + zoomBy(1 - 0.25f * numDegrees.y() / 15.0f, x, y); + + event->accept(); +} + +bool GLView::eventFilter(QObject *object, QEvent *e) +{ + if(e->type() == QEvent::ToolTip) + { + if (!m_pDoc.m_communicator) + { + if(m_pDoc.m_meta_graph) + { + if (m_pDoc.m_meta_graph->viewingProcessed() && m_pDoc.m_meta_graph->getSelCount() > 1) { + float val = m_pDoc.m_meta_graph->getSelAvg(); + int count = m_pDoc.m_meta_graph->getSelCount(); + if (val == -1.0f) + setToolTip("Null selection"); + else if (val != -2.0f) + setToolTip(QString("Selection\nAverage: %1\nCount: %2").arg(val).arg(count)); + else setToolTip(""); + } + else if (m_pDoc.m_meta_graph->viewingProcessed()) { + // and that it has an appropriate state to display a hover wnd + QHelpEvent *helpEvent = static_cast(e); // Tool tip events come as the type QHelpEvent + float val = m_pDoc.m_meta_graph->getLocationValue(getWorldPoint(helpEvent->pos())); + if (val == -1.0f) + setToolTip("No value"); + else if (val != -2.0f) { + QString s; + QTextStream txt(&s); + txt.setRealNumberNotation(QTextStream::FixedNotation); + txt << val; + setToolTip(s); + } + else setToolTip(""); + } + } + } + } + + return QObject::eventFilter(object, e); +} + +void GLView::zoomBy(float dzf, int mouseX, int mouseY) +{ + float pzf = m_zoomFactor; + m_zoomFactor = m_zoomFactor * dzf; + if(m_zoomFactor < m_minZoomFactor) m_zoomFactor = m_minZoomFactor; + else if(m_zoomFactor > m_maxZoomFactor) m_zoomFactor = m_maxZoomFactor; + m_eyePosX += (m_zoomFactor - pzf) * m_screenRatio * GLfloat(mouseX - m_screenWidth*0.5f) / GLfloat(m_screenWidth); + m_eyePosY -= (m_zoomFactor - pzf) * GLfloat(mouseY - m_screenHeight*0.5f) / GLfloat(m_screenHeight); + recalcView(); +} +void GLView::panBy(int dx, int dy) +{ + m_eyePosX += m_zoomFactor * GLfloat(dx) / m_screenHeight; + m_eyePosY -= m_zoomFactor * GLfloat(dy) / m_screenHeight; + + recalcView(); +} +void GLView::recalcView() +{ + m_mProj.setToIdentity(); + + if(m_perspectiveView) + { + m_mProj.perspective(45.0f, m_screenRatio, 0.01f, 100.0f); + m_mProj.scale(1.0f, 1.0f, m_zoomFactor); + } + else + { + m_mProj.ortho(-m_zoomFactor * 0.5f * m_screenRatio, m_zoomFactor * 0.5f * m_screenRatio, -m_zoomFactor * 0.5f, m_zoomFactor * 0.5f, 0, 10); + } + m_mProj.translate(m_eyePosX, m_eyePosY, 0.0f); + update(); +} + +Point2f GLView::getWorldPoint(const QPoint &screenPoint) { + return Point2f(+ m_zoomFactor * float(screenPoint.x() - m_screenWidth*0.5) / m_screenHeight - m_eyePosX, + - m_zoomFactor * float(screenPoint.y() - m_screenHeight*0.5) / m_screenHeight - m_eyePosY); +} + +QPoint GLView::getScreenPoint(const Point2f &worldPoint) { + return QPoint((worldPoint.x + m_eyePosX) * m_screenHeight / m_zoomFactor + m_screenWidth*0.5 , + - (worldPoint.y + m_eyePosY) * m_screenHeight / m_zoomFactor + m_screenHeight*0.5); + +} + +void GLView::matchViewToCurrentMetaGraph() { + const QtRegion ®ion = m_pDoc.m_meta_graph->getBoundingBox(); + OnViewZoomToRegion(region); + recalcView(); +} + +void GLView::OnViewZoomToRegion(QtRegion region) { + if((region.top_right.x == 0 && region.bottom_left.x == 0) + || (region.top_right.y == 0 && region.bottom_left.y == 0)) + // region is unset, don't try to change the view to it + return; + m_eyePosX = - (region.top_right.x + region.bottom_left.x)*0.5f; + m_eyePosY = - (region.top_right.y + region.bottom_left.y)*0.5f; + if(region.width() > region.height()) + { + m_zoomFactor = region.top_right.x - region.bottom_left.x; + } + else + { + m_zoomFactor = region.top_right.y - region.bottom_left.y; + } + m_minZoomFactor = m_zoomFactor * 0.001; + m_maxZoomFactor = m_zoomFactor * 10; +} + +void GLView::resetView() { + m_visiblePointMap.showLinks(false); + m_visibleShapeGraph.showLinks(false); + m_pDoc.m_meta_graph->clearSel(); + update(); +} + +void GLView::OnModeJoin() +{ + if (m_pDoc.m_meta_graph->getViewClass() & (MetaGraph::VIEWVGA | MetaGraph::VIEWAXIAL)) { + resetView(); + m_mouseMode = MOUSE_MODE_JOIN; + m_visiblePointMap.showLinks(true); + m_visibleShapeGraph.showLinks(true); + m_pDoc.m_meta_graph->clearSel(); + notifyDatasetChanged(); + } +} + +void GLView::OnModeUnjoin() +{ + if (m_pDoc.m_meta_graph->getState() & (MetaGraph::VIEWVGA | MetaGraph::VIEWAXIAL)) { + resetView(); + m_mouseMode = MOUSE_MODE_UNJOIN; + m_visiblePointMap.showLinks(true); + m_visibleShapeGraph.showLinks(true); + m_pDoc.m_meta_graph->clearSel(); + notifyDatasetChanged(); + } +} +void GLView::OnViewPan() +{ + m_mouseMode = MOUSE_MODE_PAN; +} + +void GLView::OnViewZoomIn() +{ + m_mouseMode = MOUSE_MODE_ZOOM_IN; +} + +void GLView::OnViewZoomOut() +{ + m_mouseMode = MOUSE_MODE_ZOOM_OUT; +} + +void GLView::OnEditFill() +{ + resetView(); + m_mouseMode = MOUSE_MODE_FILL_FULL; +} + +void GLView::OnEditSemiFill() +{ + resetView(); + m_mouseMode = MOUSE_MODE_FILL_SEMI; +} + +void GLView::OnEditAugmentFill() +{ + resetView(); + m_mouseMode = MOUSE_MODE_FILL_AUGMENT; +} + +void GLView::OnEditPencil() +{ + resetView(); + m_mouseMode = MOUSE_MODE_PENCIL; +} + +void GLView::OnModeIsovist() +{ + resetView(); + m_mouseMode = MOUSE_MODE_SEED_ISOVIST; +} + +void GLView::OnModeTargetedIsovist() +{ + resetView(); + m_mouseMode = MOUSE_MODE_SEED_TARGETED_ISOVIST; +} + +void GLView::OnModeSeedAxial() +{ + resetView(); + m_mouseMode = MOUSE_MODE_SEED_AXIAL; +} + +void GLView::OnModeStepDepth() +{ + resetView(); + m_mouseMode = MOUSE_MODE_POINT_STEP_DEPTH; +} + +void GLView::OnEditLineTool() +{ + resetView(); + m_mouseMode = MOUSE_MODE_LINE_TOOL; +} + +void GLView::OnEditPolygonTool() +{ + resetView(); + m_mouseMode = MOUSE_MODE_POLYGON_TOOL; +} + +void GLView::OnEditSelect() +{ + resetView(); + m_mouseMode = MOUSE_MODE_SELECT; +} + +void GLView::postLoadFile() +{ + matchViewToCurrentMetaGraph(); + setWindowTitle(m_pDoc.m_base_title+":Map View (GL)"); +} + +void GLView::OnViewZoomsel() +{ + if (m_pDoc.m_meta_graph && m_pDoc.m_meta_graph->isSelected()) { + OnViewZoomToRegion(m_pDoc.m_meta_graph->getSelBounds()); + } +} + +void GLView::closeEvent(QCloseEvent *event) +{ + m_pDoc.m_view[QGraphDoc::VIEW_MAP_GL] = NULL; + if (!m_pDoc.OnCloseDocument(QGraphDoc::VIEW_MAP_GL)) + { + m_pDoc.m_view[QGraphDoc::VIEW_MAP_GL] = this; + event->ignore(); + } +} + +void GLView::OnEditCopy() +{ + std::unique_ptr tmp(new QDepthmapView(m_pDoc, m_settings)); + Point2f topLeftWorld = getWorldPoint(QPoint(0,0)); + Point2f bottomRightWorld = getWorldPoint(QPoint(width(),height())); + + tmp->setAttribute(Qt::WA_DontShowOnScreen); + tmp->show(); + tmp->postLoadFile(); + tmp->OnViewZoomToRegion(QtRegion(topLeftWorld, bottomRightWorld)); + tmp->repaint(); + tmp->OnEditCopy(); + tmp->close(); +} + +void GLView::OnEditSave() +{ + std::unique_ptr tmp(new QDepthmapView(m_pDoc, m_settings)); + Point2f topLeftWorld = getWorldPoint(QPoint(0,0)); + Point2f bottomRightWorld = getWorldPoint(QPoint(width(),height())); + + tmp->setAttribute(Qt::WA_DontShowOnScreen); + tmp->show(); + tmp->postLoadFile(); + tmp->OnViewZoomToRegion(QtRegion(topLeftWorld, bottomRightWorld)); + tmp->OnEditSave(); + +} diff --git a/depthmapX/views/glview/glview.h b/depthmapX/views/glview/glview.h new file mode 100644 index 00000000..413c8f57 --- /dev/null +++ b/depthmapX/views/glview/glview.h @@ -0,0 +1,168 @@ +// depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "depthmapX/GraphDoc.h" + +#include "depthmapX/views/mapview.h" +#include "depthmapX/views/glview/gllines.h" +#include "depthmapX/views/glview/gllinesuniform.h" +#include "depthmapX/views/glview/glrastertexture.h" +#include "depthmapX/views/glview/glpolygons.h" +#include "depthmapX/views/glview/glpointmap.h" +#include "depthmapX/views/glview/glshapegraph.h" +#include "depthmapX/views/glview/gldynamicrect.h" +#include "depthmapX/views/glview/gldynamicline.h" + +#include +#include +#include + +QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram) + +class GLView : public MapView, protected QOpenGLFunctions +{ + Q_OBJECT + +public: + GLView(QGraphDoc &pDoc, + Settings &settings, + QWidget *parent = Q_NULLPTR); + ~GLView(); + + QSize minimumSizeHint() const override; + QSize sizeHint() const override; + void notifyDatasetChanged() { m_datasetChanged = true; update(); } + void matchViewToCurrentMetaGraph(); + + virtual void OnModeJoin() override; + virtual void OnModeUnjoin() override; + virtual void OnViewPan() override; + virtual void OnViewZoomIn() override; + virtual void OnViewZoomOut() override; + virtual void OnEditFill() override; + virtual void OnEditSemiFill() override; + virtual void OnEditAugmentFill() override; + virtual void OnEditPencil() override; + virtual void OnModeIsovist() override; + virtual void OnModeTargetedIsovist() override; + virtual void OnEditLineTool() override; + virtual void OnEditPolygonTool() override; + virtual void OnModeSeedAxial() override; + virtual void OnEditSelect() override; + virtual void OnViewZoomsel() override; + void OnModeStepDepth(); + virtual void postLoadFile() override; + virtual void OnEditCopy() override; + virtual void OnEditSave() override; + virtual void OnViewZoomToRegion(QtRegion region) override; + +protected: + void initializeGL() override; + void paintGL() override; + void resizeGL(int width, int height) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void wheelEvent(QWheelEvent *event) override; + bool eventFilter(QObject *object, QEvent *e) override; + void closeEvent(QCloseEvent *event) override; + +private: + bool m_perspectiveView = false; + bool m_core; + QMatrix4x4 m_mProj; + QMatrix4x4 m_mView; + QMatrix4x4 m_mModel; + + QRgb m_foreground; + QRgb m_background; + QSize m_initialSize; + + GLDynamicRect m_selectionRect; + GLDynamicLine m_dragLine; + GLLines m_axes; + GLShapeGraph m_visibleShapeGraph; + GLLinesUniform m_visibleDrawingLines; + GLPointMap m_visiblePointMap; + GLShapeMap m_visibleDataMap; + + QPoint m_mouseLastPos; + float m_eyePosX; + float m_eyePosY; + float m_minZoomFactor = 1; + float m_zoomFactor = 20; + float m_maxZoomFactor = 200; + GLfloat m_screenRatio; + int m_screenWidth; + int m_screenHeight; + bool m_wasPanning = false; + + int m_antialiasingSamples = 0; // set this to 0 if rendering is too slow + + Point2f getWorldPoint(const QPoint &screenPoint); + QPoint getScreenPoint(const Point2f &worldPoint); + + bool m_datasetChanged = false; + + void panBy(int dx, int dy); + void recalcView(); + void zoomBy(float dzf, int mouseX, int mouseY); + void resetView(); + + void loadAxes(); + void loadDrawingGLObjects(); + + enum { + MOUSE_MODE_NONE = 0x0000, + MOUSE_MODE_SELECT = 0x10000, + MOUSE_MODE_PAN = 0x0101, + MOUSE_MODE_ZOOM_IN = 0x0202, + MOUSE_MODE_ZOOM_OUT = 0x0204, + MOUSE_MODE_FILL_FULL = 0x0001, + MOUSE_MODE_FILL_SEMI = 0x0002, + MOUSE_MODE_FILL_AUGMENT = 0x0003, + MOUSE_MODE_PENCIL = 0x0801, + MOUSE_MODE_SEED_ISOVIST = 0x4001, + MOUSE_MODE_SEED_TARGETED_ISOVIST = 0x4002, + MOUSE_MODE_SEED_AXIAL = 0x0004, + MOUSE_MODE_LINE_TOOL = 0x0008, + MOUSE_MODE_POLYGON_TOOL = 0x0010, + MOUSE_MODE_POINT_STEP_DEPTH = 0x5000, + MOUSE_MODE_JOIN = 0x20001, + MOUSE_MODE_UNJOIN = 0x20002, + MOUSE_MODE_SECOND_POINT = 0x00400, + }; + + int m_mouseMode = MOUSE_MODE_SELECT; + + QRectF m_mouseDragRect = QRectF(0,0,0,0); + + Point2f m_tempFirstPoint; + Point2f m_tempSecondPoint; + + int m_currentlyEditingShapeRef = -1; + + Point2f m_polyStart; + int m_polyPoints = 0; + + inline int PixelDist(QPoint a, QPoint b) + { + return (int)sqrt(double((b.x()-a.x())*(b.x()-a.x())+(b.y()-a.y())*(b.y()-a.y()))); + } +}; + diff --git a/depthmapX/views/mapview.cpp b/depthmapX/views/mapview.cpp new file mode 100644 index 00000000..17613e88 --- /dev/null +++ b/depthmapX/views/mapview.cpp @@ -0,0 +1,7 @@ +#include "mapview.h" + +MapView::MapView(QGraphDoc &pDoc, Settings &settings, QWidget *parent) + : QOpenGLWidget(parent), m_pDoc(pDoc), m_settings(settings) +{ + +} diff --git a/depthmapX/views/mapview.h b/depthmapX/views/mapview.h new file mode 100644 index 00000000..1e2721a8 --- /dev/null +++ b/depthmapX/views/mapview.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include "GraphDoc.h" +#include "settings.h" + +class MapView : public QOpenGLWidget +{ + Q_OBJECT + +protected: + QGraphDoc &m_pDoc; + Settings &m_settings; + QString m_currentFile; + +public: + MapView(QGraphDoc &pDoc, + Settings &settings, + QWidget* parent = Q_NULLPTR); + + virtual void OnModeJoin() = 0; + virtual void OnModeUnjoin() = 0; + virtual void OnViewPan() = 0; + virtual void OnViewZoomIn() = 0; + virtual void OnViewZoomOut() = 0; + virtual void OnEditFill() = 0; + virtual void OnEditSemiFill() = 0; + virtual void OnEditAugmentFill() = 0; + virtual void OnEditPencil() = 0; + virtual void OnModeIsovist() = 0; + virtual void OnModeTargetedIsovist() = 0; + virtual void OnEditLineTool() = 0; + virtual void OnEditPolygonTool() = 0; + virtual void OnModeSeedAxial() = 0; + virtual void OnEditSelect() = 0; + virtual void postLoadFile() = 0; + virtual void OnViewZoomsel() = 0; + virtual void OnEditCopy() = 0; + virtual void OnEditSave() = 0; + virtual void OnViewZoomToRegion(QtRegion region) = 0; + + QGraphDoc *getGraphDoc() { return &m_pDoc; } + void setCurrentFile(const QString &fileName) { m_currentFile = fileName; } + QString getCurrentFile() { return m_currentFile; } +}; diff --git a/depthmapX/views/plotview/plotview.cpp b/depthmapX/views/plotview/plotview.cpp new file mode 100644 index 00000000..5e00fc87 --- /dev/null +++ b/depthmapX/views/plotview/plotview.cpp @@ -0,0 +1,640 @@ +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// depthmapX - spatial network analysis platform + +// PlotView.cpp : implementation file +// + +#include "plotview.h" +#include "mainwindow.h" + +#include "salalib/attributetablehelpers.h" + +#include +#include + +#ifdef _WIN32 +#define finite _finite +#endif + +///////////////////////////////////////////////////////////////////////////// +// PlotView +static int pressed_nFlags; +QPlotView::QPlotView() { + m_x_axis = -1; + m_y_axis = -1; + curr_x = -1; + curr_y = -1; + + m_queued_redraw = false; + m_view_trend_line = false; + m_view_rsquared = false; + m_view_monochrome = false; + m_view_origin = false; + m_view_equation = false; + + // for drawing drag rect + m_drawdragrect = false; + m_selecting = false; + + setAttribute(Qt::WA_NoBackground, 1); + setMouseTracking(true); + setWindowIcon(QIcon(tr(":/images/cur/icon-1-2.png"))); + + installEventFilter(this); +} + +///////////////////////////////////////////////////////////////////////////// +// QPlotView drawing + +int QPlotView::screenX(double x) { + return m_screen_bounds.left() + + m_screen_bounds.width() * + (m_data_bounds.width() ? (x - m_data_bounds.bottom_left.x) / m_data_bounds.width() : 0.5); +} + +int QPlotView::screenY(double y) { + return m_screen_bounds.top() - + (abs(m_screen_bounds.height()) * + (m_data_bounds.height() ? (y - m_data_bounds.bottom_left.y) / m_data_bounds.height() : 0.5)); +} + +double QPlotView::dataX(int x) { + return m_data_bounds.bottom_left.x + + m_data_bounds.width() * double(x - m_screen_bounds.left()) / double(m_screen_bounds.width()); +} + +double QPlotView::dataY(int y) { + return m_data_bounds.bottom_left.y + + m_data_bounds.height() * double(m_screen_bounds.top() - y) / double(abs(m_screen_bounds.height())); +} + +QSize QPlotView::sizeHint() const { return QSize(2000, 2000); } + +static QPoint hit_point; +bool QPlotView::eventFilter(QObject *object, QEvent *e) { + if (e->type() == QEvent::ToolTip) { + if (!pDoc->m_communicator) { + // first, check you have a meta graph + if (pDoc->m_meta_graph) { + if (pDoc->m_meta_graph->viewingProcessed()) { + AttributeTable &table = pDoc->m_meta_graph->getAttributeTable(); + + auto xRange = + getIndexItemsInValueRange(idx_x, table, dataX(hit_point.x() - 2), dataX(hit_point.x() + 2)); + auto yRange = + getIndexItemsInValueRange(idx_y, table, dataY(hit_point.y() + 2), dataY(hit_point.y() - 2)); + + // work out anything near this point... + std::set xkeys; + for (auto iter = xRange.first; iter != xRange.second; iter++) { + xkeys.insert(iter->key); + } + const AttributeRow *displayRow = nullptr; + for (auto iter = yRange.first; iter != yRange.second; iter++) { + if (xkeys.find(iter->key) != xkeys.end()) { + displayRow = iter->row; + break; + } + } + if (displayRow) { + // and that it has an appropriate state to display a hover wnd + float val = displayRow->getValue(pDoc->m_meta_graph->getDisplayedAttribute()); + if (val == -1.0f) + setToolTip("No value"); + else if (val != -2.0f) + setToolTip(QString("%1").arg(val)); + } + } + } + } + } + return QObject::eventFilter(object, e); +} + +void QPlotView::paintEvent(QPaintEvent *event) { + QPainter pDC(m_pixmap); + + QRect rect = QRect(0, 0, width(), height()); + PafColor selcol(SALA_SELECTED_COLOR); + pDC.setPen(QPen(QBrush(QColor(selcol.redb(), selcol.greenb(), selcol.blueb())), 1, Qt::DotLine, Qt::RoundCap)); + + /* if (pDC->IsPrinting()) + { + PrintOutput(pDC, pDoc); + } + else */ + { // if (m_clear) + if (m_drawdragrect) { + pDC.setCompositionMode(QPainter::RasterOp_SourceAndNotDestination); + if (!m_drag_rect_b.isEmpty()) + pDC.drawRect(m_drag_rect_b); + if (!m_drag_rect_a.isEmpty()) + pDC.drawRect(m_drag_rect_a); + pDC.setCompositionMode(QPainter::CompositionMode_SourceOver); + m_drag_rect_b = m_drag_rect_a; + m_drawdragrect = false; + } else { + m_background = ((MainWindow *)m_parent)->m_background; + m_foreground = ((MainWindow *)m_parent)->m_foreground; + pDC.fillRect(rect, QBrush(QColor(m_background))); + // m_clear = false; + Output(&pDC, pDoc, true); + OnRedraw(0, 0); + } + } + + QPainter screenPainter(this); + screenPainter.drawPixmap(0, 0, width(), height(), *m_pixmap); +} + +void QPlotView::resizeEvent(QResizeEvent *event) { + pDoc->m_view[QGraphDoc::VIEW_SCATTER] = this; + setWindowTitle(pDoc->m_base_title + ":Scatter Plot"); + m_pixmap = new QPixmap(width(), height()); +} + +void QPlotView::closeEvent(QCloseEvent *event) { + pDoc->m_view[QGraphDoc::VIEW_SCATTER] = NULL; + if (!pDoc->OnCloseDocument(QGraphDoc::VIEW_SCATTER)) { + pDoc->m_view[QGraphDoc::VIEW_SCATTER] = this; + event->ignore(); + } +} + +bool QPlotView::Output(QPainter *pDC, QGraphDoc *pDoc, bool screendraw) { + // this is going to need a timer at somepoint, but for now, it's all very easy to start off: + auto lock = pDoc->m_meta_graph->getLockDeferred(); + if (!lock.try_lock()) { + return false; + } + + if (pDoc->m_communicator || !pDoc->m_meta_graph->viewingProcessed()) { + return false; + } + + AttributeTable &table = pDoc->m_meta_graph->getAttributeTable(); + AttributeTableHandle &tableHandle = pDoc->m_meta_graph->getAttributeTableHandle(); + LayerManagerImpl &layers = pDoc->m_meta_graph->getLayers(); + + QRect rect = QRect(0, 0, width(), height()); + int mindim = __min(rect.width(), rect.height()); + + // TODO: the calculations are done here for the moment + // but should be placed in their own helper method + + int numVisible = 0; + float minVisibleX = std::numeric_limits::max(); + float maxVisibleX = std::numeric_limits::min(); + float minVisibleY = std::numeric_limits::max(); + float maxVisibleY = std::numeric_limits::min(); + + for (auto iter = table.begin(); iter != table.end(); iter++) { + if (isObjectVisible(layers, iter->getRow())) { + numVisible++; + float xVal = iter->getRow().getValue(m_x_axis); + float yVal = iter->getRow().getValue(m_y_axis); + minVisibleX = std::min(minVisibleX, xVal); + maxVisibleX = std::max(maxVisibleX, xVal); + minVisibleY = std::min(minVisibleY, yVal); + maxVisibleY = std::max(maxVisibleY, yVal); + } + } + + if (numVisible == 0) + m_x_axis = m_y_axis = 0; + + int spacer = floor(2.0 * sqrt(double(mindim) / double(numVisible != 0 ? numVisible : 1))); + if (!screendraw && spacer < 4) { + spacer = 4; + } + + // text formatting + int pointsize; + if (mindim > 200) { + pointsize = 100; + } else { + pointsize = 50 + mindim / 4; + } + + QFont font = QFont("Arial", 10, 10); + setFont(font); + + QPen pen = QPen(QBrush(QColor(m_foreground)), 1, Qt::SolidLine, Qt::RoundCap); + QPen oldpen = pDC->pen(); + pDC->setPen(pen); + + float minx, miny, maxx, maxy; + QString str_minx, str_miny, str_maxx, str_maxy; + + minx = m_data_bounds.bottom_left.x = m_view_origin ? 0.0 : minVisibleX; + miny = m_data_bounds.bottom_left.y = m_view_origin ? 0.0 : minVisibleY; + maxx = m_data_bounds.top_right.x = maxVisibleX; + maxy = m_data_bounds.top_right.y = maxVisibleY; + + str_minx = QString(tr("%1")).arg(minx); + str_miny = QString(tr("%1")).arg(miny); + str_maxx = QString(tr("%1")).arg(maxx); + str_maxy = QString(tr("%1")).arg(maxy); + + // now work out the drawing window for + QSize sizex = QSize(str_maxx.length() * 7, 16); + QSize sizey = QSize(str_miny.length() * 7, 16); + QSize sizey2 = QSize(str_maxy.length() * 7, 16); + if (sizey2.width() > sizey.width()) { + sizey.rwidth() = sizey2.width(); + } + // doesn't matter which, just want a height: + int texth = sizex.height(); + + int xaxis_pos = 99 * rect.height() / 100 - 2 * texth; + int yaxis_pos = rect.width() / 100 + sizey.width() + texth; + int miny_pos = xaxis_pos - texth; + m_screen_bounds.setTop(miny_pos); + int maxy_pos = rect.height() / 100 + texth / 2; + m_screen_bounds.setBottom(maxy_pos); + int minx_pos = yaxis_pos + texth; + m_screen_bounds.setLeft(minx_pos); + int maxx_pos = 99 * rect.width() / 100 - sizex.width() / 2; + m_screen_bounds.setRight(maxx_pos); + + int width = maxx_pos - minx_pos; + if (minx == maxx) { + minx_pos = maxx_pos = minx_pos + width / 2; + m_screen_bounds.setRight(minx_pos); + m_screen_bounds.setLeft(minx_pos); + width = 0; + } + int height = maxy_pos - miny_pos; + if (miny == maxy) { + miny_pos = maxy_pos = miny_pos + height / 2; + m_screen_bounds.setBottom(miny_pos); + m_screen_bounds.setTop(miny_pos); + height = 0; + } + + pDC->setPen(pen); + pDC->drawText(minx_pos - 50, 99 * rect.height() / 100 - texth, 100, 16, Qt::AlignCenter, str_minx); + if (minx != maxx) { + pDC->drawText(maxx_pos - 50, 99 * rect.height() / 100 - texth, 100, 16, Qt::AlignCenter, str_maxx); + } + + pDC->drawText(yaxis_pos - texth - 100, miny_pos - texth / 2, 100, 16, Qt::AlignRight, str_miny); + if (miny != maxy) { + pDC->drawText(yaxis_pos - texth - 100, maxy_pos - texth / 2, 100, 16, Qt::AlignRight, str_maxy); + } + + pDC->drawLine(QPoint(yaxis_pos - texth / 2, miny_pos), QPoint(yaxis_pos, miny_pos)); + if (miny != maxy) { + pDC->drawLine(QPoint(yaxis_pos, miny_pos), QPoint(yaxis_pos, maxy_pos)); + pDC->drawLine(QPoint(yaxis_pos, maxy_pos), QPoint(yaxis_pos - texth / 2, maxy_pos)); + } + + pDC->drawLine(QPoint(minx_pos, xaxis_pos + texth / 2), QPoint(minx_pos, xaxis_pos)); + if (minx != maxx) { + pDC->drawLine(QPoint(minx_pos, xaxis_pos), QPoint(maxx_pos, xaxis_pos)); + pDC->drawLine(QPoint(maxx_pos, xaxis_pos), QPoint(maxx_pos, xaxis_pos + texth / 2)); + } + + int sel_parity = 0; + QPen pen2; + for (const auto &iter : table) { + if (!isObjectVisible(layers, iter.getRow())) { + continue; + } + float x = iter.getRow().getValue(m_x_axis); + float y = iter.getRow().getValue(m_y_axis); + if (!std::isfinite(x) || !std::isfinite(y) || x == -1.0f || y == -1.0f) { + continue; + } + QRgb rgb; + if (m_view_monochrome) { + rgb = m_foreground; + } else { + PafColor color = dXreimpl::getDisplayColor(iter.getKey(), iter.getRow(), tableHandle); + rgb = qRgb(color.redb(), color.greenb(), color.blueb()); + } + int tempspacer = spacer; + if (iter.getRow().isSelected()) { + tempspacer = (spacer + 1) * 2 - 1; + if (m_view_monochrome) { + rgb = qRgb(0xff, 0, 0); + } + } + if (tempspacer == 0) { + tempspacer = 1; + } + if (!m_view_monochrome) { + pen2 = QPen(QBrush(QColor(rgb)), spacer, Qt::SolidLine, Qt::FlatCap); + // pDC->setPen(QPen(QBrush(QColor(rgb)), spacer, Qt::SolidLine, Qt::FlatCap)); + } else if (sel_parity != (iter.getRow().isSelected() ? 1 : -1)) { + pen2 = QPen(QBrush(QColor(rgb)), spacer, Qt::SolidLine, Qt::FlatCap); + // pDC->setPen(QPen(QBrush(QColor(rgb)), spacer, Qt::SolidLine, Qt::FlatCap)); + sel_parity = (iter.getRow().isSelected() ? 1 : -1); + } + pDC->setPen(pen2); + // + QPoint point(screenX(x), screenY(y)); + pDC->drawLine(QPoint(point.x() - tempspacer, point.y() - tempspacer), + QPoint(point.x() + tempspacer + 1, point.y() + tempspacer + 1)); + pDC->drawLine(QPoint(point.x() - tempspacer, point.y() + tempspacer), + QPoint(point.x() + tempspacer + 1, point.y() - tempspacer - 1)); + pDC->setPen(pen); + } + + // trend line if reqd + if (m_view_trend_line) { + QPoint bl, tr; + QString string; + if (m_regression.model(m_data_bounds.bottom_left.x) < m_data_bounds.bottom_left.y) { + // check line is on page + if (m_regression.model(m_data_bounds.top_right.x) > m_data_bounds.bottom_left.y) { + bl = QPoint(screenX(m_regression.invmodel(m_data_bounds.bottom_left.y)), m_screen_bounds.top()); + if (m_regression.model(m_data_bounds.top_right.x) < m_data_bounds.top_right.y) { + tr = QPoint(m_screen_bounds.right(), screenY(m_regression.model(m_data_bounds.top_right.x))); + } else { + tr = QPoint(screenX(m_regression.invmodel(m_data_bounds.top_right.y)), m_screen_bounds.bottom()); + } + pDC->drawLine(bl, tr); + } + } else if (m_regression.model(m_data_bounds.bottom_left.x) > m_data_bounds.top_right.y) { + // check line is on page + if (m_regression.model(m_data_bounds.top_right.x) < m_data_bounds.top_right.y) { + bl = QPoint(screenX(m_regression.invmodel(m_data_bounds.bottom_left.x)), m_screen_bounds.bottom()); + if (m_regression.model(m_data_bounds.top_right.x) > m_data_bounds.bottom_left.x) { + tr = QPoint(m_screen_bounds.right(), screenY(m_regression.model(m_data_bounds.top_right.x))); + } else { + tr = QPoint(screenX(m_regression.invmodel(m_data_bounds.top_right.y)), m_screen_bounds.top()); + } + pDC->drawLine(bl, tr); + } + } else { + bl = QPoint(m_screen_bounds.left(), screenY(m_regression.model(m_data_bounds.bottom_left.x))); + double trv = m_regression.model(m_data_bounds.top_right.x); + if (trv >= m_data_bounds.bottom_left.y && trv <= m_data_bounds.top_right.y) { + string += " v1"; + tr = QPoint(m_screen_bounds.right(), screenY(trv)); + } else if (m_regression.b() > 0) { // upward inclined + string += " v2"; + tr = QPoint(screenX(m_regression.invmodel(m_data_bounds.top_right.y)), m_screen_bounds.bottom()); + } else { // downward inclined + string += " v3"; + tr = QPoint(screenX(m_regression.invmodel(m_data_bounds.bottom_left.y)), m_screen_bounds.top()); + } + pDC->drawLine(bl, tr); + } + } + + QString string; + int textpos = texth; + if (m_view_rsquared) { + // set text formating + // hope ascii superscript 2 in place! + string = QString(tr("R\xb2 = %1").arg(sqr(m_regression.r()))); + pDC->drawText(QPointF(rect.width() - string.length() * 7, textpos), string); + textpos += texth; + } + if (m_view_equation) { + if (m_regression.a() >= 0) { + string = QString(tr("y = %1 x + %1").arg(m_regression.b()).arg(m_regression.a())); + } else { + string = QString(tr("y = %1 x - %1").arg(m_regression.b()).arg(fabs(m_regression.a()))); + } + pDC->drawText(QPointF(rect.width() - string.length() * 7, textpos), string); + } + + QString xlabel(table.getColumnName(m_x_axis).c_str()); + pDC->drawText(QPointF(width / 2 + minx_pos, 99 * rect.height() / 100 - texth), xlabel); + + QString ylabel(table.getColumnName(m_y_axis).c_str()); + // this is last to avoid switch between hfont and vfont + QMatrix matrix; + matrix.translate(sizey.width(), rect.height() / 2 + ylabel.length() * 7 / 2); + matrix.rotate(270); + pDC->setMatrix(matrix); + + pDC->drawText(QPointF(sizey.width() / 2, height + miny_pos), ylabel); + + pDC->setPen(oldpen); + + return true; +} + +// QPlotView message handlers + +int QPlotView::OnRedraw(int wParam, int lParam) { + if (pDoc->GetRemenuFlag(QGraphDoc::VIEW_SCATTER)) { + pDoc->SetRemenuFlag(QGraphDoc::VIEW_SCATTER, false); + MainWindow *m_Frm = (MainWindow *)pDoc->m_mainFrame; + m_Frm->RedoPlotViewMenu(pDoc); + } + if (pDoc->GetRedrawFlag(QGraphDoc::VIEW_SCATTER) != QGraphDoc::REDRAW_DONE) { + + if (!pDoc->m_communicator) { + + m_queued_redraw = false; + + while (!pDoc->SetRedrawFlag(QGraphDoc::VIEW_SCATTER, QGraphDoc::REDRAW_DONE)) { + // prefer waitformultipleobjects here + // Sleep(1); + } + } else { + // killTimer(Tid_redraw); + // Tid_redraw = startTimer(100); + m_queued_redraw = true; + } + } + + return 0; +} + +void QPlotView::keyPressEvent(QKeyEvent *e) { char key = e->key(); } + +void QPlotView::RedoIndices() { + if (pDoc->m_meta_graph && pDoc->m_meta_graph->viewingProcessed()) { + AttributeTable &table = pDoc->m_meta_graph->getAttributeTable(); + idx_x = makeAttributeIndex(table, m_x_axis); + idx_y = makeAttributeIndex(table, m_y_axis); + } +} + +void QPlotView::timerEvent(QTimerEvent *event) { + if (event->timerId() == Tid_redraw) { + + if (m_queued_redraw) { + + // Internal own redraw + OnRedraw(0, 0); + } + } +} + +void QPlotView::OnViewTrendLine() { + if (m_view_trend_line) { + m_view_trend_line = false; + } else { + m_view_trend_line = true; + } + update(); +} + +void QPlotView::OnViewRsquared() { + if (m_view_rsquared) { + m_view_rsquared = false; + } else { + m_view_rsquared = true; + } + update(); +} + +void QPlotView::OnViewColor() { + if (m_view_monochrome) { + m_view_monochrome = false; + } else { + m_view_monochrome = true; + } + update(); +} + +void QPlotView::SetAxis(int axis, int col, bool reset) { + if (axis == 0) { + if (m_x_axis != col) { + m_x_axis = col; + } + } else { + if (m_y_axis != col) { + m_y_axis = col; + } + } + if (reset) { + RedoIndices(); + ResetRegression(); + } +} + +void QPlotView::ResetRegression() { + m_regression.clear(); + if (m_x_axis != -1 && m_y_axis != -1 && pDoc->m_meta_graph && pDoc->m_meta_graph->viewingProcessed()) { + AttributeTable &table = pDoc->m_meta_graph->getAttributeTable(); + for (auto iter = table.begin(); iter != table.end(); iter++) { + if (isObjectVisible(pDoc->m_meta_graph->getLayers(), iter->getRow())) { + float x = iter->getRow().getValue(m_x_axis); + float y = iter->getRow().getValue(m_y_axis); + if (std::isfinite(x) && std::isfinite(y) && x != -1.0f && y != -1.0f) { + m_regression.add(x, y); + } + } + } + } +} + +void QPlotView::mousePressEvent(QMouseEvent *e) { + switch (e->button()) { + case Qt::LeftButton: + pressed_nFlags = MK_LBUTTON; + break; + case Qt::RightButton: + pressed_nFlags = MK_RBUTTON; + break; + default: + break; + } + m_mouse_point = e->pos(); + m_drag_rect_a = QRect(0, 0, 0, 0); + m_drag_rect_b = QRect(0, 0, 0, 0); + m_selecting = true; + m_drawdragrect = true; + update(); +} + +void QPlotView::mouseMoveEvent(QMouseEvent *e) { + if (pressed_nFlags == MK_RBUTTON) + return; + QPoint point = e->pos(); + if (m_selecting) { + int x1, y1, x2, y2; + if (m_mouse_point.x() > point.x()) { + x1 = point.x(); + x2 = m_mouse_point.x(); + } else { + x1 = m_mouse_point.x(); + x2 = point.x(); + } + + if (m_mouse_point.y() > point.y()) { + y1 = point.y(); + y2 = m_mouse_point.y(); + } else { + y1 = m_mouse_point.y(); + y2 = point.y(); + } + m_drag_rect_a = QRect(x1, y1, x2 - x1, y2 - y1); + m_drawdragrect = true; + update(); + } + hit_point = point; +} + +void QPlotView::mouseReleaseEvent(QMouseEvent *e) { + if (pressed_nFlags == MK_RBUTTON) { + pDoc->m_meta_graph->clearSel(); + pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_SELECTION); + return; + } + m_selecting = false; + + AttributeTable &table = pDoc->m_meta_graph->getAttributeTable(); + + auto xRange = + getIndexItemsInValueRange(idx_x, table, dataX(m_drag_rect_a.left() - 2), dataX(m_drag_rect_a.right() + 2)); + auto yRange = + getIndexItemsInValueRange(idx_y, table, dataY(m_drag_rect_a.bottom() + 2), dataY(m_drag_rect_a.top() - 2)); + + // Stop drag rect... + m_drag_rect_a = QRect(0, 0, 0, 0); + m_drawdragrect = false; + update(); + + // work out selection + std::set xkeys; + for (auto iter = xRange.first; iter != xRange.second; iter++) { + xkeys.insert(iter->key); + } + std::vector finalkeys; + for (auto iter = yRange.first; iter != yRange.second; iter++) { + if (xkeys.find(iter->key) != xkeys.end()) { + finalkeys.push_back(iter->key.value); + } + } + + // redraw selection set + bool add = false; + if (pressed_nFlags & MK_SHIFT) { + add = true; + } + pDoc->m_meta_graph->setSelSet(finalkeys, add); + pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_SELECTION); +} + +void QPlotView::OnViewOrigin() { + m_view_origin = !m_view_origin; + update(); +} + +void QPlotView::OnViewEquation() { + m_view_equation = !m_view_equation; + update(); +} diff --git a/depthmapX/views/plotview/plotview.h b/depthmapX/views/plotview/plotview.h new file mode 100644 index 00000000..a48f8ae5 --- /dev/null +++ b/depthmapX/views/plotview/plotview.h @@ -0,0 +1,119 @@ +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// depthmapX - spatial network analysis platform + +#include + +///////////////////////////////////////////////////////////////////////////// +// PlotView view + +// class CHoverWnd; + +#include "qpixmap.h" +#include +#include +#include + +#include "GraphDoc.h" +#include "genlib/linreg.h" + +#define MK_LBUTTON 0x0001 +#define MK_RBUTTON 0x0002 +#define MK_SHIFT 0x0004 +#define MK_CONTROL 0x0008 +#define MK_MBUTTON 0x0010 + +class QPlotView : public QWidget { + Q_OBJECT + + // Attributes + public: + QGraphDoc *pDoc; + QPlotView(); + QSize sizeHint() const; + + int m_x_axis; + int m_y_axis; + int curr_x; + int curr_y; + + std::vector idx_x; + std::vector idx_y; + void RedoIndices(); + + bool m_queued_redraw; + bool m_view_origin; + bool m_view_trend_line; + bool m_view_equation; + bool m_view_rsquared; + bool m_view_monochrome; + + LinReg m_regression; + + // + double dataX(int x); + int screenX(double x); + double dataY(int x); + int screenY(double x); + // + QtRegion m_data_bounds; + QRect m_screen_bounds; + // + QPoint m_mouse_point; + QRect m_drag_rect_a; + QRect m_drag_rect_b; + bool m_selecting; + bool m_drawdragrect; + QRgb m_background; + QRgb m_foreground; + + void *m_parent; // MainWindow* + + // Operations + public: + void SetAxis(int axis, int col, bool reset); + void ResetRegression(); + + bool Output(QPainter *pDC, QGraphDoc *pDoc, bool screendraw); + + // this is a tells us how many 100ms ticks have passed since the mouse moved + int Tid_redraw; + + void OnViewTrendLine(); + void OnViewRsquared(); + void OnViewColor(); + void OnViewOrigin(); + void OnViewEquation(); + int OnRedraw(int wParam, int lParam); + void OnLButtonDown(bool nFlags, QPoint point); + void OnMouseMove(bool nFlags, QPoint point); + void OnLButtonUp(bool nFlags, QPoint point); + + // Implementation + protected: + virtual bool eventFilter(QObject *object, QEvent *e); + virtual void keyPressEvent(QKeyEvent *event); + virtual void paintEvent(QPaintEvent *event); + virtual void resizeEvent(QResizeEvent *event); + virtual void mouseMoveEvent(QMouseEvent *event); + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseReleaseEvent(QMouseEvent *event); + virtual void closeEvent(QCloseEvent *event); + virtual void timerEvent(QTimerEvent *event); + + private: + QPixmap *m_pixmap; +}; diff --git a/depthmapX/views/tableview/tableview.cpp b/depthmapX/views/tableview/tableview.cpp new file mode 100644 index 00000000..8531d6da --- /dev/null +++ b/depthmapX/views/tableview/tableview.cpp @@ -0,0 +1,215 @@ +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2019, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "tableview.h" + +#include "mainwindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ROW_HEIGHT 20 +#define PG_COUNT 40 + +TableView::TableView(Settings &settings, QWidget *parent, QGraphDoc *p) : QTableWidget(parent) { + m_mainWindow = parent; + pDoc = p; + m_from = m_curr_row = 0; + + connect(this, SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(itemChanged(QTableWidgetItem *))); + + connect(this, SIGNAL(itemDoubleClicked(QTableWidgetItem *)), this, SLOT(itemEditChanged(QTableWidgetItem *))); + + RedoTable(); + setWindowIcon(QIcon(tr(":/images/cur/icon-1-5.png"))); + setWindowTitle(pDoc->m_base_title + ":Table View"); + + setVerticalScrollMode(QAbstractItemView::ScrollPerItem); + + m_protect_edit = false; + + m_initialSize = settings.readSetting(SettingTag::depthmapViewSize, QSize(2000, 2000)).toSize(); +} + +void TableView::focusInEvent(QFocusEvent *e) { + RedoTable(); + pDoc->SetRedrawFlag(QGraphDoc::VIEW_TABLE, QGraphDoc::REDRAW_DONE); + QTableWidget::focusInEvent(e); +} + +void TableView::RedoTable() { + clear(); + + if (pDoc->m_meta_graph->viewingProcessed()) { + const AttributeTable &table = pDoc->m_meta_graph->getAttributeTable(); + + m_column_count = table.getNumColumns(); + setColumnCount(m_column_count + 1); + connect(horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(colum_Sort(int))); + verticalHeader()->hide(); + + QTableWidgetItem *Item = new QTableWidgetItem("Ref Number"); + Item->setTextAlignment(Qt::AlignLeft); + setHorizontalHeaderItem(0, Item); + + for (int i = 0; i < m_column_count; i++) { + QTableWidgetItem *Item = new QTableWidgetItem(QString("%1").arg(table.getColumnName(i).c_str())); + Item->setTextAlignment(Qt::AlignLeft); + setHorizontalHeaderItem(i + 1, Item); + } + + m_row_count = table.getNumRows(); + setRowCount(m_row_count); + PrepareCache(m_curr_row); + } +} + +void TableView::scrollContentsBy(int dx, int dy) { + if (dy != 0) { + PrepareCache(m_curr_row - dy); + m_curr_row -= dy; + } + QTableWidget::scrollContentsBy(dx, dy); +} + +QSize TableView::sizeHint() const { return m_initialSize; } + +void TableView::PrepareCache(int to) { + m_updating = true; + QTableWidgetItem *Item; + const AttributeTableHandle &tableHandle = pDoc->m_meta_graph->getAttributeTableHandle(); + auto &index = tableHandle.getTableIndex(); + + int diff = PG_COUNT; + if (to + PG_COUNT >= m_row_count) { + diff = m_row_count - to; + } + for (int i = 0; i < diff; i++) { + auto &indexItem = index[to + i]; + for (int j = 0; j < m_column_count + 1; j++) { + if (!j) { + Item = item(to + i, j); + if (Item) { + if (indexItem.row->isSelected()) + Item->setCheckState(Qt::Checked); + else + Item->setCheckState(Qt::Unchecked); + } else { + Item = new QTableWidgetItem(QString("%1").arg(indexItem.key.value)); + if (indexItem.row->isSelected()) + Item->setCheckState(Qt::Checked); + else + Item->setCheckState(Qt::Unchecked); + setItem(to + i, 0, Item); + continue; + } + } + if (!item(to + i, j)) { + Item = new QTableWidgetItem(QString("%1").arg(indexItem.row->getValue(j - 1))); + setRowHeight(to + i, ROW_HEIGHT); + setItem(to + i, j, Item); + } + } + } + m_updating = false; +} + +void TableView::itemChanged(QTableWidgetItem *item) { + if (m_updating) + return; + int row = item->row(); + int col = item->column(); + MetaGraph *graph = pDoc->m_meta_graph; + AttributeTable &table = graph->getAttributeTable(); + AttributeTableHandle &tableHandle = graph->getAttributeTableHandle(); + auto &index = tableHandle.getTableIndex(); + if (col == 0) { + std::vector x; + x.push_back(index[row].key.value); + pDoc->m_meta_graph->setSelSet(x); + pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_POINTS, QGraphDoc::NEW_SELECTION, this); + PrepareCache(m_curr_row); + } else { + wchar_t *endptr; + // first reset contents: + double value = wcstod((wchar_t *)item->text().utf16(), + &endptr); // AT: Unicode conversion -- this doesn't look safe -- edittext is a CString! + if (endptr == (wchar_t *)item->text().utf16()) { + QMessageBox::warning(this, tr("Warning"), tr("Cannot convert text to number"), QMessageBox::Ok, + QMessageBox::Ok); + return; + } + + if (graph && graph->viewingProcessed()) { + // go for the change: + double value2 = index[row].row->getValue(col - 1); + if (value2 == 0 || fabs((value / value2) - 1.0) > 1e-5) { + index[row].mutable_row->setValue(col - 1, value); + pDoc->modifiedFlag = true; + } + + RedoTable(); + // note: this as caller will prevent us from redrawing ourself: + // could be either new data or new selection, just go for a big redraw: + pDoc->SetRedrawFlag(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA, this); + } + } +} + +void TableView::colum_Sort(int col_id) { + if (col_id - 1 != pDoc->m_meta_graph->getDisplayedAttribute()) { + pDoc->m_meta_graph->setDisplayedAttribute(col_id - 1); + ((MainWindow *)m_mainWindow)->chooseAttributeOnIndex(col_id); + clearContents(); + PrepareCache(m_curr_row); + return; + + RedoTable(); + } +} + +void TableView::itemEditChanged(QTableWidgetItem *item) { + int row = item->row(); + int col = item->column(); + + if (col > 0 && col < pDoc->m_meta_graph->getAttributeTable().getNumColumns() + 1) { + // don't let them edit a locked attribute + if (pDoc->m_meta_graph->getAttributeTable().getColumn(col - 1).isLocked()) { + QMessageBox::warning(this, tr("Warning"), tr("This column is locked and cannot be edited"), + QMessageBox::Ok, QMessageBox::Ok); + } + } +} + +void TableView::closeEvent(QCloseEvent *event) { + pDoc->m_view[QGraphDoc::VIEW_TABLE] = NULL; + if (!pDoc->OnCloseDocument(QGraphDoc::VIEW_TABLE)) { + pDoc->m_view[QGraphDoc::VIEW_TABLE] = this; + event->ignore(); + } +} + +void TableView::resizeEvent(QResizeEvent *event) { + QTableView::resizeEvent(event); + pDoc->m_view[QGraphDoc::VIEW_TABLE] = this; +} diff --git a/depthmapX/tableView.h b/depthmapX/views/tableview/tableview.h similarity index 52% rename from depthmapX/tableView.h rename to depthmapX/views/tableview/tableview.h index e1dc24cd..0899e3e4 100644 --- a/depthmapX/tableView.h +++ b/depthmapX/views/tableview/tableview.h @@ -1,4 +1,5 @@ // Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2019, Petros Koutsolampros // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -13,42 +14,44 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . - #include "GraphDoc.h" +#include "settings.h" #include class QEvent; class QTableWidgetItem; -class tableView : public QTableWidget -{ +class TableView : public QTableWidget { Q_OBJECT -public: - tableView(QWidget *parent = 0, QGraphDoc * p = 0); - ~tableView(); + public: + TableView(Settings &settings, QWidget *parent = 0, QGraphDoc *p = 0); QSize sizeHint() const; - int m_column_count; - int m_row_count; - int m_from; - int m_curr_row; - QGraphDoc* pDoc; - bool m_protect_edit; - -private slots: - void itemChanged ( QTableWidgetItem * item ); - void itemEditChanged(QTableWidgetItem*); - void colum_Sort(int sort); -protected: - virtual void closeEvent(QCloseEvent *event); + int m_column_count; + int m_row_count; + int m_from; + int m_curr_row; + QWidget *m_mainWindow; + QGraphDoc *pDoc; + bool m_protect_edit; + void RedoTable(); + + private slots: + void itemChanged(QTableWidgetItem *item); + void itemEditChanged(QTableWidgetItem *); + void colum_Sort(int sort); + + protected: + virtual void closeEvent(QCloseEvent *event); virtual void resizeEvent(QResizeEvent *event); - virtual void scrollContentsBy ( int dx, int dy ); + virtual void scrollContentsBy(int dx, int dy); + void focusInEvent(QFocusEvent* e); -private: - int OnRedraw(int wParam, int lParam); - void RedoTable(); - void PrepareCache(int from, int to); + private: + void PrepareCache(int to); bool m_custom; + QSize m_initialSize; + bool m_updating = false; }; diff --git a/depthmapX/viewhelpers.cpp b/depthmapX/views/viewhelpers.cpp similarity index 54% rename from depthmapX/viewhelpers.cpp rename to depthmapX/views/viewhelpers.cpp index 04acd900..ed1442e5 100644 --- a/depthmapX/viewhelpers.cpp +++ b/depthmapX/views/viewhelpers.cpp @@ -2,21 +2,20 @@ #include namespace ViewHelpers { - QPoint calculateCenter(QPoint point, const QPoint &oldCentre, double factor) + Point2f calculateCenter(const QPoint& point, const QPoint &oldCentre, double factor) { int diffX = oldCentre.x() - point.x(); int diffY = oldCentre.y() - point.y(); - point.rx() += diffX * factor; - point.ry() += diffY * factor; - return point; + return Point2f(point.x() + double(diffX) * factor, + point.y() + double(diffY) * factor); } - pstring getCurrentDate() + std::string getCurrentDate() { time_t now = time(NULL); char timeString[11]; strftime(timeString, 11, "%Y/%m/%d", localtime(&now)); - return pstring(timeString); + return timeString; } } diff --git a/depthmapX/viewhelpers.h b/depthmapX/views/viewhelpers.h similarity index 82% rename from depthmapX/viewhelpers.h rename to depthmapX/views/viewhelpers.h index 1a594645..d23b2f1e 100644 --- a/depthmapX/viewhelpers.h +++ b/depthmapX/views/viewhelpers.h @@ -18,12 +18,13 @@ #define DEPTHMAPX_VIEWHELPERS_H #include -#include "genlib/paftl.h" +#include "genlib/p2dpoly.h" +#include namespace ViewHelpers { - QPoint calculateCenter(QPoint point, const QPoint &oldCentre, double factor); - pstring getCurrentDate(); + Point2f calculateCenter(const QPoint& point, const QPoint &oldCentre, double factor); + std::string getCurrentDate(); } diff --git a/depthmapXTest/CMakeLists.txt b/depthmapXTest/CMakeLists.txt new file mode 100644 index 00000000..f91e5e61 --- /dev/null +++ b/depthmapXTest/CMakeLists.txt @@ -0,0 +1,44 @@ +set(depthmapXTest depthmapXTest) + +# Find includes in corresponding build directories +set(CMAKE_INCLUDE_CURRENT_DIR ON) +# Instruct CMake to run moc automatically when needed +set(CMAKE_AUTOMOC ON) +# Create code from a list of Qt designer ui files +# set(CMAKE_AUTOUIC ON) +# set(CMAKE_AUTORCC ON) + +# Find the QtWidgets library +find_package(Qt5 COMPONENTS Core Widgets Gui OpenGL REQUIRED) + +include_directories(${QT}) + +add_compile_definitions(_DEPTHMAP) + +set(depthmapXTest_SRCS + main.cpp + testgllines.cpp + testgllinesuniform.cpp + testglrastertexture.cpp + ../depthmapX/views/glview/gllines.h + ../depthmapX/views/glview/gllines.cpp + ../depthmapX/views/glview/gllinesuniform.h + ../depthmapX/views/glview/gllinesuniform.cpp + ../depthmapX/views/glview/glrastertexture.h + ../depthmapX/views/glview/glrastertexture.cpp) + + +include_directories("../ThirdParty/Catch") + +set(LINK_LIBS salalib genlib mgraph440) + +if(APPLE) + add_definitions(-DGL_SILENCE_DEPRECATION) +endif(APPLE) + +add_executable(${depthmapXTest} ${depthmapXTest_SRCS}) + +find_package(OpenGL REQUIRED) + +target_link_libraries(${depthmapXTest} Qt5::OpenGL salalib genlib OpenGL::GL OpenGL::GLU) + diff --git a/depthmapXTest/main.cpp b/depthmapXTest/main.cpp new file mode 100644 index 00000000..b2cdafa5 --- /dev/null +++ b/depthmapXTest/main.cpp @@ -0,0 +1,18 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#define CATCH_CONFIG_MAIN +#include "catch.hpp" diff --git a/depthmapXTest/testgllines.cpp b/depthmapXTest/testgllines.cpp new file mode 100644 index 00000000..0877fba1 --- /dev/null +++ b/depthmapXTest/testgllines.cpp @@ -0,0 +1,40 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "../depthmapX/views/glview/gllines.h" + +TEST_CASE("Test GLLines::loadLineData()", "") +{ + Point2f line1Start(0,0); + Point2f line1End(2,4); + PafColor line1colour(255,0,0); + Point2f line2Start(1,1); + Point2f line2End(3,5); + PafColor line2colour(0,255,0); + + std::vector> colouredLines; + + std::pair colouredLine1 = std::pair (SimpleLine(line1Start, line1End), line1colour); + colouredLines.push_back(colouredLine1); + + std::pair colouredLine2 = std::pair (SimpleLine(line2Start, line2End), line2colour); + colouredLines.push_back(colouredLine2); + + GLLines gllines; + gllines.loadLineData(colouredLines); + + REQUIRE(gllines.vertexCount() == 4); +} diff --git a/depthmapXTest/testgllinesuniform.cpp b/depthmapXTest/testgllinesuniform.cpp new file mode 100644 index 00000000..b4e268dd --- /dev/null +++ b/depthmapXTest/testgllinesuniform.cpp @@ -0,0 +1,41 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "../depthmapX/views/glview/gllinesuniform.h" + +TEST_CASE("Test GLLinesUniform::loadLineData()", "") +{ + Point2f line1Start(0,0); + Point2f line1End(2,4); + + Point2f line2Start(1,1); + Point2f line2End(3,5); + + std::vector lines; + + SimpleLine line1 = SimpleLine(line1Start, line1End); + lines.push_back(line1); + + SimpleLine line2 = SimpleLine(line2Start, line2End); + lines.push_back(line2); + + QRgb lineColour = qRgb(255,0,0); + + GLLinesUniform gllinesuniform; + gllinesuniform.loadLineData(lines, lineColour); + + REQUIRE(gllinesuniform.vertexCount() == 4); +} diff --git a/depthmapXTest/testglrastertexture.cpp b/depthmapXTest/testglrastertexture.cpp new file mode 100644 index 00000000..d107c9ff --- /dev/null +++ b/depthmapXTest/testglrastertexture.cpp @@ -0,0 +1,32 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "../depthmapX/views/glview/glrastertexture.h" + +TEST_CASE("Test GLRasterTexture::loadRegionData()", "") +{ + float bottomLeftX = 0; + float bottomLeftY = 0; + float topRightX = 2; + float topRightY = 4; + + QRgb lineColour = qRgb(255,0,0); + + GLRasterTexture glrastertexture; + glrastertexture.loadRegionData(bottomLeftX, bottomLeftY, topRightX, topRightY); + + REQUIRE(glrastertexture.vertexCount() == 4); +} diff --git a/depthmapXcli/CMakeLists.txt b/depthmapXcli/CMakeLists.txt new file mode 100644 index 00000000..ba25529b --- /dev/null +++ b/depthmapXcli/CMakeLists.txt @@ -0,0 +1,26 @@ +set(depthmapXcli depthmapXcli) + +set(depthmapXcli_SRCS + main.cpp + commandlineparser.cpp + runmethods.cpp + radiusconverter.cpp + vgaparser.cpp + linkparser.cpp + performancewriter.cpp + modeparserregistry.cpp + visprepparser.cpp + axialparser.cpp + parsingutils.cpp + agentparser.cpp + isovistparser.cpp + exportparser.cpp + importparser.cpp + stepdepthparser.cpp + segmentparser.cpp + mapconvertparser.cpp) + +set(LINK_LIBS salalib genlib mgraph440) + +add_executable(${depthmapXcli} ${depthmapXcli_SRCS}) +target_link_libraries(${depthmapXcli} ${LINK_LIBS}) diff --git a/depthmapXcli/agentparser.cpp b/depthmapXcli/agentparser.cpp new file mode 100644 index 00000000..4caa946f --- /dev/null +++ b/depthmapXcli/agentparser.cpp @@ -0,0 +1,351 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "agentparser.h" +#include "exceptions.h" +#include +#include "radiusconverter.h" +#include "runmethods.h" +#include "parsingutils.h" +#include "salalib/entityparsing.h" +#include + +using namespace depthmapX; + +AgentParser::AgentParser() : m_agentMode(AgentMode::NONE) +{} + +void AgentParser::parse(int argc, char *argv[]) +{ + std::vector points; + std::string pointFile; + + for ( int i = 1; i < argc; ) + { + + if ( std::strcmp ("-am", argv[i]) == 0) + { + if (m_agentMode != AgentMode::NONE) + { + throw CommandLineException("-am can only be used once, modes are mutually exclusive"); + } + ENFORCE_ARGUMENT("-am", i) + if ( std::strcmp(argv[i], "standard") == 0 ) + { + m_agentMode = AgentMode::STANDARD; + } + else if ( std::strcmp(argv[i], "los-length") == 0 ) + { + m_agentMode = AgentMode::LOS_LENGTH; + } + else if ( std::strcmp(argv[i], "occ-length") == 0 ) + { + m_agentMode = AgentMode::OCC_LENGTH; + } + else if ( std::strcmp(argv[i], "occ-any") == 0 ) + { + m_agentMode = AgentMode::OCC_ANY; + } + else if ( std::strcmp(argv[i], "occ-group-45") == 0) + { + m_agentMode = AgentMode::OCC_GROUP_45; + } + else if ( std::strcmp(argv[i], "occ-group-60") == 0) + { + m_agentMode = AgentMode::OCC_GROUP_60; + } + else if ( std::strcmp(argv[i], "occ-furthest") == 0) + { + m_agentMode = AgentMode::OCC_FURTHEST; + } + else if ( std::strcmp(argv[i], "bin-far-dist") == 0) + { + m_agentMode = AgentMode::BIN_FAR_DIST; + } + else if ( std::strcmp(argv[i], "bin-angle") == 0) + { + m_agentMode = AgentMode::BIN_ANGLE; + } + else if ( std::strcmp(argv[i], "bin-far-dist-angle") == 0) + { + m_agentMode = AgentMode::BIN_FAR_DIST_ANGLE; + } + else if ( std::strcmp(argv[i], "bin-memory") == 0) + { + m_agentMode = AgentMode::BIN_MEMORY; + } + else + { + throw CommandLineException(std::string("Invalid AGENTS mode: ") + argv[i]); + } + } + else if ( std::strcmp(argv[i], "-ats") == 0 ) + { + if (m_totalSystemTimestemps > 0) + { + throw CommandLineException("-ats can only be used once"); + } + ENFORCE_ARGUMENT("-ats", i) + if (!has_only_digits(argv[i])) + { + throw CommandLineException(std::string("-ats must be a number >0, got ") + argv[i]); + } + m_totalSystemTimestemps = std::atoi(argv[i]); + if (m_totalSystemTimestemps <= 0) + { + throw CommandLineException(std::string("-ats must be a number >0, got ") + argv[i]); + } + } + else if ( std::strcmp(argv[i], "-arr") == 0 ) + { + if (m_releaseRate > 0) + { + throw CommandLineException("-arr can only be used once"); + } + ENFORCE_ARGUMENT("-arr", i) + if (!has_only_digits_dots_commas(argv[i])) + { + throw CommandLineException(std::string("-arr must be a number >0, got ") + argv[i]); + } + m_releaseRate = std::atof(argv[i]); + if (m_releaseRate <= 0) + { + throw CommandLineException(std::string("-arr must be a number >0, got ") + argv[i]); + } + } + else if (std::strcmp(argv[i], "-atrails") == 0) + { + if (m_recordTrailsForAgents >= 0) + { + throw CommandLineException("-atrails can only be used once"); + } + ENFORCE_ARGUMENT("-atrails", i) + if (!has_only_digits(argv[i])) + { + throw CommandLineException(std::string("-atrails must be a number >=1 or 0 for all (max possible = 50), got ") + argv[i]); + } + m_recordTrailsForAgents = std::atoi(argv[i]); + if (m_recordTrailsForAgents < 0) + { + throw CommandLineException(std::string("-atrails must be a number >=1 or 0 for all (max possible = 50), got ") + argv[i]); + } + } + else if (std::strcmp(argv[i], "-afov") == 0) + { + if (m_agentFOV > 0) + { + throw CommandLineException("-afov can only be used once"); + } + ENFORCE_ARGUMENT("-afov", i) + if (!has_only_digits(argv[i])) + { + throw CommandLineException(std::string("-afov must be a number between 1 and 32, got ") + argv[i]); + } + m_agentFOV = std::atoi(argv[i]); + if (m_agentFOV <= 0 || m_agentFOV > 32) + { + throw CommandLineException(std::string("-afov must be a number between 1 and 32, got ") + argv[i]); + } + } + else if (std::strcmp(argv[i], "-asteps") == 0) + { + if (m_agentStepsBeforeTurnDecision > 0) + { + throw CommandLineException("-asteps can only be used once"); + } + ENFORCE_ARGUMENT("-asteps", i) + if (!has_only_digits(argv[i])) + { + throw CommandLineException(std::string("-asteps must be a number >0, got ") + argv[i]); + } + m_agentStepsBeforeTurnDecision = std::atoi(argv[i]); + if (m_agentStepsBeforeTurnDecision <= 0) + { + throw CommandLineException(std::string("-asteps must be a number >0, got ") + argv[i]); + } + } + else if (std::strcmp(argv[i], "-alife") == 0) + { + if (m_agentLifeTimesteps > 0) + { + throw CommandLineException("-alife can only be used once"); + } + ENFORCE_ARGUMENT("-alife", i) + if (!has_only_digits(argv[i])) + { + throw CommandLineException(std::string("-alife must be a number >0, got ") + argv[i]); + } + m_agentLifeTimesteps = std::atoi(argv[i]); + if (m_agentLifeTimesteps <= 0) + { + throw CommandLineException(std::string("-alife must be a number >0, got ") + argv[i]); + } + } + else if (std::strcmp(argv[i], "-alocseed") == 0) + { + if (!pointFile.empty()) + { + throw CommandLineException("-alocseed cannot be used together with -alocfile"); + } + if (!points.empty()) + { + throw CommandLineException("-alocseed cannot be used together with -aloc"); + } + ENFORCE_ARGUMENT("-alocseed", i) + if (!has_only_digits(argv[i])) + { + std::stringstream message; + message << "Invalid starting location seed provided (" + << argv[i] + << "). Should only contain digits" + << std::flush; + throw CommandLineException(message.str().c_str()); + } + m_randomReleaseLocationSeed = std::atof(argv[i]); + if (m_randomReleaseLocationSeed < 0 || m_randomReleaseLocationSeed > 10) + { + throw CommandLineException(std::string("-alocseed must be a number between 0 and 10, got ") + argv[i]); + } + } + else if (std::strcmp(argv[i], "-alocfile") == 0) + { + if (!points.empty()) + { + throw CommandLineException("-alocfile cannot be used together with -aloc"); + } + if (m_randomReleaseLocationSeed > -1) + { + throw CommandLineException("-alocfile cannot be used together with -alocseed"); + } + ENFORCE_ARGUMENT("-alocfile", i) + pointFile = argv[i]; + } + else if (std::strcmp(argv[i], "-aloc") == 0) + { + if (!pointFile.empty()) + { + throw CommandLineException("-aloc cannot be used together with -alocfile"); + } + if (m_randomReleaseLocationSeed > -1) + { + throw CommandLineException("-aloc cannot be used together with -alocseed"); + } + ENFORCE_ARGUMENT("-aloc", i) + if (!has_only_digits_dots_commas(argv[i])) + { + std::stringstream message; + message << "Invalid starting point provided (" + << argv[i] + << "). Should only contain digits dots and commas" + << std::flush; + throw CommandLineException(message.str().c_str()); + } + points.push_back(argv[i]); + } + else if (std::strcmp(argv[i], "-ot") == 0) + { + ENFORCE_ARGUMENT("-ot", i) + if ( std::strcmp(argv[i], "graph") == 0 ) + { + if(std::find(m_outputTypes.begin(), m_outputTypes.end(), OutputType::GRAPH) != m_outputTypes.end()) { + throw CommandLineException("Same output type argument (graph) provided twice"); + } + m_outputTypes.push_back(OutputType::GRAPH); + } + else if ( std::strcmp(argv[i], "gatecounts") == 0 ) + { + if(std::find(m_outputTypes.begin(), m_outputTypes.end(), OutputType::GATECOUNTS) != m_outputTypes.end()) { + throw CommandLineException("Same output type argument (gatecounts) provided twice"); + } + m_outputTypes.push_back(OutputType::GATECOUNTS); + } + else if ( std::strcmp(argv[i], "trails") == 0 ) + { + if(std::find(m_outputTypes.begin(), m_outputTypes.end(), OutputType::TRAILS) != m_outputTypes.end()) { + throw CommandLineException("Same output type argument (trails) provided twice"); + } + m_outputTypes.push_back(OutputType::TRAILS); + } + } + ++i; + } + + if(m_agentMode == AgentMode::NONE) + { + m_agentMode = AgentMode::STANDARD; + } + + if (m_totalSystemTimestemps == 0) + { + throw CommandLineException("Total number of timesteps (-ats ) is required"); + } + + if (m_releaseRate == 0) + { + throw CommandLineException("Release rate (-arr ) is required"); + } + + if (m_agentFOV == 0) + { + throw CommandLineException("Agent field-of-view (-afov ) is required"); + } + + if (m_agentStepsBeforeTurnDecision == 0) + { + throw CommandLineException("Agent number of steps before turn decision (-asteps ) is required"); + } + + if (m_agentLifeTimesteps == 0) + { + throw CommandLineException("Agent life in timesteps (-alife ) is required"); + } + + if (pointFile.empty() && points.empty() && m_randomReleaseLocationSeed == -1) + { + throw CommandLineException("Either -aloc, -alocfile or -alocseed must be given"); + } + + if(!pointFile.empty()) + { + std::ifstream pointsStream(pointFile); + if (!pointsStream) + { + std::stringstream message; + message << "Failed to load file " << pointFile << ", error " << std::strerror(errno) << std::flush; + throw depthmapX::RuntimeException(message.str().c_str()); + } + std::vector parsed = EntityParsing::parsePoints(pointsStream, '\t'); + m_releasePoints.insert(std::end(m_releasePoints), std::begin(parsed), std::end(parsed)); + } + else if(!points.empty()) + { + std::stringstream pointsStream; + pointsStream << "x,y"; + std::vector::iterator iter = points.begin(), end = + points.end(); + for ( ; iter != end; ++iter ) + { + pointsStream << "\n" << *iter; + } + std::vector parsed = EntityParsing::parsePoints(pointsStream, ','); + m_releasePoints.insert(std::end(m_releasePoints), std::begin(parsed), std::end(parsed)); + + } +} + +void AgentParser::run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const +{ + dm_runmethods::runAgentAnalysis(clp, *this, perfWriter); +} diff --git a/depthmapXcli/agentparser.h b/depthmapXcli/agentparser.h new file mode 100644 index 00000000..5e56755f --- /dev/null +++ b/depthmapXcli/agentparser.h @@ -0,0 +1,122 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include +#include "imodeparser.h" +#include "genlib/p2dpoly.h" +#include "commandlineparser.h" + +class AgentParser : public IModeParser +{ +public: + virtual std::string getModeName() const + { + return "AGENTS"; + } + + virtual std::string getHelp() const + { + return "Mode options for AGENTS:\n"\ + "-am one of:\n" + " standard\n"\ + " los-length (Line of Sight length)\n"\ + " occ-length (Occluded length)\n"\ + " occ-any (Any occlusions)\n"\ + " occ-group-45 (Occlusion group bins - 45 degrees)\n"\ + " occ-group-60 (Occlusion group bins - 60 degrees)\n"\ + " occ-furthest (Furthest occlusion per bin)\n"\ + " bin-far-dist (Per bin far distance weighted)\n"\ + " bin-angle (Per bin angle weighted)\n"\ + " bin-far-dist-angle (Per bin far-distance and angle weighted)\n"\ + " bin-memory (Per bin memory)\n"\ + "-ats set total system timesteps\n"\ + "-arr set agent release rate (likelyhood of release per timestep)\n"\ + "-atrails record trails for this amount of agents (set to 0 to record all"\ + ", with max possible currently = 50)\n"\ + "-afov set agent field-of-view (bins)\n"\ + "-asteps set agent steps before turn decision\n"\ + "-alife set agent total lifetime (in timesteps)\n"\ + "-alocseed set agents to start at random locations with specific seed (0 to 10)\n"\ + "-alocfile \n"\ + "-aloc provided in csv (x1,y1) "\ + "for example \"0.1,0.2\". Provide multiple times for multiple links\n"\ + "-ot available output types (may use more than one):"\ + " graph (graph file, default)"\ + " gatecounts (csv with cells of grid with gate counts)"\ + " trails (csv with lines showing path traversed by each agent)"; + } + +public: + AgentParser(); + virtual void parse(int argc, char *argv[]); + virtual void run(const CommandLineParser &clp, IPerformanceSink& perfWriter) const; + + enum AgentMode{ + NONE, + STANDARD, + LOS_LENGTH, + OCC_LENGTH, + OCC_ANY, + OCC_GROUP_45, + OCC_GROUP_60, + OCC_FURTHEST, + BIN_FAR_DIST, + BIN_ANGLE, + BIN_FAR_DIST_ANGLE, + BIN_MEMORY + }; + + enum OutputType{ + GRAPH, + GATECOUNTS, + TRAILS + }; + + // agent options + AgentMode getAgentMode() const { return m_agentMode; } + + int totalSystemTimestemps() const { return m_totalSystemTimestemps; } + double releaseRate() const { return m_releaseRate; } + int recordTrailsForAgents() const { return m_recordTrailsForAgents; } + int randomReleaseLocationSeed() const { return m_randomReleaseLocationSeed; } + + int agentFOV() const { return m_agentFOV; } + int agentStepsBeforeTurnDecision() const { return m_agentStepsBeforeTurnDecision; } + int agentLifeTimesteps() const { return m_agentLifeTimesteps; } + + std::vector getReleasePoints() const { return m_releasePoints; } + + std::vector outputTypes() const { return m_outputTypes; } + +private: + // agent options + AgentMode m_agentMode; + + int m_totalSystemTimestemps = 0; + double m_releaseRate = 0.0; + int m_recordTrailsForAgents = -1; + + int m_agentFOV = 0; // Field of view (bins) + int m_agentStepsBeforeTurnDecision = 0; // Steps before turn decision + int m_agentLifeTimesteps = 0; // Timesteps in system + + int m_randomReleaseLocationSeed = -1; + std::vector m_releasePoints; + + std::vector m_outputTypes; +}; + diff --git a/depthmapXcli/axialparser.cpp b/depthmapXcli/axialparser.cpp new file mode 100644 index 00000000..eb733f81 --- /dev/null +++ b/depthmapXcli/axialparser.cpp @@ -0,0 +1,97 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#include "axialparser.h" +#include "parsingutils.h" +#include "exceptions.h" +#include "salalib/entityparsing.h" +#include "runmethods.h" +#include + +using namespace depthmapX; + +AxialParser::AxialParser() : m_runFewestLines(false), m_runAnalysis(false), m_choice(false), m_local(false), m_rra(false) +{ + +} + + +std::string AxialParser::getModeName() const +{ + return "AXIAL"; +} + +std::string AxialParser::getHelp() const +{ + return "Mode options for Axial Analysis:\n"\ + " -xl , Calculate all lines map from this seed point (can be used more than once)\n" + " -xf Calculate fewest lines map from all lines map\n"\ + " -xa run axial anlysis\n"\ + " All modes expect to find the required input in the in graph\n"\ + " Any combination of flags above can be specified, they will always be run in the order -aa -af -au -ax\n"\ + " Further flags for axial analysis are:\n"\ + " -xac Include choice (betweenness)\n"\ + " -xal Include local measures\n"\ + " -xar Inlcude RA, RRA and total depth\n\n"; +} + +void AxialParser::parse(int argc, char **argv) +{ + for (int i = 1; i < argc; ++i) + { + if (std::strcmp(argv[i], "-xl") == 0) + { + ENFORCE_ARGUMENT("-xl", i) + m_allAxesRoots.push_back(EntityParsing::parsePoint(argv[i])); + } + else if(std::strcmp(argv[i], "-xf") == 0) + { + m_runFewestLines = true; + } + else if (std::strcmp(argv[i], "-xa") == 0) + { + ENFORCE_ARGUMENT("-xa", i) + if (m_runAnalysis) + { + throw CommandLineException("-xa can only be used once"); + } + m_radii = depthmapX::parseRadiusList(argv[i]); + m_runAnalysis = true; + } + else if (std::strcmp(argv[i], "-xal") == 0) + { + m_local = true; + } + else if (std::strcmp(argv[i], "-xac") == 0) + { + m_choice = true; + } + else if(std::strcmp(argv[i], "-xar") == 0) + { + m_rra = true; + } + } + + if (!runAllLines() && !runFewestLines() && !runUnlink() && !runAnalysis()) + { + throw CommandLineException("No axial analysis mode present"); + } +} + +void AxialParser::run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const +{ + dm_runmethods::runAxialAnalysis(clp, *this, perfWriter); +} diff --git a/depthmapXcli/axialparser.h b/depthmapXcli/axialparser.h new file mode 100644 index 00000000..64199d02 --- /dev/null +++ b/depthmapXcli/axialparser.h @@ -0,0 +1,73 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "imodeparser.h" +#include "genlib/p2dpoly.h" + +class AxialParser : public IModeParser +{ +public: + AxialParser(); + + // IModeParser interface +public: + std::string getModeName() const; + std::string getHelp() const; + void parse(int argc, char **argv); + void run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const; + + // accessors + bool runAllLines() const + { + return !m_allAxesRoots.empty(); + } + + const std::vector & getAllAxesRoots() const{ + return m_allAxesRoots; + } + + bool runFewestLines() const + { + return m_runFewestLines; + } + + bool runUnlink() const + { + // not supported for now + return false; + } + + bool runAnalysis() const + { + return m_runAnalysis; + } + + bool useChoice() const { return m_choice; } + bool useLocal() const { return m_local; } + bool calculateRRA() const { return m_rra; } + + const std::vector& getRadii() const { return m_radii;} + +private: + std::vector m_allAxesRoots; + bool m_runFewestLines; + bool m_runAnalysis; + std::vector m_radii; + bool m_choice; + bool m_local; + bool m_rra; +}; diff --git a/depthmapXcli/commandlineparser.cpp b/depthmapXcli/commandlineparser.cpp index d586facb..86876208 100644 --- a/depthmapXcli/commandlineparser.cpp +++ b/depthmapXcli/commandlineparser.cpp @@ -15,121 +15,124 @@ #include "commandlineparser.h" #include "exceptions.h" +#include "imodeparserfactory.h" +#include "parsingutils.h" +#include "version.h" #include -//#include #include +#include using namespace depthmapX; void CommandLineParser::printHelp(){ std::cout << "Usage: depthmapXcli -m -f -o [-s] [mode options]\n" + << " depthmapXcli -v prints the current version\n" << " depthmapXcli -h prints this help text\n" << "-s enables simple mode\n" - << "-t enables output of runtimes as csv file" - << "Possible modes are:\n VGA\n" - << "Mode options for VGA:\n" - << "-vm one of isovist, visiblity, metric, angular\n" - << "-vg turn on global measures for visibility, requires radius between 1 and 99 or n\n" - << "-vl turn on local measures for visibility\n" - << "-vr set visibility radius\n" - << std::flush; + << "-t enables output of runtimes as csv file\n" + + << "Possible modes are:\n"; + std::for_each(_parserFactory.getModeParsers().begin(), _parserFactory.getModeParsers().end(), [](const ModeParserVec::value_type &p)->void{ std::cout << " " << p->getModeName() << "\n"; }); + std::cout << "\n"; + std::for_each(_parserFactory.getModeParsers().begin(), _parserFactory.getModeParsers().end(), [](const ModeParserVec::value_type &p)->void{ std::cout << p->getHelp() << "\n"; }); + std::cout << std::flush; +} + +void CommandLineParser::printVersion(){ + std::cout << TITLE_BASE << "\n" << std::flush; } +CommandLineParser::CommandLineParser(const IModeParserFactory &parserFactory) + : m_simpleMode(false), _parserFactory(parserFactory), _modeParser(0) +{} -CommandLineParser::CommandLineParser( size_t argc, char *argv[] ) - : _mode(DepthmapMode::NONE), _simpleMode(false), _vgaParser(nullptr) +void CommandLineParser::parse(size_t argc, char *argv[]) { + m_valid = false; + m_printVersionMode = false; if (argc <= 1) { throw CommandLineException("No commandline parameters provided - don't know what to do"); } - _valid = true; for ( size_t i = 1; i < argc; ) { - if ( strcmp("-h", argv[i])== 0) + if ( std::strcmp("-h", argv[i])== 0) + { + return; + } + else if ( std::strcmp("-v", argv[i])== 0) { - _valid = false; + m_printVersionMode = true; return; } - else if ( strcmp ("-m", argv[i]) == 0) + else if ( std::strcmp ("-m", argv[i]) == 0) { - if ( ++i >= argc || argv[i][0] == '-' ) + if ( _modeParser) { - throw CommandLineException("-m requires an argument"); + throw CommandLineException("-m can only be used once"); } - if ( strcmp(argv[i], "VGA") == 0 ) + ENFORCE_ARGUMENT("-m", i) + + for (auto iter = _parserFactory.getModeParsers().begin(), end = _parserFactory.getModeParsers().end(); + iter != end; ++iter ) { - _mode = DepthmapMode::VGA_ANALYSIS; + if ((*iter)->getModeName() == argv[i]) + { + _modeParser = iter->get(); + break; + } } - else + + if (!_modeParser) { throw CommandLineException(std::string("Invalid mode: ") + argv[i]); } } - else if ( strcmp ("-f", argv[i]) == 0) + else if ( std::strcmp ("-f", argv[i]) == 0) { - if ( ++i >= argc || argv[i][0] == '-' ) - { - throw CommandLineException("-f requires an argument"); - } - _fileName = argv[i]; + ENFORCE_ARGUMENT("-f", i) + m_fileName = argv[i]; } - else if ( strcmp ("-o", argv[i]) == 0) + else if ( std::strcmp ("-o", argv[i]) == 0) { - if ( ++i >= argc || argv[i][0] == '-' ) - { - throw CommandLineException("-o requires an argument"); - } - _outputFile = argv[i]; + ENFORCE_ARGUMENT("-o", i) + m_outputFile = argv[i]; } - else if ( strcmp ("-t", argv[i]) == 0) + else if ( std::strcmp ("-t", argv[i]) == 0) { - if ( ++i >= argc || argv[i][0] == '-' ) - { - throw CommandLineException("-t requires an argument"); - } - _timingFile = argv[i]; + ENFORCE_ARGUMENT("-t", i) + m_timingFile = argv[i]; } - else if ( strcmp("-s", argv[i]) == 0) + else if ( std::strcmp("-s", argv[i]) == 0) { - _simpleMode = true; + m_simpleMode = true; } ++i; } - if (_mode == DepthmapMode::NONE) + if (!_modeParser) { throw CommandLineException("-m for mode is required"); } - if (_fileName.empty()) + if (m_fileName.empty()) { throw CommandLineException("-f for input file is required"); } - if (_outputFile.empty()) + if (m_outputFile.empty()) { throw CommandLineException("-o for output file is required"); } - - if (_mode == DepthmapMode::VGA_ANALYSIS) - { - _vgaParser = new VgaParser(argc, argv); - } + _modeParser->parse(argc, argv); + m_valid = true; } -const VgaParser& CommandLineParser::vgaOptions() const +void CommandLineParser::run(IPerformanceSink &perfWriter) const { - if ( _vgaParser == nullptr ) + if (!m_valid || !_modeParser) { - throw CommandLineException("VGA options are not available when mode is not VGA"); + throw CommandLineException("Trying to run with invalid command line parameters"); } - return *_vgaParser; + _modeParser->run(*this, perfWriter); } -CommandLineParser::~CommandLineParser() -{ - if ( _vgaParser != nullptr) - { - delete _vgaParser; - } -} diff --git a/depthmapXcli/commandlineparser.h b/depthmapXcli/commandlineparser.h index 48b83f92..1e6009e5 100644 --- a/depthmapXcli/commandlineparser.h +++ b/depthmapXcli/commandlineparser.h @@ -13,47 +13,46 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#ifndef COMMANDLINEPARSER_H -#define COMMANDLINEPARSER_H +#pragma once #include -#include "vgaparser.h" - -enum DepthmapMode{ - NONE = 0, - VGA_ANALYSIS -}; +#include +#include +class IModeParserFactory; +class IModeParser; +class IPerformanceSink; class CommandLineParser { public: - CommandLineParser(size_t argc, char *argv[]); - ~CommandLineParser(); + CommandLineParser(const IModeParserFactory &parserFactory); + void parse(size_t argc, char *argv[]); - DepthmapMode getMode() const { return _mode; } - const std::string &getFileName() const { return _fileName; } - const std::string &getOuputFile() const {return _outputFile;} - const std::string &getTimingFile() const {return _timingFile;} - bool isValid() const { return _valid; } - bool simpleMode() const { return _simpleMode; } - const VgaParser& vgaOptions() const; + const std::string &getFileName() const { return m_fileName; } + const std::string &getOuputFile() const {return m_outputFile;} + const std::string &getTimingFile() const {return m_timingFile;} + bool isValid() const { return m_valid; } + bool printVersionMode() const { return m_printVersionMode; } + bool simpleMode() const { return m_simpleMode; } + const IModeParser& modeOptions() const{ return *_modeParser;}; - static void printHelp(); + void printHelp(); + void printVersion(); + void run(IPerformanceSink &perfWriter) const; private: - DepthmapMode _mode; - std::string _fileName; - std::string _outputFile; - std::string _timingFile; - bool _valid; - bool _simpleMode; + std::string m_fileName; + std::string m_outputFile; + std::string m_timingFile; + bool m_valid; + bool m_printVersionMode; + bool m_simpleMode; - const VgaParser * _vgaParser; + const IModeParserFactory &_parserFactory; + IModeParser * _modeParser; }; - -#endif // COMMANDLINEPARSER_H diff --git a/depthmapXcli/depthmapXcli.pro b/depthmapXcli/depthmapXcli.pro deleted file mode 100644 index 7809c419..00000000 --- a/depthmapXcli/depthmapXcli.pro +++ /dev/null @@ -1,27 +0,0 @@ -include(../defaults.pri) -TEMPLATE = app -CONFIG += console c++11 -CONFIG -= app_bundle -CONFIG -= qt - -SOURCES += main.cpp \ - commandlineparser.cpp \ - runmethods.cpp \ - radiusconverter.cpp \ - vgaparser.cpp \ - performancewriter.cpp - -HEADERS += \ - commandlineparser.h \ - runmethods.h \ - radiusconverter.h \ - exceptions.h \ - simpletimer.h \ - vgaparser.h \ - performancewriter.h - -win32:Release:LIBS += -L../genlib/release -L../salalib/release -win32:Debug:LIBS += -L../genlib/debug -L../salalib/debug -!win32:LIBS += -L../genlib -L../salalib - -LIBS += -lsalalib -lgenlib diff --git a/depthmapXcli/exceptions.h b/depthmapXcli/exceptions.h index 91f433de..984b2953 100644 --- a/depthmapXcli/exceptions.h +++ b/depthmapXcli/exceptions.h @@ -13,49 +13,24 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#ifndef EXCEPTIONS_H -#define EXCEPTIONS_H +#pragma once -#include +#include "genlib/exceptions.h" +#include namespace depthmapX { - class BaseException : public std::exception - { - protected: - BaseException(){} - BaseException(std::string message) : _message(message) - {} - public: - virtual const char * what() const noexcept - { - return _message.c_str(); - } - private: - std::string _message; - }; - - class CommandLineException : public BaseException - { - public: - CommandLineException(std::string message) : BaseException(message) - {} - }; - - class SetupCheckException : public BaseException + class CommandLineException : public depthmapX::BaseException { public: - SetupCheckException(std::string message) : BaseException(message) + CommandLineException(std::string message) : depthmapX::BaseException(message) {} }; - class RuntimeException: public BaseException + class SetupCheckException : public depthmapX::BaseException { public: - RuntimeException(std::string message) : BaseException(message) + SetupCheckException(std::string message) : depthmapX::BaseException(message) {} }; - } - -#endif // EXCEPTIONS_H diff --git a/depthmapXcli/exportparser.cpp b/depthmapXcli/exportparser.cpp new file mode 100644 index 00000000..294d8049 --- /dev/null +++ b/depthmapXcli/exportparser.cpp @@ -0,0 +1,76 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "exportparser.h" +#include "exceptions.h" +#include +#include "runmethods.h" +#include "parsingutils.h" +#include + +using namespace depthmapX; + +ExportParser::ExportParser() : m_exportMode(ExportMode::NONE) +{} + +void ExportParser::parse(int argc, char *argv[]) +{ + for ( int i = 1; i < argc; ) + { + + if ( std::strcmp ("-em", argv[i]) == 0) + { + if (m_exportMode != ExportParser::NONE) + { + throw CommandLineException("-em can only be used once, modes are mutually exclusive"); + } + ENFORCE_ARGUMENT("-em", i) + if ( std::strcmp(argv[i], "pointmap-data-csv") == 0 ) + { + m_exportMode = ExportMode::POINTMAP_DATA_CSV; + } + else if ( std::strcmp(argv[i], "pointmap-connections-csv") == 0 ) + { + m_exportMode = ExportMode::POINTMAP_CONNECTIONS_CSV; + } + else if ( std::strcmp(argv[i], "pointmap-links-csv") == 0 ) + { + m_exportMode = ExportMode::POINTMAP_LINKS_CSV; + } + else if ( std::strcmp(argv[i], "shapegraph-map-csv") == 0 ) + { + m_exportMode = ExportMode::SHAPEGRAPH_MAP_CSV; + } + else if ( std::strcmp(argv[i], "shapegraph-map-mif") == 0 ) + { + m_exportMode = ExportMode::SHAPEGRAPH_MAP_MIF; + } + else if ( std::strcmp(argv[i], "shapegraph-connections-csv") == 0 ) + { + m_exportMode = ExportMode::SHAPEGRAPH_CONNECTIONS_CSV; + } + else + { + throw CommandLineException(std::string("Invalid EXPORT mode: ") + argv[i]); + } + } + ++i; + } +} + +void ExportParser::run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const +{ + dm_runmethods::exportData(clp, *this, perfWriter); +} diff --git a/depthmapXcli/exportparser.h b/depthmapXcli/exportparser.h new file mode 100644 index 00000000..ca16ea7a --- /dev/null +++ b/depthmapXcli/exportparser.h @@ -0,0 +1,61 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "imodeparser.h" +#include "commandlineparser.h" +#include + +class ExportParser : public IModeParser +{ +public: + virtual std::string getModeName() const + { + return "EXPORT"; + } + + virtual std::string getHelp() const + { + return "Mode options for EXPORT:\n"\ + "-em one of:\n"\ + " pointmap-data-csv\n"\ + " pointmap-connections-csv\n"\ + " pointmap-links-csv\n"\ + " shapegraph-map-csv\n"\ + " shapegraph-map-mif\n"\ + " shapegraph-connections-csv\n"; + } + +public: + ExportParser(); + virtual void parse(int argc, char *argv[]); + virtual void run(const CommandLineParser &clp, IPerformanceSink& perfWriter) const; + + enum ExportMode{ + NONE, + POINTMAP_DATA_CSV, + POINTMAP_CONNECTIONS_CSV, + POINTMAP_LINKS_CSV, + SHAPEGRAPH_MAP_CSV, + SHAPEGRAPH_MAP_MIF, + SHAPEGRAPH_CONNECTIONS_CSV + }; + ExportMode getExportMode() const { return m_exportMode; } + +private: + ExportMode m_exportMode; +}; + diff --git a/depthmapXcli/imodeparser.h b/depthmapXcli/imodeparser.h new file mode 100644 index 00000000..7c893742 --- /dev/null +++ b/depthmapXcli/imodeparser.h @@ -0,0 +1,32 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +// Interface to encapsulate handling command line and invoking the respective +// depthmapX mode + +#include "performancesink.h" +#include "commandlineparser.h" + +class IModeParser +{ +public: + virtual std::string getModeName() const = 0; + virtual std::string getHelp() const = 0; + virtual void parse( int argc, char **argv) = 0; + virtual void run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const = 0; + virtual ~IModeParser(){} +}; diff --git a/depthmapXcli/imodeparserfactory.h b/depthmapXcli/imodeparserfactory.h new file mode 100644 index 00000000..163448a9 --- /dev/null +++ b/depthmapXcli/imodeparserfactory.h @@ -0,0 +1,29 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "imodeparser.h" +#include +#include + +typedef std::vector > ModeParserVec; + +class IModeParserFactory +{ +public: + virtual const ModeParserVec &getModeParsers() const = 0; + virtual ~IModeParserFactory(){} +}; diff --git a/depthmapXcli/importparser.cpp b/depthmapXcli/importparser.cpp new file mode 100644 index 00000000..6a7e4827 --- /dev/null +++ b/depthmapXcli/importparser.cpp @@ -0,0 +1,44 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "importparser.h" +#include "exceptions.h" +#include "runmethods.h" +#include "parsingutils.h" +#include +#include +#include + +using namespace depthmapX; + +void ImportParser::parse(int argc, char *argv[]) +{ + for ( int i = 1; i < argc; ++i) + { + if ( strcmp ("-if", argv[i]) == 0) + { + ENFORCE_ARGUMENT("-if", i) + m_filesToImport.push_back(argv[i]); + } else if ( strcmp ("-iaa", argv[i]) == 0) + { + m_importAsAttributes = true; + } + } +} + +void ImportParser::run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const +{ + dm_runmethods::importFiles(clp, *this, perfWriter); +} diff --git a/depthmapXcli/importparser.h b/depthmapXcli/importparser.h new file mode 100644 index 00000000..52b30469 --- /dev/null +++ b/depthmapXcli/importparser.h @@ -0,0 +1,50 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "imodeparser.h" +#include "commandlineparser.h" +#include +#include + +class ImportParser : public IModeParser +{ +public: + virtual std::string getModeName() const + { + return "IMPORT"; + } + + virtual std::string getHelp() const + { + return "Mode options for IMPORT:\n"\ + " The file provided by -f here will be used as the base. If that file"\ + "is not a graph, a new graph will be created and the file will be imported\n"\ + " -if one or more files to import\n"\ + " -iaa will import and attach attributes to an existing map\n"; + } + +public: + virtual void parse(int argc, char *argv[]); + virtual void run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const; + + const std::vector & getFilesToImport() const { return m_filesToImport; } + const bool toImportAsAttrbiutes() const { return m_importAsAttributes; } + +private: + std::vector m_filesToImport; + bool m_importAsAttributes = false; +}; diff --git a/depthmapXcli/isovistparser.cpp b/depthmapXcli/isovistparser.cpp new file mode 100644 index 00000000..b15f5a41 --- /dev/null +++ b/depthmapXcli/isovistparser.cpp @@ -0,0 +1,100 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +#include "isovistparser.h" +#include "parsingutils.h" +#include "exceptions.h" +#include "salalib/entityparsing.h" +#include +#include "runmethods.h" +#include + +using namespace depthmapX; + +IsovistParser::IsovistParser() +{ + +} + + +std::string IsovistParser::getModeName() const +{ + return "ISOVIST"; +} + +std::string IsovistParser::getHelp() const +{ + return "Arguments for isovist mode:\n" \ + " -ii Define an isoivist at position x,y with\n"\ + " optional direction angle and view angle for partial isovists\n"\ + " -if load isovist definitions from a file (csv)\n"\ + " the relevant headers must be called x, y, angle and viewangle\n"\ + " the latter two are optional.\n"\ + " Those two arguments cannot be mixed\n"\ + " Angles for partial isovists are in degrees, counted anti-clockwise with 0°\n"\ + " pointing to the right.\n\n"; +} + +void IsovistParser::parse(int argc, char **argv) +{ + std::string isovistFile; + + for( int i = 1; i < argc; ++i) + { + if (std::strcmp(argv[i], "-ii") == 0 ) + { + if ( !isovistFile.empty()) + { + throw CommandLineException("-ii cannot be used together with -if"); + } + ENFORCE_ARGUMENT("-ii", i); + m_isovists.push_back(EntityParsing::parseIsovist(argv[i])); + } + else if( std::strcmp(argv[i], "-if") == 0) + { + if ( !isovistFile.empty()) + { + throw CommandLineException("-if can only be used once"); + } + if (!m_isovists.empty()) + { + throw depthmapX::CommandLineException("-if cannot be used together with -ii"); + } + ENFORCE_ARGUMENT("-if",i); + isovistFile = argv[i]; + } + } + + if (!isovistFile.empty()) + { + std::ifstream file(isovistFile); + if ( !file.good()) + { + std::stringstream message; + message << "Failed to find file " << isovistFile; + throw depthmapX::CommandLineException(message.str()); + } + m_isovists = EntityParsing::parseIsovists(file, ','); + } + if (m_isovists.empty()) + { + throw CommandLineException("No isovists defined. Use -ii or -if"); + } + +} + +void IsovistParser::run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const +{ + dm_runmethods::runIsovists(clp, m_isovists, perfWriter); +} diff --git a/depthmapXcli/isovistparser.h b/depthmapXcli/isovistparser.h new file mode 100644 index 00000000..f9ec098c --- /dev/null +++ b/depthmapXcli/isovistparser.h @@ -0,0 +1,37 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "imodeparser.h" +#include "salalib/isovistdef.h" +#include + +class IsovistParser : public IModeParser +{ +public: + IsovistParser(); + + // IModeParser interface +public: + std::string getModeName() const; + std::string getHelp() const; + void parse(int argc, char **argv); + void run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const; + + const std::vector &getIsovists() const{ return m_isovists;} +private: + std::vector m_isovists; +}; diff --git a/depthmapXcli/linkparser.cpp b/depthmapXcli/linkparser.cpp new file mode 100644 index 00000000..94128e34 --- /dev/null +++ b/depthmapXcli/linkparser.cpp @@ -0,0 +1,125 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "linkparser.h" +#include "salalib/mgraph.h" +#include "exceptions.h" +#include "runmethods.h" +#include "parsingutils.h" +#include +#include +#include + +using namespace depthmapX; + +void LinkParser::parse(int argc, char *argv[]) +{ + for ( int i = 1; i < argc; ) + { + if ( std::strcmp ("-lmt", argv[i]) == 0) + { + ENFORCE_ARGUMENT("-lmt", i) + if ( std::strcmp(argv[i], "pointmaps") == 0 ) + { + m_mapTypeGroup = MapTypeGroup::POINTMAPS; + } + else if ( std::strcmp(argv[i], "shapegraphs") == 0 ) + { + m_mapTypeGroup = MapTypeGroup::SHAPEGRAPHS; + } + else + { + throw CommandLineException(std::string("Invalid LINK map type group: ") + argv[i]); + } + } + else if ( std::strcmp ("-lm", argv[i]) == 0) + { + ENFORCE_ARGUMENT("-lm", i) + if ( std::strcmp(argv[i], "link") == 0 ) + { + m_linkMode = LinkMode::LINK; + } + else if ( std::strcmp(argv[i], "unlink") == 0 ) + { + m_linkMode = LinkMode::UNLINK; + } + else + { + throw CommandLineException(std::string("Invalid LINK mode: ") + argv[i]); + } + } + else if ( std::strcmp ("-lt", argv[i]) == 0) + { + ENFORCE_ARGUMENT("-lt", i) + if ( std::strcmp(argv[i], "coords") == 0 ) + { + m_linkType = LinkType::COORDS; + } + else if ( std::strcmp(argv[i], "refs") == 0 ) + { + m_linkType = LinkType::REFS; + } + else + { + throw CommandLineException(std::string("Invalid LINK type: ") + argv[i]); + } + } + else if ( std::strcmp ("-lf", argv[i]) == 0) + { + if (!m_linksFile.empty()) + { + throw CommandLineException("-lf can only be used once at the moment"); + } + else if (m_manualLinks.size() != 0) + { + throw CommandLineException("-lf can not be used in conjunction with -lnk"); + } + ENFORCE_ARGUMENT("-lf", i) + m_linksFile = argv[i]; + } + else if ( std::strcmp ("-lnk", argv[i]) == 0) + { + if (!m_linksFile.empty()) + { + throw CommandLineException("-lf can not be used in conjunction with -lnk"); + } + ENFORCE_ARGUMENT("-lnk", i) + if (!has_only_digits_dots_commas(argv[i])) + { + std::stringstream message; + message << "Invalid link provided (" + << argv[i] + << "). Should only contain digits dots and commas" + << std::flush; + throw CommandLineException(message.str().c_str()); + } + m_manualLinks.push_back(argv[i]); + } + ++i; + } + if ( m_manualLinks.size() == 0 && m_linksFile.empty()) + { + throw CommandLineException("one of -lf or -lnk must be provided"); + } + if (m_mapTypeGroup == MapTypeGroup::POINTMAPS && m_linkMode == LinkMode::UNLINK) + { + throw CommandLineException("unlinking is not supported for pointmaps"); + } +} + +void LinkParser::run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const +{ + dm_runmethods::linkGraph(clp, *this, perfWriter); +} diff --git a/depthmapXcli/linkparser.h b/depthmapXcli/linkparser.h new file mode 100644 index 00000000..51d932dd --- /dev/null +++ b/depthmapXcli/linkparser.h @@ -0,0 +1,78 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/mgraph.h" +#include "imodeparser.h" +#include "commandlineparser.h" +#include +#include + +class LinkParser : public IModeParser +{ +public: + enum MapTypeGroup { POINTMAPS, SHAPEGRAPHS }; + enum LinkMode { LINK, UNLINK }; + enum LinkType { COORDS, REFS }; + + LinkParser(): + m_mapTypeGroup(POINTMAPS), + m_linkMode(LINK), + m_linkType(COORDS) + {} + + virtual std::string getModeName() const + { + return "LINK"; + } + + virtual std::string getHelp() const + { + return "Mode options for LINK:\n"\ + " -lmt Map type group to select displayed map from. One of:\n"\ + " pointmaps (default, vga: link)\n"\ + " shapegraphs (axial:link/unlink, segment:link, convex:link)\n"\ + " -lm one of:\n"\ + " link (default)\n"\ + " unlink\n"\ + " -lt one of:\n"\ + " coords (default, provided as x,y or x1,y1,x2,y2 coordinates)\n"\ + " refs (provided as the ids (Ref) of the shapes)\n"\ + " -lnk provided in csv (x1,y1,x2,y2)\n"\ + " for example \"0.1,0.2,0.2,0.4\" to create a link from 0.1,0.2\n"\ + " to 0.2,0.4. In the case of axial-map unlinks a single (x,y) set may\n" + " be provided. In the case of refs provide the ids in csv (reffrom,refto)" + " Provide multiple times for multiple links/unlinks\n"\ + " -lf as in -lnk\n"; + } + +public: + virtual void parse(int argc, char *argv[]); + virtual void run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const; + + //link options + const std::string & getLinksFile() const { return m_linksFile; } + const std::vector & getManualLinks() const { return m_manualLinks; } + const MapTypeGroup& getMapTypeGroup() const { return m_mapTypeGroup; } + const LinkMode& getLinkMode() const { return m_linkMode; } + const LinkType& getLinkType() const { return m_linkType; } +private: + std::string m_linksFile; + std::vector m_manualLinks; + MapTypeGroup m_mapTypeGroup; + LinkMode m_linkMode; + LinkType m_linkType; +}; diff --git a/depthmapXcli/main.cpp b/depthmapXcli/main.cpp index 762199ed..f72eddf9 100644 --- a/depthmapXcli/main.cpp +++ b/depthmapXcli/main.cpp @@ -16,30 +16,38 @@ #include #include "commandlineparser.h" #include "runmethods.h" - -using namespace std; +#include "performancewriter.h" +#include "modeparserregistry.h" int main(int argc, char *argv[]) { + ModeParserRegistry registry; + CommandLineParser args(registry); try{ - CommandLineParser args(argc, argv); + args.parse(argc, argv); if (!args.isValid()) { - CommandLineParser::printHelp(); + if (args.printVersionMode()) + { + args.printVersion(); + } + else + { + args.printHelp(); + } return 0; } - if ( args.getMode() == DepthmapMode::VGA_ANALYSIS) - { - RadiusConverter converter; - dm_runmethods::runVga(args, converter); - } + PerformanceWriter perfWriter(args.getTimingFile()); + + args.run(perfWriter); + perfWriter.write(); } catch( std::exception &e) { - cout << e.what() << "\n"; - CommandLineParser::printHelp(); + std::cout << e.what() << "\n"; + args.printHelp(); return -1; } return 0; diff --git a/depthmapXcli/mapconvertparser.cpp b/depthmapXcli/mapconvertparser.cpp new file mode 100644 index 00000000..5e445aff --- /dev/null +++ b/depthmapXcli/mapconvertparser.cpp @@ -0,0 +1,103 @@ +// Copyright (C) 2018 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#include "mapconvertparser.h" +#include "parsingutils.h" +#include "exceptions.h" +#include "runmethods.h" +#include + +using namespace depthmapX; + +void MapConvertParser::parse(int argc, char **argv) +{ + for (int i = 1; i < argc; ++i) + { + if ( std::strcmp ("-co", argv[i]) == 0) + { + if (m_outMapType != ShapeMap::EMPTYMAP) + { + throw CommandLineException("-co can only be used once, modes are mutually exclusive"); + } + ENFORCE_ARGUMENT("-co", i) + if ( std::strcmp(argv[i], "drawing") == 0 ) + { + m_outMapType = ShapeMap::DRAWINGMAP; + } + else if ( std::strcmp(argv[i], "axial") == 0 ) + { + m_outMapType = ShapeMap::AXIALMAP; + } + else if ( std::strcmp(argv[i], "segment") == 0 ) + { + m_outMapType = ShapeMap::SEGMENTMAP; + } + else if ( std::strcmp(argv[i], "data") == 0 ) + { + m_outMapType = ShapeMap::DATAMAP; + } + else if ( std::strcmp(argv[i], "convex") == 0) + { + m_outMapType = ShapeMap::CONVEXMAP; + } + else + { + throw CommandLineException(std::string("Invalid map output (-co) type: ") + argv[i]); + } + } + else if(std::strcmp(argv[i], "-con") == 0) + { + ENFORCE_ARGUMENT("-con", i) + m_outMapName = argv[i]; + } + else if(std::strcmp(argv[i], "-cir") == 0) + { + m_removeInputMap = true; + } + else if (std::strcmp(argv[i], "-coc") == 0) + { + m_copyAttributes = true; + } + else if (std::strcmp(argv[i], "-crsl") == 0) + { + ENFORCE_ARGUMENT("-crsl", i) + if (!has_only_digits_dots(argv[i])) + { + throw CommandLineException(std::string("-crsl must be a number >0, got ") + argv[i]); + } + m_removeStubLengthPRC = std::stod(argv[i]); + if (!(m_removeStubLengthPRC > 0)) + { + throw CommandLineException(std::string("-crsl must be a number >0, got ") + argv[i]); + } + } + } + + if (m_outMapType == ShapeMap::EMPTYMAP) + { + throw CommandLineException("A valid output map type (-co) is required"); + } + + if (m_outMapName == "") + { + throw CommandLineException("A valid output map name (-con) is required"); + } +} + +void MapConvertParser::run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const +{ + dm_runmethods::runMapConversion(clp, *this, perfWriter); +} diff --git a/depthmapXcli/mapconvertparser.h b/depthmapXcli/mapconvertparser.h new file mode 100644 index 00000000..608691cb --- /dev/null +++ b/depthmapXcli/mapconvertparser.h @@ -0,0 +1,69 @@ +// Copyright (C) 2018 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "imodeparser.h" +#include "salalib/shapemap.h" + +class MapConvertParser : public IModeParser +{ +public: + MapConvertParser(): + m_outMapType(ShapeMap::EMPTYMAP), + m_outMapName(""), + m_removeInputMap(false), + m_copyAttributes(false), + m_removeStubLengthPRC(0) + {} + + // IModeParser interface +public: + std::string getModeName() const + { + return "MAPCONVERT"; + } + + std::string getHelp() const + { + return "Mode options for Map Conversion:\n"\ + " -co Output map type (to convert to)\n"\ + " Possible input/output map types:\n"\ + " - drawing\n"\ + " - axial\n"\ + " - segment\n"\ + " - data\n"\ + " - convex\n"\ + " -con Output map name\n"\ + " -cir Remove input map\n"\ + " -coc Copy attributes to output map (Only between DATA, AXIAL and SEGMENT)\n"\ + " -crsl <%> Percent of line length of axial stubs to remove (Only for AXIAL -> SEGMENT)\n\n"; + } + void parse(int argc, char **argv); + void run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const; + + int outputMapType() const { return m_outMapType; } + std::string outputMapName() const { return m_outMapName; } + bool removeInputMap() const { return m_removeInputMap; } + bool copyAttributes() const { return m_copyAttributes; } + double removeStubLength() const { return m_removeStubLengthPRC; } + +private: + int m_outMapType; + std::string m_outMapName; + bool m_removeInputMap; + bool m_copyAttributes; + double m_removeStubLengthPRC; +}; diff --git a/depthmapXcli/modeparserregistry.cpp b/depthmapXcli/modeparserregistry.cpp new file mode 100644 index 00000000..fb2fdd40 --- /dev/null +++ b/depthmapXcli/modeparserregistry.cpp @@ -0,0 +1,45 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "modeparserregistry.h" +#include "importparser.h" +#include "linkparser.h" +#include "vgaparser.h" +#include "visprepparser.h" +#include "axialparser.h" +#include "segmentparser.h" +#include "agentparser.h" +#include "isovistparser.h" +#include "exportparser.h" +#include "stepdepthparser.h" +#include "mapconvertparser.h" + + +void ModeParserRegistry::populateParsers() +{ + // Register any mode parsers here + REGISTER_PARSER(VgaParser); + REGISTER_PARSER(LinkParser); + REGISTER_PARSER(VisPrepParser); + REGISTER_PARSER(AxialParser); + REGISTER_PARSER(SegmentParser); + REGISTER_PARSER(AgentParser); + REGISTER_PARSER(IsovistParser); + REGISTER_PARSER(ExportParser); + REGISTER_PARSER(ImportParser); + REGISTER_PARSER(StepDepthParser); + REGISTER_PARSER(MapConvertParser); + // ********* +} diff --git a/depthmapXcli/modeparserregistry.h b/depthmapXcli/modeparserregistry.h new file mode 100644 index 00000000..8aaea5c6 --- /dev/null +++ b/depthmapXcli/modeparserregistry.h @@ -0,0 +1,38 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "imodeparser.h" +#include "imodeparserfactory.h" +#include +#include + +class ModeParserRegistry : public IModeParserFactory +{ +public: + ModeParserRegistry() + { + populateParsers(); + } + + const ModeParserVec &getModeParsers() const {return m_availableParsers;} +private: + void populateParsers(); + ModeParserVec m_availableParsers; +}; + +#define REGISTER_PARSER(parser)\ + m_availableParsers.push_back(std::unique_ptr(new parser)); diff --git a/depthmapXcli/parsingutils.cpp b/depthmapXcli/parsingutils.cpp new file mode 100644 index 00000000..3a9d23a6 --- /dev/null +++ b/depthmapXcli/parsingutils.cpp @@ -0,0 +1,67 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "parsingutils.h" +#include +#include +#include +#include +#include "exceptions.h" + +std::vector depthmapX::parseRadiusList(const std::string &radiusList) +{ + std::vector result; + std::stringstream stream(radiusList); + bool addN = false; + + while(stream.good()) + { + std::string value; + getline(stream, value, ','); + if ( value == "n" || value == "N") + { + addN = true; + } + else + { + char *end; + long int val = std::strtol(value.c_str(), &end, 10 ); + if (val == 0 ) + { + std::stringstream message; + message << "Found either 0 or unparsable radius " << value << std::flush; + throw CommandLineException(message.str()); + } + if (val < 0) + { + throw CommandLineException("Radius must be either n or a positive integer"); + } + if (strlen(end) > 0) + { + std::stringstream message; + message << "Found non integer radius " << value << std::flush; + throw CommandLineException(message.str()); + } + result.push_back((double)val); + } + } + + std::sort(result.begin(), result.end()); + if (result.empty() || addN) + { + result.push_back(-1.0); + } + return result; +} diff --git a/depthmapXcli/parsingutils.h b/depthmapXcli/parsingutils.h new file mode 100644 index 00000000..b32e7a74 --- /dev/null +++ b/depthmapXcli/parsingutils.h @@ -0,0 +1,45 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#define PASTE(arg) arg +#define ENFORCE_ARGUMENT(flag, counter)\ + if ( ++ PASTE(counter) >= argc \ + || (argv[ PASTE(counter)][0] == '-' && !isdigit(argv[ PASTE(counter)][1]) && argv[ PASTE(counter)][1] != '.') )\ + {\ + throw CommandLineException(flag " requires an argument");\ + }\ + +#include +#include + +namespace depthmapX{ + + inline bool has_only_digits(const std::string &s){ + return s.find_first_not_of( "0123456789" ) == std::string::npos; + } + + inline bool has_only_digits_dots(const std::string &s){ + return s.find_first_not_of( "0123456789." ) == std::string::npos; + } + + inline bool has_only_digits_dots_commas(const std::string &s){ + return s.find_first_not_of( "0123456789,.-" ) == std::string::npos; + } + + std::vector parseRadiusList(const std::string &radiusList); + +} diff --git a/depthmapXcli/performancesink.h b/depthmapXcli/performancesink.h new file mode 100644 index 00000000..7143e91f --- /dev/null +++ b/depthmapXcli/performancesink.h @@ -0,0 +1,26 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include + +//Interface for performance writers +class IPerformanceSink +{ +public: + virtual void addData(const std::string &message, double timeInSeconds) = 0; + virtual ~IPerformanceSink(){} +}; diff --git a/depthmapXcli/performancewriter.cpp b/depthmapXcli/performancewriter.cpp index 844b9fab..df18b539 100644 --- a/depthmapXcli/performancewriter.cpp +++ b/depthmapXcli/performancewriter.cpp @@ -1,29 +1,43 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + #include "performancewriter.h" #include +#include +#include -PerformanceWriter::PerformanceWriter(const std::string &filename) : _filename(filename) +PerformanceWriter::PerformanceWriter(const std::string &filename) : m_filename(filename) { } -void PerformanceWriter::AddData(const string &message, double time) +void PerformanceWriter::addData(const std::string &message, double timeInSeconds) { std::stringstream ss; - ss << "\"" << message << ",\"" << time << "\n"; - _data.push_back(ss.str()); + ss << "\"" << message << "\"," << timeInSeconds << "\n"; + m_data.push_back(ss.str()); } -void PerformanceWriter::Write() const +void PerformanceWriter::write() const { - if (!_filename.empty()) + if (!m_filename.empty()) { - std::ofstream outfile(_filename); + std::ofstream outfile(m_filename); outfile << "\"action\",\"duration\"\n"; - foreach(line, _data) - { - outfile << line; - } - outfile << std::flush(); + std::for_each(m_data.begin(), m_data.end(), [&outfile](const std::string& line)mutable ->void{(outfile) << line;}); + outfile << std::flush; } } diff --git a/depthmapXcli/performancewriter.h b/depthmapXcli/performancewriter.h index f1893754..7e8d501b 100644 --- a/depthmapXcli/performancewriter.h +++ b/depthmapXcli/performancewriter.h @@ -1,18 +1,33 @@ -#ifndef PERFORMANCEWRITER_H -#define PERFORMANCEWRITER_H +// Copyright (C) 2017 Christian Sailer +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "performancesink.h" #include #include -class PerformanceWriter + +class PerformanceWriter : public IPerformanceSink { private: - std::vector _data; - std::string _filename; + std::vector m_data; + std::string m_filename; public: PerformanceWriter(const std::string &filename); - void AddData( const string &message, double time); - void Write() const; + void addData( const std::string &message, double timeInSeconds); + void write() const; }; -#endif // PERFORMANCEWRITER_H diff --git a/depthmapXcli/radiusconverter.h b/depthmapXcli/radiusconverter.h index 5c327bdf..c14ad504 100644 --- a/depthmapXcli/radiusconverter.h +++ b/depthmapXcli/radiusconverter.h @@ -13,8 +13,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#ifndef RADIUSCONVERTER_H -#define RADIUSCONVERTER_H +#pragma once + #include class IRadiusConverter @@ -33,4 +33,3 @@ class RadiusConverter : public IRadiusConverter virtual double ConvertForMetric(const std::string &radius) const; }; -#endif // RADIUSCONVERTER_H diff --git a/depthmapXcli/runmethods.cpp b/depthmapXcli/runmethods.cpp index 6cc11a7a..0ce75475 100644 --- a/depthmapXcli/runmethods.cpp +++ b/depthmapXcli/runmethods.cpp @@ -1,4 +1,5 @@ // Copyright (C) 2017 Christian Sailer +// Copyright (C) 2017 Petros Koutsolampros // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -15,55 +16,849 @@ #include "runmethods.h" #include "salalib/mgraph.h" +#include "salalib/linkutils.h" #include "radiusconverter.h" #include "exceptions.h" #include "simpletimer.h" #include #include +#include +#include "salalib/entityparsing.h" +#include +#include namespace dm_runmethods { - void runVga(const CommandLineParser &cmdP, const IRadiusConverter &converter) - { - MetaGraph mgraph; - auto result = mgraph.read(cmdP.getFileName().c_str()); + +#define CONCAT_(x,y) x##y +#define CONCAT(x,y) CONCAT_(x,y) +#define DO_TIMED(message, code)\ + SimpleTimer CONCAT(t_, __LINE__); \ + code; \ + perfWriter.addData(message, CONCAT(t_, __LINE__).getTimeInSeconds()); + + + std::unique_ptr loadGraph(const std::string& filename, IPerformanceSink &perfWriter) { + std::unique_ptr mgraph(new MetaGraph); + std::cout << "Loading graph " << filename << std::flush; + DO_TIMED( "Load graph file", auto result = mgraph->readFromFile(filename);) if ( result != MetaGraph::OK) { std::stringstream message; - message << "Failed to load graph from file " << cmdP.getFileName() << ", error " << result << flush; + message << "Failed to load graph from file " << filename << ", error " << result << std::flush; + throw depthmapX::RuntimeException(message.str().c_str()); + } + std::cout << " ok\n" << std::flush; + return mgraph; + } + + void importFiles(const CommandLineParser &cmdP, const ImportParser &parser, IPerformanceSink &perfWriter) + { + std::ifstream mainFileStream(cmdP.getFileName().c_str()); + if(!mainFileStream.good()) { + std::stringstream message; + message << "File not found: " << cmdP.getFileName() << std::flush; throw depthmapX::RuntimeException(message.str().c_str()); } + + std::unique_ptr mgraph(new MetaGraph); + DO_TIMED( "Load graph file", auto result = mgraph->readFromFile(cmdP.getFileName());) + if ( result != MetaGraph::OK && result != MetaGraph::NOT_A_GRAPH) + { + std::stringstream message; + message << "Failed to load graph from file " << cmdP.getFileName() << ", error " << result << std::flush; + throw depthmapX::RuntimeException(message.str().c_str()); + } + + if ( result == MetaGraph::NOT_A_GRAPH) + { + // not a graph, try to import the file + std::string ext = cmdP.getFileName().substr(cmdP.getFileName().length() - 4, cmdP.getFileName().length() - 1); + std::ifstream file(cmdP.getFileName()); + + std::unique_ptr comm(new ICommunicator()); + + depthmapX::ImportFileType importFileType = depthmapX::ImportFileType::TSV; + if(dXstring::toLower(ext) == ".csv") { + importFileType = depthmapX::ImportFileType::CSV; + } else if (dXstring::toLower(ext) == ".dxf") { + importFileType = depthmapX::ImportFileType::DXF; + } + + depthmapX::importFile(*mgraph, + file, + 0, + cmdP.getFileName(), + depthmapX::ImportType::DRAWINGMAP, + importFileType); + } else if ( result == MetaGraph::OK) { + if(parser.toImportAsAttrbiutes()) { + + if(mgraph->getDisplayedMapType() == ShapeMap::EMPTYMAP) { + throw depthmapX::RuntimeException("No map displayed to attach attributes to"); + } + + std::vector fileNames = parser.getFilesToImport(); + for(std::string fileName: fileNames) { + std::string ext = fileName.substr(fileName.length() - 4, fileName.length() - 1); + std::ifstream file(fileName); + char delimiter = '\t'; + if(dXstring::toLower(ext) == ".csv") { + delimiter = ','; + } + + DO_TIMED("Importing attributes", depthmapX::importAttributes(mgraph->getDisplayedMapAttributes(), + file, + delimiter);) + } + } + } + DO_TIMED("Writing graph", mgraph->write(cmdP.getOuputFile().c_str(),METAGRAPH_VERSION, false);) + } + + void linkGraph(const CommandLineParser &cmdP, const LinkParser &parser, IPerformanceSink &perfWriter) + { + + auto mgraph = loadGraph(cmdP.getFileName().c_str(), perfWriter); + + if (parser.getLinkMode() == LinkParser::LinkMode::UNLINK + && mgraph->getDisplayedShapeGraph().getMapType() != ShapeMap::AXIALMAP) { + throw depthmapX::RuntimeException("Unlinking is only available for axial maps"); + } + + char delimiter = '\t'; + std::stringstream linksStream; + if(!parser.getLinksFile().empty()) + { + std::ifstream fileStream(parser.getLinksFile()); + if (!linksStream) + { + std::stringstream message; + message << "Failed to load file " << parser.getLinksFile() << ", error " << std::flush; + throw depthmapX::RuntimeException(message.str().c_str()); + } + linksStream << fileStream.rdbuf(); + fileStream.close(); + } + else if(!parser.getManualLinks().empty()) + { + delimiter = ','; + std::string header = "x1,y1,x2,y2"; + if(parser.getLinkType() == LinkParser::LinkType::REFS) { + header = "reffrom,refto"; + } else if(parser.getLinkMode() == LinkParser::LinkMode::UNLINK) { + header = "x,y"; + } + linksStream << header; + auto iter = parser.getManualLinks().begin(), + end = parser.getManualLinks().end(); + for ( ; iter != end; ++iter ) + { + linksStream << "\n" << *iter; + } + } + + SimpleTimer t; + if(parser.getLinkMode() == LinkParser::LinkMode::LINK) { + if(parser.getMapTypeGroup() == LinkParser::MapTypeGroup::SHAPEGRAPHS) { + auto& shapeGraph = mgraph->getDisplayedShapeGraph(); + if(parser.getLinkType() == LinkParser::LinkType::COORDS) { + std::vector mergeLines = EntityParsing::parseLines(linksStream, delimiter); + for(auto line: mergeLines) { + QtRegion region(line.start(), line.start()); + shapeGraph.setCurSel(region); + shapeGraph.linkShapes(line.end()); + } + } else { + auto mergePairs = EntityParsing::parseRefPairs(linksStream, delimiter); + for(auto pair: mergePairs) { + // apparently this also unlinks if already linked or crossing + shapeGraph.linkShapesFromRefs(pair.first, pair.second); + } + } + } else { + std::vector newLinks; + PointMap& currentMap = mgraph->getDisplayedPointMap(); + if(parser.getLinkType() == LinkParser::LinkType::COORDS) { + std::vector mergeLines = EntityParsing::parseLines(linksStream, delimiter); + std::vector linkPairsFromCoords = depthmapX::pixelateMergeLines(mergeLines, currentMap); + newLinks.insert(newLinks.end(), linkPairsFromCoords.begin(), linkPairsFromCoords.end()); + } else { + auto mergePairs = EntityParsing::parseRefPairs(linksStream, delimiter); + for(auto pair: mergePairs) { + newLinks.push_back(PixelRefPair(pair.first, pair.second)); + } + } + depthmapX::mergePixelPairs(newLinks, currentMap); + } + } else { + auto& shapeGraph = mgraph->getDisplayedShapeGraph(); + if(parser.getLinkType() == LinkParser::LinkType::COORDS) { + auto mergePoints = EntityParsing::parsePoints(linksStream, delimiter); + for(auto point: mergePoints) { + shapeGraph.unlinkAtPoint(point); + } + } else { + auto mergePairs = EntityParsing::parseRefPairs(linksStream, delimiter); + for(auto pair: mergePairs) { + shapeGraph.unlinkShapesFromRefs(pair.first, pair.second); + } + } + } + + perfWriter.addData("Linking graph", t.getTimeInSeconds()); + DO_TIMED("Writing graph", mgraph->write(cmdP.getOuputFile().c_str(),METAGRAPH_VERSION, false);) + } + + void runVga(const CommandLineParser &cmdP, const VgaParser &vgaP, const IRadiusConverter &converter, IPerformanceSink &perfWriter) + { + auto mgraph = loadGraph(cmdP.getFileName().c_str(), perfWriter); + std::unique_ptr comm(new ICommunicator()); std::unique_ptr options(new Options()); - switch(cmdP.vgaOptions().getVgaMode()) + std::cout << "Getting options..." << std::flush; + switch(vgaP.getVgaMode()) { case VgaParser::VgaMode::VISBILITY: options->output_type = Options::OUTPUT_VISUAL; - options->local = cmdP.vgaOptions().localMeasures(); - options->global = cmdP.vgaOptions().globalMeasures(); + options->local = vgaP.localMeasures(); + options->global = vgaP.globalMeasures(); if (options->global ) { - options->radius = converter.ConvertForVisibility(cmdP.vgaOptions().getRadius()); + options->radius = converter.ConvertForVisibility(vgaP.getRadius()); } break; case VgaParser::VgaMode::METRIC: options->output_type = Options::OUTPUT_METRIC; - options->radius = converter.ConvertForMetric(cmdP.vgaOptions().getRadius()); + options->radius = converter.ConvertForMetric(vgaP.getRadius()); break; case VgaParser::VgaMode::ANGULAR: options->output_type = Options::OUTPUT_ANGULAR; break; case VgaParser::VgaMode::ISOVIST: options->output_type = Options::OUTPUT_ISOVIST; + break; + case VgaParser::VgaMode::THRU_VISION: + options->output_type = Options::OUTPUT_THRU_VISION; + break; default: throw depthmapX::SetupCheckException("Unsupported VGA mode"); } - SimpleTimer timer; - mgraph.analyseGraph(comm.get(), *options, cmdP.simpleMode() ); - std::cout << "Analysis took " << timer.getTimeInSeconds() << " seconds." << std::endl; - mgraph.write(cmdP.getOuputFile().c_str(),METAGRAPH_VERSION, false); + std::cout << " ok\nAnalysing graph..." << std::flush; + + DO_TIMED("Run VGA", mgraph->analyseGraph(comm.get(), *options, cmdP.simpleMode() )) + std::cout << " ok\nWriting out result..." << std::flush; + DO_TIMED("Writing graph", mgraph->write(cmdP.getOuputFile().c_str(),METAGRAPH_VERSION, false)) + std::cout << " ok" << std::endl; + } + + void fillGraph(MetaGraph& graph, const Point2f& point) + { + auto r = graph.getRegion(); + if (!r.contains(point)) + { + throw depthmapX::RuntimeException("Point outside of target region"); + } + graph.makePoints(point, 0, 0); } + void runVisualPrep( + const CommandLineParser &clp, + double gridSize, const std::vector &fillPoints, + double maxVisibility, + bool boundaryGraph, + bool makeGraph, + bool unmakeGraph, + bool removeLinksWhenUnmaking, + IPerformanceSink &perfWriter) + { + auto mGraph = loadGraph(clp.getFileName().c_str(),perfWriter); + + std::cout << "Initial checks... " << std::flush; + auto state = mGraph->getState(); + if (~state & MetaGraph::LINEDATA) + { + throw depthmapX::RuntimeException("Graph must have line data before preparing VGA"); + } + if(gridSize > 0) { + // Create a new pointmap and set tha grid + QtRegion r = mGraph->getRegion(); + + GridProperties gp(__max(r.width(), r.height())); + if ( gridSize > gp.getMax() || gridSize < gp.getMin()) + { + std::stringstream message; + message << "Chosen grid spacing " << gridSize << " is outside of the expected interval of " + << gp.getMin() << " <= spacing <= " << gp.getMax() << std::flush; + throw depthmapX::RuntimeException(message.str()); + } + + std::cout << "ok\nSetting up grid... " << std::flush; + mGraph->addNewPointMap(); + DO_TIMED("Setting grid", mGraph->setGrid(gridSize, Point2f(0.0, 0.0))) + } else if(mGraph->getPointMaps().empty()) { + std::stringstream message; + message << "No map exists to use. Please create a new one by providing a grid size" << std::flush; + throw depthmapX::RuntimeException(message.str()); + } + + if(unmakeGraph) { + if(!mGraph->getDisplayedPointMap().isProcessed()) { + std::stringstream message; + message << "Current map has not had its graph made so there's nothing to unmake" << std::flush; + throw depthmapX::RuntimeException(message.str()); + } + DO_TIMED("Unmaking graph", mGraph->getDisplayedPointMap().unmake(removeLinksWhenUnmaking)) + } else { + if(fillPoints.size() > 0) { + std::cout << "ok\nFilling grid... " << std::flush; + DO_TIMED("Filling grid", + for_each(fillPoints.begin(), fillPoints.end(), [&mGraph](const Point2f &point)->void{fillGraph(*mGraph, point);})) + } + if(makeGraph) { + std::cout << "ok\nMaking graph... " << std::flush; + DO_TIMED("Making graph", mGraph->makeGraph(0, boundaryGraph ? 1 : 0, maxVisibility)) + } + } + + std::cout << " ok\nWriting out result..." << std::flush; + DO_TIMED("Writing graph", mGraph->write(clp.getOuputFile().c_str(),METAGRAPH_VERSION, false)) + std::cout << " ok" << std::endl; + } + + void runAxialAnalysis(const CommandLineParser &clp, const AxialParser &ap, IPerformanceSink &perfWriter) + { + auto mGraph = loadGraph(clp.getFileName().c_str(), perfWriter); + + auto state = mGraph->getState(); + if ( ap.runAllLines()) + { + if (~state & MetaGraph::LINEDATA) + { + throw depthmapX::RuntimeException("Line drawing must be loaded before axial map can be constructed"); + } + std::cout << "Making all line map... " << std::flush; + DO_TIMED("Making all axes map", for_each (ap.getAllAxesRoots().begin(),ap.getAllAxesRoots().end(), [&mGraph](const Point2f &point)->void{mGraph->makeAllLineMap(0, point);} )) + std::cout << "ok" << std::endl; + } + + if (ap.runFewestLines()) + { + if (~state & MetaGraph::LINEDATA) + { + throw depthmapX::RuntimeException("Line drawing must be loaded before fewest line map can be constructed"); + } + if (!mGraph->hasAllLineMap()) + { + throw depthmapX::RuntimeException("All line map must be constructed before fewest lines can be constructed. Use -aa to do this"); + } + std::cout << "Constructing fewest line map... " << std::flush; + DO_TIMED("Fewest line map", mGraph->makeFewestLineMap(0,1)) + std::cout << "ok" << std::endl; + } + + if (ap.runAnalysis()) + { + std::cout << "Running axial analysis... " << std::flush; + Options options; + const std::vector& radii = ap.getRadii(); + options.radius_set.insert(radii.begin(), radii.end()); + options.choice = ap.useChoice(); + options.local = ap.useLocal(); + options.fulloutput = ap.calculateRRA(); + DO_TIMED("Axial analysis", mGraph->analyseAxial(0, options, clp.simpleMode())) + std::cout << "ok\n" << std::flush; + + } + std::cout << "Writing out result..." << std::flush; + DO_TIMED("Writing graph", mGraph->write(clp.getOuputFile().c_str(),METAGRAPH_VERSION, false)) + std::cout << " ok" << std::endl; + + } + + void runSegmentAnalysis(const CommandLineParser &clp, const SegmentParser &sp, IPerformanceSink &perfWriter) + { + auto mGraph = loadGraph(clp.getFileName().c_str(), perfWriter); + + std::cout << "Running segment analysis... " << std::flush; + Options options; + const std::vector& radii = sp.getRadii(); + options.radius_set.insert(radii.begin(), radii.end()); + options.choice = sp.includeChoice(); + options.tulip_bins = sp.getTulipBins(); + options.weighted_measure_col = -1; + + if(!sp.getAttribute().empty()) { + const ShapeGraph& map = mGraph->getDisplayedShapeGraph(); + const AttributeTable& table = map.getAttributeTable(); + for (size_t i = 0; i < table.getNumColumns(); i++) { + if(sp.getAttribute() == table.getColumnName(i).c_str()) { + options.weighted_measure_col = i; + } + } + if(options.weighted_measure_col == -1) { + throw depthmapX::RuntimeException("Given attribute (" + sp.getAttribute() + + ") does not exist in currently selected map"); + } + } + + switch(sp.getRadiusType()) { + case SegmentParser::RadiusType::SEGMENT_STEPS: { + options.radius_type = Options::RADIUS_STEPS; + break; + } + case SegmentParser::RadiusType::METRIC: { + options.radius_type = Options::RADIUS_METRIC; + break; + } + case SegmentParser::RadiusType::ANGULAR: { + options.radius_type = Options::RADIUS_ANGULAR; + break; + } + case SegmentParser::RadiusType::NONE: + break; + } + switch(sp.getAnalysisType()) { + case SegmentParser::AnalysisType::ANGULAR_TULIP: { + DO_TIMED("Segment tulip analysis", mGraph->analyseSegmentsTulip(0, options)) + break; + } + case SegmentParser::AnalysisType::ANGULAR_FULL: { + DO_TIMED("Segment angular analysis", mGraph->analyseSegmentsAngular(0, options)) + break; + } + case SegmentParser::AnalysisType::TOPOLOGICAL: { + options.output_type = 0; + DO_TIMED("Segment topological", mGraph->analyseTopoMetMultipleRadii(0, options)) + break; + } + case SegmentParser::AnalysisType::METRIC: { + options.output_type = 1; + DO_TIMED("Segment metric", mGraph->analyseTopoMetMultipleRadii(0, options)) + break; + } + case SegmentParser::AnalysisType::NONE: + throw depthmapX::RuntimeException("No segment analysis type given"); + } + std::cout << "ok\n" << std::flush; + + std::cout << "Writing out result..." << std::flush; + DO_TIMED("Writing graph", mGraph->write(clp.getOuputFile().c_str(),METAGRAPH_VERSION, false)) + std::cout << " ok" << std::endl; + + } + + void runAgentAnalysis(const CommandLineParser &cmdP, const AgentParser &agentP, IPerformanceSink &perfWriter) { + + std::unique_ptr comm(new ICommunicator()); + + auto mgraph = loadGraph(cmdP.getFileName().c_str(), perfWriter); + + PointMap& currentMap = mgraph->getDisplayedPointMap(); + + AgentEngine& eng = mgraph->getAgentEngine(); + + // set up eng here... + if (!eng.agentSets.size()) { + eng.agentSets.push_back(AgentSet()); + } + + eng.m_timesteps = agentP.totalSystemTimestemps(); + eng.agentSets.back().m_release_rate = agentP.releaseRate(); + eng.agentSets.back().m_lifetime = agentP.agentLifeTimesteps(); + if (agentP.agentFOV() == 32) { + eng.agentSets.back().m_vbin = -1; + } + else { + eng.agentSets.back().m_vbin = (agentP.agentFOV() - 1) / 2; + } + eng.agentSets.back().m_steps = agentP.agentStepsBeforeTurnDecision(); + switch(agentP.getAgentMode()) { + case AgentParser::NONE: + case AgentParser::STANDARD: + eng.agentSets.back().m_sel_type = AgentProgram::SEL_STANDARD; + break; + case AgentParser::LOS_LENGTH: + eng.agentSets.back().m_sel_type = AgentProgram::SEL_LOS; + break; + case AgentParser::OCC_LENGTH: + eng.agentSets.back().m_sel_type = AgentProgram::SEL_LOS_OCC; + break; + case AgentParser::OCC_ANY: + eng.agentSets.back().m_sel_type = AgentProgram::SEL_OCC_ALL; + break; + case AgentParser::OCC_GROUP_45: + eng.agentSets.back().m_sel_type = AgentProgram::SEL_OCC_BIN45; + break; + case AgentParser::OCC_GROUP_60: + eng.agentSets.back().m_sel_type = AgentProgram::SEL_OCC_BIN60; + break; + case AgentParser::OCC_FURTHEST: + eng.agentSets.back().m_sel_type = AgentProgram::SEL_OCC_STANDARD; + break; + case AgentParser::BIN_FAR_DIST: + eng.agentSets.back().m_sel_type = AgentProgram::SEL_OCC_WEIGHT_DIST; + break; + case AgentParser::BIN_ANGLE: + eng.agentSets.back().m_sel_type = AgentProgram::SEL_OCC_WEIGHT_ANG; + break; + case AgentParser::BIN_FAR_DIST_ANGLE: + eng.agentSets.back().m_sel_type = AgentProgram::SEL_OCC_WEIGHT_DIST_ANG; + break; + case AgentParser::BIN_MEMORY: + eng.agentSets.back().m_sel_type = AgentProgram::SEL_OCC_MEMORY; + break; + } + + // if the m_release_locations is not set the locations are + // set later by picking random pixels + if(agentP.randomReleaseLocationSeed() >= 0) { + eng.agentSets.back().m_release_locations_seed = agentP.randomReleaseLocationSeed(); + } + else { + eng.agentSets.back().m_release_locations.clear(); + for_each(agentP.getReleasePoints().begin(), agentP.getReleasePoints().end(), + [&eng, ¤tMap](const Point2f &point) + ->void{eng.agentSets.back().m_release_locations.push_back(currentMap.pixelate(point, false));}); + } + + // the ui and code suggest that the results can be put on a separate + // 'data map', but the functionality does not seem to actually be + // there thus it is skipped for now + // eng.m_gatelayer = m_gatelayer; + + // note, trails currently per run, but output per engine + if (agentP.recordTrailsForAgents() == 0) { + eng.m_record_trails = true; + } + else if (agentP.recordTrailsForAgents() > 0) { + eng.m_record_trails = true; + eng.m_trail_count = agentP.recordTrailsForAgents(); + } + + std::cout << "ok\nRunning agent analysis... " << std::flush; + DO_TIMED("Running agent analysis", eng.run(comm.get(), ¤tMap)) + std::cout << " ok\nWriting out result..." << std::flush; + std::vector resultTypes = agentP.outputTypes(); + if(resultTypes.size() == 0) + { + // if no choice was made for an output type assume the user just + // wants a graph file + + DO_TIMED("Writing graph", mgraph->write(cmdP.getOuputFile().c_str(),METAGRAPH_VERSION, false)) + } + else if(resultTypes.size() == 1) + { + // if only one type of output is given, assume that the user has + // correctly entered a name with the correct extension and export + // exactly with that name and extension + + switch(resultTypes[0]) { + case AgentParser::OutputType::GRAPH: + { + DO_TIMED("Writing graph", mgraph->write(cmdP.getOuputFile().c_str(),METAGRAPH_VERSION, false)) + break; + } + case AgentParser::OutputType::GATECOUNTS: + { + std::ofstream gatecountStream(cmdP.getOuputFile().c_str()); + DO_TIMED("Writing gatecounts", currentMap.outputSummary(gatecountStream, ',')) + break; + } + case AgentParser::OutputType::TRAILS: + { + std::ofstream trailStream(cmdP.getOuputFile().c_str()); + ShapeMap trailMap("Agent Trails"); + eng.insertTrailsInMap(trailMap); + DO_TIMED("Writing trails", mgraph->writeMapShapesAsCat(trailMap, trailStream)) + break; + } + } + } + else + { + // if more than one output type is given assume the user has given + // a filename without an extension and thus the new file must have + // an extension. Also to avoid name clashes in cases where the user + // asked for outputs that would yield the same extension also add + // a related suffix + + if(std::find(resultTypes.begin(), resultTypes.end(), AgentParser::OutputType::GRAPH) != resultTypes.end()) { + std::string outFile = cmdP.getOuputFile() + ".graph"; + DO_TIMED("Writing graph", mgraph->write(outFile.c_str(),METAGRAPH_VERSION, false)) + } + if(std::find(resultTypes.begin(), resultTypes.end(), AgentParser::OutputType::GATECOUNTS) != resultTypes.end()) { + std::string outFile = cmdP.getOuputFile() + "_gatecounts.csv"; + std::ofstream gatecountStream(outFile.c_str()); + DO_TIMED("Writing gatecounts", currentMap.outputSummary(gatecountStream, ',')) + } + if(std::find(resultTypes.begin(), resultTypes.end(), AgentParser::OutputType::TRAILS) != resultTypes.end()) { + std::string outFile = cmdP.getOuputFile() + "_trails.cat"; + std::ofstream trailStream(outFile.c_str()); + ShapeMap trailMap("Agent Trails"); + eng.insertTrailsInMap(trailMap); + DO_TIMED("Writing trails", mgraph->writeMapShapesAsCat(trailMap, trailStream)) + } + } + } + + void runIsovists(const CommandLineParser &clp, const std::vector &isovists, IPerformanceSink &perfWriter) + { + auto mGraph = loadGraph(clp.getFileName().c_str(),perfWriter); + + auto communicator = std::unique_ptr(new ICommunicator); + std::cout << "Making " << isovists.size() << " isovists... " << std::flush; + DO_TIMED("Make isovists", std::for_each(isovists.begin(), isovists.end(), + [&mGraph, &communicator, &clp](const IsovistDefinition &isovist)->void{ + mGraph->makeIsovist(communicator.get(), isovist.getLocation(), isovist.getLeftAngle(), isovist.getRightAngle(), clp.simpleMode()); + })) + std::cout << " ok\nWriting out result..." << std::flush; + DO_TIMED("Writing graph", mGraph->write(clp.getOuputFile().c_str(),METAGRAPH_VERSION, false)) + std::cout << " ok" << std::endl; + } + + void exportData(const CommandLineParser &cmdP, const ExportParser &exportP, IPerformanceSink &perfWriter ) { + + std::unique_ptr comm(new ICommunicator()); + + auto mgraph = loadGraph(cmdP.getFileName().c_str(), perfWriter); + + switch(exportP.getExportMode()) { + case ExportParser::POINTMAP_DATA_CSV: + { + PointMap& currentMap = mgraph->getDisplayedPointMap(); + std::ofstream stream(cmdP.getOuputFile().c_str()); + DO_TIMED("Writing pointmap data", currentMap.outputSummary(stream, ',')) + stream.close(); + break; + } + case ExportParser::POINTMAP_CONNECTIONS_CSV: + { + PointMap& currentMap = mgraph->getDisplayedPointMap(); + std::ofstream stream(cmdP.getOuputFile().c_str()); + DO_TIMED("Writing pointmap connections", currentMap.outputConnectionsAsCSV(stream, ",")) + stream.close(); + break; + } + case ExportParser::POINTMAP_LINKS_CSV: + { + PointMap& currentMap = mgraph->getDisplayedPointMap(); + std::ofstream stream(cmdP.getOuputFile().c_str()); + DO_TIMED("Writing pointmap connections", currentMap.outputLinksAsCSV(stream, ",")) + stream.close(); + break; + } + case ExportParser::SHAPEGRAPH_MAP_CSV: + { + ShapeGraph& currentMap = mgraph->getDisplayedShapeGraph(); + std::ofstream stream(cmdP.getOuputFile().c_str()); + DO_TIMED("Writing pointmap connections", currentMap.output(stream, ',')) + stream.close(); + break; + } + case ExportParser::SHAPEGRAPH_MAP_MIF: + { + ShapeGraph& currentMap = mgraph->getDisplayedShapeGraph(); + std::string fileName = cmdP.getOuputFile().c_str(); + std::string mifFile = fileName + ".mif"; + std::string midFile = fileName + ".mid"; + if (0 == fileName.compare(fileName.length() - 4, 4, ".mif")) { + // we are given the .mif + mifFile = fileName; + midFile = fileName.substr(0, fileName.length() - 4) + ".mid"; + + } else if (0 == fileName.compare(fileName.length() - 4, 4, ".mid")) { + // we are given the .mid + mifFile = fileName.substr(0, fileName.length() - 4) + ".mif"; + midFile = fileName; + } + std::ofstream mifStream(mifFile); + std::ofstream midStream(midFile); + DO_TIMED("Writing pointmap connections", currentMap.outputMifMap(mifStream, midStream)) + mifStream.close(); + midStream.close(); + break; + } + case ExportParser::SHAPEGRAPH_CONNECTIONS_CSV: + { + ShapeGraph& currentMap = mgraph->getDisplayedShapeGraph(); + std::ofstream stream(cmdP.getOuputFile().c_str()); + DO_TIMED("Writing shapegraph connections", + currentMap.isAxialMap() ? currentMap.writeAxialConnectionsAsPairsCSV(stream) : + currentMap.writeSegmentConnectionsAsPairsCSV(stream)) + stream.close(); + break; + } + default: + { + throw depthmapX::SetupCheckException("Error, unsupported export mode"); + } + } + } + + void runStepDepth( + const CommandLineParser &clp, + const StepDepthParser::StepType &stepType, + const std::vector &stepDepthPoints, + IPerformanceSink &perfWriter) + { + auto mGraph = loadGraph(clp.getFileName().c_str(),perfWriter); + + std::cout << "ok\nSelecting cells... " << std::flush; + + for( auto & point : stepDepthPoints ) { + auto graphRegion = mGraph->getRegion(); + if (!graphRegion.contains(point)) + { + throw depthmapX::RuntimeException("Point outside of target region"); + } + QtRegion r(point, point); + mGraph->setCurSel(r, true); + } + + std::cout << "ok\nCalculating step-depth... " << std::flush; + + Options options; + options.global = 0; + + switch (stepType) { + case StepDepthParser::StepType::ANGULAR: + options.point_depth_selection = 3; + break; + case StepDepthParser::StepType::METRIC: + options.point_depth_selection = 2; + break; + case StepDepthParser::StepType::VISUAL: + options.point_depth_selection = 1; + break; + default: { throw depthmapX::SetupCheckException("Error, unsupported step type"); } + } + + std::unique_ptr comm(new ICommunicator()); + + DO_TIMED("Calculating step-depth", mGraph->analyseGraph( comm.get(), options, false)) + + std::cout << " ok\nWriting out result..." << std::flush; + DO_TIMED("Writing graph", mGraph->write(clp.getOuputFile().c_str(),METAGRAPH_VERSION, false)) + std::cout << " ok" << std::endl; + } + + void runMapConversion(const CommandLineParser &clp, const MapConvertParser &mcp, IPerformanceSink &perfWriter) + { + auto mGraph = loadGraph(clp.getFileName().c_str(), perfWriter); + + int currentMapType = mGraph->getDisplayedMapType(); + + if (currentMapType == ShapeMap::EMPTYMAP) { + if(mGraph->hasVisibleDrawingLayers()) { + currentMapType = ShapeMap::DRAWINGMAP; + } else { + throw depthmapX::RuntimeException("No currently available map to convert from"); + } + } + + if (mcp.copyAttributes()) { + if(currentMapType != ShapeMap::DATAMAP && + currentMapType != ShapeMap::AXIALMAP && + currentMapType != ShapeMap::SEGMENTMAP) { + throw depthmapX::RuntimeException("Copying attributes is only available when "\ + "converting between Data, Axial and Segment maps "\ + "(current map type is not of those types)"); + } + if(mcp.outputMapType() != ShapeMap::DATAMAP && + mcp.outputMapType() != ShapeMap::AXIALMAP && + mcp.outputMapType() != ShapeMap::SEGMENTMAP) { + throw depthmapX::RuntimeException("Copying attributes is only available when "\ + "converting between Data, Axial and Segment maps "\ + "(selected output map type is not of those types)"); + } + } + if (mcp.removeStubLength() > 0) { + if(currentMapType != ShapeMap::AXIALMAP) { + throw depthmapX::RuntimeException("Removing stubs (-crsl) is only available when"\ + "converting from Axial to Segment maps"\ + "(current map type is not Axial)"); + } + if(mcp.outputMapType() != ShapeMap::SEGMENTMAP) { + throw depthmapX::RuntimeException("Removing stubs (-crsl) is only available when"\ + "converting from Axial to Segment maps"\ + "(selected output map type is not Segment)"); + } + } + + std::unique_ptr comm(new ICommunicator()); + + switch(mcp.outputMapType()) { + case ShapeMap::DRAWINGMAP: { + DO_TIMED("Converting to drawing", + mGraph->convertToDrawing(comm.get(), mcp.outputMapName(), currentMapType == ShapeMap::DATAMAP)); + break; + } + case ShapeMap::AXIALMAP: { + switch(currentMapType) { + case ShapeMap::DRAWINGMAP: { + DO_TIMED("Converting from drawing to axial", + mGraph->convertDrawingToAxial(comm.get(), mcp.outputMapName())); + break; + } + case ShapeMap::DATAMAP: { + DO_TIMED("Converting from data to axial", + mGraph->convertDataToAxial(comm.get(), mcp.outputMapName(), + !mcp.removeInputMap(), mcp.copyAttributes())); + break; + } + default: { + throw depthmapX::RuntimeException("Unsupported conversion to axial"); + } + } + break; + } + case ShapeMap::SEGMENTMAP: { + switch(currentMapType) { + case ShapeMap::DRAWINGMAP: { + DO_TIMED("Converting from drawing to segment", + mGraph->convertDrawingToSegment(comm.get(), mcp.outputMapName())); + break; + } + case ShapeMap::AXIALMAP: { + DO_TIMED("Converting from axial to segment", + mGraph->convertAxialToSegment(comm.get(), mcp.outputMapName(), !mcp.removeInputMap(), + mcp.copyAttributes(), mcp.removeStubLength() / 100.0)); + break; + } + case ShapeMap::DATAMAP: { + DO_TIMED("Converting from data to segment", + mGraph->convertDataToSegment(comm.get(), mcp.outputMapName(), + !mcp.removeInputMap(), mcp.copyAttributes())); + break; + } + default: { + throw depthmapX::RuntimeException("Unsupported conversion to segment"); + } + } + break; + } + case ShapeMap::DATAMAP: { + DO_TIMED("Converting to data", + mGraph->convertToData(comm.get(), mcp.outputMapName(), + !mcp.removeInputMap(), currentMapType, mcp.copyAttributes())); + break; + } + case ShapeMap::CONVEXMAP: { + DO_TIMED("Converting to convex", + mGraph->convertToConvex(comm.get(), mcp.outputMapName(), + !mcp.removeInputMap(), currentMapType, mcp.copyAttributes())); + break; + } + default: { + throw depthmapX::RuntimeException("Unsupported conversion"); + } + } + + std::cout << " ok\nWriting out result..." << std::flush; + DO_TIMED("Writing graph", mGraph->write(clp.getOuputFile().c_str(),METAGRAPH_VERSION, false)) + std::cout << " ok" << std::endl; + } } diff --git a/depthmapXcli/runmethods.h b/depthmapXcli/runmethods.h index 866b369e..3f7ad03d 100644 --- a/depthmapXcli/runmethods.h +++ b/depthmapXcli/runmethods.h @@ -1,4 +1,5 @@ // Copyright (C) 2017 Christian Sailer +// Copyright (C) 2017 Petros Koutsolampros // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -13,13 +14,37 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#ifndef RUNMETHODS_H -#define RUNMETHODS_H +#pragma once + #include #include "commandlineparser.h" #include "radiusconverter.h" +#include "performancesink.h" +#include "vgaparser.h" +#include "axialparser.h" +#include "mapconvertparser.h" +#include "segmentparser.h" +#include "agentparser.h" +#include "exportparser.h" +#include "linkparser.h" +#include "importparser.h" +#include "stepdepthparser.h" +#include "salalib/isovistdef.h" +#include + +class Line; +class Point2f; namespace dm_runmethods{ - void runVga(const CommandLineParser &cmdP, const IRadiusConverter &converter); + void importFiles(const CommandLineParser &cmdP, const ImportParser &parser, IPerformanceSink &perfWriter); + void linkGraph(const CommandLineParser &cmdP, const LinkParser &parser, IPerformanceSink &perfWriter ); + void runVga(const CommandLineParser &cmdP, const VgaParser &vgaP, const IRadiusConverter &converter, IPerformanceSink &perfWriter ); + void runVisualPrep(const CommandLineParser &clp, double gridSize, const std::vector &fillPoints, double maxVisibility, bool boundaryGraph, bool makeGraph, bool unmakeGraph, bool removeLinksWhenUnmaking, IPerformanceSink &perfWriter); + void runAxialAnalysis(const CommandLineParser& clp, const AxialParser &ap, IPerformanceSink &perfWriter); + void runSegmentAnalysis(const CommandLineParser& clp, const SegmentParser &sp, IPerformanceSink &perfWriter); + void runAgentAnalysis(const CommandLineParser &cmdP, const AgentParser &agentP, IPerformanceSink &perfWriter ); + void runIsovists(const CommandLineParser &cmdP, const std::vector &isovists, IPerformanceSink &perfWriter ); + void exportData(const CommandLineParser &cmdP, const ExportParser &exportP, IPerformanceSink &perfWriter ); + void runStepDepth(const CommandLineParser &clp, const StepDepthParser::StepType &stepType, const std::vector &stepDepthPoints, IPerformanceSink &perfWriter); + void runMapConversion(const CommandLineParser& clp, const MapConvertParser &mcp, IPerformanceSink &perfWriter); } -#endif // RUNMETHODS_H diff --git a/depthmapXcli/segmentparser.cpp b/depthmapXcli/segmentparser.cpp new file mode 100644 index 00000000..f07ce0ac --- /dev/null +++ b/depthmapXcli/segmentparser.cpp @@ -0,0 +1,171 @@ +// Copyright (C) 2018 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#include "segmentparser.h" +#include "parsingutils.h" +#include "exceptions.h" +#include "salalib/entityparsing.h" +#include "runmethods.h" +#include + +using namespace depthmapX; + +SegmentParser::SegmentParser() : m_analysisType(AnalysisType::NONE), m_radiusType(RadiusType::NONE), m_includeChoice(false), + m_tulipBins(0) +{ + +} + +std::string SegmentParser::getModeName() const +{ + return "SEGMENT"; +} + +std::string SegmentParser::getHelp() const +{ + return "Mode options for Segment Analysis:\n"\ + " -st one of:\n" + " tulip (Angular Tulip - Faster)\n"\ + " angular (Angular Full - Slower)\n"\ + " topological\n"\ + " metric\n"\ + " -sr \n"\ + " -srt (only for Tulip) one of:\n"\ + " steps\n"\ + " metric\n"\ + " angular\n"\ + " -sic to include choice (only for Tulip)\n"\ + " -stb (4 to 1024, 1024 approximates full angular)\n"\ + " -swa perform weighted analysis using this attribute (only for Tulip)\n"; +} + +void SegmentParser::parse(int argc, char **argv) +{ + for (int i = 1; i < argc; ++i) + { + if ( std::strcmp ("-st", argv[i]) == 0) + { + if (m_analysisType != AnalysisType::NONE) + { + throw CommandLineException("-st can only be used once, modes are mutually exclusive"); + } + ENFORCE_ARGUMENT("-st", i) + if ( std::strcmp(argv[i], "tulip") == 0 ) + { + m_analysisType = AnalysisType::ANGULAR_TULIP; + } + else if ( std::strcmp(argv[i], "angular") == 0 ) + { + m_analysisType = AnalysisType::ANGULAR_FULL; + } + else if ( std::strcmp(argv[i], "topological") == 0 ) + { + m_analysisType = AnalysisType::TOPOLOGICAL; + } + else if ( std::strcmp(argv[i], "metric") == 0 ) + { + m_analysisType = AnalysisType::METRIC; + } + else + { + throw CommandLineException(std::string("Invalid SEGMENT mode: ") + argv[i]); + } + } + else if (std::strcmp(argv[i], "-srt") == 0) + { + if (m_radiusType != RadiusType::NONE) + { + throw CommandLineException("-srt can only be used once, modes are mutually exclusive"); + } + ENFORCE_ARGUMENT("-srt", i) + if ( std::strcmp(argv[i], "steps") == 0 ) + { + m_radiusType = RadiusType::SEGMENT_STEPS; + } + else if ( std::strcmp(argv[i], "angular") == 0 ) + { + m_radiusType = RadiusType::ANGULAR; + } + else if ( std::strcmp(argv[i], "metric") == 0 ) + { + m_radiusType = RadiusType::METRIC; + } + else + { + throw CommandLineException(std::string("Invalid SEGMENT radius type: ") + argv[i]); + } + } + else if(std::strcmp(argv[i], "-sic") == 0) + { + m_includeChoice = true; + } + else if (std::strcmp(argv[i], "-sr") == 0) + { + ENFORCE_ARGUMENT("-sr", i) + m_radii = depthmapX::parseRadiusList(argv[i]); + } + else if (std::strcmp(argv[i], "-stb") == 0) + { + ENFORCE_ARGUMENT("-stb", i) + + if (!has_only_digits(argv[i])) + { + throw CommandLineException(std::string("-stb must be a number between 4 and 1024, got ") + argv[i]); + } + m_tulipBins = std::atoi(argv[i]); + if (m_tulipBins < 4 || m_tulipBins > 1024) + { + throw CommandLineException(std::string("-stb must be a number between 4 and 1024, got ") + argv[i]); + } + } + else if (std::strcmp(argv[i], "-swa") == 0) + { + ENFORCE_ARGUMENT("-swa", i) + m_attribute = argv[i]; + } + } + + if (getAnalysisType() == AnalysisType::NONE) + { + throw CommandLineException("No analysis type given"); + } + + if (getRadii().empty()) + { + throw CommandLineException("At least one radius must be provided"); + } + + if (getAnalysisType() == AnalysisType::ANGULAR_TULIP && getRadiusType() == RadiusType::NONE) + { + throw CommandLineException("Radius type is required for tulip analysis"); + } + + if (getAnalysisType() == AnalysisType::ANGULAR_TULIP && getTulipBins() == 0) + { + throw CommandLineException("Tulip bins are required for tulip analysis"); + } + + if (getAnalysisType() != AnalysisType::ANGULAR_TULIP + && (getTulipBins() != 0 || getRadiusType() != RadiusType::NONE || m_includeChoice)) + { + throw CommandLineException("-stb, -srt and -sic can only be used with tulip analysis"); + } +} + +void SegmentParser::run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const +{ + dm_runmethods::runSegmentAnalysis(clp, *this, perfWriter); +} diff --git a/depthmapXcli/segmentparser.h b/depthmapXcli/segmentparser.h new file mode 100644 index 00000000..9de74b51 --- /dev/null +++ b/depthmapXcli/segmentparser.h @@ -0,0 +1,67 @@ +// Copyright (C) 2018 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "imodeparser.h" +#include "genlib/p2dpoly.h" + +class SegmentParser : public IModeParser +{ +public: + SegmentParser(); + + // IModeParser interface +public: + std::string getModeName() const; + std::string getHelp() const; + void parse(int argc, char **argv); + void run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const; + + enum class AnalysisType { + NONE, + ANGULAR_TULIP, + ANGULAR_FULL, + TOPOLOGICAL, + METRIC + }; + + enum class RadiusType { + NONE, + SEGMENT_STEPS, + ANGULAR, + METRIC + }; + + AnalysisType getAnalysisType() const { return m_analysisType; } + + RadiusType getRadiusType() const { return m_radiusType; } + + bool includeChoice() const { return m_includeChoice; } + + int getTulipBins() const { return m_tulipBins; } + + const std::vector getRadii() const { return m_radii;} + + const std::string getAttribute() const { return m_attribute;} + +private: + AnalysisType m_analysisType; + RadiusType m_radiusType; + bool m_includeChoice; + int m_tulipBins; + std::vector m_radii; + std::string m_attribute; +}; diff --git a/depthmapXcli/simpletimer.h b/depthmapXcli/simpletimer.h index 6945e2d5..93460738 100644 --- a/depthmapXcli/simpletimer.h +++ b/depthmapXcli/simpletimer.h @@ -13,30 +13,28 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#ifndef SIMPLETIMER_H -#define SIMPLETIMER_H +#pragma once + #include class SimpleTimer { public: - SimpleTimer() : _startTime(std::chrono::high_resolution_clock::now()) + SimpleTimer() : m_startTime(std::chrono::high_resolution_clock::now()) { } double getTimeInSeconds() const { auto t2 = std::chrono::high_resolution_clock::now(); - return static_cast(std::chrono::duration_cast(t2-_startTime).count()) / 1000.0; + return static_cast(std::chrono::duration_cast(t2-m_startTime).count()) / 1000.0; } void reset() { - _startTime = std::chrono::high_resolution_clock::now(); + m_startTime = std::chrono::high_resolution_clock::now(); } private: - std::chrono::time_point _startTime; + std::chrono::time_point m_startTime; }; - -#endif // SIMPLETIMER_H diff --git a/depthmapXcli/stepdepthparser.cpp b/depthmapXcli/stepdepthparser.cpp new file mode 100644 index 00000000..df352e2a --- /dev/null +++ b/depthmapXcli/stepdepthparser.cpp @@ -0,0 +1,122 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "stepdepthparser.h" +#include "exceptions.h" +#include "parsingutils.h" +#include "salalib/entityparsing.h" +#include "runmethods.h" +#include +#include + +using namespace depthmapX; + +void StepDepthParser::parse(int argc, char ** argv) +{ + + std::vector points; + std::string pointFile; + for ( int i = 1; i < argc; ++i ) + { + if ( std::strcmp ("-sdp", argv[i]) == 0) + { + if (!pointFile.empty()) + { + throw CommandLineException("-sdp cannot be used together with -sdf"); + } + ENFORCE_ARGUMENT("-sdp", i) + if (!has_only_digits_dots_commas(argv[i])) + { + std::stringstream message; + message << "Invalid step depth point provided (" + << argv[i] + << "). Should only contain digits dots and commas" + << std::flush; + throw CommandLineException(message.str().c_str()); + } + points.push_back(argv[i]); + } + else if ( std::strcmp("-sdf", argv[i]) == 0 ) + { + if (!points.empty()) + { + throw CommandLineException("-sdf cannot be used together with -sdp"); + } + ENFORCE_ARGUMENT("-sdf", i) + pointFile = argv[i]; + } + else if ( std::strcmp ("-sdt", argv[i]) == 0) + { + ENFORCE_ARGUMENT("-sdt", i) + if ( std::strcmp(argv[i], "angular") == 0 ) + { + m_stepType = StepType::ANGULAR; + } + else if ( std::strcmp(argv[i], "metric") == 0 ) + { + m_stepType = StepType::METRIC; + } + else if ( std::strcmp(argv[i], "visual") == 0 ) + { + m_stepType = StepType::VISUAL; + } + else + { + throw CommandLineException(std::string("Invalid step type: ") + argv[i]); + } + } + } + + if (pointFile.empty() && points.empty()) + { + throw CommandLineException("Either -sdp or -sdf must be given"); + } + + if(!pointFile.empty()) + { + std::ifstream pointsStream(pointFile); + if (!pointsStream) + { + std::stringstream message; + message << "Failed to load file " << pointFile << ", error " << std::strerror(errno) << std::flush; + throw depthmapX::RuntimeException(message.str().c_str()); + } + std::vector parsed = EntityParsing::parsePoints(pointsStream, '\t'); + m_stepDepthPoints.insert(std::end(m_stepDepthPoints), std::begin(parsed), std::end(parsed)); + } + else if(!points.empty()) + { + std::stringstream pointsStream; + pointsStream << "x,y"; + std::vector::iterator iter = points.begin(), end = + points.end(); + for ( ; iter != end; ++iter ) + { + pointsStream << "\n" << *iter; + } + std::vector parsed = EntityParsing::parsePoints(pointsStream, ','); + m_stepDepthPoints.insert(std::end(m_stepDepthPoints), std::begin(parsed), std::end(parsed)); + } + + if (m_stepType == StepType::NONE) + { + throw CommandLineException("Step depth type (-sdt) must be provided"); + } +} + +void StepDepthParser::run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const +{ + dm_runmethods::runStepDepth(clp, m_stepType, m_stepDepthPoints, perfWriter); +} diff --git a/depthmapXcli/stepdepthparser.h b/depthmapXcli/stepdepthparser.h new file mode 100644 index 00000000..73c324ca --- /dev/null +++ b/depthmapXcli/stepdepthparser.h @@ -0,0 +1,62 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "imodeparser.h" +#include "genlib/p2dpoly.h" +#include + +class StepDepthParser : public IModeParser +{ +public: + StepDepthParser() : m_stepType(StepType::NONE) + {} + + virtual std::string getModeName() const + { + return "STEPDEPTH"; + } + + virtual std::string getHelp() const + { + return "Mode options for pointmap STEPDEPTH are:\n" \ + " -sdp point where to calculate step depth from. Can be repeated\n" \ + " -sdf a file with a point per line to calculate step depth from\n" \ + " -sdt step type. One of metric, angular or visual\n"; + } + + enum class StepType { + NONE, + ANGULAR, + METRIC, + VISUAL + }; + + virtual void parse(int argc, char** argv); + + virtual void run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const; + + std::vector getStepDepthPoints() const { return m_stepDepthPoints; } + + StepType getStepType() const { return m_stepType; } + +private: + std::vector m_stepDepthPoints; + + StepType m_stepType; +}; + + diff --git a/depthmapXcli/vgaparser.cpp b/depthmapXcli/vgaparser.cpp index eb23e071..2299d9d2 100644 --- a/depthmapXcli/vgaparser.cpp +++ b/depthmapXcli/vgaparser.cpp @@ -16,94 +16,97 @@ #include "vgaparser.h" #include "exceptions.h" #include +#include "radiusconverter.h" +#include "runmethods.h" +#include "parsingutils.h" using namespace depthmapX; -namespace { - bool has_only_digits(const std::string &s){ - return s.find_first_not_of( "0123456789" ) == std::string::npos; - } -} +VgaParser::VgaParser() : m_vgaMode(VgaMode::NONE), m_localMeasures(false), m_globalMeasures(false) +{} -VgaParser::VgaParser(size_t argc, char *argv[]) : _vgaMode(VgaMode::NONE), _globalMeasures(false), _localMeasures(false) +void VgaParser::parse(int argc, char *argv[]) { - for ( size_t i = 1; i < argc; ) + for ( int i = 1; i < argc; ) { - if ( strcmp ("-vm", argv[i]) == 0) + if ( std::strcmp ("-vm", argv[i]) == 0) { - if (_vgaMode != VgaMode::NONE) + if (m_vgaMode != VgaMode::NONE) { throw CommandLineException("-vm can only be used once, modes are mutually exclusive"); } - if ( ++i >= argc || argv[i][0] == '-' ) + ENFORCE_ARGUMENT("-vm", i) + if ( std::strcmp(argv[i], "isovist") == 0 ) { - throw CommandLineException("-vm requires an argument"); + m_vgaMode = VgaMode::ISOVIST; } - if ( strcmp(argv[i], "isovist") == 0 ) + else if ( std::strcmp(argv[i], "visibility") == 0 ) { - _vgaMode = VgaMode::ISOVIST; + m_vgaMode = VgaMode::VISBILITY; } - else if ( strcmp(argv[i], "visibility") == 0 ) + else if ( std::strcmp(argv[i], "metric") == 0 ) { - _vgaMode = VgaMode::VISBILITY; + m_vgaMode = VgaMode::METRIC; } - else if ( strcmp(argv[i], "metric") == 0 ) + else if ( std::strcmp(argv[i], "angular") == 0 ) { - _vgaMode = VgaMode::METRIC; + m_vgaMode = VgaMode::ANGULAR; } - else if ( strcmp(argv[i], "angular") == 0 ) + else if ( std::strcmp(argv[i], "thruvision") == 0) { - _vgaMode = VgaMode::ANGULAR; + m_vgaMode = VgaMode::THRU_VISION; } else { throw CommandLineException(std::string("Invalid VGA mode: ") + argv[i]); } } - else if ( strcmp(argv[i], "-vg") == 0 ) + else if ( std::strcmp(argv[i], "-vg") == 0 ) { - _globalMeasures = true; + m_globalMeasures = true; } - else if ( strcmp(argv[i], "-vl") == 0 ) + else if ( std::strcmp(argv[i], "-vl") == 0 ) { - _localMeasures = true; + m_localMeasures = true; } - else if (strcmp(argv[i], "-vr") == 0) + else if (std::strcmp(argv[i], "-vr") == 0) { - if ( ++i >= argc || argv[i][0] == '-' ) - { - throw CommandLineException("-vr requires an argument"); - } - _radius = argv[i]; + ENFORCE_ARGUMENT("-vr", i) + m_radius = argv[i]; } ++i; } - if(_vgaMode == VgaMode::NONE) + if(m_vgaMode == VgaMode::NONE) { - _vgaMode = VgaMode::ISOVIST; + m_vgaMode = VgaMode::ISOVIST; } - if (_vgaMode == VgaMode::VISBILITY && _globalMeasures) + if (m_vgaMode == VgaMode::VISBILITY && m_globalMeasures) { - if (_radius.empty()) + if (m_radius.empty()) { throw CommandLineException("Global measures in VGA/visibility analysis require a radius, use -vr "); } - if (_radius != "n" && !has_only_digits(_radius)) + if (m_radius != "n" && !has_only_digits(m_radius)) { - throw CommandLineException(std::string("Radius must be a positive integer number or n, got ") + _radius); + throw CommandLineException(std::string("Radius must be a positive integer number or n, got ") + m_radius); } } - else if (_vgaMode == VgaMode::METRIC) + else if (m_vgaMode == VgaMode::METRIC) { - if (_radius.empty()) + if (m_radius.empty()) { throw CommandLineException("Metric vga requires a radius, use -vr "); } } +} +void VgaParser::run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const +{ + RadiusConverter radiusConverter; + dm_runmethods::runVga(clp, *this, radiusConverter, perfWriter); } diff --git a/depthmapXcli/vgaparser.h b/depthmapXcli/vgaparser.h index edf108f2..5bcf949a 100644 --- a/depthmapXcli/vgaparser.h +++ b/depthmapXcli/vgaparser.h @@ -13,36 +13,53 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#ifndef VGAPARSER_H -#define VGAPARSER_H +#pragma once #include +#include "imodeparser.h" +#include "commandlineparser.h" -class VgaParser +class VgaParser : public IModeParser { public: - VgaParser(size_t argc, char *argv[]); + virtual std::string getModeName() const + { + return "VGA"; + } + + virtual std::string getHelp() const + { + return "Mode options for VGA:\n"\ + "-vm one of isovist, visiblity, metric, angular, thruvision\n"\ + "-vg turn on global measures for visibility, requires radius between 1 and 99 or n\n"\ + "-vl turn on local measures for visibility\n"\ + "-vr set visibility radius\n"; + } + +public: + VgaParser(); + virtual void parse(int argc, char *argv[]); + virtual void run(const CommandLineParser &clp, IPerformanceSink& perfWriter) const; enum VgaMode{ NONE, ISOVIST, VISBILITY, METRIC, - ANGULAR + ANGULAR, + THRU_VISION }; // vga options - VgaMode getVgaMode() const { return _vgaMode; } - bool localMeasures() const { return _localMeasures; } - bool globalMeasures() const { return _globalMeasures; } - const std::string & getRadius() const { return _radius; } - + VgaMode getVgaMode() const { return m_vgaMode; } + bool localMeasures() const { return m_localMeasures; } + bool globalMeasures() const { return m_globalMeasures; } + const std::string & getRadius() const { return m_radius; } private: // vga options - VgaMode _vgaMode; - bool _localMeasures; - bool _globalMeasures; - std::string _radius; + VgaMode m_vgaMode; + bool m_localMeasures; + bool m_globalMeasures; + std::string m_radius; }; -#endif // VGAPARSER_H diff --git a/depthmapXcli/visprepparser.cpp b/depthmapXcli/visprepparser.cpp new file mode 100644 index 00000000..fb1c4a6e --- /dev/null +++ b/depthmapXcli/visprepparser.cpp @@ -0,0 +1,177 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "visprepparser.h" +#include "exceptions.h" +#include "parsingutils.h" +#include "salalib/entityparsing.h" +#include "runmethods.h" +#include +#include + +using namespace depthmapX; + +void VisPrepParser::parse(int argc, char ** argv) +{ + + // All options: + // Create grid (m_grid > 0) + // Fill grid (pointFile or points not empty) + // Make graph + // Unmake graph + + // All possible combinations: + // Create Grid + Fill Grid + // Create Grid + Fill Grid + Make graph + // Fill Grid + // Fill Grid + Make graph + // Make Graph + // Unmake Graph + + // Bad combinations: + // Create Grid + Make graph = Creates empty graph + // Unmake graph + Anything else = Pointless action + + std::vector points; + std::string pointFile; + for ( int i = 1; i < argc; ++i ) + { + if ( std::strcmp ("-pg", argv[i]) == 0) + { + if (m_grid >= 0) + { + throw CommandLineException("-pg can only be used once"); + } + ENFORCE_ARGUMENT("-pg", i) + m_grid = std::atof(argv[i]); + if (m_grid <= 0) + { + throw CommandLineException(std::string("-pg must be a number >0, got ") + argv[i]); + } + } + else if ( std::strcmp ("-pp", argv[i]) == 0) + { + if (!pointFile.empty()) + { + throw CommandLineException("-pp cannot be used together with -pf"); + } + ENFORCE_ARGUMENT("-pp", i) + if (!has_only_digits_dots_commas(argv[i])) + { + std::stringstream message; + message << "Invalid fill point provided (" + << argv[i] + << "). Should only contain digits dots and commas" + << std::flush; + throw CommandLineException(message.str().c_str()); + } + points.push_back(argv[i]); + } + else if ( std::strcmp("-pf", argv[i]) == 0 ) + { + if (!points.empty()) + { + throw CommandLineException("-pf cannot be used together with -pp"); + } + ENFORCE_ARGUMENT("-pf", i) + pointFile = argv[i]; + } + else if ( std::strcmp("-pr", argv[i]) == 0) + { + ENFORCE_ARGUMENT("-pr", i); + m_maxVisibility = std::atof(argv[i]); + if ( m_maxVisibility == 0.0) + { + std::stringstream message; + message << "Restricted visibility of '" << argv[i] << "' makes no sense, use a positive number or -1 for unrestricted"; + throw CommandLineException(message.str()); + } + } + else if ( std::strcmp("-pb", argv[i]) == 0 ) + { + m_boundaryGraph = true; + } + else if ( std::strcmp("-pm", argv[i]) == 0 ) + { + if (getUnmakeGraph()) + { + throw CommandLineException("-pm cannot be used together with -pu"); + } + m_makeGraph = true; + } + else if ( std::strcmp("-pu", argv[i]) == 0 ) + { + if (getMakeGraph()) + { + throw CommandLineException("-pu cannot be used together with -pm"); + } + m_unmakeGraph = true; + } + else if ( std::strcmp("-pl", argv[i]) == 0 ) + { + m_removeLinksWhenUnmaking = true; + } + } + + if(!getMakeGraph() && !getUnmakeGraph() && m_grid <= 0 && pointFile.empty() && points.empty()) + { + throw CommandLineException("Nothing to do"); + } + + if(m_grid > 0 && getMakeGraph() && pointFile.empty() && points.empty()) { + throw CommandLineException("Creating a graph for an unfilled grid is not possible. " \ + "Either -pp or -pf must be given"); + } + + if(!pointFile.empty()) + { + std::ifstream pointsStream(pointFile); + if (!pointsStream) + { + std::stringstream message; + message << "Failed to load file " << pointFile << ", error " << std::strerror(errno) << std::flush; + throw depthmapX::RuntimeException(message.str().c_str()); + } + std::vector parsed = EntityParsing::parsePoints(pointsStream, '\t'); + m_fillPoints.insert(std::end(m_fillPoints), std::begin(parsed), std::end(parsed)); + } + else if(!points.empty()) + { + std::stringstream pointsStream; + pointsStream << "x,y"; + std::vector::iterator iter = points.begin(), end = + points.end(); + for ( ; iter != end; ++iter ) + { + pointsStream << "\n" << *iter; + } + std::vector parsed = EntityParsing::parsePoints(pointsStream, ','); + m_fillPoints.insert(std::end(m_fillPoints), std::begin(parsed), std::end(parsed)); + + } + + if(getUnmakeGraph() && (m_grid > 0 || !m_fillPoints.empty())) { + throw CommandLineException("-pu can not be used with any other option apart from -pl"); + } + + if(m_removeLinksWhenUnmaking && !m_unmakeGraph) { + throw CommandLineException("-pl can only be used together with -pu"); + } +} + +void VisPrepParser::run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const +{ + dm_runmethods::runVisualPrep(clp, m_grid, m_fillPoints, m_maxVisibility, m_boundaryGraph, m_makeGraph, m_unmakeGraph, m_removeLinksWhenUnmaking, perfWriter); +} diff --git a/depthmapXcli/visprepparser.h b/depthmapXcli/visprepparser.h new file mode 100644 index 00000000..02375839 --- /dev/null +++ b/depthmapXcli/visprepparser.h @@ -0,0 +1,69 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "imodeparser.h" +#include "genlib/p2dpoly.h" +#include + +class VisPrepParser : public IModeParser +{ +public: + VisPrepParser() : m_grid(-1.0), m_maxVisibility(-1.0), m_boundaryGraph(false), m_makeGraph(false), m_unmakeGraph(false), m_removeLinksWhenUnmaking(false) + {} + + virtual std::string getModeName() const + { + return "VISPREP"; + } + + virtual std::string getHelp() const + { + return "Mode options for VISPREP (visual analysis preparation) are:\n" \ + " -pg floating point number defining the grid spacing. If this\n" \ + " is provided it will create a new map\n" \ + " -pp point where to fill. Can be repeated\n" \ + " -pf a file with a point per line to fill\n" \ + " -pr restrict visibility (-1 is unrestricted, default)\n" \ + " -pb Make boundary graph\n" \ + " -pm Make graph\n" \ + " -pu Unmake graph\n" \ + " -pl Remove links when unmaking\n"; + } + + virtual void parse(int argc, char** argv); + + virtual void run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const; + + double getGrid() const { return m_grid; } + std::vector getFillPoints() const { return m_fillPoints; } + bool getBoundaryGraph() const { return m_boundaryGraph; } + double getMaxVisibility() const { return m_maxVisibility; } + bool getMakeGraph() const { return m_makeGraph; } + bool getUnmakeGraph() const { return m_unmakeGraph; } + bool getRemoveLinksWhenUnmaking() const { return m_removeLinksWhenUnmaking; } + +private: + double m_grid; + std::vector m_fillPoints; + double m_maxVisibility; + bool m_boundaryGraph; + bool m_makeGraph; + bool m_unmakeGraph; + bool m_removeLinksWhenUnmaking; +}; + + diff --git a/dist/beta/map_opengl/macos/depthmapX.zip b/dist/beta/map_opengl/macos/depthmapX.zip new file mode 100644 index 00000000..b1554baf Binary files /dev/null and b/dist/beta/map_opengl/macos/depthmapX.zip differ diff --git a/dist/beta/map_opengl/win-32/depthmapX.zip b/dist/beta/map_opengl/win-32/depthmapX.zip new file mode 100644 index 00000000..ce2cb5ec Binary files /dev/null and b/dist/beta/map_opengl/win-32/depthmapX.zip differ diff --git a/dist/beta/map_opengl/win-64/depthmapX.zip b/dist/beta/map_opengl/win-64/depthmapX.zip new file mode 100644 index 00000000..dd266ae4 Binary files /dev/null and b/dist/beta/map_opengl/win-64/depthmapX.zip differ diff --git a/dist/beta/master/macos/depthmapX.zip b/dist/beta/master/macos/depthmapX.zip new file mode 100644 index 00000000..ec7975d4 Binary files /dev/null and b/dist/beta/master/macos/depthmapX.zip differ diff --git a/docs/Agents_Manual_Draft01_2012.pdf b/docs/Agents_Manual_Draft01_2012.pdf new file mode 100644 index 00000000..59050bf2 Binary files /dev/null and b/docs/Agents_Manual_Draft01_2012.pdf differ diff --git a/docs/DepthmapManualForDummies-v13.pdf b/docs/DepthmapManualForDummies-v13.pdf new file mode 100644 index 00000000..92d612d0 Binary files /dev/null and b/docs/DepthmapManualForDummies-v13.pdf differ diff --git a/README.txt b/docs/about.md similarity index 92% rename from README.txt rename to docs/about.md index ae23e704..7dc685c5 100644 --- a/README.txt +++ b/docs/about.md @@ -1,8 +1,4 @@ -## depthmapX - multi-platform spatial network analyses software ## - -## Get the latest MacOSX/Windows version and learn more about depthmapX: -## ## http://varoudis.github.io/depthmapX/ -## +## About depthmapX depthmapX is a multi-platform software platform to perform a set of spatial network analyses designed to understand social processes within the built environment. It works at a variety of scales from building through small urban to whole cities or states. At each scale, the aim of the software is to produce a map of open space elements, connect them via some relationship (for example, intervisibility or overlap) and then perform graph analysis of the resulting network. The objective of the analysis is to derive variables which may have social or experiential significance. @@ -16,9 +12,4 @@ The analyses described so far are fairly fixed, however depthmapX also offers th depthmapX can display information as coloured maps, tables and scattergrams that comparing measures against other measures or observed data, as well as a three-dimensional view of agents walking. Data for plans can be imported from AutoCAD’s DXF format, or from Ordnance Survey NTF files or US Tiger Line maps, as well as from GIS through MapInfo’s MIF/MID format. Export may also be to MIF/MID, or to text files which may be analysed further using statistical analysis packages. Additionally, maps may be exported as vector graphics EPS files, or by copying and pasting into other software such as Microsoft Word. -## - -depthmapX is using GPLv3 licence. Please read http://www.gnu.org/licenses/gpl-3.0.html and also join www.jiscmail.ac.uk/lists/DEPTHMAP.html . -Thanks, -Tasos Varoudis diff --git a/docs/building.md b/docs/building.md new file mode 100644 index 00000000..440f4056 --- /dev/null +++ b/docs/building.md @@ -0,0 +1,56 @@ +# Building depthmapX + +## Building natively + +To build depthmapX on your machine, you need the following dependencies: +- A C++ compiler that supports C++-11 or later. Tested compilers are + - MSVC 2015 or later (on Windows) + - Clang (on MacOS and Linux) + - g++ (on Linux) +- Qt 5.7 or later +- cmake 3.13 or later - this is a fairly recent version + +If these dependencies are available, then building depthmapX should be +``` +mkdir build +cd build +cmake .. +make +``` + +## Building in docker + +depthmapX can be built in a docker container that provides an image including +all the required dependencies. It will build depthmapX on Unbuntu 18.04, i.e. +it will produce a linux executable. The docker image can also be used to run +the command line app interactively. +In order to use the docker build image, docker must be running on the computer +in use - please refer to the docker documentation at www.docker.com. + +### Windows + +To run the docker build on windows, use this command line: +``` +docker run -v \depthmapX:/mnt/code/ -it blackseamonster/depthmapx-buildenv:0.3 bash -c ci/build.sh +``` + +To run the build environment interactively, use +``` +docker run -v \depthmapX:/mnt/code/ -it blackseamonster/depthmapx-buildenv:0.3 bash +``` + +### Mac/Linux + +To run the docker build on a Unix based system, use this command line: +``` +docker run --security-opt seccomp:unconfined --user $UID -v $PWD:/mnt/code blackseamonster/depthmapx-buildenv:0.3 bash -c ci/build.sh +``` + +To run the build environment interactively, use: +``` +docker run --security-opt seccomp:unconfined --user $UID -v $PWD:/mnt/code blackseamonster/depthmapx-buildenv:0.3 bash +``` + +## Using an IDE + +As depthmapX uses cmake as build toolchain, any IDE that supports cmake should be usable. diff --git a/docs/commandline.md b/docs/commandline.md new file mode 100644 index 00000000..abd2f755 --- /dev/null +++ b/docs/commandline.md @@ -0,0 +1,198 @@ +# depthmapX Command Line Interface + +## Overview +The depthmapX command line interface allows to run steps that are traditionally +executed by loading a file into the GUI and clicking buttons/menu entries +by running a command from a command line/shell. + +The command line interface is especially useful in cases where a similar kind of +analysis needs to be repeated regularly, as +the steps can be written into a script and run automatically or +semi-automatically, do not require user input via mouse/GUI and can be +parallelised into multiple processes or on multiple machines. + +The general idea is that each call to the command line interface reads in a +depthmapX graph file, then applies some transformation/analysis to it and saves +the result into a different file. Thus, a pipeline of operations can be +created where each step reads in the input of the previous step, and in the end +we have the end result and all intermediate steps. This is particularly helpful +if something has gone wrong, as we can go back, figure out which step went wrong +and rerun this and all subsequent steps. + +The command line interface also supports importing of data from DXF and csv +formats and export to csv so that a whole pipeline from plan to statistical +output can be run programmatically. + +## The Command Line + +The functionality in the depthmapX cli is split up into execution modes - each +mode roughly represents a class of functionalities in the UI. The overall +commandline looks like: + +Mac/Linux: `./depthmapXcli -f -o -m [mode +options]` +Windows: `depthmapXcli.exe -f -o -m +[mode options]` + +### Global option + +These are command line parameters that can be used for any run of the +application, no matter what the used mode is. + +- `-m ` This chooses the mode (what depthmapX operation to execute). +Available modes are + - `VGA` run visual graph analysis + - `LINK` create extra links between pixels + - `VISPREP` various operations to prepare a blank map for VGA or agent + analysis + - `AXIAL` run axial analysis + - `AGENTS` run an agent analysis + - `ISOVIST` calculate isovists + - `EXPORT` export data from the given graph file + - `IMPORT` import data into a graph file +- `-f ` input graph file to base the operation on +- `-o ` graph file the result of the operation will be written to +- `-h` print a help text and exit +- `-s` enable simple mode (off by default) +- `-t ` enables dumping of the time used for various steps of +the processing into the specified file. + +Each mode has a set of suboptions to tailor what exactly will we done. + +### Mode options for `VGA` + +- `-vm` Sets the VGA mode. This option must be set when using `VGA`. These +reflect the options from the VGA submenu in +the depthmap UI. Possible options are + - `isovist` + - `visibility` + - `metric` + - `angular` + - `thruvision` +- `-vg` Turn on global measures (optional). When set, `-vr` must be used to set +a visibility radius. +- `-vl` Turn on local measures (optional). +- `-vr ` Set the visibility radius to a number between 1 and 99 steps. + + +### Mode options for `LINK` + +Use this mode to add links to a grid before running a `VGA` analysis. It takes +tuples of coordinates and links the two closes pixels (as if using the link +tool in the graphical user interface - the coordinates represent the mouse +positions when clicking). This mode either takes a list of tuples on the command +line, or it reads it in from a file + +- `-lf ` Reads in the link coordinates from a file. +- `-lnk Defines one link to be made in the format +`x1,y1,x2,y2` - e.g. to link from 0.0,0.0 to 1.0,2.3, specify 0.0,0.0,1.0,2.3. + +The file format for the links file is 4 tabulator separated columns with headers +x1, x2, y1, and y2. So the file for the example above would be: +``` +x1 y1 x2 y2 +0.0 0.0 1.0 2.3 +``` + +### Mode options for `VISPREP` + +This mode can be used to run the preparation steps required after a map (dxf) +has been imported into depthmapX, but before a VGA or agent analysis can be +run. It will define a grid, fill the graph, and run the connectivity +calculation. It takes the following options +- `-pg ` defines the grid size in units of your drawing +- `-pp ` Defines a point where the fill algorithm starts in `x,y` +format. This option can be repeated if separate parts of the plan need to be +filled. +- `-pf ` Reads the points for filling from the specified file (tab +separated, headers `X` and `Y`). This option cannot be combined with `-pp` +- `-pr ` This restricts the visiblity in the connectivity +calculation to the given value. The default value is unrestricted (`-1`) +- `-pb` Enables creating a boundary graph. + +Example: `./depthmapXcli_macos -f gallery.graph -o gallery_prep.graph -m VISPREP +-pg 0.4 -pf 3.0,4.0 -pr 5` + +### Mode options for `AXIAL` + +This modes runs the various things that depthmapX can do around axial analysis. +It has two different kinds of options: command options that specify what to run, +and modifiers that impact how these are run. + +Each command options expects an input file that has the required inputs for +these options (e.g. an axial analysis expects the graph file to contain an +axial map). The command options are +- `-xl ` Calculate an all lines map starting at the point given in +`x,y` format. +- `-xf` reduce an all lines map to a fewest lines map. Expects an axial map +that can be reduced to be in the graph file. +- `-xu` Process unlink data (not yet supported on the command line) +- `-xa` run the actual axial analysis. Expects an axial map to be present in +the graph file. + +These command flags can be combined within one run, they will always run in the +order `-xl -xf -xu -xa` and each step can produce the input for the next. + +In addition to these flags, the following modifiers are available +- `-xac` Include choice (betweenness) calculations +- `-xal` Include local measures +- `-xar` Include RA, RRA and total depth calculations + + +### Mode options for `AGENTS` +- `-am ` one of + - `standard` + - `los-length` (Line of Sight length) + - `occ-length` (Occluded length) + - `occ-any` (Any occlusions) + - `occ-group-45` (Occlusion group bins - 45 degrees) + - `occ-group-60` (Occlusion group bins - 60 degrees) + - `occ-furthest` (Furthest occlusion per bin) + - `bin-far-dist` (Per bin far distance weighted) + - `bin-angle` (Per bin angle weighted) + - `bin-far-dist-angle` (Per bin far-distance and angle weighted) + - `bin-memory` (Per bin memory) +- `-ats ` set total system timesteps to be run +- `-arr ` set agent release rate (likelyhood of release per timestep) +- `-atrails ` record trails for this amount of agents (set to 0 +to record all, with max possible currently = 50) +- `-afov ` set agent field-of-view (bins) +- `-asteps ` set agent steps before turn decision +- `-alife ` set agent total lifetime (in timesteps) +- `-alocseed ` set agents to start at random locations with specific seed (0 to 10) +- `-alocfile ` +- `-aloc ` provide the single agent starting point in format +`x1,y1` for example `-aloc 0.1,0.2`. +- `-ot ` available output types (may use more than one + - `graph` (graph file, default) + - `gatecounts` (csv with cells of grid with gate counts) + - `trails` (csv with lines showing path traversed by each agent) + +### Mode options for `ISOVIST` +- `-ii ` Define an isoivist at position x,y with + optional direction angle and view angle for partial isovists +- `-if ` load isovist definitions from a file (csv) + the relevant headers must be called x, y, angle and viewangle + the latter two are optional. + +Those two arguments cannot be mixed +Angles for partial isovists are in degrees, counted anti-clockwise with 0 +pointing to the right. + + +### Mode options for `EXPORT` +This mode exports data from a graph file to a csv for further analysis in +other tools, e.g. Excel or a statistics package. Thus, the output file (`-o` +argument) should be a csv file, not a graph file in this mode. +- `-em ` one of + - `pointmap-data-csv` + - `pointmap-connections-csv` + +### Mode options for `IMPORT` +The file provided by -f here will be used as the base. If that fileis not a +graph, a new graph will be created and the file will be imported. +- `-if ` one or more files to import + +Example for importing a dxf: + +`./depthmapXcli -f in.dxf -o out.graph` diff --git a/docs/gui.md b/docs/gui.md new file mode 100644 index 00000000..7fca6a2c --- /dev/null +++ b/docs/gui.md @@ -0,0 +1,10 @@ +# depthmapX Graphical User Interface + +The graphical user interface is the standard way of interacting with depthmapX. +It allows to load files, import plans, runs analyses and explore the data in +an interactive way. + +A lot of the available functionality has been described in the [Depthmap Manual +for Dummies](./DepthmapManualForDummies-v13.pdf) by Akkie van Nes, which is slightly +outdated but still worth a read to get an idea how things work in the GUI. + diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..934ea371 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,14 @@ +# depthmapX Documentation + +depthmapX is a tool for spatial analysis, originally written as a research +project by Alasdair Turner (targeting the Windows platform only), then later +ported to Qt and made available cross platform by Tasos Varoudis, and is now +under active development by a small team of members of Bartlett School of +Architecture at UCL and volunteers. + +## Table of Contents +- [About](./about.md) +- [Using the Graphical User Interface (GUI)](./gui.md) +- [The command line interface](./commandline.md) +- [Building depthmapX yourself](./building.md) + diff --git a/genlib/CMakeLists.txt b/genlib/CMakeLists.txt new file mode 100644 index 00000000..a7fe7c0b --- /dev/null +++ b/genlib/CMakeLists.txt @@ -0,0 +1,11 @@ +set(genlib genlib) +set(genlib_SRCS + bsptree.cpp + p2dpoly.cpp + pafmath.cpp + stringutils.cpp + xmlparse.cpp) + +add_compile_definitions(GENLIB_LIBRARY) + +add_library(${genlib} STATIC ${genlib_SRCS}) diff --git a/genlib/bsptree.cpp b/genlib/bsptree.cpp new file mode 100644 index 00000000..32d22ee0 --- /dev/null +++ b/genlib/bsptree.cpp @@ -0,0 +1,182 @@ +// genlib - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010 University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "bsptree.h" + +#include + +// Binary Space Partition + +/* Takes a set of lines and creates a binary-space-partition tree by starting from a + * root node, setting its left and right nodes and recursively doing the same process + * over those. Through this process the set of lines is split in two (one set for each + * left and right nodes) and those are split and passed again further down the recursion. + * While the original implementation was actually recursive it was hitting the recursion + * limit when the input was a large number of lines that fell on the same side (i.e. an + * arc divided in 500 pieces). It has been refactored here to an iterative solution, where + * the current node (left or right) is pushed to a stack along with the relevant set of lines. + */ + +void BSPTree::make(Communicator *communicator, time_t atime, const std::vector &lines, BSPNode *root) { + + typedef std::pair, std::vector> TagLineVecPair; + + std::stack nodeStack; + std::stack lineStack; + + nodeStack.push(root); + lineStack.push(makeLines(communicator, atime, lines, root)); + + int progress = 0; + while (!nodeStack.empty()) { + progress++; // might need to increase by 2 because it was one for each left/right in the previous iteration + + if (communicator) { + if (communicator->IsCancelled()) { + throw Communicator::CancelledException(); + } + if (qtimer(atime, 500)) { + communicator->CommPostMessage(Communicator::CURRENT_RECORD, progress); + } + } + BSPNode *currNode = nodeStack.top(); + nodeStack.pop(); + TagLineVecPair currLines = lineStack.top(); + lineStack.pop(); + + if (!currLines.first.empty()) { + currNode->m_left = std::unique_ptr(new BSPNode(currNode)); + nodeStack.push(currNode->m_left.get()); + lineStack.push(makeLines(communicator, atime, currLines.first, currNode->m_left.get())); + } + if (!currLines.second.empty()) { + currNode->m_right = std::unique_ptr(new BSPNode(currNode)); + nodeStack.push(currNode->m_right.get()); + lineStack.push(makeLines(communicator, atime, currLines.second, currNode->m_right.get())); + } + } +} + +/* Finds the midpoint from all the lines given and returns the index of the line + * closest to it. + */ + +int BSPTree::pickMidpointLine(const std::vector &lines, BSPNode *par) { + int chosen = -1; + Point2f midpoint; + for (size_t i = 0; i < lines.size(); i++) { + midpoint += lines[i].line.start() + lines[i].line.end(); + } + midpoint /= 2.0 * lines.size(); + bool ver = true; + if (par && par->getLine().height() > par->getLine().width()) { + ver = false; + } + double chosendist = -1.0; + for (size_t i = 0; i < lines.size(); i++) { + const Line &line = lines[i].line; + if (ver) { + if (line.height() > line.width() && (chosen == -1 || dist(line.midpoint(), midpoint) < chosendist)) { + chosen = static_cast(i); + chosendist = dist(line.midpoint(), midpoint); + } + } else { + if (line.width() > line.height() && (chosen == -1 || dist(line.midpoint(), midpoint) < chosendist)) { + chosen = static_cast(i); + chosendist = dist(line.midpoint(), midpoint); + } + } + } + // argh... and again... there weren't any hoz / ver: + if (chosen == -1) { + for (size_t i = 0; i < lines.size(); i++) { + if (chosen == -1 || dist(lines[i].line.midpoint(), midpoint) < chosendist) { + chosen = static_cast(i); + chosendist = dist(lines[i].line.midpoint(), midpoint); + } + } + } + return chosen; +} + +/* Breaks a set of lines in two (left-right). First chooses a line closest to the midpoint + * of the set ("chosen") and then classifies lines left or right depending on whether they + * lie clockwise or anti-clockwise of the chosen one (with chosen start as centre, angles + * from the chosen end up to 180 are clockwise, down to -180 anti-clockwise). Lines that cross + * from one side of the chosen to the other are split in two and each part goes to the relevant set. + */ + +std::pair, std::vector> +BSPTree::makeLines(Communicator *, time_t, const std::vector &lines, BSPNode *base) { + std::vector leftlines; + std::vector rightlines; + + // for optimization of the tree (this reduced a six-minute gen time to a 38 second gen time) + int chosen = -1; + if (lines.size() > 3) { + chosen = BSPTree::pickMidpointLine(lines, base->m_parent); + } else { + chosen = pafrand() % lines.size(); + } + + Line chosenLine = lines[chosen].line; + int chosenTag = lines[chosen].tag; + base->setLine(chosenLine); + base->setTag(chosenTag); + + Point2f v0 = chosenLine.end() - chosenLine.start(); + v0.normalise(); + + for (size_t i = 0; i < lines.size(); i++) { + if (i == static_cast(chosen)) { + continue; + } + const Line &testline = lines[i].line; + int tag = lines[i].tag; + Point2f v1 = testline.start() - chosenLine.start(); + v1.normalise(); + Point2f v2 = testline.end() - chosenLine.start(); + v2.normalise(); + // should use approxeq here: + double a = testline.start() == chosenLine.start() ? 0 : det(v0, v1); + double b = testline.end() == chosenLine.start() ? 0 : det(v0, v2); + // note sure what to do if a == 0 and b == 0 (i.e., it's parallel... this test at least ensures on the line is + // one or the other side) + if (a >= 0 && b >= 0) { + leftlines.push_back(TaggedLine(testline, tag)); + } else if (a <= 0 && b <= 0) { + rightlines.push_back(TaggedLine(testline, tag)); + } else { + Point2f p = intersection_point(chosenLine, testline); + Line x = Line(testline.start(), p); + Line y = Line(p, testline.end()); + if (a >= 0) { + if (x.length() > 0.0) // should use a tolerance here too + leftlines.push_back(TaggedLine(x, tag)); + if (y.length() > 0.0) // should use a tolerance here too + rightlines.push_back(TaggedLine(y, tag)); + } else { + if (x.length() > 0.0) // should use a tolerance here too + rightlines.push_back(TaggedLine(x, tag)); + if (y.length() > 0.0) // should use a tolerance here too + leftlines.push_back(TaggedLine(y, tag)); + } + } + } + + return std::make_pair(leftlines, rightlines); +} diff --git a/genlib/bsptree.h b/genlib/bsptree.h new file mode 100644 index 00000000..2fe6fc7c --- /dev/null +++ b/genlib/bsptree.h @@ -0,0 +1,65 @@ +// genlib - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010 University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "genlib/p2dpoly.h" + +#include + +// Binary Space Partition + +struct BSPNode { + + private: + Line m_line; + int m_tag; + + public: + enum { BSPLEFT, BSPRIGHT }; + std::unique_ptr m_left; + std::unique_ptr m_right; + BSPNode *m_parent; + + BSPNode(BSPNode *parent = NULL) : m_left(nullptr), m_right(nullptr) { + m_parent = parent; + m_tag = -1; + } + bool isLeaf() { return m_left == nullptr && m_right == nullptr; } + int classify(const Point2f &p) { + Point2f v0 = m_line.end() - m_line.start(); + v0.normalise(); + Point2f v1 = p - m_line.start(); + v1.normalise(); + if (det(v0, v1) >= 0) { + return BSPLEFT; + } else { + return BSPRIGHT; + } + } + const Line &getLine() const { return m_line; } + void setLine(const Line &line) { m_line = line; } + int getTag() const { return m_tag; } + void setTag(const int tag) { m_tag = tag; } +}; + +namespace BSPTree { + void make(Communicator *communicator, time_t atime, const std::vector &lines, BSPNode *root); + int pickMidpointLine(const std::vector &lines, BSPNode *par); + std::pair, std::vector> + makeLines(Communicator *communicator, time_t atime, const std::vector &lines, BSPNode *base); +} // namespace BSPTree diff --git a/genlib/comm.h b/genlib/comm.h index a719c37b..47f853bc 100644 --- a/genlib/comm.h +++ b/genlib/comm.h @@ -14,216 +14,179 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#ifndef __COMM_H__ -#define __COMM_H__ +#pragma once //#include -#include +#include +#include #include +#include +#include #ifdef _WIN32 // Quick mod - TV -#pragma warning (disable: 4244) -#pragma warning (disable: 4100) +#pragma warning(disable : 4244) +#pragma warning(disable : 4100) #else #endif -// distinguish between UTF-16 used by Windows and UTF-8 used by Linus / MacOS: -// converted to Unicode path for Win32 (AT 31.01.11) -// typedef solution AT 29.04.11 -#ifdef _MSC_VER // MSVC compiler - typedef wstring comm_string; - typedef wchar_t comm_char; - typedef __time64_t comm_time_t; - const comm_char *const g_default_file_set = L"File set"; -#else - typedef string comm_string; - typedef char comm_char; - typedef time_t comm_time_t; - const comm_char *const g_default_file_set = "File set"; -#endif +const char *const g_default_file_set = "File set"; struct FilePath { - comm_string m_path; - comm_string m_name; - comm_string m_ext; - FilePath(const comm_string& pathname) - { - size_t dot = pathname.find_last_of('.'); + std::string m_path; + std::string m_name; + std::string m_ext; + FilePath(const std::string &pathname) { + size_t dot = pathname.find_last_of('.'); #ifdef _WIN32 - size_t slash = pathname.find_last_of('\\'); // WIN32 + size_t slash = pathname.find_last_of('\\'); // WIN32 #else - size_t slash = pathname.find_last_of('/'); // Other + size_t slash = pathname.find_last_of('/'); // Other #endif - if (slash != paftl::npos) { - m_path = pathname.substr(0,slash+1); - } - if (dot != paftl::npos) { - m_name = pathname.substr(slash+1,dot-slash-1); - m_ext = pathname.substr(dot+1); - } - else { - m_name = pathname.substr(slash+1); - } - } + if (slash != std::string::npos) { + m_path = pathname.substr(0, slash + 1); + } + if (dot != std::string::npos) { + m_name = pathname.substr(slash + 1, dot - slash - 1); + m_ext = pathname.substr(dot + 1); + } else { + m_name = pathname.substr(slash + 1); + } + } }; -class Communicator -{ -public: - class CancelledException // throw from your class - { - public: - CancelledException() {;} - }; - enum { NUM_STEPS, CURRENT_STEP, NUM_RECORDS, CURRENT_RECORD }; -protected: - bool m_cancelled; - bool m_delete_flag; - // nb. converted to Win32 UTF-16 Unicode path (AT 31.01.11) Linux, MacOS use UTF-8 (AT 29.04.11) - comm_string m_infilename; - ifstream *m_infile; - ifstream *m_infile2; // <- MapInfo MIF files come in two parts - ofstream *m_outfile; - // nb. converted to Win32 UTF-16 Unicode path (AT 31.01.11) Linux, MacOS use UTF-8 (AT 29.04.11) - pqvector m_fileset; // <- sometimes you want to load a whole set of files -public: - Communicator() - { m_infile = NULL; m_infile2 = NULL; m_outfile = NULL; m_cancelled = false; m_delete_flag = false; } - // - bool GetDeleteFlag() // used by ICommunicator and IComm together - { return m_delete_flag; } - // - virtual ~Communicator() - { if (m_infile) delete m_infile; m_infile = NULL; - if (m_infile2) delete m_infile2; m_infile2 = NULL; - if (m_outfile) delete m_outfile; m_outfile = NULL; } - // - void SetInfile( const comm_char* filename ) - { - m_infile = new ifstream( filename ); - FilePath fp(filename); - m_infilename = fp.m_name; - } - void SetInfile2( const comm_char* filename ) - { - m_infile2 = new ifstream( filename ); - } - comm_string GetInfileName() - { - return m_fileset.size() ? comm_string(g_default_file_set) : m_infilename; - } - pstring GetMBInfileName() - { - pstring ret; - if (m_fileset.size()) { - ret = "File set"; - } - else { - ret = pstring(m_infilename.c_str()); - } - return ret; - } - size_t GetInfileSize() - { - if (m_infile) { - m_infile->seekg(0, ios::beg); - size_t begin_pos = m_infile->tellg(); - m_infile->seekg(0, ios::end); - size_t end_pos = m_infile->tellg(); - m_infile->seekg(0, ios::beg); - return size_t(end_pos - begin_pos); - } - return 0; - } - void SetOutfile( const char *filename ) - { m_outfile = new ofstream( filename ); } - // - bool IsCancelled() const - { return m_cancelled; } - void Cancel() - { m_cancelled = true; } - // - operator ofstream& () - { return *m_outfile; } - operator ifstream& () - { return *m_infile; } - ifstream& GetInfile2() - { return *m_infile2; } - // - const pqvector& GetFileSet() const - { return m_fileset; } - // - virtual void CommPostMessage(int m, int x, int y = 0) const = 0; // Override for specific operating system +class Communicator { + public: + class CancelledException // throw from your class + { + public: + CancelledException() { ; } + }; + enum { NUM_STEPS, CURRENT_STEP, NUM_RECORDS, CURRENT_RECORD }; + + protected: + bool m_cancelled; + bool m_delete_flag; + // nb. converted to Win32 UTF-16 Unicode path (AT 31.01.11) Linux, MacOS use UTF-8 (AT 29.04.11) + std::string m_infilename; + std::ifstream *m_infile; + std::ifstream *m_infile2; // <- MapInfo MIF files come in two parts + std::ofstream *m_outfile; + // nb. converted to Win32 UTF-16 Unicode path (AT 31.01.11) Linux, MacOS use UTF-8 (AT 29.04.11) + std::vector m_fileset; // <- sometimes you want to load a whole set of files + public: + Communicator() { + m_infile = NULL; + m_infile2 = NULL; + m_outfile = NULL; + m_cancelled = false; + m_delete_flag = false; + } + // + bool GetDeleteFlag() // used by ICommunicator and IComm together + { + return m_delete_flag; + } + // + virtual ~Communicator() { + if (m_infile) + delete m_infile; + m_infile = NULL; + if (m_infile2) + delete m_infile2; + m_infile2 = NULL; + if (m_outfile) + delete m_outfile; + m_outfile = NULL; + } + // + void SetInfile(const char *filename) { + m_infile = new std::ifstream(filename); + FilePath fp(filename); + m_infilename = fp.m_name; + } + void SetInfile2(const char *filename) { m_infile2 = new std::ifstream(filename); } + std::string GetInfileName() { return m_fileset.size() ? std::string(g_default_file_set) : m_infilename; } + std::string GetMBInfileName() { + std::string ret; + if (m_fileset.size()) { + ret = "File set"; + } else { + ret = std::string(m_infilename.c_str()); + } + return ret; + } + size_t GetInfileSize() { + if (m_infile) { + m_infile->seekg(0, std::ios::beg); + size_t begin_pos = m_infile->tellg(); + m_infile->seekg(0, std::ios::end); + size_t end_pos = m_infile->tellg(); + m_infile->seekg(0, std::ios::beg); + return size_t(end_pos - begin_pos); + } + return 0; + } + void SetOutfile(const char *filename) { m_outfile = new std::ofstream(filename); } + // + bool IsCancelled() const { return m_cancelled; } + void Cancel() { m_cancelled = true; } + // + operator std::ofstream &() { return *m_outfile; } + operator std::ifstream &() { return *m_infile; } + std::ifstream &GetInfile2() { return *m_infile2; } + // + const std::vector &GetFileSet() const { return m_fileset; } + // + virtual void CommPostMessage(int m, int x) const = 0; // Override for specific operating system }; // this is a simple version of the Communicator which can be used for // an interface -class ICommunicator : public Communicator -{ - friend class IComm; // IComm is found in idepthmap.h - // -protected: - mutable int num_steps; - mutable int num_records; - mutable int step; - mutable int record; - // -public: - ICommunicator() { m_delete_flag = true; } // note: an ICommunicator lets IComm know that it should delete it - virtual ~ICommunicator() {;} - virtual void CommPostMessage(int m, int x, int y = 0) const; +class ICommunicator : public Communicator { + friend class IComm; // IComm is found in idepthmap.h + // + protected: + mutable int num_steps; + mutable int num_records; + mutable int step; + mutable int record; + // + public: + ICommunicator() { m_delete_flag = true; } // note: an ICommunicator lets IComm know that it should delete it + virtual ~ICommunicator() { ; } + virtual void CommPostMessage(int m, int x) const; }; -inline void ICommunicator::CommPostMessage(int m, int x, int y) const -{ - switch (m) { - case Communicator::NUM_STEPS: - num_steps = x; - break; - case Communicator::CURRENT_STEP: - step = x; - break; - case Communicator::NUM_RECORDS: - num_records = x; - break; - case Communicator::CURRENT_RECORD: - record = x; - break; - default: - y = 0; - break; +inline void ICommunicator::CommPostMessage(int m, int x) const { + switch (m) { + case Communicator::NUM_STEPS: + num_steps = x; + break; + case Communicator::CURRENT_STEP: + step = x; + break; + case Communicator::NUM_RECORDS: + num_records = x; + break; + case Communicator::CURRENT_RECORD: + record = x; + break; + default: + break; } } - // a helpful little function... -#ifdef _MSC_VER // MSVC compiler -inline bool qtimer( __time64_t& t1, __time64_t timeout ) -{ - /* static */ _timeb time2; // static removed for multithreaded usage - _ftime( &time2 ); - __time64_t t2 = (time2.time % 100) * 1000 + time2.millitm; - if ((t2 - t1) > timeout || (t2 - t1) < 0) { // also catch a loop - t1 = t2; - return true; - } - return false; -} -#else -inline bool qtimer( time_t& t1, time_t timeout ) -{ - /* static */ timeb time2; // static removed for multithreaded usage - ftime( &time2 ); - time_t t2 = (time2.time % 100) * 1000 + time2.millitm; - if ((t2 - t1) > timeout || (t2 - t1) < 0) { // also catch a loop - t1 = t2; - return true; - } - return false; +inline bool qtimer(time_t &t1, time_t timeout) { + /* static */ timeb time2; // static removed for multithreaded usage + ftime(&time2); + time_t t2 = (time2.time % 100) * 1000 + time2.millitm; + if ((t2 - t1) > timeout || (t2 - t1) < 0) { // also catch a loop + t1 = t2; + return true; + } + return false; } -#endif - -#endif diff --git a/genlib/containerutils.h b/genlib/containerutils.h new file mode 100644 index 00000000..86c1aeb4 --- /dev/null +++ b/genlib/containerutils.h @@ -0,0 +1,88 @@ +// genlib - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include +#include + +namespace depthmapX { + + template void findAndErase(std::vector &vec, T element) { + auto it = std::find(vec.begin(), vec.end(), element); + if (it != vec.end()) + vec.erase(it); + } + + template bool addIfNotExists(std::vector &vec, T element) { + auto it = std::find(vec.begin(), vec.end(), element); + if (it == vec.end()) { + vec.push_back(element); + return true; + } + return false; + } + + template bool addIfNotExists(std::map &map, const K &key, const V &value) { + auto it = map.find(key); + if (it == map.end()) { + map[key] = value; + return true; + } + return false; + } + + template + typename std::map::const_iterator getMapAtIndex(const std::map &m, size_t idx) { + auto iter = m.begin(); + std::advance(iter, idx); + return iter; + } + + template typename std::map::iterator getMapAtIndex(std::map &m, size_t idx) { + auto iter = m.begin(); + std::advance(iter, idx); + return iter; + } + + template int findIndexFromKey(const std::map &m, K key) { + auto iter = m.find(key); + return iter == m.end() ? -1 : std::distance(m.begin(), iter); + } + + template + typename TContainer::iterator findBinary(TContainer &container, const TValue val) { + auto res = std::lower_bound(container.begin(), container.end(), val); + if (res == container.end() || val < *res) { + return container.end(); + } + return res; + } + + template + typename TContainer::const_iterator findBinary(const TContainer &container, const TValue val) { + auto res = std::lower_bound(container.begin(), container.end(), val); + if (res == container.end() || val < *res) { + return container.end(); + } + return res; + } + + template typename std::vector::iterator insert_sorted(std::vector &vec, T const &item) { + return vec.insert(std::upper_bound(vec.begin(), vec.end(), item), item); + } + +} // namespace depthmapX diff --git a/genlib/exceptions.h b/genlib/exceptions.h new file mode 100644 index 00000000..5578efb6 --- /dev/null +++ b/genlib/exceptions.h @@ -0,0 +1,37 @@ +// Copyright (C) 2017 Christian Sailer +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include +#include + +namespace depthmapX { + class BaseException : public std::exception { + public: + BaseException() {} + BaseException(std::string message) : _message(message) {} + virtual const char *what() const noexcept { return _message.c_str(); } + + private: + std::string _message; + }; + + class RuntimeException : public BaseException { + public: + RuntimeException(std::string message) : BaseException(message) {} + }; +} // namespace depthmapX diff --git a/genlib/genlib.pro b/genlib/genlib.pro deleted file mode 100644 index 66c62487..00000000 --- a/genlib/genlib.pro +++ /dev/null @@ -1,41 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2017-02-09T16:17:22 -# -#------------------------------------------------- -include(../defaults.pri) - -QT -= qt -CONFIG -= qt app_bundle - -TARGET = genlib -TEMPLATE = lib -CONFIG += staticlib c++11 - -DEFINES += GENLIB_LIBRARY - -# The following define makes your compiler emit warnings if you use -# any feature of Qt which as been marked as deprecated (the exact warnings -# depend on your compiler). Please consult the documentation of the -# deprecated API in order to know how to port your code away from it. -DEFINES += QT_DEPRECATED_WARNINGS - -# You can also make your code fail to compile if you use deprecated APIs. -# In order to do so, uncomment the following line. -# You can also select to disable deprecated APIs only up to a certain version of Qt. -#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 - -SOURCES += \ - dxfp.cpp \ - p2dpoly.cpp \ - pafmath.cpp \ - xmlparse.cpp - -HEADERS += \ - comm.h \ - dxfp.h \ - p2dpoly.h \ - pafmath.h \ - paftl.h \ - paftl_old.h \ - xmlparse.h diff --git a/genlib/linreg.h b/genlib/linreg.h new file mode 100644 index 00000000..f73e36ab --- /dev/null +++ b/genlib/linreg.h @@ -0,0 +1,74 @@ +// genlib - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010 University College London, Alasdair Turner + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "genlib/p2dpoly.h" + +// linear regression +// T should be int, float or double +template struct LinReg +{ + double S_x; + double S_y; + double S_xx; + double S_yy; + double S_xy; + double n; + // + bool cached; + double ca; + double cb; + // + LinReg() + { + S_x = 0; S_y = 0; S_xx = 0; S_yy = 0; S_xy = 0; n = 0; cached = false; + } + void clear() + { + S_x = 0; S_y = 0; S_xx = 0; S_yy = 0; S_xy = 0; n = 0; + cached = false; + } + void add(T x, T y) + { + n++; + S_x += double(x); S_y += double(y); + S_xx += sqr(double(x)); S_yy += sqr(double(y)); + S_xy += double(x) * double(y); + cached = false; + } + void makecache() + { + cb = (n*S_xy-S_x*S_y)/(n*S_xx-S_x*S_x); ca = (S_y - cb * S_x) / n; cached = true; + } + // Y = bX + a + double a() + { if (!cached) makecache(); return ca; } + double b() + { if (!cached) makecache(); return cb; } + double r() + { return (n*S_xy-S_x*S_y)/sqrt( (n*S_xx-sqr(S_x))*(n*S_yy-sqr(S_y)) ); } + double mu_x() + { return S_x / n; } + double mu_y() + { return S_y / n; } + // note you will need to keep the vectors if you need + // to calculate the residuals: e[i] = y[i] - b() * x[i] - a(); + double model(double x) + { if (!cached) makecache(); return cb * x + ca; } + double invmodel(double y) + { if (!cached) makecache(); return (y -ca) / cb ; } +}; diff --git a/genlib/p2dpoly.cpp b/genlib/p2dpoly.cpp index 85da3f64..2958e016 100644 --- a/genlib/p2dpoly.cpp +++ b/genlib/p2dpoly.cpp @@ -16,12 +16,13 @@ // 2d polygons (and line sets too...) +#include "p2dpoly.h" + +#include "genlib/comm.h" // used in BSP construction + #include #include -#include -#include // used in BSP construction -#include ////////////////////////////////////////////////////////////////////////////////////// @@ -46,112 +47,112 @@ // According to OS, accurate to within about 5 metres -Point2f gps2os(const Point2f& pt) -{ - // *first*, we have ETRS89 data... - - // Convert it to 3D Cartesian Coordinates - double lambda = M_PI * pt.x / 180.0; - double phi = M_PI * pt.y / 180.0; - - // GRS80 ellipsoid - double a = 6378137.0000; - double b = 6356752.3141; - double e_sq = (sqr(a) - sqr(b)) / sqr(a); - - double nu = a / sqrt(1.0 - e_sq * sqr(sin(phi))); - - double x = nu * cos(phi) * cos(lambda); - double y = nu * cos(phi) * sin(lambda); - double z = (1 - e_sq) * nu * sin(phi); - - // Now we have the ETRS89 location, convert it to a rough OSGB36 location: - - // rough conversion chart - - // t_x (m) t_y (m) t_z (m) s (ppm) r_x (sec) r_y (sec) r_z (sec) - // -446.448 +125.157 -542.060 +20.4894 -0.1502 -0.2470 -0.8421 = (in radians: ) - - // nb, seconds converted to radians: - double r_x = -0.7281901490265230623720509817416e-6; - double r_y = -1.1974897923405539041670878328241e-6; - double r_z = -4.0826160086234026020206666559563e-6; - - x = -446.448 + (1.0 + 2.04894e-5) * x - r_z * y + r_y * z; - y = +125.157 + r_z * x + (1.0 + 2.04894e-5) * y - r_x * z; - z = -542.060 - r_y * x + r_x * y + (1.0 + 2.04894e-5) * z; - - double p = sqrt(sqr(x)+sqr(y)); - - // now place it back in long lat on the OSGB36 ellipsoid: - - // Airy 1830 (OSGB36) ellipsoid - a = 6377563.396; - b = 6356256.910; - e_sq = (sqr(a) - sqr(b)) / sqr(a); - - lambda = atan( y / x ); - phi = atan( z / (p * (1.0 - e_sq)) ); - double lastphi = phi; - - nu = a / sqrt(1.0 - e_sq * sqr(sin(phi))); - do { - phi = atan( (z + e_sq * nu * sin(phi)) / p ); - } while (fabs(lastphi - phi) > 1e-6); - - // now, it's on the ellipsoid, project it onto the OSGB36 grid: - - // E_0 easting of true origin 400 000m - double E_0 = 400000; - // N_0 northing of true origin -100 000m - double N_0 = -100000; - // F_0 scaling factor on central meridian 0.9996012717 - double F_0 = 0.9996012717; - // lambda_0 longitude of true origin -2.0 radians: -0.034906585039886591538473815369772 - double lambda_0 = -0.034906585039886591538473815369772; - // phi_0 latitude of true origin 49.0 radians: - double phi_0 = 0.85521133347722149269260847655942; - - nu = a * F_0 * pow((1 - e_sq * sqr(sin(phi))),-0.5); - - double n = (a-b) / (a+b); - double rho = a * F_0 * (1.0 - e_sq) * pow((1 - e_sq * sqr(sin(phi))),-1.5); - double eta_sq = nu / rho - 1; - - double n_sq = pow(n,2); - double n_cubed = pow(n,3); - double M = b * F_0 * ( (1.0 + n + 0.25 * 5 * (n_sq + n_cubed)) * (phi - phi_0) - -(3.0 * (n + n_sq + 0.125 * 7 * n_cubed)) * sin(phi - phi_0) * cos(phi + phi_0) - +(0.125 * 15.0 * (n_sq + n_cubed)) * sin(2.0 * (phi - phi_0)) * cos(2.0 * (phi + phi_0)) - -(35.0/24.0 * n_cubed) * sin(3.0 * (phi - phi_0)) * cos(3.0 * (phi + phi_0)) - ); - double I = M + N_0; - double II = 0.5 * nu * sin(phi) * cos(phi); - double tanphi = tan(phi); - double III = nu * sin(phi) * pow(cos(phi),3.0) * (5.0 - sqr(tanphi)+ 9.0 * eta_sq) / 24.0; - double IIIA = nu * sin(phi) * pow(cos(phi),5.0) * (61.0 - 58.0 * sqr(tanphi) + pow(tanphi,4.0)) / 720.0; - double IV = nu * cos(phi); - double V = nu * pow(cos(phi),3.0) * (nu/rho - sqr(tanphi)) / 6.0; - double VI = nu * pow(cos(phi),5.0) * (5.0 - 18.0 * sqr(tanphi) + pow(tanphi,4) + 14.0 * eta_sq - 58.0 * sqr(tanphi) * eta_sq) / 120.0; - - double E = E_0 + IV * (lambda - lambda_0) + V * pow((lambda - lambda_0),3) + VI * pow((lambda - lambda_0),5); - double N = I + II * pow((lambda - lambda_0),2) + III * pow((lambda - lambda_0),4) + IIIA * pow((lambda - lambda_0),6); - - return Point2f(E,N); +Point2f gps2os(const Point2f &pt) { + // *first*, we have ETRS89 data... + + // Convert it to 3D Cartesian Coordinates + double lambda = M_PI * pt.x / 180.0; + double phi = M_PI * pt.y / 180.0; + + // GRS80 ellipsoid + double a = 6378137.0000; + double b = 6356752.3141; + double e_sq = (sqr(a) - sqr(b)) / sqr(a); + + double nu = a / sqrt(1.0 - e_sq * sqr(sin(phi))); + + double x = nu * cos(phi) * cos(lambda); + double y = nu * cos(phi) * sin(lambda); + double z = (1 - e_sq) * nu * sin(phi); + + // Now we have the ETRS89 location, convert it to a rough OSGB36 location: + + // rough conversion chart + + // t_x (m) t_y (m) t_z (m) s (ppm) r_x (sec) r_y (sec) r_z (sec) + // -446.448 +125.157 -542.060 +20.4894 -0.1502 -0.2470 -0.8421 = (in radians: ) + + // nb, seconds converted to radians: + double r_x = -0.7281901490265230623720509817416e-6; + double r_y = -1.1974897923405539041670878328241e-6; + double r_z = -4.0826160086234026020206666559563e-6; + + x = -446.448 + (1.0 + 2.04894e-5) * x - r_z * y + r_y * z; + y = +125.157 + r_z * x + (1.0 + 2.04894e-5) * y - r_x * z; + z = -542.060 - r_y * x + r_x * y + (1.0 + 2.04894e-5) * z; + + double p = sqrt(sqr(x) + sqr(y)); + + // now place it back in long lat on the OSGB36 ellipsoid: + + // Airy 1830 (OSGB36) ellipsoid + a = 6377563.396; + b = 6356256.910; + e_sq = (sqr(a) - sqr(b)) / sqr(a); + + lambda = atan(y / x); + phi = atan(z / (p * (1.0 - e_sq))); + double lastphi = phi; + + nu = a / sqrt(1.0 - e_sq * sqr(sin(phi))); + do { + phi = atan((z + e_sq * nu * sin(phi)) / p); + } while (fabs(lastphi - phi) > 1e-6); + + // now, it's on the ellipsoid, project it onto the OSGB36 grid: + + // E_0 easting of true origin 400 000m + double E_0 = 400000; + // N_0 northing of true origin -100 000m + double N_0 = -100000; + // F_0 scaling factor on central meridian 0.9996012717 + double F_0 = 0.9996012717; + // lambda_0 longitude of true origin -2.0 radians: -0.034906585039886591538473815369772 + double lambda_0 = -0.034906585039886591538473815369772; + // phi_0 latitude of true origin 49.0 radians: + double phi_0 = 0.85521133347722149269260847655942; + + nu = a * F_0 * pow((1 - e_sq * sqr(sin(phi))), -0.5); + + double n = (a - b) / (a + b); + double rho = a * F_0 * (1.0 - e_sq) * pow((1 - e_sq * sqr(sin(phi))), -1.5); + double eta_sq = nu / rho - 1; + + double n_sq = pow(n, 2); + double n_cubed = pow(n, 3); + double M = b * F_0 * + ((1.0 + n + 0.25 * 5 * (n_sq + n_cubed)) * (phi - phi_0) - + (3.0 * (n + n_sq + 0.125 * 7 * n_cubed)) * sin(phi - phi_0) * cos(phi + phi_0) + + (0.125 * 15.0 * (n_sq + n_cubed)) * sin(2.0 * (phi - phi_0)) * cos(2.0 * (phi + phi_0)) - + (35.0 / 24.0 * n_cubed) * sin(3.0 * (phi - phi_0)) * cos(3.0 * (phi + phi_0))); + double I = M + N_0; + double II = 0.5 * nu * sin(phi) * cos(phi); + double tanphi = tan(phi); + double III = nu * sin(phi) * pow(cos(phi), 3.0) * (5.0 - sqr(tanphi) + 9.0 * eta_sq) / 24.0; + double IIIA = nu * sin(phi) * pow(cos(phi), 5.0) * (61.0 - 58.0 * sqr(tanphi) + pow(tanphi, 4.0)) / 720.0; + double IV = nu * cos(phi); + double V = nu * pow(cos(phi), 3.0) * (nu / rho - sqr(tanphi)) / 6.0; + double VI = nu * pow(cos(phi), 5.0) * + (5.0 - 18.0 * sqr(tanphi) + pow(tanphi, 4) + 14.0 * eta_sq - 58.0 * sqr(tanphi) * eta_sq) / 120.0; + + double E = E_0 + IV * (lambda - lambda_0) + V * pow((lambda - lambda_0), 3) + VI * pow((lambda - lambda_0), 5); + double N = + I + II * pow((lambda - lambda_0), 2) + III * pow((lambda - lambda_0), 4) + IIIA * pow((lambda - lambda_0), 6); + + return Point2f(E, N); } ////////////////////////////////////////////////////////////////////////////////////// static long g_count = 0L; -int bitcount(int a) -{ - int ret = 0; - while (a != 0) { - ret += (a & 1) ? 1 : 0; - a = a >> 1; - } - return ret; +int bitcount(int a) { + int ret = 0; + while (a != 0) { + ret += (a & 1) ? 1 : 0; + a = a >> 1; + } + return ret; } //////////////////////////////////////////////////////////////////////////////////////// @@ -159,210 +160,186 @@ int bitcount(int a) // EdgeU is used for polygon clipping to viewports // are a,b,c in ccw order (true) or cw order (false) -bool ccwEdgeU(const EdgeU& a, const EdgeU& b, const EdgeU& c) -{ - bool ccw = false; - if (c.edge > a.edge || (c.edge == a.edge && c.u > a.u)) { - if (b.edge > a.edge || (b.edge == a.edge && b.u > a.u)) { - if (b.edge < c.edge || (b.edge == c.edge && b.u < c.u)) { +bool ccwEdgeU(const EdgeU &a, const EdgeU &b, const EdgeU &c) { + bool ccw = false; + if (c.edge > a.edge || (c.edge == a.edge && c.u > a.u)) { + if (b.edge > a.edge || (b.edge == a.edge && b.u > a.u)) { + if (b.edge < c.edge || (b.edge == c.edge && b.u < c.u)) { + ccw = true; + } + } + } else { + if (b.edge > a.edge || (b.edge == a.edge && b.u > a.u)) { ccw = true; - } - } - } - else { - if (b.edge > a.edge || (b.edge == a.edge && b.u > a.u)) { - ccw = true; - } - else if (b.edge < c.edge || (b.edge == c.edge && b.u < c.u)) { + } else if (b.edge < c.edge || (b.edge == c.edge && b.u < c.u)) { ccw = true; - } - } - return ccw; + } + } + return ccw; } // EdgeU is used for polygon clipping to viewports // get the actual point from an EdgeU -Point2f QtRegion::getEdgeUPoint(const EdgeU& eu) -{ - switch (eu.edge) { - case 0: - return Point2f(bottom_left.x + (eu.u * width()), bottom_left.y); - case 1: - return Point2f(top_right.x, bottom_left.y + (eu.u * height())); - case 2: - return Point2f(top_right.x - (eu.u * width()), top_right.y); - case 3: - return Point2f(bottom_left.x, top_right.y - (eu.u * height())); - } - return Point2f(); +Point2f QtRegion::getEdgeUPoint(const EdgeU &eu) { + switch (eu.edge) { + case 0: + return Point2f(bottom_left.x + (eu.u * width()), bottom_left.y); + case 1: + return Point2f(top_right.x, bottom_left.y + (eu.u * height())); + case 2: + return Point2f(top_right.x - (eu.u * width()), top_right.y); + case 3: + return Point2f(bottom_left.x, top_right.y - (eu.u * height())); + } + return Point2f(); } // EdgeU is used for polygon clipping to viewports // get where the polygon exits the viewport -EdgeU QtRegion::getCutEdgeU(const Point2f& inside, const Point2f& outside) -{ - EdgeU eu; - if (outside.x < bottom_left.x) { - double y = outside.y + (inside.y - outside.y) * (bottom_left.x - outside.x) / (inside.x-outside.x); - if (y >= bottom_left.y && y <= top_right.y) { - eu.edge = 3; - eu.u = (top_right.y - y) / height(); - } - } - if (eu.edge == -1 && outside.x > top_right.x) { - double y = inside.y + (outside.y - inside.y) * (top_right.x - inside.x) / (outside.x-inside.x); - if (y >= bottom_left.y && y <= top_right.y) { - eu.edge = 1; - eu.u = (y - bottom_left.y) / height(); - } - } - if (eu.edge == -1 && outside.y < bottom_left.y) { - double x = outside.x + (inside.x - outside.x) * (bottom_left.y - outside.y) / (inside.y-outside.y); - if (x >= bottom_left.x && x <= top_right.x) { - eu.edge = 0; - eu.u = (x - bottom_left.x) / width(); - } - } - if (eu.edge == -1 && outside.y > top_right.y) { - double x = inside.x + (outside.x - inside.x) * (top_right.y - inside.y) / (outside.y-inside.y); - if (x >= bottom_left.x && x <= top_right.x) { - eu.edge = 2; - eu.u = (top_right.x - x) / width(); - } - } - // if at this stage eu.edge is still -1 there's a problem! - return eu; +EdgeU QtRegion::getCutEdgeU(const Point2f &inside, const Point2f &outside) { + EdgeU eu; + if (outside.x < bottom_left.x) { + double y = outside.y + (inside.y - outside.y) * (bottom_left.x - outside.x) / (inside.x - outside.x); + if (y >= bottom_left.y && y <= top_right.y) { + eu.edge = 3; + eu.u = (top_right.y - y) / height(); + } + } + if (eu.edge == -1 && outside.x > top_right.x) { + double y = inside.y + (outside.y - inside.y) * (top_right.x - inside.x) / (outside.x - inside.x); + if (y >= bottom_left.y && y <= top_right.y) { + eu.edge = 1; + eu.u = (y - bottom_left.y) / height(); + } + } + if (eu.edge == -1 && outside.y < bottom_left.y) { + double x = outside.x + (inside.x - outside.x) * (bottom_left.y - outside.y) / (inside.y - outside.y); + if (x >= bottom_left.x && x <= top_right.x) { + eu.edge = 0; + eu.u = (x - bottom_left.x) / width(); + } + } + if (eu.edge == -1 && outside.y > top_right.y) { + double x = inside.x + (outside.x - inside.x) * (top_right.y - inside.y) / (outside.y - inside.y); + if (x >= bottom_left.x && x <= top_right.x) { + eu.edge = 2; + eu.u = (top_right.x - x) / width(); + } + } + // if at this stage eu.edge is still -1 there's a problem! + return eu; } ////////////////////////////////////////////////////////////////////////// // union of two regions -QtRegion runion(const QtRegion& a, const QtRegion& b) -{ - QtRegion n; - n.bottom_left.x = a.bottom_left.x < b.bottom_left.x ? - a.bottom_left.x : b.bottom_left.x; - n.bottom_left.y = a.bottom_left.y < b.bottom_left.y ? - a.bottom_left.y : b.bottom_left.y; - n.top_right.x = a.top_right.x > b.top_right.x ? - a.top_right.x : b.top_right.x; - n.top_right.y = a.top_right.y > b.top_right.y ? - a.top_right.y : b.top_right.y; - return n; +QtRegion runion(const QtRegion &a, const QtRegion &b) { + QtRegion n; + n.bottom_left.x = a.bottom_left.x < b.bottom_left.x ? a.bottom_left.x : b.bottom_left.x; + n.bottom_left.y = a.bottom_left.y < b.bottom_left.y ? a.bottom_left.y : b.bottom_left.y; + n.top_right.x = a.top_right.x > b.top_right.x ? a.top_right.x : b.top_right.x; + n.top_right.y = a.top_right.y > b.top_right.y ? a.top_right.y : b.top_right.y; + return n; } // test intersecting regions, touching counts -bool intersect_region(const QtRegion& a, const QtRegion& b, double tolerance) -{ - if (overlap_x(a,b,tolerance) && overlap_y(a,b,tolerance)) { - return true; - } - else { - return false; - } +bool intersect_region(const QtRegion &a, const QtRegion &b, double tolerance) { + if (overlap_x(a, b, tolerance) && overlap_y(a, b, tolerance)) { + return true; + } else { + return false; + } } -bool overlap_x(const QtRegion& a, const QtRegion& b, double tolerance) -{ - if (a.bottom_left.x > b.bottom_left.x) { - if (b.top_right.x >= a.bottom_left.x - tolerance) { - return true; - } - } - else { - if (a.top_right.x >= b.bottom_left.x - tolerance) { - return true; - } - } - return false; +bool overlap_x(const QtRegion &a, const QtRegion &b, double tolerance) { + if (a.bottom_left.x > b.bottom_left.x) { + if (b.top_right.x >= a.bottom_left.x - tolerance) { + return true; + } + } else { + if (a.top_right.x >= b.bottom_left.x - tolerance) { + return true; + } + } + return false; } -bool overlap_y(const QtRegion& a, const QtRegion& b, double tolerance) -{ - if (a.bottom_left.y > b.bottom_left.y) { - if (b.top_right.y >= a.bottom_left.y - tolerance) { - return true; - } - } - else { - if (a.top_right.y >= b.bottom_left.y - tolerance) { - return true; - } - } - return false; +bool overlap_y(const QtRegion &a, const QtRegion &b, double tolerance) { + if (a.bottom_left.y > b.bottom_left.y) { + if (b.top_right.y >= a.bottom_left.y - tolerance) { + return true; + } + } else { + if (a.top_right.y >= b.bottom_left.y - tolerance) { + return true; + } + } + return false; } // line set up // default: nothing: -Line::Line() -{ - bits.parity = 0; - bits.direction = 0; - // Points automatically assigned to 0,0 -} - -Line::Line(const Point2f& a, const Point2f& b) -{ - if (a.x == b.x) { - bottom_left.x = a.x; - top_right.x = b.x; - // vertical lines stored consistently as parity 1 - if (a.y <= b.y) { - bottom_left.y = a.y; - top_right.y = b.y; - bits.parity = 1; - bits.direction = 1; - } - else { - bottom_left.y = b.y; - top_right.y = a.y; - bits.parity = 1; - bits.direction = 0; - } - } - else if (a.x < b.x) { - bottom_left.x = a.x; - top_right.x = b.x; - if (a.y <= b.y) { - bottom_left.y = a.y; - top_right.y = b.y; - bits.parity = 1; - bits.direction = 1; - } - else { - bottom_left.y = b.y; - top_right.y = a.y; - bits.parity = 0; // -1 - bits.direction = 1; - } - } - else { - bottom_left.x = b.x; - top_right.x = a.x; - if (b.y <= a.y) { - bottom_left.y = b.y; - top_right.y = a.y; - bits.parity = 1; - bits.direction = 0; - } - else { - bottom_left.y = a.y; - top_right.y = b.y; - bits.parity = 0; // -1 - bits.direction = 0; - } - } +Line::Line() { + bits.parity = 0; + bits.direction = 0; + // Points automatically assigned to 0,0 +} + +Line::Line(const Point2f &a, const Point2f &b) { + if (a.x == b.x) { + bottom_left.x = a.x; + top_right.x = b.x; + // vertical lines stored consistently as parity 1 + if (a.y <= b.y) { + bottom_left.y = a.y; + top_right.y = b.y; + bits.parity = 1; + bits.direction = 1; + } else { + bottom_left.y = b.y; + top_right.y = a.y; + bits.parity = 1; + bits.direction = 0; + } + } else if (a.x < b.x) { + bottom_left.x = a.x; + top_right.x = b.x; + if (a.y <= b.y) { + bottom_left.y = a.y; + top_right.y = b.y; + bits.parity = 1; + bits.direction = 1; + } else { + bottom_left.y = b.y; + top_right.y = a.y; + bits.parity = 0; // -1 + bits.direction = 1; + } + } else { + bottom_left.x = b.x; + top_right.x = a.x; + if (b.y <= a.y) { + bottom_left.y = b.y; + top_right.y = a.y; + bits.parity = 1; + bits.direction = 0; + } else { + bottom_left.y = a.y; + top_right.y = b.y; + bits.parity = 0; // -1 + bits.direction = 0; + } + } } ////////////////////////////////////////////////////////////////////////////// -double dot(const Line& a, const Line& b) { - return (a.bx() - a.ax()) * (b.bx() - b.ax()) + - (a.by() - a.ay()) * (b.by() - b.ay()); +double dot(const Line &a, const Line &b) { + return (a.bx() - a.ax()) * (b.bx() - b.ax()) + (a.by() - a.ay()) * (b.by() - b.ay()); } // intersection test: touching counts as an intersection @@ -371,256 +348,216 @@ double dot(const Line& a, const Line& b) { // NB You must MUST check that line *regions do not intersect* before using this test // By this test, *all parallel lines intersect* -bool intersect_line(const Line& a, const Line& b, double tolerance) -{ - g_count++; - - if ( ((a.ay() - a.by()) * (b.ax() - a.ax()) + - (a.bx() - a.ax()) * (b.ay() - a.ay())) * - ((a.ay() - a.by()) * (b.bx() - a.ax()) + - (a.bx() - a.ax()) * (b.by() - a.ay())) <= tolerance && - ((b.ay() - b.by()) * (a.ax() - b.ax()) + - (b.bx() - b.ax()) * (a.ay() - b.ay())) * - ((b.ay() - b.by()) * (a.bx() - b.ax()) + - (b.bx() - b.ax()) * (a.by() - b.ay())) <= tolerance) - { - return true; - } - - return false; +bool intersect_line(const Line &a, const Line &b, double tolerance) { + g_count++; + + if (((a.ay() - a.by()) * (b.ax() - a.ax()) + (a.bx() - a.ax()) * (b.ay() - a.ay())) * + ((a.ay() - a.by()) * (b.bx() - a.ax()) + (a.bx() - a.ax()) * (b.by() - a.ay())) <= + tolerance && + ((b.ay() - b.by()) * (a.ax() - b.ax()) + (b.bx() - b.ax()) * (a.ay() - b.ay())) * + ((b.ay() - b.by()) * (a.bx() - b.ax()) + (b.bx() - b.ax()) * (a.by() - b.ay())) <= + tolerance) { + return true; + } + + return false; } // intersection test: touching does not count as an intersection // (uses dot product comparison) -bool intersect_line_no_touch(const Line& a, const Line& b, double tolerance) -{ - g_count++; - - if ( ((a.ay() - a.by()) * (b.ax() - a.ax()) + - (a.bx() - a.ax()) * (b.ay() - a.ay())) * - ((a.ay() - a.by()) * (b.bx() - a.ax()) + - (a.bx() - a.ax()) * (b.by() - a.ay())) < -tolerance && - ((b.ay() - b.by()) * (a.ax() - b.ax()) + - (b.bx() - b.ax()) * (a.ay() - b.ay())) * - ((b.ay() - b.by()) * (a.bx() - b.ax()) + - (b.bx() - b.ax()) * (a.by() - b.ay())) < -tolerance) - { - return true; - } - - return false; +bool intersect_line_no_touch(const Line &a, const Line &b, double tolerance) { + g_count++; + + if (((a.ay() - a.by()) * (b.ax() - a.ax()) + (a.bx() - a.ax()) * (b.ay() - a.ay())) * + ((a.ay() - a.by()) * (b.bx() - a.ax()) + (a.bx() - a.ax()) * (b.by() - a.ay())) < + -tolerance && + ((b.ay() - b.by()) * (a.ax() - b.ax()) + (b.bx() - b.ax()) * (a.ay() - b.ay())) * + ((b.ay() - b.by()) * (a.bx() - b.ax()) + (b.bx() - b.ax()) * (a.by() - b.ay())) < + -tolerance) { + return true; + } + + return false; } // returns 0 for no intersect, 1 for touching and 2 for crossing -int intersect_line_distinguish(const Line& a, const Line& b, double tolerance) -{ - g_count++; - - double alpha = ((a.ay() - a.by()) * (b.ax() - a.ax()) + - (a.bx() - a.ax()) * (b.ay() - a.ay())) * - ((a.ay() - a.by()) * (b.bx() - a.ax()) + - (a.bx() - a.ax()) * (b.by() - a.ay())); - - double beta = ((b.ay() - b.by()) * (a.ax() - b.ax()) + - (b.bx() - b.ax()) * (a.ay() - b.ay())) * - ((b.ay() - b.by()) * (a.bx() - b.ax()) + - (b.bx() - b.ax()) * (a.by() - b.ay())); - - if (alpha <= tolerance && beta <= tolerance) { - if (alpha < -tolerance && beta < -tolerance) { - return 2; - } - else { - return 1; - } - } - - return 0; +int intersect_line_distinguish(const Line &a, const Line &b, double tolerance) { + g_count++; + + double alpha = ((a.ay() - a.by()) * (b.ax() - a.ax()) + (a.bx() - a.ax()) * (b.ay() - a.ay())) * + ((a.ay() - a.by()) * (b.bx() - a.ax()) + (a.bx() - a.ax()) * (b.by() - a.ay())); + + double beta = ((b.ay() - b.by()) * (a.ax() - b.ax()) + (b.bx() - b.ax()) * (a.ay() - b.ay())) * + ((b.ay() - b.by()) * (a.bx() - b.ax()) + (b.bx() - b.ax()) * (a.by() - b.ay())); + + if (alpha <= tolerance && beta <= tolerance) { + if (alpha < -tolerance && beta < -tolerance) { + return 2; + } else { + return 1; + } + } + + return 0; } // returns 0 for no intersect, 1 for touching and 2 for crossing // n.b. only used by polygon contains -- throws if the first point of line b is touching line a // (first point of line b is the point to be tested) -- i.e., throws if point touches polygon -int intersect_line_b(const Line& a, const Line& b, double tolerance) -{ - g_count++; - - double alpha = ((a.ay() - a.by()) * (b.ax() - a.ax()) + - (a.bx() - a.ax()) * (b.ay() - a.ay())); - - double beta = ((a.ay() - a.by()) * (b.bx() - a.ax()) + - (a.bx() - a.ax()) * (b.by() - a.ay())); - - double gamma = ((b.ay() - b.by()) * (a.ax() - b.ax()) + - (b.bx() - b.ax()) * (a.ay() - b.ay())) * - ((b.ay() - b.by()) * (a.bx() - b.ax()) + - (b.bx() - b.ax()) * (a.by() - b.ay())); - - if (alpha * beta <= tolerance && gamma <= tolerance) { - if (alpha * beta < -tolerance && gamma < -tolerance) { - return 2; - } - else { - // this function is only used for poly contains point, - // the throw is defined if the point is *on* the polygon edge - // (within the tolerance) - if (fabs(alpha) <= tolerance) { - throw 1; - } - return 1; - } - } - return 0; -} +int intersect_line_b(const Line &a, const Line &b, double tolerance) { + g_count++; -double Line::intersection_point(const Line& l, int axis, double tolerance) const -{ - // use axis = XAXIS for width() > height() - double loc; - if (axis == XAXIS) { - if (l.width() == 0.0) { - loc = l.bottom_left.x; - } - else { - double lg = l.grad(YAXIS); - double g = grad(YAXIS); - if (fabs(lg - g) <= tolerance) { - // these have almost the same gradient, so it's impossible to tell where they intersect: going for midpoint - Point2f p = l.midpoint(); - loc = (p.x > top_right.x) ? top_right.x : ((p.x < bottom_left.x) ? bottom_left.x : p.x); - } - else { - // this is the same as: constant(YAXIS) - l.constant(YAXIS)) / (l.grad(YAXIS) - grad(YAXIS)); - loc = ((ay() - g * ax()) - (l.ay() - lg * l.ax())) / (lg - g); - } - } - } - else { - if (l.height() == 0.0) { - loc = l.bottom_left.y; - } - else { - double lg = l.grad(XAXIS); - double g = grad(XAXIS); - if (fabs(lg - g) <= tolerance) { - // these have almost the same gradient, so it's impossible to tell where they intersect: going for midpoint - Point2f p = l.midpoint(); - loc = (p.y > top_right.y) ? top_right.y : ((p.y < bottom_left.y) ? bottom_left.y : p.y); - } - else { - // this is the same as: constant(XAXIS) - l.constant(XAXIS)) / (l.grad(XAXIS) - grad(XAXIS)); - loc = ((ax() - g * ay()) - (l.ax() - lg * l.ay())) / (lg - g); - } - } - } - return loc; + double alpha = ((a.ay() - a.by()) * (b.ax() - a.ax()) + (a.bx() - a.ax()) * (b.ay() - a.ay())); + + double beta = ((a.ay() - a.by()) * (b.bx() - a.ax()) + (a.bx() - a.ax()) * (b.by() - a.ay())); + + double gamma = ((b.ay() - b.by()) * (a.ax() - b.ax()) + (b.bx() - b.ax()) * (a.ay() - b.ay())) * + ((b.ay() - b.by()) * (a.bx() - b.ax()) + (b.bx() - b.ax()) * (a.by() - b.ay())); + + if (alpha * beta <= tolerance && gamma <= tolerance) { + if (alpha * beta < -tolerance && gamma < -tolerance) { + return 2; + } else { + // this function is only used for poly contains point, + // the throw is defined if the point is *on* the polygon edge + // (within the tolerance) + if (fabs(alpha) <= tolerance) { + throw 1; + } + return 1; + } + } + return 0; +} + +double Line::intersection_point(const Line &l, int axis, double tolerance) const { + // use axis = XAXIS for width() > height() + double loc; + if (axis == XAXIS) { + if (l.width() == 0.0) { + loc = l.bottom_left.x; + } else { + double lg = l.grad(YAXIS); + double g = grad(YAXIS); + if (fabs(lg - g) <= tolerance) { + // these have almost the same gradient, so it's impossible to tell where they intersect: going for + // midpoint + Point2f p = l.midpoint(); + loc = (p.x > top_right.x) ? top_right.x : ((p.x < bottom_left.x) ? bottom_left.x : p.x); + } else { + // this is the same as: constant(YAXIS) - l.constant(YAXIS)) / (l.grad(YAXIS) - grad(YAXIS)); + loc = ((ay() - g * ax()) - (l.ay() - lg * l.ax())) / (lg - g); + } + } + } else { + if (l.height() == 0.0) { + loc = l.bottom_left.y; + } else { + double lg = l.grad(XAXIS); + double g = grad(XAXIS); + if (fabs(lg - g) <= tolerance) { + // these have almost the same gradient, so it's impossible to tell where they intersect: going for + // midpoint + Point2f p = l.midpoint(); + loc = (p.y > top_right.y) ? top_right.y : ((p.y < bottom_left.y) ? bottom_left.y : p.y); + } else { + // this is the same as: constant(XAXIS) - l.constant(XAXIS)) / (l.grad(XAXIS) - grad(XAXIS)); + loc = ((ax() - g * ay()) - (l.ax() - lg * l.ay())) / (lg - g); + } + } + } + return loc; } // intersecting line segments, touching counts // (uses intersection point comparison) -bool Line::intersect_line(const Line& l, int axis, double& loc) const -{ - // please be intelligent when passing the axis... - if (axis == XAXIS) { - if (l.width() == 0.0) { - // Special case: - double y = ay() + sign() * (l.ax() - ax()) * height() / width(); - if (y >= bottom_left.y && y <= l.top_right.y) { // <- you must have checked - loc = l.bottom_left.x; // the regions overlap first - return true; - } - return false; - } - else { - // Standard: (note: if m1 == m2, loc is NaN) - loc = (constant(YAXIS) - l.constant(YAXIS)) / (l.grad(YAXIS) - grad(YAXIS)); - if (std::isnan(loc)) { - // lines are parallel --- are they coincident? - // you must have checked the regions overlap first - if (constant(YAXIS) == l.constant(YAXIS)) { - return true; +bool Line::intersect_line(const Line &l, int axis, double &loc) const { + // please be intelligent when passing the axis... + if (axis == XAXIS) { + if (l.width() == 0.0) { + // Special case: + double y = ay() + sign() * (l.ax() - ax()) * height() / width(); + if (y >= bottom_left.y && y <= l.top_right.y) { // <- you must have checked + loc = l.bottom_left.x; // the regions overlap first + return true; } - } - else if (loc >= l.bottom_left.x && loc <= l.top_right.x) { - return true; - } - return false; - } - } - else { - if (l.height() == 0.0) { - // Special case: - double x = ax() + sign() * (l.ay() - ay()) * width() / height(); - if (x >= bottom_left.x && x <= top_right.x) { // <- you must have checked - loc = l.bottom_left.y; // the regions overlap first - return true; - } - return false; - } - else { - // Standard: (note: if m1 == m2, loc is NaN) - loc = (constant(XAXIS) - l.constant(XAXIS)) / (l.grad(XAXIS) - grad(XAXIS)); - if (std::isnan(loc)) { - // lines are parallel --- are they coincident? - // you must have checked the regions overlap first - if (constant(XAXIS) == l.constant(XAXIS)) { - return true; + } else { + // Standard: (note: if m1 == m2, loc is NaN) + loc = (constant(YAXIS) - l.constant(YAXIS)) / (l.grad(YAXIS) - grad(YAXIS)); + if (std::isnan(loc)) { + // lines are parallel --- are they coincident? + // you must have checked the regions overlap first + if (constant(YAXIS) == l.constant(YAXIS)) { + return true; + } + } else if (loc >= l.bottom_left.x && loc <= l.top_right.x) { + return true; } - } - else if (loc >= l.bottom_left.y && loc <= l.top_right.y) { - return true; - } - return false; - } - } - return false; + } + } else { + if (l.height() == 0.0) { + // Special case: + double x = ax() + sign() * (l.ay() - ay()) * width() / height(); + if (x >= bottom_left.x && x <= top_right.x) { // <- you must have checked + loc = l.bottom_left.y; // the regions overlap first + return true; + } + } else { + // Standard: (note: if m1 == m2, loc is NaN) + loc = (constant(XAXIS) - l.constant(XAXIS)) / (l.grad(XAXIS) - grad(XAXIS)); + if (std::isnan(loc)) { + // lines are parallel --- are they coincident? + // you must have checked the regions overlap first + if (constant(XAXIS) == l.constant(XAXIS)) { + return true; + } + } else if (loc >= l.bottom_left.y && loc <= l.top_right.y) { + return true; + } + } + } + return false; } // this converts the loc back into a point: -Point2f Line::point_on_line(double loc, int axis) const -{ - Point2f p; - if (axis == XAXIS) { - p = Point2f(loc, grad(YAXIS) * loc + constant(YAXIS)); - } - else { - p = Point2f(grad(XAXIS) * loc + constant(XAXIS), loc); - } - return p; +Point2f Line::point_on_line(double loc, int axis) const { + Point2f p; + if (axis == XAXIS) { + p = Point2f(loc, grad(YAXIS) * loc + constant(YAXIS)); + } else { + p = Point2f(grad(XAXIS) * loc + constant(XAXIS), loc); + } + return p; } ////////////////////////////////////////////////////////////////////////////// // distance from a point to a line segment -double dist(const Point2f& point, const Line& line) -{ - double d = 0.0; - - Point2f alpha = line.end() - line.start(); - Point2f beta = point - line.end(); - Point2f gamma = line.start() - line.end(); - Point2f delta = point - line.start(); - - if (dot(alpha,beta) > 0) { - d = beta.length(); - } - else if (dot(gamma,delta) > 0) { - d = delta.length(); - } - else { - if (alpha.length() < 1e-9 * beta.length()) { - // should actually be a user-specified tolerance test - d = beta.length(); - } - else { - d = fabs(det(alpha,beta)) / alpha.length(); - } - } - return d; +double dist(const Point2f &point, const Line &line) { + double d = 0.0; + + Point2f alpha = line.end() - line.start(); + Point2f beta = point - line.end(); + Point2f gamma = line.start() - line.end(); + Point2f delta = point - line.start(); + + if (dot(alpha, beta) > 0) { + d = beta.length(); + } else if (dot(gamma, delta) > 0) { + d = delta.length(); + } else { + if (alpha.length() < 1e-9 * beta.length()) { + // should actually be a user-specified tolerance test + d = beta.length(); + } else { + d = fabs(det(alpha, beta)) / alpha.length(); + } + } + return d; } /* @@ -633,63 +570,53 @@ double dist(const Point2f& point, const Line& line) // intersection test -bool intersect(const RegionTree& a, const RegionTree& b) -{ - if (a.is_leaf() && b.is_leaf()) { - if (intersect_region( QtRegion(a), QtRegion(b))) { - return intersect_line( (const Line&) QtRegion(a), (const Line&) QtRegion(b) ); - } - else { - return false; - } - } - else { - if (intersect_region( QtRegion(a), QtRegion(b))) { - return subintersect(a, b); - } - else { - return false; - } - } -} - -bool subintersect(const RegionTree& a, const RegionTree& b) -{ - if (intersect(a.left(),b.left())) { - return true; - } - else if (intersect(a.right(),b.right())) { - return true; - } - else if (intersect(a.left(),b.right())) { - return true; - } - else if (intersect(a.right(),b.left())) { - return true; - } - - return false; +bool intersect(const RegionTree &a, const RegionTree &b) { + if (a.is_leaf() && b.is_leaf()) { + if (intersect_region(QtRegion(a), QtRegion(b))) { + return intersect_line((const Line &)QtRegion(a), (const Line &)QtRegion(b)); + } else { + return false; + } + } else { + if (intersect_region(QtRegion(a), QtRegion(b))) { + return subintersect(a, b); + } else { + return false; + } + } +} + +bool subintersect(const RegionTree &a, const RegionTree &b) { + if (intersect(a.left(), b.left())) { + return true; + } else if (intersect(a.right(), b.right())) { + return true; + } else if (intersect(a.left(), b.right())) { + return true; + } else if (intersect(a.right(), b.left())) { + return true; + } + + return false; } // Intersection count -int intersections(const RegionTree& a, const Line& b) -{ - int n = 0; - - if (!a.is_leaf()) { - if (intersect_region( QtRegion(a), QtRegion(b))) { - n += intersections(a.left(), b); - n += intersections(a.right(), b); - } - } - else { - // Note: touching lines count 1, non-touching lines count 2, this allows through - // vertex lines (where it touches both vertices) - n += intersect_line_b( (const Line&) a, (const Line&) b ); - } - - return n; +int intersections(const RegionTree &a, const Line &b) { + int n = 0; + + if (!a.is_leaf()) { + if (intersect_region(QtRegion(a), QtRegion(b))) { + n += intersections(a.left(), b); + n += intersections(a.right(), b); + } + } else { + // Note: touching lines count 1, non-touching lines count 2, this allows through + // vertex lines (where it touches both vertices) + n += intersect_line_b((const Line &)a, (const Line &)b); + } + + return n; } ////////////////////////////////////////////////////////////////////////////// @@ -697,441 +624,267 @@ int intersections(const RegionTree& a, const Line& b) // crop a line to fit within bounds of region // if line lies outside region, returns false -bool Line::crop(const QtRegion& r) -{ - if (bx() >= r.bottom_left.x) { - if (ax() < r.bottom_left.x) { - // crop! - ay() += sign() * (height() * (r.bottom_left.x - ax()) / width()); - ax() = r.bottom_left.x; - } - if (ax() <= r.top_right.x) { - if (bx() > r.top_right.x) { +bool Line::crop(const QtRegion &r) { + if (bx() >= r.bottom_left.x) { + if (ax() < r.bottom_left.x) { // crop! - by() -= sign() * height() * (bx() - r.top_right.x) / width(); - bx() = r.top_right.x; - } - if (top_right.y >= r.bottom_left.y) { - if (bottom_left.y < r.bottom_left.y) { - // crop! - if (bits.parity) { - ax() += width() * (r.bottom_left.y - bottom_left.y) / height(); - } - else { - bx() -= width() * (r.bottom_left.y - bottom_left.y) / height(); - } - bottom_left.y = r.bottom_left.y; + ay() += sign() * (height() * (r.bottom_left.x - ax()) / width()); + ax() = r.bottom_left.x; + } + if (ax() <= r.top_right.x) { + if (bx() > r.top_right.x) { + // crop! + by() -= sign() * height() * (bx() - r.top_right.x) / width(); + bx() = r.top_right.x; } - if (bottom_left.y <= r.top_right.y) { - if (top_right.y > r.top_right.y) { - // crop! - if (bits.parity) { - bx() -= width() * (top_right.y - r.top_right.y) / height(); - } - else { - ax() += width() * (top_right.y - r.top_right.y) / height(); - } - top_right.y = r.top_right.y; - } - // if we got this far, well done, it's in the region: - return true; + if (top_right.y >= r.bottom_left.y) { + if (bottom_left.y < r.bottom_left.y) { + // crop! + if (bits.parity) { + ax() += width() * (r.bottom_left.y - bottom_left.y) / height(); + } else { + bx() -= width() * (r.bottom_left.y - bottom_left.y) / height(); + } + bottom_left.y = r.bottom_left.y; + } + if (bottom_left.y <= r.top_right.y) { + if (top_right.y > r.top_right.y) { + // crop! + if (bits.parity) { + bx() -= width() * (top_right.y - r.top_right.y) / height(); + } else { + ax() += width() * (top_right.y - r.top_right.y) / height(); + } + top_right.y = r.top_right.y; + } + // if we got this far, well done, it's in the region: + return true; + } } - } - } - } - // returns false if the entire line is outside the region: - return false; + } + } + // returns false if the entire line is outside the region: + return false; } // cast a ray to the edge of a box -void Line::ray(short dir, const QtRegion& r) -{ - if (dir == bits.direction) { - if (width() >= height()) { - by() = ay() + sign() * height() * (r.top_right.x - ax()) / width(); - bx() = r.top_right.x; - } - else if (bits.parity) { - bx() = ax() + width() * (r.top_right.y - ay()) / height(); - by() = r.top_right.y; - } - else { - bx() = ax() + width() * (ay() - r.bottom_left.y) / height(); - by() = r.bottom_left.y; - } - } - else { - if (width() >= height()) { - ay() = by() - sign() * height() * (bx() - r.bottom_left.x) / width(); - ax() = r.bottom_left.x; - } - else if (bits.parity) { - ax() = bx() - width() * (by() - r.bottom_left.y) / height(); - ay() = r.bottom_left.y; - } - else { - ax() = bx() - width() * (r.top_right.y - by()) / height(); - ay() = r.top_right.y; - } - } - // now fit within bounds... - crop(r); +void Line::ray(short dir, const QtRegion &r) { + if (dir == bits.direction) { + if (width() >= height()) { + by() = ay() + sign() * height() * (r.top_right.x - ax()) / width(); + bx() = r.top_right.x; + } else if (bits.parity) { + bx() = ax() + width() * (r.top_right.y - ay()) / height(); + by() = r.top_right.y; + } else { + bx() = ax() + width() * (ay() - r.bottom_left.y) / height(); + by() = r.bottom_left.y; + } + } else { + if (width() >= height()) { + ay() = by() - sign() * height() * (bx() - r.bottom_left.x) / width(); + ax() = r.bottom_left.x; + } else if (bits.parity) { + ax() = bx() - width() * (by() - r.bottom_left.y) / height(); + ay() = r.bottom_left.y; + } else { + ax() = bx() - width() * (r.top_right.y - by()) / height(); + ay() = r.top_right.y; + } + } + // now fit within bounds... + crop(r); } ////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// +// Polygon set up (the hard bit!) -// Binary Space Partition - -void BSPNode::make(Communicator *communicator, comm_time_t atime, const prefvec& lines, BSPNode *par) -{ - m_count++; - - if (communicator) - { - if (communicator->IsCancelled()) { - throw Communicator::CancelledException(); - } - if (qtimer( atime, 500 )) { - communicator->CommPostMessage( Communicator::CURRENT_RECORD, m_count ); - } - } - - prefvec leftlines; - prefvec rightlines; - - parent = par; - - // for optimization of the tree (this reduced a six-minute gen time to a 38 second gen time) - size_t chosen = paftl::npos; - if (lines.size() > 3) { - size_t i; - Point2f midpoint; - for (i = 0; i < lines.size(); i++) { - midpoint += lines[i].line.start() + lines[i].line.end(); - } - midpoint /= 2.0 * lines.size(); - bool ver = true; - if (par && par->line.height() > par->line.width()) { - ver = false; - } - double chosendist = -1.0; - for (i = 0; i < lines.size(); i++) { - const Line& line = lines[i].line; - if (ver) { - if (line.height() > line.width() && (chosen == paftl::npos || dist(line.midpoint(),midpoint) < chosendist)) { - chosen = i; - chosendist = dist(line.midpoint(),midpoint); - } - } - else { - if (line.width() > line.height() && (chosen == paftl::npos || dist(line.midpoint(),midpoint) < chosendist)) { - chosen = i; - chosendist = dist(line.midpoint(),midpoint); - } - } - } - // argh... and again... there weren't any hoz / ver: - if (chosen == paftl::npos) { - for (size_t i = 0; i < lines.size(); i++) { - if (chosen == paftl::npos || dist(lines[i].line.midpoint(),midpoint) < chosendist) { - chosen = i; - chosendist = dist(lines[i].line.midpoint(),midpoint); +void Poly::add_line_segment(const Line &l) { + m_line_segments++; + RegionTreeLeaf *leaf = new RegionTreeLeaf(l); + + if (m_p_root == NULL) { + // first ever node + + m_p_root = (RegionTree *)leaf; + } else { + // traverse the tree to the insertion point + // you'll just have to take my word for it that the next line + // gives you the correct position to insert + int cut_level = bitcount(m_line_segments - 1) - 2; + + if (cut_level < 0) { + // replace the root node + + QtRegion new_region = runion(QtRegion(*m_p_root), QtRegion(*leaf)); + RegionTree *new_root = new RegionTreeBranch(new_region, *m_p_root, *leaf); + m_p_root = new_root; + } else { + RegionTree *here = m_p_root; + for (int i = 0; i < cut_level; i++) { + here = here->m_p_right; } - } - } - } - else { - chosen = pafrand() % lines.size(); - } - - line = lines[chosen].line; - m_tag = lines[chosen].tag; - - Point2f v0 = line.end() - line.start(); - v0.normalise(); - - for (size_t i = 0; i < lines.size(); i++) { - if (i == chosen) { - continue; - } - const Line& testline = lines[i].line; - int tag = lines[i].tag; - Point2f v1 = testline.start()-line.start(); - v1.normalise(); - Point2f v2 = testline.end()-line.start(); - v2.normalise(); - // should use approxeq here: - double a = testline.start() == line.start() ? 0 : det(v0,v1); - double b = testline.end() == line.start() ? 0 : det(v0,v2); - // note sure what to do if a == 0 and b == 0 (i.e., it's parallel... this test at least ensures on the line is one or the other side) - if (a >= 0 && b >= 0) { - leftlines.push_back(TaggedLine(testline,tag)); - } - else if (a <= 0 && b <= 0) { - rightlines.push_back(TaggedLine(testline,tag)); - } - else { - Point2f p = intersection_point(line,testline); - Line x = Line(testline.start(),p); - Line y = Line(p,testline.end()); - if (a >= 0) { - if (x.length() > 0.0) // should use a tolerance here too - leftlines.push_back(TaggedLine(x,tag)); - if (y.length() > 0.0) // should use a tolerance here too - rightlines.push_back(TaggedLine(y,tag)); - } - else { - if (x.length() > 0.0) // should use a tolerance here too - rightlines.push_back(TaggedLine(x,tag)); - if (y.length() > 0.0) // should use a tolerance here too - leftlines.push_back(TaggedLine(y,tag)); - } - } - } - - if (leftlines.size()) { - left = new BSPNode(); - left->make(communicator,atime,leftlines,this); - } - if (rightlines.size()) { - right = new BSPNode(); - right->make(communicator,atime,rightlines,this); - } -} -int BSPNode::classify(const Point2f& p) -{ - Point2f v0 = line.end() - line.start(); - v0.normalise(); - Point2f v1 = p - line.start(); - v1.normalise(); - if (det(v0,v1) >= 0) { - return BSPLEFT; - } - else { - return BSPRIGHT; - } -} + // cut and insert -////////////////////////////////////////////////////////////////////////////// + RegionTree &insertion_point = here->right(); -// Polygon set up (the hard bit!) + QtRegion new_region = runion(QtRegion(insertion_point), QtRegion(*leaf)); + + RegionTree *new_node = new RegionTreeBranch(new_region, insertion_point, *leaf); -void Poly::add_line_segment(const Line& l) -{ - m_line_segments++; - RegionTreeLeaf *leaf = new RegionTreeLeaf( l ); - - if (m_p_root == NULL) - { - // first ever node - - m_p_root = (RegionTree *) leaf; - } - else - { - // traverse the tree to the insertion point - // you'll just have to take my word for it that the next line - // gives you the correct position to insert - int cut_level = bitcount(m_line_segments - 1) - 2; - - if (cut_level < 0) - { - // replace the root node - - QtRegion new_region = - runion( QtRegion(*m_p_root), QtRegion(*leaf) ); - RegionTree *new_root = - new RegionTreeBranch( new_region, *m_p_root, *leaf ); - m_p_root = new_root; - } - else - { - RegionTree *here = m_p_root; - for (int i = 0; i < cut_level; i++) { - here = here->m_p_right; - } - - // cut and insert - - RegionTree& insertion_point = here->right(); - - QtRegion new_region = - runion( QtRegion(insertion_point), QtRegion(*leaf) ); - - RegionTree *new_node = - new RegionTreeBranch( new_region, insertion_point, *leaf ); - - here->m_p_right = new_node; - - // traverse up tree unioning regions - // (saving data by not recording parents!) - // Note must be '>=' to catch current root node --- I really stuffed up earlier with '>'! - while (cut_level >= 0) - { - here = m_p_root; - for (int j = 0; j < cut_level; j++) { - here = here->m_p_right; + here->m_p_right = new_node; + + // traverse up tree unioning regions + // (saving data by not recording parents!) + // Note must be '>=' to catch current root node --- I really stuffed up earlier with '>'! + while (cut_level >= 0) { + here = m_p_root; + for (int j = 0; j < cut_level; j++) { + here = here->m_p_right; + } + here->m_p_region = new Line(runion(QtRegion(here->left()), QtRegion(here->right()))); + cut_level--; } - here->m_p_region = new Line( - runion(QtRegion(here->left()), QtRegion(here->right())) ); - cut_level--; - } - } - } + } + } } // ...and after all the efficient stuff, we have a really // inefficient polygon copy... hmm -RegionTree *Poly::copy_region_tree( const RegionTree* tree ) -{ - if ( !tree ) { - return NULL; - } - - RegionTree *newtree; - - if (tree->is_leaf()) { - newtree = new RegionTreeLeaf(); - newtree->m_p_region = new Line( *(tree->m_p_region) ); - return newtree; - } - else { - newtree = new RegionTreeBranch(); - } - - pvector newlist; - pvector oldlist; - - oldlist.push_back( (RegionTree *) tree ); - newlist.push_back( (RegionTree *) newtree ); - - do { - RegionTree *oldnode = oldlist.tail(); oldlist.pop_back(); - RegionTree *newnode = newlist.tail(); newlist.pop_back(); - - newnode->m_p_region = new Line( *oldnode->m_p_region ); - - if (oldnode->m_p_left) { - if (oldnode->m_p_left->is_leaf()) { - newnode->m_p_left = new RegionTreeLeaf(); - newnode->m_p_left->m_p_region = - new Line( *(oldnode->m_p_left->m_p_region) ); - } - else { - oldlist.push_back( oldnode->m_p_left ); - newnode->m_p_left = new RegionTreeBranch(); - newlist.push_back( newnode->m_p_left ); - } - } - if (oldnode->m_p_right) { - if (oldnode->m_p_right->is_leaf()) { - newnode->m_p_right = new RegionTreeLeaf(); - newnode->m_p_right->m_p_region = - new Line( *(oldnode->m_p_right->m_p_region) ); - } - else { - oldlist.push_back( oldnode->m_p_right ); - newnode->m_p_right = new RegionTreeBranch(); - newlist.push_back( newnode->m_p_right ); - } - } - - } while (oldlist.size() > 0); - - return newtree; +RegionTree *Poly::copy_region_tree(const RegionTree *tree) { + if (!tree) { + return NULL; + } + + RegionTree *newtree; + + if (tree->is_leaf()) { + newtree = new RegionTreeLeaf(); + newtree->m_p_region = new Line(*(tree->m_p_region)); + return newtree; + } else { + newtree = new RegionTreeBranch(); + } + + std::vector newlist; + std::vector oldlist; + + oldlist.push_back((RegionTree *)tree); + newlist.push_back((RegionTree *)newtree); + + do { + RegionTree *oldnode = oldlist.back(); + oldlist.pop_back(); + RegionTree *newnode = newlist.back(); + newlist.pop_back(); + + newnode->m_p_region = new Line(*oldnode->m_p_region); + + if (oldnode->m_p_left) { + if (oldnode->m_p_left->is_leaf()) { + newnode->m_p_left = new RegionTreeLeaf(); + newnode->m_p_left->m_p_region = new Line(*(oldnode->m_p_left->m_p_region)); + } else { + oldlist.push_back(oldnode->m_p_left); + newnode->m_p_left = new RegionTreeBranch(); + newlist.push_back(newnode->m_p_left); + } + } + if (oldnode->m_p_right) { + if (oldnode->m_p_right->is_leaf()) { + newnode->m_p_right = new RegionTreeLeaf(); + newnode->m_p_right->m_p_region = new Line(*(oldnode->m_p_right->m_p_region)); + } else { + oldlist.push_back(oldnode->m_p_right); + newnode->m_p_right = new RegionTreeBranch(); + newlist.push_back(newnode->m_p_right); + } + } + + } while (oldlist.size() > 0); + + return newtree; } // polygon destruction -void Poly::destroy_region_tree() -{ - if ( !m_p_root ) { - return; - } +void Poly::destroy_region_tree() { + if (!m_p_root) { + return; + } - pvector del_node_list; - pvector del_node_dir; + std::vector del_node_list; + std::vector del_node_dir; - del_node_list.push_back( m_p_root ); + del_node_list.push_back(m_p_root); - do { - RegionTree *current_node = del_node_list.tail(); + do { + RegionTree *current_node = del_node_list.back(); - if (current_node->m_p_left == current_node && - current_node->m_p_right == current_node) { + if (current_node->m_p_left == current_node && current_node->m_p_right == current_node) { - delete current_node; - del_node_list.pop_back(); + delete current_node; + del_node_list.pop_back(); - if (del_node_list.size() > 0) { - if (del_node_dir.tail() == 0) { - del_node_list.tail()->m_p_left = del_node_list.tail(); - del_node_dir.pop_back(); + if (del_node_list.size() > 0) { + if (del_node_dir.back() == 0) { + del_node_list.back()->m_p_left = del_node_list.back(); + del_node_dir.pop_back(); + } else { + del_node_list.back()->m_p_right = del_node_list.back(); + del_node_dir.pop_back(); + } } - else { - del_node_list.tail()->m_p_right = del_node_list.tail(); - del_node_dir.pop_back(); + } else { + if (current_node->m_p_right == NULL) { + current_node->m_p_right = current_node; + } else if (current_node->m_p_right != current_node) { + del_node_list.push_back(current_node->m_p_right); + del_node_dir.push_back(1); + } else { + del_node_list.push_back(current_node->m_p_left); + del_node_dir.push_back(0); } - } - } - else { - if (current_node->m_p_right == NULL) { - current_node->m_p_right = current_node; - } - else if (current_node->m_p_right != current_node) { - del_node_list.push_back( current_node->m_p_right ); - del_node_dir.push_back( 1 ); - } - else { - del_node_list.push_back( current_node->m_p_left ); - del_node_dir.push_back( 0 ); - } - } - } - while (del_node_list.size() > 0); - - m_p_root = NULL; + } + } while (del_node_list.size() > 0); + + m_p_root = NULL; } // contains? intersects?? // Here they are! -bool Poly::contains( const Point2f& p ) -{ - // n.b., intersections throws on some accidental alignments -- - // we must use a point outside the polygon to extend our test - // line from to prevent them - Line l( p, Point2f( get_bounding_box().top_right.x + get_bounding_box().width(), - get_bounding_box().top_right.y + get_bounding_box().height()) ); - - int double_n; - - // note, touching intersections count 1/2 - try { - double_n = intersections( *(m_p_root), l ); - } - catch (int) { - throw 1; // throws if on edge - } - - if (double_n % 2 == 0 && double_n % 4 != 0) { - return true; - } - - return false; -} +bool Poly::contains(const Point2f &p) { + // n.b., intersections throws on some accidental alignments -- + // we must use a point outside the polygon to extend our test + // line from to prevent them + Line l(p, Point2f(get_bounding_box().top_right.x + get_bounding_box().width(), + get_bounding_box().top_right.y + get_bounding_box().height())); -bool intersect( const Poly& a, const Poly& b ) -{ - if ( intersect( *(a.m_p_root), *(b.m_p_root)) ) { - return true; - } - return false; + int double_n; + + // note, touching intersections count 1/2 + try { + double_n = intersections(*(m_p_root), l); + } catch (int) { + throw 1; // throws if on edge + } + + if (double_n % 2 == 0 && double_n % 4 != 0) { + return true; + } + + return false; } +bool intersect(const Poly &a, const Poly &b) { + if (intersect(*(a.m_p_root), *(b.m_p_root))) { + return true; + } + return false; +} diff --git a/genlib/p2dpoly.h b/genlib/p2dpoly.h index de58f17f..38c3716d 100644 --- a/genlib/p2dpoly.h +++ b/genlib/p2dpoly.h @@ -14,31 +14,36 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . - // 2d poly (own format, adapted from the original Sala libraries // The idea is that from this format, // we can read into Cosmo3d as well as Sala based applications -#ifndef __P2DPOLY_H__ -#define __P2DPOLY_H__ +#pragma once // Using doubles right the way through can really eat memory for isovist // polygon files, thus we use a defined type, change as appropriate: +#include "genlib/comm.h" // communicator used in BSP tree construction +#include "genlib/pafmath.h" + #include -#include -#include // communicator used in BSP tree construction -#include // has to be compatible with DXF file parser types // Note: code depends on XAXIS being 0 and YAXIS being 1 --- do not change -enum { - NOAXIS = -1, XAXIS = 0, YAXIS = 1 -}; - -class Point2f; -struct Line; -class QtRegion; +enum { NOAXIS = -1, XAXIS = 0, YAXIS = 1 }; + +class Point2f; +bool approxeq(const Point2f &p1, const Point2f &p2, double tolerance = 0.0); +class QtRegion; +bool intersect_region(const QtRegion &a, const QtRegion &b, double tolerance = 0.0); +bool overlap_x(const QtRegion &a, const QtRegion &b, double tolerance = 0.0); +bool overlap_y(const QtRegion &a, const QtRegion &b, double tolerance = 0.0); +class Line; +bool intersect_line(const Line &a, const Line &b, double tolerance = 0.0); +bool intersect_line_no_touch(const Line &a, const Line &b, double tolerance = 0.0); +int intersect_line_distinguish(const Line &a, const Line &b, double tolerance = 0.0); +int intersect_line_b(const Line &a, const Line &b, double tolerance = 0.0); +Point2f intersection_point(const Line &a, const Line &b, double tolerance = 0.0); // NaN on Intel: // Quick mod - TV @@ -47,236 +52,215 @@ class QtRegion; // Point -class Point2f -{ -public: - double x; - double y; - Point2f() -// { x = P2DNULL; y = P2DNULL; } - { x = 0.0; y = 0.0; } - Point2f(double a, double b) - { x = a; y = b; } - Point2f(const DxfVertex& p) - { x = p.x; y = p.y; } - bool isNull() const -// { return x == P2DNULL || y == P2DNULL; } - { return x == 0.0 && y == 0.0; } - void normalScale( const QtRegion& ); // inline function: below region - void denormalScale( const QtRegion& ); - void operator += (const Point2f& p) - { x += p.x; y += p.y; } - void operator -= (const Point2f& p) - { x -= p.x; y -= p.y; } - void operator *= (const double s) - { x *= s; y *= s; } - void operator /= (const double s) - { x /= s; y /= s; } - double& operator [] (int i) - { return (i == XAXIS) ? x : y; } - const double& operator [] (int i) const - { return (i == XAXIS) ? x : y; } - friend Point2f operator - (Point2f& p); - friend Point2f operator + (const Point2f& p1, const Point2f& p2); - friend Point2f operator - (const Point2f& p1, const Point2f& p2); - friend bool operator == (const Point2f& p1, const Point2f& p2); - friend bool operator != (const Point2f& p1, const Point2f& p2); - friend bool operator > (const Point2f& a, const Point2f& b); - friend bool operator < (const Point2f& a, const Point2f& b); - friend Point2f operator * (const double s, const Point2f& p); - friend Point2f operator / (const Point2f& p, const double s); - friend double dot(const Point2f& p1, const Point2f& p2); - friend double det(const Point2f& p1, const Point2f& p2); - friend double dist(const Point2f& p1, const Point2f& p2); - friend double dist(const Point2f& point, const Line& line); - friend double angle(const Point2f& p1, const Point2f& p2, const Point2f& p3); - friend bool approxeq(const Point2f& p1, const Point2f& p2, double tolerance = 0.0); - friend Point2f pointfromangle(double angle); - // a couple of useful tests - bool intriangle(const Point2f& p1, const Point2f& p2, const Point2f& p3); - bool insegment(const Point2f& key, const Point2f& p2, const Point2f& p3, double tolerance = 0.0); - // for OS transformation (note: accurate only to 5 metres according to OS) - Point2f longlat2os(const Point2f& p); -public: - // A few simple vector ops: - double length() const - { return (double) sqrt(x * x + y * y); } - Point2f& scale(const double scalar) - { x *= scalar; y *= scalar; return *this; } - Point2f& scale(const Point2f& scalevec) - { x *= scalevec.x; y *= scalevec.y; return *this; } - Point2f& normalise() - { return scale( 1.0 / length() ); } - Point2f& rotate(const double angle) - { double t = x; - x = x * cos(angle) - y * sin(angle); - y = y * cos(angle) + t * sin(angle); - return *this; } - double angle() const - { return (y < 0) ? (2.0 * M_PI - acos(x)) : acos(x); } +class Point2f { + public: + double x; + double y; + Point2f() + // { x = P2DNULL; y = P2DNULL; } + { + x = 0.0; + y = 0.0; + } + Point2f(double a, double b) { + x = a; + y = b; + } + bool atZero() const + // { return x == P2DNULL || y == P2DNULL; } + { + return x == 0.0 && y == 0.0; + } + void normalScale(const QtRegion &); // inline function: below region + void denormalScale(const QtRegion &); + void operator+=(const Point2f &p) { + x += p.x; + y += p.y; + } + void operator-=(const Point2f &p) { + x -= p.x; + y -= p.y; + } + void operator*=(const double s) { + x *= s; + y *= s; + } + void operator/=(const double s) { + x /= s; + y /= s; + } + double &operator[](int i) { return (i == XAXIS) ? x : y; } + const double &operator[](int i) const { return (i == XAXIS) ? x : y; } + friend Point2f operator-(Point2f &p); + friend Point2f operator+(const Point2f &p1, const Point2f &p2); + friend Point2f operator-(const Point2f &p1, const Point2f &p2); + friend bool operator==(const Point2f &p1, const Point2f &p2); + friend bool operator!=(const Point2f &p1, const Point2f &p2); + friend bool operator>(const Point2f &a, const Point2f &b); + friend bool operator<(const Point2f &a, const Point2f &b); + friend Point2f operator*(const double s, const Point2f &p); + friend Point2f operator/(const Point2f &p, const double s); + friend double dot(const Point2f &p1, const Point2f &p2); + friend double det(const Point2f &p1, const Point2f &p2); + friend double dist(const Point2f &p1, const Point2f &p2); + friend double dist(const Point2f &point, const Line &line); + friend double angle(const Point2f &p1, const Point2f &p2, const Point2f &p3); + friend bool approxeq(const Point2f &p1, const Point2f &p2, double tolerance); + friend Point2f pointfromangle(double angle); + // a couple of useful tests + bool intriangle(const Point2f &p1, const Point2f &p2, const Point2f &p3); + bool insegment(const Point2f &key, const Point2f &p2, const Point2f &p3, double tolerance = 0.0); + // for OS transformation (note: accurate only to 5 metres according to OS) + Point2f longlat2os(const Point2f &p); + + public: + // A few simple vector ops: + double length() const { return (double)sqrt(x * x + y * y); } + Point2f &scale(const double scalar) { + x *= scalar; + y *= scalar; + return *this; + } + Point2f &scale(const Point2f &scalevec) { + x *= scalevec.x; + y *= scalevec.y; + return *this; + } + Point2f &normalise() { return scale(1.0 / length()); } + Point2f &rotate(const double angle) { + double t = x; + x = x * cos(angle) - y * sin(angle); + y = y * cos(angle) + t * sin(angle); + return *this; + } + double angle() const { return (y < 0) ? (2.0 * M_PI - acos(x)) : acos(x); } }; -typedef pqvector pvecpoint; +inline Point2f operator-(Point2f &p) { return Point2f(-p.x, -p.y); } -inline Point2f operator - (Point2f& p) -{ - return Point2f(-p.x, -p.y); -} +inline Point2f operator+(const Point2f &p1, const Point2f &p2) { return Point2f(p1.x + p2.x, p1.y + p2.y); } -inline Point2f operator + (const Point2f& p1, const Point2f& p2) -{ - return Point2f(p1.x + p2.x, p1.y + p2.y); -} +inline Point2f operator-(const Point2f &p1, const Point2f &p2) { return Point2f(p1.x - p2.x, p1.y - p2.y); } -inline Point2f operator - (const Point2f& p1, const Point2f& p2) -{ - return Point2f(p1.x - p2.x, p1.y - p2.y); -} +inline bool operator==(const Point2f &p1, const Point2f &p2) { return (p1.x == p2.x && p1.y == p2.y); } +inline bool operator!=(const Point2f &p1, const Point2f &p2) { return (p1.x != p2.x || p1.y != p2.y); } +inline bool operator>(const Point2f &p1, const Point2f &p2) { return (p1.x > p2.x || (p1.x == p2.x && p1.y > p2.y)); } +inline bool operator<(const Point2f &p1, const Point2f &p2) { return (p1.x < p2.x || (p1.x == p2.x && p1.y < p2.y)); } -inline bool operator == (const Point2f& p1, const Point2f& p2) -{ return (p1.x == p2.x && p1.y == p2.y); } -inline bool operator != (const Point2f& p1, const Point2f& p2) -{ return (p1.x != p2.x || p1.y != p2.y); } -inline bool operator > (const Point2f& p1, const Point2f& p2) -{ return (p1.x > p2.x || (p1.x == p2.x && p1.y > p2.y)); } -inline bool operator < (const Point2f& p1, const Point2f& p2) -{ return (p1.x < p2.x || (p1.x == p2.x && p1.y < p2.y)); } - -inline Point2f operator * (const double s, const Point2f& p) -{ - return Point2f(s * p.x, s * p.y); -} +inline Point2f operator*(const double s, const Point2f &p) { return Point2f(s * p.x, s * p.y); } -inline Point2f operator / (const Point2f& p, const double s) -{ - return Point2f(p.x / s, p.y / s); -} +inline Point2f operator/(const Point2f &p, const double s) { return Point2f(p.x / s, p.y / s); } -inline double dot(const Point2f& p1, const Point2f& p2) -{ - return (p1.x * p2.x + p1.y * p2.y); -} +inline double dot(const Point2f &p1, const Point2f &p2) { return (p1.x * p2.x + p1.y * p2.y); } // greater than 0 => p2 left (anticlockwise) of p1, less than 0 => p2 right (clockwise) of p1 -inline double det(const Point2f& p1, const Point2f& p2) -{ - return (p1.x * p2.y - p1.y * p2.x); -} - -inline double dist(const Point2f& p1, const Point2f& p2) -{ - return sqrt(sqr(p1.x - p2.x) + sqr(p1.y - p2.y)); -} - -inline double angle(const Point2f& p1, const Point2f& p2, const Point2f& p3) -{ - Point2f a = p1 - p2; - Point2f b = p3 - p2; - a.normalise(); - b.normalise(); - // ensure in range (f.p. error can throw out) - double d = std::min(std::max(dot(a,b),-1.0),1.0); - return (sgn(det(a,b)) == 1) ? acos(d) : 2.0 * M_PI - acos(d); +inline double det(const Point2f &p1, const Point2f &p2) { return (p1.x * p2.y - p1.y * p2.x); } + +inline double dist(const Point2f &p1, const Point2f &p2) { return sqrt(sqr(p1.x - p2.x) + sqr(p1.y - p2.y)); } + +inline double angle(const Point2f &p1, const Point2f &p2, const Point2f &p3) { + Point2f a = p1 - p2; + Point2f b = p3 - p2; + a.normalise(); + b.normalise(); + // ensure in range (f.p. error can throw out) + double d = std::min(std::max(dot(a, b), -1.0), 1.0); + return (sgn(det(a, b)) == 1) ? acos(d) : 2.0 * M_PI - acos(d); } -inline bool approxeq(const Point2f& p1, const Point2f& p2, double tolerance) -{ - return (fabs(p1.x - p2.x) <= tolerance && fabs(p1.y - p2.y) <= tolerance); +inline bool approxeq(const Point2f &p1, const Point2f &p2, double tolerance) { + return (fabs(p1.x - p2.x) <= tolerance && fabs(p1.y - p2.y) <= tolerance); } -inline bool Point2f::insegment(const Point2f& key, const Point2f& p2, const Point2f& p3, double tolerance) -{ - Point2f va = p2 - key; - Point2f vb = p3 - key; - Point2f vp = *this - key; - double ap = det(va,vp); - double bp = det(vb,vp); - if ((dot(va,vp) > 0 && dot(vb,vp) > 0) && (sgn(ap) != sgn(bp) || fabs(ap) < tolerance || fabs(bp) < tolerance) ) { - return true; - } - return false; +inline bool Point2f::insegment(const Point2f &key, const Point2f &p2, const Point2f &p3, double tolerance) { + Point2f va = p2 - key; + Point2f vb = p3 - key; + Point2f vp = *this - key; + double ap = det(va, vp); + double bp = det(vb, vp); + if ((dot(va, vp) > 0 && dot(vb, vp) > 0) && (sgn(ap) != sgn(bp) || fabs(ap) < tolerance || fabs(bp) < tolerance)) { + return true; + } + return false; } -inline bool Point2f::intriangle(const Point2f& p1, const Point2f& p2, const Point2f& p3) -{ - // touching counts - int test = sgn(det(p2-p1,*this-p1)); - if (test == sgn(det(p3-p2,*this-p2)) && test == sgn(det(p1-p3,*this-p3))) { - return true; - } - return false; +inline bool Point2f::intriangle(const Point2f &p1, const Point2f &p2, const Point2f &p3) { + // touching counts + int test = sgn(det(p2 - p1, *this - p1)); + if (test == sgn(det(p3 - p2, *this - p2)) && test == sgn(det(p1 - p3, *this - p3))) { + return true; + } + return false; } -inline Point2f pointfromangle(double angle) -{ - Point2f p; - p.x = cos(angle); - p.y = sin(angle); - return p; +inline Point2f pointfromangle(double angle) { + Point2f p; + p.x = cos(angle); + p.y = sin(angle); + return p; } -Point2f gps2os(const Point2f& p); +Point2f gps2os(const Point2f &p); // an event is a point plus time (as in spacetime technical language) -class Event2f : public Point2f -{ -public: - double t; // time in seconds - Event2f() : Point2f() - { t = 0.0; } - Event2f(double _x, double _y, double _t) : Point2f(_x,_y) - { t = _t; } - Event2f(Point2f& _p) : Point2f(_p) - { t = 0.0; } - Event2f(Point2f& _p, double _t) : Point2f(_p) - { t = _t; } +class Event2f : public Point2f { + public: + double t; // time in seconds + Event2f() : Point2f() { t = 0.0; } + Event2f(double _x, double _y, double _t) : Point2f(_x, _y) { t = _t; } + Event2f(Point2f &_p) : Point2f(_p) { t = 0.0; } + Event2f(Point2f &_p, double _t) : Point2f(_p) { t = _t; } }; /////////////////////////////////////////////////////////////////////////////////////////// -class Point3f -{ -public: - double x; - double y; - double z; - Point3f(double a = 0.0, double b = 0.0, double c = 0.0) - { x = a; y = b; z = c;} - Point3f(const Point2f& p) - { x = p.x; y = 0.0; z = p.y; } // Note! not z = -y (due to an incosistency earlier...) - bool inside( const Point3f& bl, const Point3f& tr ) // now inclusive (...) - { return (x >= bl.x && y >= bl.y && z >= bl.z && x <= tr.x && y <= tr.y && z <= tr.z); } - operator Point2f() - { return Point2f( x, z ); } // Note! not x, -z (due to an inconsistency earlier...) - Point2f xy() - { return Point2f(x, y); } // From the x, y plane - // A few simple vector ops: - double length() const - { return (double) sqrt(x * x + y * y + z * z); } - Point3f& scale(const double scalar) - { x *= scalar; y *= scalar; z *= scalar; return *this; } - Point3f& normalise() - { return scale( 1.0 / length() ); } - Point3f& rotate(double theta, double phi) - { double t = x; +class Point3f { + public: + double x; + double y; + double z; + Point3f(double a = 0.0, double b = 0.0, double c = 0.0) { + x = a; + y = b; + z = c; + } + Point3f(const Point2f &p) { + x = p.x; + y = 0.0; + z = p.y; + } // Note! not z = -y (due to an incosistency earlier...) + bool inside(const Point3f &bl, const Point3f &tr) // now inclusive (...) + { + return (x >= bl.x && y >= bl.y && z >= bl.z && x <= tr.x && y <= tr.y && z <= tr.z); + } + operator Point2f() { return Point2f(x, z); } // Note! not x, -z (due to an inconsistency earlier...) + Point2f xy() { return Point2f(x, y); } // From the x, y plane + // A few simple vector ops: + double length() const { return (double)sqrt(x * x + y * y + z * z); } + Point3f &scale(const double scalar) { + x *= scalar; + y *= scalar; + z *= scalar; + return *this; + } + Point3f &normalise() { return scale(1.0 / length()); } + Point3f &rotate(double theta, double phi) { + double t = x; x = t * cos(theta) - y * sin(theta); y = y * cos(theta) + t * sin(theta); t = x; x = t * cos(phi) - z * sin(phi); z = z * cos(phi) - t * sin(phi); - return *this; } - // - friend double dot(const Point3f& a, const Point3f& b); - friend Point3f cross(const Point3f& a, const Point3f& b); + return *this; + } + // + friend double dot(const Point3f &a, const Point3f &b); + friend Point3f cross(const Point3f &a, const Point3f &b); }; -inline double dot(const Point3f& a, const Point3f& b) -{ - return (a.x * b.x + a.y * b.y + a.z * b.z); -} -inline Point3f cross(const Point3f& a, const Point3f& b) -{ - return Point3f( a.y * b.z - b.y * a.z, a.z * b.x - b.z * a.x, a.x * b.y - b.x * a.y ); +inline double dot(const Point3f &a, const Point3f &b) { return (a.x * b.x + a.y * b.y + a.z * b.z); } +inline Point3f cross(const Point3f &a, const Point3f &b) { + return Point3f(a.y * b.z - b.y * a.z, a.z * b.x - b.z * a.x, a.x * b.y - b.x * a.y); } // @@ -286,231 +270,259 @@ inline Point3f cross(const Point3f& a, const Point3f& b) // used for clipping of polygons to regions struct EdgeU { - int edge; - double u; - EdgeU(int e = -1, double _u = 0.0) - { edge = e; u = _u; } - EdgeU(const EdgeU& eu) - { edge = eu.edge; u = eu.u; } - friend bool ccwEdgeU(const EdgeU& a, const EdgeU& b, const EdgeU& c); + int edge; + double u; + EdgeU(int e = -1, double _u = 0.0) { + edge = e; + u = _u; + } + EdgeU(const EdgeU &eu) { + edge = eu.edge; + u = eu.u; + } + friend bool ccwEdgeU(const EdgeU &a, const EdgeU &b, const EdgeU &c); }; // QtRegion -class QtRegion -{ -public: - Point2f bottom_left; - Point2f top_right; - QtRegion(const Point2f& bl = Point2f(), const Point2f& tr = Point2f()) - { bottom_left = bl; top_right = tr; } - QtRegion(const QtRegion& r) - { bottom_left = r.bottom_left; top_right = r.top_right; } - QtRegion& operator = (const QtRegion& r) - { bottom_left = r.bottom_left; top_right = r.top_right; return *this; } - // - double height() const - { return top_right.y - bottom_left.y; } - double width() const - // The assumption that top_right.x is always > bottom_left.x is not always true. - // Returning a negative value here causes an infinite loop at axialmap.cpp line 3106 - // after overlapdist is assigned a negative value at axialmap.cpp line 3084. - // height() above could also be changed for this reason, but this is a band-aid - // fix for the real problem, which is why the top_right > bottom_left assumption - // is assumed to be 100% valid but is, in some instances, not valid. - // { return top_right.x - bottom_left.x; } - { return fabs(top_right.x - bottom_left.x); } - double area() const - { return height() * width(); } - void normalScale( const QtRegion& r ) - { top_right.normalScale(r); bottom_left.normalScale(r); } - void denormalScale( const QtRegion& r ) - { top_right.denormalScale(r); bottom_left.denormalScale(r); } - void scale( const Point2f& scalevec ) - { top_right.scale(scalevec); bottom_left.scale(scalevec); } - void offset( const Point2f& offset ) - { top_right += offset; bottom_left += offset; } - Point2f getCentre() const - { return Point2f( (bottom_left.x + top_right.x) / 2.0, - (bottom_left.y + top_right.y) / 2.0 ); } - // - bool contains ( const Point2f& p ) const - { return (p.x > bottom_left.x && p.x < top_right.x && p.y > bottom_left.y && p.y < top_right.y); } - bool contains_touch ( const Point2f& p ) const - { return (p.x >= bottom_left.x && p.x <= top_right.x && p.y >= bottom_left.y && p.y <= top_right.y); } - void encompass( const Point2f& p ) - { if (p.x < bottom_left.x) bottom_left.x = p.x; if (p.x > top_right.x) top_right.x = p.x; - if (p.y < bottom_left.y) bottom_left.y = p.y; if (p.y > top_right.y) top_right.y = p.y; } - // - bool isNull() const - { return bottom_left.isNull() || top_right.isNull(); } - // - Point2f getEdgeUPoint(const EdgeU& eu); - EdgeU getCutEdgeU(const Point2f& inside, const Point2f& outside); - // - friend bool intersect_region(const QtRegion& a, const QtRegion& b, double tolerance = 0.0); - friend bool overlap_x(const QtRegion& a, const QtRegion& b, double tolerance = 0.0); - friend bool overlap_y(const QtRegion& a, const QtRegion& b, double tolerance = 0.0); - // - // set functions - friend QtRegion runion(const QtRegion& a, const QtRegion& b); - friend QtRegion rintersect( const QtRegion& a, const QtRegion& b); // undefined? - // - void grow(const double scalar) - { Point2f dim = top_right - bottom_left; - dim.scale(scalar - 1.0); - top_right += dim; - bottom_left -= dim; } +class QtRegion { + public: + Point2f bottom_left; + Point2f top_right; + QtRegion(const Point2f &bl = Point2f(), const Point2f &tr = Point2f()) { + bottom_left = bl; + top_right = tr; + } + QtRegion(const QtRegion &r) { + bottom_left = r.bottom_left; + top_right = r.top_right; + } + QtRegion &operator=(const QtRegion &r) { + bottom_left = r.bottom_left; + top_right = r.top_right; + return *this; + } + // + double height() const { return top_right.y - bottom_left.y; } + double width() const + // The assumption that top_right.x is always > bottom_left.x is not always true. + // Returning a negative value here causes an infinite loop at axialmap.cpp line 3106 + // after overlapdist is assigned a negative value at axialmap.cpp line 3084. + // height() above could also be changed for this reason, but this is a band-aid + // fix for the real problem, which is why the top_right > bottom_left assumption + // is assumed to be 100% valid but is, in some instances, not valid. + // { return top_right.x - bottom_left.x; } + { + return fabs(top_right.x - bottom_left.x); + } + double area() const { return height() * width(); } + void normalScale(const QtRegion &r) { + top_right.normalScale(r); + bottom_left.normalScale(r); + } + void denormalScale(const QtRegion &r) { + top_right.denormalScale(r); + bottom_left.denormalScale(r); + } + void scale(const Point2f &scalevec) { + top_right.scale(scalevec); + bottom_left.scale(scalevec); + } + void offset(const Point2f &offset) { + top_right += offset; + bottom_left += offset; + } + Point2f getCentre() const { + return Point2f((bottom_left.x + top_right.x) / 2.0, (bottom_left.y + top_right.y) / 2.0); + } + // + bool contains(const Point2f &p) const { + return (p.x > bottom_left.x && p.x < top_right.x && p.y > bottom_left.y && p.y < top_right.y); + } + bool contains_touch(const Point2f &p) const { + return (p.x >= bottom_left.x && p.x <= top_right.x && p.y >= bottom_left.y && p.y <= top_right.y); + } + void encompass(const Point2f &p) { + if (p.x < bottom_left.x) + bottom_left.x = p.x; + if (p.x > top_right.x) + top_right.x = p.x; + if (p.y < bottom_left.y) + bottom_left.y = p.y; + if (p.y > top_right.y) + top_right.y = p.y; + } + // + bool atZero() const { return bottom_left.atZero() || top_right.atZero(); } + // + Point2f getEdgeUPoint(const EdgeU &eu); + EdgeU getCutEdgeU(const Point2f &inside, const Point2f &outside); + // + friend bool intersect_region(const QtRegion &a, const QtRegion &b, double tolerance); + friend bool overlap_x(const QtRegion &a, const QtRegion &b, double tolerance); + friend bool overlap_y(const QtRegion &a, const QtRegion &b, double tolerance); + // + // set functions + friend QtRegion runion(const QtRegion &a, const QtRegion &b); + friend QtRegion rintersect(const QtRegion &a, const QtRegion &b); // undefined? + // + void grow(const double scalar) { + Point2f dim = top_right - bottom_left; + dim.scale(scalar - 1.0); + top_right += dim; + bottom_left -= dim; + } }; // First time we have a region available to use... -inline void Point2f::normalScale( const QtRegion& r ) -{ - if(r.width()) x = (x - r.bottom_left.x) / r.width(); - else x = 0.0; - if(r.height()) y = (y - r.bottom_left.y) / r.height(); - else y = 0.0; +inline void Point2f::normalScale(const QtRegion &r) { + if (r.width()) + x = (x - r.bottom_left.x) / r.width(); + else + x = 0.0; + if (r.height()) + y = (y - r.bottom_left.y) / r.height(); + else + y = 0.0; } -inline void Point2f::denormalScale( const QtRegion& r ) -{ - x = x * r.width() + r.bottom_left.x; - y = y * r.height() + r.bottom_left.y; +inline void Point2f::denormalScale(const QtRegion &r) { + x = x * r.width() + r.bottom_left.x; + y = y * r.height() + r.bottom_left.y; } // Lines are stored left to right as regions, // the parity tells us whether the region should be inverted // top to bottom to get the line -class Line : public QtRegion -{ -protected: - struct Bits { - char parity : 8; // 1 ... positive, 0 ... negative - char direction : 8; // 1 ... positive, 0 ... negative -#ifndef _WIN32 - int z_dummy : 32; -#endif - }; - Bits bits; -public: - Line(); - Line(const Point2f& a, const Point2f& b); - Line(const QtRegion& r) : QtRegion(r) - { bits.parity = 1; bits.direction = 1; } - Line(const Line& l) : QtRegion(l) - { bits = l.bits; } - Line& operator = (const Line& l) - { this->QtRegion::operator = (l); bits = l.bits; return *this; } - // - friend bool intersect_line(const Line& a, const Line& b, double tolerance = 0.0); - friend bool intersect_line_no_touch(const Line& a, const Line& b, double tolerance = 0.0); - friend int intersect_line_distinguish(const Line& a, const Line& b, double tolerance = 0.0); - friend int intersect_line_b(const Line& a, const Line& b, double tolerance = 0.0); - // - // fills in the location along the axis where the intersection happens - bool intersect_line(const Line& l, int axis, double& loc) const; - double intersection_point(const Line& l, int axis, double tolerance = 0.0) const; - // this converts a loc retrieved from intersect line or intersection point back into a point: - Point2f point_on_line(double loc, int axis) const; - // ...and a quick do it all in one go: - friend Point2f intersection_point(const Line& a, const Line& b, double tolerance = 0.0); - // - bool crop(const QtRegion& r); - void ray(short dir, const QtRegion& r); - // - friend double dot(const Line& a, const Line& b); - // - double ax() const { return bottom_left.x; } - double& ax() { return bottom_left.x; } - double bx() const { return top_right.x; } - double& bx() { return top_right.x; } - double ay() const { return bits.parity ? bottom_left.y : top_right.y; } - double& ay() { return bits.parity ? bottom_left.y : top_right.y; } - double by() const { return bits.parity ? top_right.y : bottom_left.y; } - double& by() { return bits.parity ? top_right.y : bottom_left.y; } - // - const Point2f start() const - { return Point2f( bottom_left.x, (bits.parity ? bottom_left.y : top_right.y) ); } - const Point2f end() const - { return Point2f( top_right.x, (bits.parity ? top_right.y : bottom_left.y) ); } - const Point2f midpoint() const - { return Point2f( (start() + end()) / 2); } - // - // helpful to have a user friendly indication of direction: - bool rightward() const - { return bits.direction == 1; } - bool upward() const - { return bits.direction == bits.parity; } - // - const Point2f t_start() const - { return Point2f( (rightward() ? bottom_left.x : top_right.x), (upward() ? bottom_left.y : top_right.y) ); } - const Point2f t_end() const - { return Point2f( (rightward() ? top_right.x : bottom_left.x), (upward() ? top_right.y : bottom_left.y) ); } - // - short sign() const - { return bits.parity ? 1 : -1; } - // - double grad(int axis) const { - return (axis == YAXIS) ? sign() * height() / width() : sign() * width() / height(); - } - double constant(int axis) const { - return (axis == YAXIS) ? ay() - grad(axis) * ax() : ax() - grad(axis) * ay(); - } - // - double length() const - { return (double) sqrt((top_right.x - bottom_left.x) * (top_right.x - bottom_left.x) + - (top_right.y - bottom_left.y) * (top_right.y - bottom_left.y)); } - // - short direction() const - { return bits.direction; } - Point2f vector() const - { return t_end() - t_start(); } +class Line : public QtRegion { + protected: + struct Bits { + Bits() : x_dummy(0), y_dummy(0), z_dummy(0) {} + char parity : 8; // 1 ... positive, 0 ... negative + char direction : 8; // 1 ... positive, 0 ... negative + + // dummy variables as it seems to be necessary that the width of this struct is 8 bytes + // and I don't want any uninitialised memory that gets written to file accidentally + char x_dummy : 8; + char y_dummy : 8; + int z_dummy : 32; + }; + Bits bits; + + public: + Line(); + Line(const Point2f &a, const Point2f &b); + Line(const QtRegion &r) : QtRegion(r) { + bits.parity = 1; + bits.direction = 1; + } + Line(const Line &l) : QtRegion(l) { bits = l.bits; } + Line &operator=(const Line &l) { + this->QtRegion::operator=(l); + bits = l.bits; + return *this; + } + // + friend bool intersect_line(const Line &a, const Line &b, double tolerance); + friend bool intersect_line_no_touch(const Line &a, const Line &b, double tolerance); + friend int intersect_line_distinguish(const Line &a, const Line &b, double tolerance); + friend int intersect_line_b(const Line &a, const Line &b, double tolerance); + // + // fills in the location along the axis where the intersection happens + bool intersect_line(const Line &l, int axis, double &loc) const; + double intersection_point(const Line &l, int axis, double tolerance = 0.0) const; + // this converts a loc retrieved from intersect line or intersection point back into a point: + Point2f point_on_line(double loc, int axis) const; + // ...and a quick do it all in one go: + friend Point2f intersection_point(const Line &a, const Line &b, double tolerance); + // + bool crop(const QtRegion &r); + void ray(short dir, const QtRegion &r); + // + friend double dot(const Line &a, const Line &b); + // + double ax() const { return bottom_left.x; } + double &ax() { return bottom_left.x; } + double bx() const { return top_right.x; } + double &bx() { return top_right.x; } + double ay() const { return bits.parity ? bottom_left.y : top_right.y; } + double &ay() { return bits.parity ? bottom_left.y : top_right.y; } + double by() const { return bits.parity ? top_right.y : bottom_left.y; } + double &by() { return bits.parity ? top_right.y : bottom_left.y; } + // + const Point2f start() const { return Point2f(bottom_left.x, (bits.parity ? bottom_left.y : top_right.y)); } + const Point2f end() const { return Point2f(top_right.x, (bits.parity ? top_right.y : bottom_left.y)); } + const Point2f midpoint() const { return Point2f((start() + end()) / 2); } + // + // helpful to have a user friendly indication of direction: + bool rightward() const { return bits.direction == 1; } + bool upward() const { return bits.direction == bits.parity; } + // + const Point2f t_start() const { + return Point2f((rightward() ? bottom_left.x : top_right.x), (upward() ? bottom_left.y : top_right.y)); + } + const Point2f t_end() const { + return Point2f((rightward() ? top_right.x : bottom_left.x), (upward() ? top_right.y : bottom_left.y)); + } + // + short sign() const { return bits.parity ? 1 : -1; } + // + double grad(int axis) const { return (axis == YAXIS) ? sign() * height() / width() : sign() * width() / height(); } + double constant(int axis) const { return (axis == YAXIS) ? ay() - grad(axis) * ax() : ax() - grad(axis) * ay(); } + // + double length() const { + return (double)sqrt((top_right.x - bottom_left.x) * (top_right.x - bottom_left.x) + + (top_right.y - bottom_left.y) * (top_right.y - bottom_left.y)); + } + // + short direction() const { return bits.direction; } + Point2f vector() const { return t_end() - t_start(); } }; -inline Point2f intersection_point(const Line& a, const Line& b, double tolerance) -{ - int axis = (a.width() >= a.height()) ? XAXIS : YAXIS; - return a.point_on_line(a.intersection_point(b,axis,tolerance),axis); +inline Point2f intersection_point(const Line &a, const Line &b, double tolerance) { + int axis = (a.width() >= a.height()) ? XAXIS : YAXIS; + return a.point_on_line(a.intersection_point(b, axis, tolerance), axis); } -typedef prefvec pvecline; - //////////////////////////////////////////////////////////////////////////////////////// -struct TaggedLine -{ - Line line; - int tag; - TaggedLine(const Line& l = Line(),int t = -1) { line = l; tag = t; } +struct TaggedLine { + Line line; + int tag; + TaggedLine(const Line &l = Line(), int t = -1) { + line = l; + tag = t; + } }; -// Binary Space Partition - -struct BSPNode -{ -public: - enum { BSPLEFT, BSPRIGHT }; - BSPNode *left; - BSPNode *right; - BSPNode *parent; - Line line; - int m_tag; - int m_count; - // -public: - BSPNode() - { left = NULL; right = NULL; parent = NULL; m_count = 0; m_tag = -1; } - virtual ~BSPNode() - { if (left) delete left; left = NULL; if (right) delete right; right = NULL; } - // - bool isLeaf() { - return left == NULL && right == NULL; - } - void make(Communicator *communicator, comm_time_t atime, const prefvec& lines, BSPNode *par); - int classify(const Point2f& p); - const Line& getLine() const { return line; } - const int getTag() const { return m_tag; } +// plain 2-point line without regions +struct SimpleLine { + public: + SimpleLine(const Line &line) { + m_start.x = line.t_start().x; + m_start.y = line.t_start().y; + m_end.x = line.t_end().x; + m_end.y = line.t_end().y; + } + SimpleLine(const Point2f &a, const Point2f &b) { + m_start.x = a.x; + m_start.y = a.y; + m_end.x = b.x; + m_end.y = b.y; + } + SimpleLine(double x1, double y1, double x2, double y2) { + m_start.x = x1; + m_start.y = y1; + m_end.x = x2; + m_end.y = y2; + } + const Point2f &start() const { return m_start; } + const Point2f &end() const { return m_end; } + + private: + Point2f m_start; + Point2f m_end; }; //////////////////////////////////////////////////////////////////////////////////////// @@ -520,117 +532,99 @@ struct BSPNode // Now the difficult bit: making the line segments into polygons... // The polygons are stored in a tree format so that intersection testing is easier -class RegionTree -{ -friend class Poly; -protected: - Line *m_p_region; - RegionTree *m_p_left; - RegionTree *m_p_right; -public: - RegionTree() - { m_p_region = NULL; m_p_left = this; m_p_right = this; } - virtual ~RegionTree() - { if (m_p_region) delete m_p_region; } - // - virtual bool is_leaf() const = 0; - // - RegionTree& left() const - { return *m_p_left; } - RegionTree& right() const - { return *m_p_right; } - // - operator QtRegion() const - { return *(QtRegion *)m_p_region; } - operator Line() const - { return *(Line *)m_p_region; } - // - friend bool intersect(const RegionTree& a, const RegionTree& b); - friend bool subintersect(const RegionTree& a, const RegionTree& b); - friend int intersections(const RegionTree& a, const Line& b); +class RegionTree { + friend class Poly; + + protected: + Line *m_p_region; + RegionTree *m_p_left; + RegionTree *m_p_right; + + public: + RegionTree() { + m_p_region = NULL; + m_p_left = this; + m_p_right = this; + } + virtual ~RegionTree() { + if (m_p_region) + delete m_p_region; + } + // + virtual bool is_leaf() const = 0; + // + RegionTree &left() const { return *m_p_left; } + RegionTree &right() const { return *m_p_right; } + // + operator QtRegion() const { return *(QtRegion *)m_p_region; } + operator Line() const { return *(Line *)m_p_region; } + // + friend bool intersect(const RegionTree &a, const RegionTree &b); + friend bool subintersect(const RegionTree &a, const RegionTree &b); + friend int intersections(const RegionTree &a, const Line &b); }; // Branch on a region tree... -class RegionTreeBranch : public RegionTree -{ -public: - RegionTreeBranch() : RegionTree() {;} - RegionTreeBranch( const Line& r, - const RegionTree& a, - const RegionTree& b ) - { - m_p_left = (RegionTree *) &a; - m_p_right = (RegionTree *) &b; - m_p_region = new Line(r); // copy - } - virtual bool is_leaf() const - { return false; } +class RegionTreeBranch : public RegionTree { + public: + RegionTreeBranch() : RegionTree() { ; } + RegionTreeBranch(const Line &r, const RegionTree &a, const RegionTree &b) { + m_p_left = (RegionTree *)&a; + m_p_right = (RegionTree *)&b; + m_p_region = new Line(r); // copy + } + virtual bool is_leaf() const { return false; } }; // Leaf on a region tree... -class RegionTreeLeaf : public RegionTree -{ -public: - RegionTreeLeaf() : RegionTree() {;} - RegionTreeLeaf(const Line &l) - { - // no subnodes (but nice recursive properties) - m_p_left = this; - m_p_right = this; - m_p_region = new Line(l); - } - virtual bool is_leaf() const - { return true; } +class RegionTreeLeaf : public RegionTree { + public: + RegionTreeLeaf() : RegionTree() { ; } + RegionTreeLeaf(const Line &l) { + // no subnodes (but nice recursive properties) + m_p_left = this; + m_p_right = this; + m_p_region = new Line(l); + } + virtual bool is_leaf() const { return true; } }; -class Poly -{ -protected: - int m_line_segments; - RegionTree *m_p_root; -public: - Poly() - { - m_p_root = NULL; m_line_segments = 0; - } - Poly( const Poly& p ) - { - m_line_segments = p.m_line_segments; - m_p_root = copy_region_tree( p.m_p_root ); - } - Poly& operator = (const Poly& p) - { - if (this != &p) { - m_line_segments = p.m_line_segments; - m_p_root = copy_region_tree( p.m_p_root ); - } - return *this; - } - virtual ~Poly() - { - destroy_region_tree(); - } - // essentially, the copy constructor... - RegionTree *copy_region_tree( const RegionTree* tree ); - // essentially, the destructor... - void destroy_region_tree(); - // - RegionTree& get_region_tree() const - { - return *m_p_root; - } - // - void add_line_segment(const Line& l); - // - int get_line_segments() - { return m_line_segments; } - QtRegion get_bounding_box() - { return *(QtRegion *)(m_p_root->m_p_region); } - // - bool contains( const Point2f& p ); - friend bool intersect( const Poly& a, const Poly& b ); +class Poly { + protected: + int m_line_segments; + RegionTree *m_p_root; + + public: + Poly() { + m_p_root = NULL; + m_line_segments = 0; + } + Poly(const Poly &p) { + m_line_segments = p.m_line_segments; + m_p_root = copy_region_tree(p.m_p_root); + } + Poly &operator=(const Poly &p) { + if (this != &p) { + m_line_segments = p.m_line_segments; + m_p_root = copy_region_tree(p.m_p_root); + } + return *this; + } + virtual ~Poly() { destroy_region_tree(); } + // essentially, the copy constructor... + RegionTree *copy_region_tree(const RegionTree *tree); + // essentially, the destructor... + void destroy_region_tree(); + // + RegionTree &get_region_tree() const { return *m_p_root; } + // + void add_line_segment(const Line &l); + // + int get_line_segments() { return m_line_segments; } + QtRegion get_bounding_box() { return *(QtRegion *)(m_p_root->m_p_region); } + // + bool contains(const Point2f &p); + friend bool intersect(const Poly &a, const Poly &b); }; - -#endif diff --git a/genlib/pafmath.cpp b/genlib/pafmath.cpp index c3140940..b896c844 100644 --- a/genlib/pafmath.cpp +++ b/genlib/pafmath.cpp @@ -14,25 +14,25 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . - - // a collection of math functions +#include "pafmath.h" + +#include #include -#include -uint64 g_rand[11] = {1,2,3,5,7,11,13,17,19,23,29}; +uint64_t g_rand[11] = {1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29}; // 25-Jul-2007: changed the g_mult and g_const used for random number generation // for some reason, there appeared to be a pattern to the numbers // Quick mod - TV -const uint64 g_mult = /*(0xF9561B2E << 32) + */0x71A7FA85; -const uint64 g_const = /*(0x9BB3920E << 32) + */0xF5E958B9; +const uint64_t g_mult = /*(0xF9561B2E << 32) + */ 0x71A7FA85; +const uint64_t g_const = /*(0x9BB3920E << 32) + */ 0xF5E958B9; void pafsrand(unsigned int seed, int set) // = 0 { - g_rand[set] = seed; + g_rand[set] = seed; } // Pafrand is a Linear Congruential Generator @@ -48,47 +48,44 @@ void pafsrand(unsigned int seed, int set) // = 0 unsigned int pafrand(int set) // = 0 { - g_rand[set] = g_mult * g_rand[set] + g_const; + g_rand[set] = g_mult * g_rand[set] + g_const; - return (unsigned int)((g_rand[set] >> 32) & PAF_RAND_MAX); + return (unsigned int)((g_rand[set] >> 32) & PAF_RAND_MAX); } /////////////////////////////////////////////////////////////////////////////// -double poisson(int x, double lambda) -{ - double f = exp(-lambda); - for (int i = 1; i <= x; i++) { - f *= lambda / double(i); - } - return f; +double poisson(int x, double lambda) { + double f = exp(-lambda); + for (int i = 1; i <= x; i++) { + f *= lambda / double(i); + } + return f; } -double cumpoisson(int x, double lambda) -{ - double f = exp(-lambda); - double c = f; - for (int i = 1; i <= x; i++) { - f *= lambda / double(i); - c += f; - } - return c; +double cumpoisson(int x, double lambda) { + double f = exp(-lambda); + double c = f; + for (int i = 1; i <= x; i++) { + f *= lambda / double(i); + c += f; + } + return c; } -int invcumpoisson(double p, double lambda) -{ - if (p <= 0) { - return 0; - } - if (p >= 1) { - // passing this 1 will cause an infinite loop, try this instead: - p = 1-1e-9; - } - double f = exp(-lambda); - int i = 0; - for (double c = f; c < p; c += f) { - i++; - f *= lambda / double(i); - } - return i; +int invcumpoisson(double p, double lambda) { + if (p <= 0) { + return 0; + } + if (p >= 1) { + // passing this 1 will cause an infinite loop, try this instead: + p = 1 - 1e-9; + } + double f = exp(-lambda); + int i = 0; + for (double c = f; c < p; c += f) { + i++; + f *= lambda / double(i); + } + return i; } diff --git a/genlib/pafmath.h b/genlib/pafmath.h index 1582d44d..202df5f3 100644 --- a/genlib/pafmath.h +++ b/genlib/pafmath.h @@ -24,25 +24,17 @@ // a collection of math functions -#ifndef __PAFMATH_H__ -#define __PAFMATH_H__ +#pragma once -#include #include #ifndef M_PI #define M_PI 3.1415926535897932384626433832795 #endif -inline double sqr(double a) -{ - return (a*a); -} +inline double sqr(double a) { return (a * a); } -inline int sgn(double a) -{ - return (a < 0) ? -1 : 1; -} +inline int sgn(double a) { return (a < 0) ? -1 : 1; } #ifndef M_ROOT_1_2 #define M_ROOT_1_2 0.70710678118654752440084436210485 @@ -57,25 +49,16 @@ void pafsrand(unsigned int seed, int set = 0); unsigned int pafrand(int set = 0); // a random number from 0 to 1 -inline double prandom(int set = 0) -{ - return double(pafrand(set)) / double(PAF_RAND_MAX); -} +inline double prandom(int set = 0) { return double(pafrand(set)) / double(PAF_RAND_MAX); } // a random number from 0 to just less than 1 -inline double prandomr(int set = 0) -{ - return double(pafrand(set)) / double(PAF_RAND_MAX + 1); -} +inline double prandomr(int set = 0) { return double(pafrand(set)) / double(PAF_RAND_MAX + 1); } // note, in order to stop confusing myself I have ln defined: #define ln(X) log(X) -inline double log2(double a) -{ - return (ln(a) * M_1_LN2); -} +inline double log2(double a) { return (ln(a) * M_1_LN2); } // Hillier Hanson dvalue /* @@ -86,103 +69,26 @@ inline double dvalue(double k) */ // Hillier Hanson dvalue (from Kruger 1989 -- see Teklenburg et al) -inline double dvalue(double k) -{ - return 2.0 * (k * (log2((k+2.0)/3.0) - 1.0) + 1.0) / ((k - 1.0) * (k - 2.0)); -} +inline double dvalue(double k) { return 2.0 * (k * (log2((k + 2.0) / 3.0) - 1.0) + 1.0) / ((k - 1.0) * (k - 2.0)); } // Hillier Hanson pvalue -inline double pvalue(double k) -{ - return 2.0 * (k - log2(k) - 1.0) / ((k - 1.0) * (k - 2.0)); -} +inline double pvalue(double k) { return 2.0 * (k - log2(k) - 1.0) / ((k - 1.0) * (k - 2.0)); } // Teklenburg integration (correction 31.01.11 due to Ulrich Thaler -inline double teklinteg(double nodecount, double totaldepth) -{ - return ln(0.5 * (nodecount - 2.0)) / ln(double(totaldepth - nodecount + 1)); +inline double teklinteg(double nodecount, double totaldepth) { + return ln(0.5 * (nodecount - 2.0)) / ln(double(totaldepth - nodecount + 1)); } // Penn palmtree -inline double palmtree(double n, double r) -{ - if (n > r) { - return r * (n - 0.5 * (r+1)); - } - else { - return 0.5 * n * (n - 1); - } +inline double palmtree(double n, double r) { + if (n > r) { + return r * (n - 0.5 * (r + 1)); + } else { + return 0.5 * n * (n - 1); + } } double poisson(int x, double lambda); double cumpoisson(int x, double lambda); int invcumpoisson(double p, double lambda); - -// linear regression -// T should be int, float or double -template struct LinReg -{ - double S_x; - double S_y; - double S_xx; - double S_yy; - double S_xy; - double n; - // - bool cached; - double ca; - double cb; - // - LinReg() - { - S_x = 0; S_y = 0; S_xx = 0; S_yy = 0; S_xy = 0; n = 0; cached = false; - } - LinReg(const pvector& X, const pvector& Y) - { - S_x = 0; S_y = 0; S_xx = 0; S_yy = 0; S_xy = 0; - n = __min(X.size(),Y.size()); - for (int i = 0; i < n; i++) { - S_x += double(X[i]); S_y += double(Y[i]); - S_xx += sqr(double(X[i])); S_yy += sqr(double(Y[i])); - S_xy += double(X[i]) * double(Y[i]); - } - cached = false; - } - void clear() - { - S_x = 0; S_y = 0; S_xx = 0; S_yy = 0; S_xy = 0; n = 0; - cached = false; - } - void add(T x, T y) - { - n++; - S_x += double(x); S_y += double(y); - S_xx += sqr(double(x)); S_yy += sqr(double(y)); - S_xy += double(x) * double(y); - cached = false; - } - void makecache() - { - cb = (n*S_xy-S_x*S_y)/(n*S_xx-S_x*S_x); ca = (S_y - cb * S_x) / n; cached = true; - } - // Y = bX + a - double a() - { if (!cached) makecache(); return ca; } - double b() - { if (!cached) makecache(); return cb; } - double r() - { return (n*S_xy-S_x*S_y)/sqrt( (n*S_xx-sqr(S_x))*(n*S_yy-sqr(S_y)) ); } - double mu_x() - { return S_x / n; } - double mu_y() - { return S_y / n; } - // note you will need to keep the vectors if you need - // to calculate the residuals: e[i] = y[i] - b() * x[i] - a(); - double model(double x) - { if (!cached) makecache(); return cb * x + ca; } - double invmodel(double y) - { if (!cached) makecache(); return (y -ca) / cb ; } -}; - -#endif diff --git a/genlib/paftl_old.h b/genlib/paftl_old.h deleted file mode 100644 index 197ccb11..00000000 --- a/genlib/paftl_old.h +++ /dev/null @@ -1,2829 +0,0 @@ -// Paf Template Library --- a set of useful C++ templates -// -// Copyright (c) 1996-2006 PAF Turner (a.turner@ucl.ac.uk) -// -//----------------------------------------------------------------------------- -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -// -// See the lgpl.txt file for details -//----------------------------------------------------------------------------- -// -// Paf's cross platform box of tricks -// Everything you need to write any C++. All in one file! -// -// pstring similar to STL string -// pmemvec base clase for pvector and prefvec -// pvector similar to STL vector -// prefvec pvector with a different allocator (vector of references) -// pqvector searchable prefvec -// pqmap a simple map class, based on a binary tree -// plist a simple list class -// ptree a simple tree template -// pflipper used for flipping between two vectors (or anythings...) -// pexception exception class, base for various exception types -// -// -// A3 eliminates the double referencing used previously in the -// vector classes - -#ifndef __PAFTL_H__ -#define __PAFTL_H__ - -#define PAFTL_DATE "19-MAR-2006" - -#include -#include -#include -#include -#include -#include - -#ifndef bool -// #define bool int -#endif -#ifndef true - #define true 1 -#endif -#ifndef false - #define false 0 -#endif - -/////////////////////////////////////////////////////////////////////////////// - -// namespace paftl { - -class pexception; -class pstring; -template class pvector; -template class prefvec; -template class pqvector; -template class pqmap; -template class plist; -template class ptree; -template class pflipper; - -// a few basic types - -typedef pvector pvecint; -typedef pvector pvecfloat; -typedef pvector pvecdouble; -typedef pqvector pvecstring; - -/////////////////////////////////////////////////////////////////////////////// - -// miscellaneous enums (paftl used as namespace) - -class paftl -{ -public: - enum add_t {ADD_UNIQUE, ADD_REPLACE, ADD_DUPLICATE}; -}; - -/////////////////////////////////////////////////////////////////////////////// - -class pexception -{ -public: - enum exception_t { UNDEFINED = 0x0000, - MEMORY_ALLOCATION = 0x0001, - FILE_ERROR = 0x0002 }; - -protected: - int m_exception; - -public: - pexception(int n_exception = UNDEFINED) - { m_exception = n_exception; } - int error_code() - { return m_exception; } -}; - - -/////////////////////////////////////////////////////////////////////////////// - -// pmemvec: base allocation for pvector and prefvec - -template class pmemvec -{ -public: - class exception : public pexception - { - public: - enum exception_t { PVECTOR_UNDEFINED = 0x1000, - EMPTY_VECTOR = 0x1001, - UNASSIGNED_ITERATOR = 0x1002, - OUT_OF_RANGE = 0x1003 }; - public: - exception(int n_exception = PVECTOR_UNDEFINED) : pexception( n_exception ) {} - }; - enum base_t { npos = -1 }; -protected: - T *m_data; - short m_shift; - int m_length; -public: - // redefine - pmemvec(int sz = 0); - pmemvec(const pmemvec& ); - virtual ~pmemvec(); - pmemvec& operator = (const pmemvec& ); - // - virtual void push_back(const T& item); - virtual void pop_back(); - virtual void remove_at(int pos = 0); - virtual void remove_at(const pvecint& list); - virtual void insert_at(int pos, const T& item); - // - virtual void set(int count); - virtual void set(const T& item, int count); - // - virtual void clear(); - virtual void clearnofree(); -protected: - int storage_size() const - { return m_shift ? (2 << m_shift) : 0; } - void grow(int pos); - void shrink(); -public: - int size() const - { return m_length; } - T& base_at(int pos) - { return m_data[pos]; } - const T& base_at(int pos) const - { return m_data[pos]; } -public: - istream& read( istream& stream, streampos offset = -1 ); - ostream& write( ostream& stream ); -}; - -template -pmemvec::pmemvec(int sz) -{ - // note: uses same as grow / storage_size, but cannot rely on function existence when calling constructor - if (sz == 0) { - m_data = NULL; - m_shift = 0; - } - else { - do { - m_shift++; - } while ((2 << m_shift) < sz); - m_data = new T [(2 << m_shift)]; - } - m_length = 0; -} - -template -pmemvec::pmemvec(const pmemvec& v) -{ - m_shift = v.m_shift; - m_length = v.m_length; - - if (m_shift) { - m_data = new T [storage_size()]; - if (!m_data) - throw pexception( pexception::MEMORY_ALLOCATION ); - - if (m_length) { - for (int i = 0; i < m_length; i++) - m_data[i] = v.m_data[i]; - } - } - else { - m_data = NULL; - } -} - -template -pmemvec::~pmemvec() -{ - if (m_data) - { - delete [] m_data; - m_data = NULL; - } -} - -template -pmemvec& pmemvec::operator = (const pmemvec& v) -{ - if (m_shift < v.m_shift) - { - if (m_shift != 0) { - delete [] m_data; - } - m_shift = v.m_shift; - if (m_shift) { - m_data = new T [storage_size()]; - if (!m_data) - throw pexception( pexception::MEMORY_ALLOCATION ); - } - else { - m_data = NULL; - } - } - m_length = v.m_length; - if (m_length) { - for (int i = 0; i < m_length; i++) - m_data[i] = v.m_data[i]; - } - return *this; -} - -template -void pmemvec::push_back(const T& item) -{ - if (m_length >= storage_size()) { - grow( m_length ); - } - m_data[m_length++] = item; -} - -template -void pmemvec::pop_back() -{ - if (m_length == 0) - throw exception( exception::EMPTY_VECTOR ); - - --m_length; - - // Preferably include shrink code here -} - -template -void pmemvec::insert_at(int pos, const T& item) -{ - if (pos == npos || pos > m_length) { - throw exception( exception::OUT_OF_RANGE ); - } - if (m_length >= storage_size()) { - grow( pos ); - } - else { - for (int i = m_length; i > pos; i--) { - m_data[i] = m_data[i - 1]; - } - } - m_data[pos] = item; - m_length++; -} - -template -void pmemvec::remove_at(int pos) -{ - // This is a simple but reliable remove item from vector - if (m_length == 0) - throw exception( exception::EMPTY_VECTOR ); - else if (pos == npos || pos >= m_length) - throw exception( exception::OUT_OF_RANGE ); - - for (int i = pos; i < m_length - 1; i++) { - m_data[i] = m_data[i + 1]; - } - --m_length; - - // Preferably include shrink code here -} - -// this version for bulk deletes: copies over entries to new list -template -void pmemvec::remove_at(const pvecint& list) -{ - if (m_length == 0) - throw exception( exception::EMPTY_VECTOR ); - if (list.size() >= m_length) { - // if the list does not contain duplicates, then this simply means delete all contents: - clear(); - return; - } - // shrink new vector: - while ((m_length - list.size()) * 2 < storage_size()) { - m_shift--; - } - int new_length = 0; - T *new_data = new T [storage_size()]; - bool *rem_flag = new bool [m_length]; - if (!new_data || !rem_flag) - throw pexception( pexception::MEMORY_ALLOCATION ); - for (int i = 0; i < m_length; i++) { - rem_flag[i] = false; - } - for (i = 0; i < list.size(); i++) { - if (list[i] == npos || list[i] >= m_length) - throw exception( exception::OUT_OF_RANGE ); - rem_flag[list[i]] = true; - } - for (i = 0; i < m_length; i++) { - if (!rem_flag[i]) { - new_data[new_length] = m_data[i]; - new_length++; - } - } - m_length = new_length; - delete [] m_data; - delete [] rem_flag; - m_data = new_data; -} - -template -void pmemvec::set(int count) -{ - clear(); - do { - m_shift++; - } while ((2 << m_shift) < count); - m_data = new T [(2 << m_shift)]; - m_length = count; -} - -template -void pmemvec::set(const T& item, int count) -{ - clear(); - do { - m_shift++; - } while ((2 << m_shift) < count); - m_data = new T [(2 << m_shift)]; - m_length = count; - for (int i = 0; i < m_length; i++) { - m_data[i] = item; - } -} - -template -void pmemvec::clear() -{ - m_length = 0; - m_shift = 0; - if (m_data) - { - delete [] m_data; - m_data = NULL; - } -} - -template -void pmemvec::clearnofree() -{ - m_length = 0; -} - -template -void pmemvec::grow(int pos) -{ - m_shift++; - - T *new_data = new T [storage_size()]; - if (!new_data) - throw pexception( pexception::MEMORY_ALLOCATION ); - - if (m_length) { - for (int i = 0; i < m_length + 1; i++) - new_data[i] = (i < pos) ? m_data[i] : m_data[i-1]; - } - if (m_data) { - delete [] m_data; - } - m_data = new_data; -} - -template -void pmemvec::shrink() -{ -} - -template -istream& pmemvec::read( istream& stream, streampos offset ) -{ - int length; - if (offset != -1) { - stream.seekg( offset ); - } - stream.read( (char *) &length, sizeof(int) ); - if (length >= storage_size()) { - if (m_data) { - delete [] m_data; - m_data = NULL; - } - while (length >= storage_size()) - m_shift++; - m_data = new T [storage_size()]; - if (!m_data) - throw pexception( pexception::MEMORY_ALLOCATION ); - } - m_length = length; - if (m_length > 0) { - stream.read( (char *) m_data, sizeof(T) * m_length ); - } - return stream; -} - -template -ostream& pmemvec::write( ostream& stream ) -{ - stream.write( (char *) &m_length, sizeof(int) ); - if (m_length != 0) { - stream.write( (char *) m_data, sizeof(T) * m_length ); - } - return stream; -} - -/////////////////////////////////////////////////////////////////////////////// - -template class pvector : public pmemvec -{ -protected: - mutable int m_current; -public: - pvector(int sz = 0) : pmemvec(sz) - {m_current = npos;} - pvector(const pvector& v) : pmemvec(v) - {m_current = v.m_current;} - pvector& operator = (const pvector& ); - virtual ~pvector() - {;} - // - T& at(int pos) - { return m_data[pos]; } - const T& at(int pos) const - { return m_data[pos]; } - T& operator[](int pos) - { return at(pos); } - const T& operator[](int pos) const - { return at(pos); } - // - T& head() - { return at(0); } - const T& head() const - { return at(0); } - T& tail() - { return at(m_length-1); } - const T& tail() const - { return at(m_length-1); } - // standard operations (unordered vector) - T& find(const T& item); - const T& find(const T& item) const; - int findindex(const T& item) const; - // binary operations (ordered vector) - int add(const T& item, int type = paftl::ADD_UNIQUE); // ignored if already exists - T& search(const T& item); - const T& search(const T& item) const; - int searchindex(const T& item) const; - int searchfloorindex(const T& item) const; - int searchceilindex(const T& item) const; - void remove(const T& item) - { remove_at(searchindex(item)); } - // set operations (ordered vector) - void operator += (const pvector& v); - // qsort algo: - void sort(); - void sort(int lo, int hi); - // - friend pvector intersect(const pvector& a, const pvector& b); -}; - -template -pvector& pvector::operator = (const pvector& v) -{ - if (&v != this) - { - pmemvec::operator = (v); - } - return *this; -} - -template -T& pvector::find(const T& item) -{ - if (findindex(item) == npos) { - throw exception(exception::OUT_OF_RANGE); - } - return at(m_current); -} -template -const T& pvector::find(const T& item) const -{ - if (findindex(item) == npos) { - throw exception(exception::OUT_OF_RANGE); - } - return at(m_current); -} - -template -int pvector::findindex(const T& item) const -{ - for (int i = 0; i < m_length; i++) { - if (at(i) == item) { - m_current = i; - return i; - } - } - return npos; -} - -// oops... we need an iterator... add use a current position marker. - -template -T& pvector::search(const T& item) -{ - if (searchindex(item) == npos) { - throw exception(exception::OUT_OF_RANGE); // Not found - } - return at(m_current); -} -template -const T& pvector::search(const T& item) const -{ - if (searchindex(item) == npos) { - throw exception(exception::OUT_OF_RANGE); // Not found - } - return at(m_current); -} - -template -int pvector::searchindex(const T& item) const -{ - if (m_length) { - int ifloor = -1; int itop = m_length; int ihere = 0; - while (itop - ifloor > 1) { - ihere = (itop + ifloor) / 2; - if (item < at(ihere)) - itop = ihere; - else - ifloor = ihere; - } - ihere = (itop + ifloor) / 2; - m_current = ihere; - if (at(m_current) == item) { - return m_current; - } - } - return npos; -} - -template -int pvector::searchfloorindex(const T& item) const -{ - searchindex(item); - while (m_current > -1 && at(m_current) > item) { - m_current--; - } - return m_current; -} - -template -int pvector::searchceilindex(const T& item) const -{ - searchindex(item); - while (m_current < m_length && at(m_current) < item) { - m_current++; - } - return m_current; -} - - -// Note: uses m_current set by searchindex - -// Really need a list 'merge' function as well... will write this soon! - -template -int pvector::add(const T& item, int type) // UNIQUE by default -{ - int where = -1; - if (m_length == 0) { - this->pmemvec::push_back( item ); - where = 0; - } - else { - searchindex(item); - if (item < at(m_current)) { - this->pmemvec::insert_at( m_current, item ); - where = m_current; - } - else if (item > at(m_current) || type == paftl::ADD_DUPLICATE) { - this->pmemvec::insert_at( m_current + 1, item ); - where = m_current + 1; - } - else if (type == paftl::ADD_REPLACE) { - // relies on good assignment operator - at(m_current) = item; - } - // n.b., type "UNIQUE" does not replace, returns -1 - } - return where; -} - -template -void pvector::operator += (const pvector& v) -{ - if (this != &v && m_length + v.m_length > 0) { - - while (m_length + v.m_length >= storage_size()) - m_shift++; - - T *new_data = new T [storage_size()]; - if (!new_data) - throw pexception( pexception::MEMORY_ALLOCATION ); - - int i = 0, j = 0, k = 0; - while (i + j < m_length + v.m_length) { - if ( i < m_length ) { - if (j < v.m_length) { - if (m_data[i] < v.m_data[j]) { - new_data[k++] = m_data[i++]; - } - else if (the_data()[i] > v.the_data()[j]) { - new_data[k++] = v.m_data[j++]; - } - else { - new_data[k++] = m_data[i++]; j++; - } - } - else { - while (i < m_length) { - new_data[k++] = m_data[i++]; - } - } - } - else { - while (j < v.m_length) { - new_data[k++] = v.m_data[j++]; - } - } - } - if (m_data) { - delete [] m_data; - } - m_length = k; - m_data = new_data; - } -} - -template -void pvector::sort() -{ - sort(0,m_length-1); -} - -template -void pvector::sort(int lo, int hi) -{ - int curlo = lo; int curhi = hi; - if (curhi > curlo) - { - const T& val = at((curlo+curhi)/2); - while (lo <= hi) { - while (lo < curhi && at(lo) < val) - lo++; - while (hi > curlo && at(hi) > val) - hi--; - if (lo <= hi) - { - // swap contents - T temp = m_data[lo]; - m_data[hi] = m_data[lo]; - m_data[lo] = temp; - // - lo++; hi--; - } - if (curlo < hi) - sort(curlo, hi); - - if(lo < curhi) - sort(lo, curhi); - } - } -} - -// requires two sorted lists -template -inline pvector intersect(const pvector& a, const pvector& b) -{ - pvector retvec; - int i = 0; - int j = 0; - while (i < a.size() && j < b.size()) { - if (a[i] == b[j]) { - retvec.push_back(a[i]); - i++; j++; - } - else { - while (a[i] < b[j] && i < a.size()) { - i++; - } - while (a[i] > b[j] && j < b.size()) { - j++; - } - } - } - return retvec; -} - -/////////////////////////////////////////////////////////////////////////////// - -// prefvec: a vector of references (useful for larger objects) -// should be able to use pqvector in most cases - -template class prefvec : public pmemvec -{ -public: - prefvec(int sz = 0) : pmemvec(sz) - {;} - prefvec(const prefvec& ); - virtual ~prefvec(); - prefvec& operator = (const prefvec& ); - // - void push_back(const T& item); - void pop_back(); - void remove_at(int pos = 0); - void remove_at(const pvecint& list); - void insert_at(int pos, const T& item); - // - void set(int count); - void set(const T& item, int count); - // - void clear(); - // - T& at(int pos) - { return *(m_data[pos]); } - const T& at(int pos) const - { return *(m_data[pos]); } - T& operator[](int pos) - { return at(pos); } - const T& operator[](int pos) const - { return at(pos); } - // - T& head() - { return at(0); } - const T& head() const - { return at(0); } - T& tail() - { return at(m_length-1); } - const T& tail() const - { return at(m_length-1); } - // - // NOTE: no find (as often equivalence operator will not be defined) - // - // Override read and write - istream& read( istream& stream ); - ostream& write( ostream& stream ); -}; - -template -prefvec::prefvec(const prefvec& v) : pmemvec(v) -{ - for (int i = 0; i < m_length; i++) { - m_data[i] = new T; - *(m_data[i]) = v.at(i); - } -} - -template -prefvec& prefvec::operator = (const prefvec& v) -{ - if (&v != this) { - for (int i = 0; i < m_length; i++) { - delete m_data[i]; - } - this->pmemvec::operator = (v); - for (int j = 0; j < m_length; j++) { - m_data[j] = new T(v.at(j)); - } - } - return *this; -} - -template -prefvec::~prefvec() -{ - for (int i = 0; i < m_length; i++) { - if (m_data[i]) - delete m_data[i]; - } - // virtual destructor called for pmemvec -} - -template -void prefvec::push_back(const T& item) -{ - T *p = new T(item); - pmemvec::push_back( p ); -} - -template -void prefvec::pop_back() -{ - delete m_data[m_length - 1]; - pmemvec::pop_back(); -} - -template -void prefvec::remove_at(int pos) -{ - if (m_length == 0) - throw exception( exception::EMPTY_VECTOR ); - else if (pos == npos || pos >= m_length) - throw exception( exception::OUT_OF_RANGE ); - - delete m_data[pos]; - pmemvec::remove_at( pos ); -} - -// this version for intended for bulk deletes (also retains previous ordering) -template -void prefvec::remove_at(const pvecint& list) -{ - if (m_length == 0) - throw exception( exception::EMPTY_VECTOR ); - - for (int i = 0; i < list.size(); i++) { - if (list[i] == npos || list[i] >= m_length) - throw exception( exception::OUT_OF_RANGE ); - delete m_data[list[i]]; - } - pmemvec::remove_at( list ); -} - - -template -void prefvec::insert_at(int pos, const T& item) -{ - T *p = new T(item); - pmemvec::insert_at(pos, p); -} - -template -void prefvec::set(int count) -{ - pmemvec::set(count); - for (int i = 0; i < m_length; i++) { - m_data[i] = new T; - } -} - -template -void prefvec::set(const T& item, int count) -{ - pmemvec::set(count); - for (int i = 0; i < m_length; i++) { - m_data[i] = new T(item); - } -} - - -template -void prefvec::clear() -{ - for (int i = 0; i < m_length; i++) { - delete m_data[i]; - } - pmemvec::clear(); -} - -// Note: read and write only work for structures without pointers - -template -istream& prefvec::read( istream& stream ) -{ - for (int i = 0; i < m_length; i++) { - delete m_data[i]; - } - int length; - stream.read( (char *) &length, sizeof(int) ); - if (stream.fail()) { - throw pexception(pexception::FILE_ERROR); - } - if (length >= storage_size()) { - if (m_data) { - delete [] m_data; - } - while (length >= storage_size()) - m_shift++; - m_data = new T * [storage_size()]; - } - m_length = length; - for (int j = 0; j < m_length; j++) { - T *p = new T; - stream.read( (char *) p, sizeof(T) ); - if (stream.fail()) { - throw pexception(pexception::FILE_ERROR); - } - m_data[j] = p; - } - return stream; -} - -template -ostream& prefvec::write( ostream& stream ) -{ - stream.write( (char *) &m_length, sizeof(int) ); - for (int i = 0; i < m_length; i++) { - stream.write( (char *) &at(i), sizeof(T) ); - } - return stream; -} - -/////////////////////////////////////////////////////////////////////////////// - -// pqvector... prefvec with the binary addition routine... -// (i.e., almost the hash table...) - -// (so... I think we might replace pqmap with an inherited form of this soon) -// (if MS would oblige...) - -template class pqvector : public prefvec -{ -protected: - mutable int m_current; -public: - pqvector(int sz = 0) : prefvec(sz) {;} - pqvector(const pqvector& v) : prefvec( v ) {;} - virtual ~pqvector() {;} - pqvector& operator = (const pqvector& v) - { this->prefvec::operator = (v); return *this; } - // - // at, [] and so on as before - // - // standard operations (unordered vector) - T& find(const T& item); - const T& find(const T& item) const; - int findindex(const T& item) const; - // - // binary operations (ordered vector) - T& search(const T& item); - const T& search(const T& item) const; - int searchindex(const T& item) const; - void remove(const T& item) - { remove_at(searchindex(item)); } - int add(const T& item, int type = paftl::ADD_UNIQUE); - T& current() - { return at(m_current); } - const T& current() const - { return at(m_current); } - // qsort algo: - void sort(); - void sort(int lo, int hi); -}; - -template -T& pqvector::find(const T& item) -{ - if (findindex(item) == npos) { - throw exception(exception::OUT_OF_RANGE); - } - return at(m_current); -} -template -const T& pqvector::find(const T& item) const -{ - if (findindex(item) == npos) { - throw exception(exception::OUT_OF_RANGE); - } - return at(m_current); -} - -template -int pqvector::findindex(const T& item) const -{ - for (int i = 0; i < m_length; i++) { - if (at(i) == item) { - m_current = i; - return i; - } - } - return npos; -} - -// oops... we need an iterator... add use a current position marker. - -template -T& pqvector::search(const T& item) -{ - if (searchindex(item) == npos) { - throw exception(exception::OUT_OF_RANGE); // Not found - } - return at(m_current); -} -template -const T& pqvector::search(const T& item) const -{ - if (searchindex(item) == npos) { - throw exception(exception::OUT_OF_RANGE); // Not found - } - return at(m_current); -} - -template -int pqvector::searchindex(const T& item) const -{ - if (m_length) { - int ifloor = -1; int itop = m_length; int ihere = 0; - while (itop - ifloor > 1) { - ihere = (itop + ifloor) / 2; - if (item < at(ihere)) - itop = ihere; - else - ifloor = ihere; - } - ihere = (itop + ifloor) / 2; - m_current = ihere; - if (at(m_current) == item) { - return m_current; - } - } - return npos; -} - -// Note: uses m_current set by searchindex - -// Really need a list 'merge' function as well... will write this soon! - -template -int pqvector::add(const T& item, int type) // default type UNIQUE -{ - int where = -1; - if (m_length == 0) { - this->prefvec::push_back( item ); - where = 0; - } - else { - searchindex(item); - if (item < at(m_current)) { - this->prefvec::insert_at( m_current, item ); - where = m_current; - } - else if (item > at(m_current) || type == paftl::ADD_DUPLICATE) { - this->prefvec::insert_at( m_current + 1, item ); - where = m_current + 1; - } - else if (type == paftl::ADD_REPLACE) { - // relies on good assignment operator - this->prefvec::at(m_current) = item; - } - // n.b., type "UNIQUE" does not replace, returns -1 - } - return where; -} - -template -void pqvector::sort() -{ - sort(0,m_length-1); -} - -template -void pqvector::sort(int lo, int hi) -{ - int curlo = lo; int curhi = hi; - if (curhi > curlo) - { - const T& val = at((curlo+curhi)/2); - while (lo <= hi) { - while (lo < curhi && at(lo) < val) - lo++; - while (hi > curlo && at(hi) > val) - hi--; - if (lo <= hi) - { - // swap contents (using pointer) - T* temp = m_data[lo]; - m_data[hi] = m_data[lo]; - m_data[lo] = temp; - // - lo++; hi--; - } - if (curlo < hi) - sort(curlo, hi); - - if(lo < curhi) - sort(lo, curhi); - } - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////// - -// psubvec is based on pvector, designed for arrays of chars or shorts, it subsumes itself -// so can be stored as a single pointer: useful if you have a lot of empty arrays - -template class psubvec -{ -public: - enum base_t { npos = -1 }; -protected: - T *m_data; -public: - psubvec() - { m_data = NULL; } - psubvec(const psubvec& ); - ~psubvec(); - psubvec& operator = (const psubvec& ); - // - virtual void push_back(const T item); - virtual void clear(); -public: - bool isEmpty() // isEmpty is provided in addition to size as is quicker to test - { return m_data == NULL; } - T size() const - { return m_data ? m_data[0] : 0; } - T& operator [] (T pos) - { return m_data[pos+1]; } - const T& operator [] (T pos) const - { return m_data[pos+1]; } -public: - istream& read( istream& stream, streampos offset = -1 ); - ostream& write( ostream& stream ); -}; - -template -psubvec::psubvec(const psubvec& v) -{ - if (v.m_data) { - T length = v.m_data[0]; - T count = 0; - while (length >>= 1) // find bit length (note: cannot assume int) - count++; - m_data = new T [1 << count]; - length = v.m_data[0]; - for (T i = 0; i < length + 1; i++) { - m_data[i] = v.m_data[i]; - } - } - else { - m_data = NULL; - } -} - -template -psubvec::~psubvec() -{ - if (m_data) - { - delete [] m_data; - m_data = NULL; - } -} - -template -psubvec& psubvec::operator = (const psubvec& v) -{ - if (this != &v) { - if (v.m_data) { - T length = v.m_data[0]; - T count = 0; - while (length >>= 1) // find bit length (note: cannot assume int) - count++; - m_data = new T [1 << count]; - length = v.m_data[0]; - for (T i = 0; i < length + 1; i++) { - m_data[i] = v.m_data[i]; - } - } - else { - m_data = NULL; - } - } - return *this; -} - -template -void psubvec::push_back(const T item) -{ - if (!m_data) { - m_data = new T [2]; - m_data[0] = 1; - m_data[1] = item; - } - else { - int length = m_data[0] + 1; - if ((length & (length - 1)) == 0) { // determine if next length would be power of 2 - T *new_data = new T [length << 1]; - for (T i = 0; i < length; i++) - new_data[i] = m_data[i]; - delete [] m_data; - m_data = new_data; - } - m_data[0] = length; - m_data[length] = item; - } -} - -template -void psubvec::clear() -{ - if (m_data) - { - delete [] m_data; - m_data = NULL; - } -} - -template -istream& psubvec::read( istream& stream, streampos offset ) -{ - if (m_data) { - delete [] m_data; - m_data = NULL; - } - T length; - stream.read( (char *) &length, sizeof(T) ); - if (length) { - T copy = length; - while (length >>= 1) // find bit length (note: cannot assume int) - count++; - m_data = new T [1 << count]; - stream.read((char *) &m_data, sizeof(T*(copy+1)) ); - } -} - -template -ostream& psubvec::write( ostream& stream ) -{ - if (m_data) { - stream.write((char *) &m_data, sizeof(T*(m_data[0]+1))); - } -} - - - -/////////////////////////////////////////////////////////////////////////////////////////////// - -// And now the quick mapping routine - -// Helper class keyvaluepair... - -template class keyvaluepair { -protected: - T1 m_key; - T2 m_value; -public: - keyvaluepair(const T1 key = T1(), const T2 value = T2()) - { m_key = key; m_value = value; } - T1& key() { return m_key; } - const T1 key() const { return m_key; } - T2& value() { return m_value; } - const T2& value() const { return m_value; } - friend bool operator == (const keyvaluepair& a, const keyvaluepair& b); - friend bool operator < (const keyvaluepair& a, const keyvaluepair& b); - friend bool operator > (const keyvaluepair& a, const keyvaluepair& b); - istream& read( istream& stream ); - ostream& write( ostream& stream ); -}; -template -inline bool operator == (const keyvaluepair& a, const keyvaluepair& b) -{ return (a.m_key == b.m_key); } -template -inline bool operator < (const keyvaluepair& a, const keyvaluepair& b) -{ return (a.m_key < b.m_key); } -template -inline bool operator > (const keyvaluepair& a, const keyvaluepair& b) -{ return (a.m_key > b.m_key); } -// Note: read and write only work for structures without pointers -template -istream& keyvaluepair::read( istream& stream ) -{ - stream.read( (char *) &m_key, sizeof(T1) ); - stream.read( (char *) &m_value, sizeof(T2) ); - return stream; -} -template -ostream& keyvaluepair::write( ostream& stream ) -{ - stream.write( (char *) &m_key, sizeof(T1) ); - stream.write( (char *) &m_value, sizeof(T2) ); - return stream; -} - -template class keyvaluepairref -{ -protected: - T1 m_key; - T2 *m_value; -public: - keyvaluepairref(const T1 key = T1()) - { m_key = key; m_value = NULL; } - keyvaluepairref(const T1 key, const T2& value) - { m_key = key; m_value = new T2(value); } - keyvaluepairref(const keyvaluepairref& k) - { m_key = k.m_key; m_value = new T2(*(k.m_value)); } - keyvaluepairref& operator = (const keyvaluepairref& k) - { - if (this != &k) - { - m_key = k.m_key; - m_value = new T2(*(k.m_value)); - } - return *this; - } - ~keyvaluepairref() - { if (m_value) {delete m_value; m_value = NULL;} } - T1& key() { return m_key; } - const T1 key() const { return m_key; } - T2& value() { return *m_value; } - const T2& value() const { return *m_value; } - friend bool operator == (const keyvaluepairref& a, const keyvaluepairref& b); - friend bool operator < (const keyvaluepairref& a, const keyvaluepairref& b); - friend bool operator > (const keyvaluepairref& a, const keyvaluepairref& b); - // - virtual istream& read( istream& stream ); - virtual ostream& write( ostream& stream ); -}; -template -inline bool operator == (const keyvaluepairref& a, const keyvaluepairref& b) -{ return (a.m_key == b.m_key); } -template -inline bool operator < (const keyvaluepairref& a, const keyvaluepairref& b) -{ return (a.m_key < b.m_key); } -template -inline bool operator > (const keyvaluepairref& a, const keyvaluepairref& b) -{ return (a.m_key > b.m_key); } -// Note: read and write only work for structures without pointers -template -istream& keyvaluepairref::read( istream& stream ) -{ - stream.read( (char *) &m_key, sizeof(T1) ); - m_value = new T2; - stream.read( (char *) m_value, sizeof(T2) ); - return stream; -} -template -ostream& keyvaluepairref::write( ostream& stream ) -{ - stream.write( (char *) &m_key, sizeof(T1) ); - stream.write( (char *) m_value, sizeof(T2) ); - return stream; -} - -// ...and yuk! it gets worse... now we have to define a whole new class: - -template class pmemmap -{ -// It looks very similar to a pqvector... -protected: - pqvector m_vector; -public: - pmemmap() {;} - pmemmap(const pmemmap& map ) { m_vector = map.m_vector; } - ~pmemmap() {;} - pmemmap& operator = (const pmemmap& map ) - { if (this != &map) m_vector = map.m_vector; return *this; } - // - // at, [] and so on - T2& at(int i) - { return m_vector.at(i).value(); } - const T2& at(int i) const - { return m_vector.at(i).value(); } - T2& operator [] (int i) - { return m_vector.at(i).value(); } - const T2& operator [] (int i) const - { return m_vector.at(i).value(); } - T2& head() - { return m_vector.head().value(); } - const T2& head() const - { return m_vector.head().value(); } - T2& tail() - { return m_vector.tail().value(); } - const T2& tail() const - { return m_vector.tail().value(); } - int size() const - { return m_vector.size(); } - void clear() - { m_vector.clear(); } - // - // standard operations (unordered vector) - T2& find(const T1& item) const - { return m_vector.find(Pair(item)).value(); } - int findindex(const T1& item) const - { return m_vector.findindex(Pair(item)); } - // - // binary operations (ordered vector) - T2& search(const T1& item) - { return m_vector.search(Pair(item)).value(); } - const T2& search(const T1& item) const - { return m_vector.search(Pair(item)).value(); } - const int searchindex(const T1& item) const - { return m_vector.searchindex(Pair(item)); } - void remove_at(int i) - { m_vector.remove_at(i); } - void remove_at(const pvecint& list) - { m_vector.remove_at(list); } - void remove(const T1& item) - { remove_at(m_vector.searchindex(item)); } - int add(const T1& k, const T2& v, int type = paftl::ADD_UNIQUE) // note: does not replace! - { return m_vector.add( Pair(k,v), type ); } - // extras - T1& key(int i) - { return m_vector.at(i).key(); } - const T1 key(int i) const - { return m_vector.at(i).key(); } - T2& value(int i) - { return m_vector.at(i).value(); } - const T2& value(int i) const - { return m_vector.at(i).value(); } - T2& current() - { return m_vector.current().value(); } - const T2& current() const - { return m_vector.current().value(); } - // read and write (structures without pointers *only*) - istream& read( istream& stream ); - ostream& write( ostream& stream ); -}; - -// Note: read and write only work for structures without pointers - -template -istream& pmemmap::read( istream& stream ) -{ - for (int i = m_vector.size() - 1; i >= 0; i--) { - m_vector.remove_at(i); - } - int length; - stream.read( (char *) &length, sizeof(int) ); - for (int j = 0; j < length; j++) { - // these should be in order, so just push them: - Pair p; - p.read(stream); - m_vector.push_back(p); - } - return stream; -} - -template -ostream& pmemmap::write( ostream& stream ) -{ - int length = m_vector.size(); - stream.write( (char *) &length, sizeof(int) ); - for (int i = 0; i < m_vector.size(); i++) { - m_vector[i].write(stream); - } - return stream; -} - -// ...to stop the MS compiler complaining... -#define kvp(T1,T2) keyvaluepair - -template class pmap : public pmemmap -{ -}; - -// ...to stop the MS compiler complaining... -#define kvpr(T1,T2) keyvaluepairref - -template class pqmap : public pmemmap -{ -}; - -/////////////////////////////////////////////////////////////////////////////// - -// and a simple list class... -// (with integrated iterator) - -template class plist -{ -protected: - class pitem - { - protected: - T *m_data; - public: - pitem *m_previous; - pitem *m_next; - pitem(const T *d = NULL, pitem *p = NULL, pitem *n = NULL) - { - if (d) - m_data = new T(*d); - else - m_data = NULL; - m_previous = p; - m_next = n; - } - pitem(const pitem& p) - { - throw 1; - } - pitem& operator = (const pitem& p) - { - throw 1; - } - ~pitem() - { - if (m_data) - delete m_data; - m_data = NULL; - m_previous = NULL; - m_next = NULL; - } - void predel() - { - if (m_previous != NULL) { - pitem *temp = m_previous->m_previous; - temp->m_next = this; // should work without reallocation - delete m_previous; - m_previous = temp; // should work without reallocation - } - } - void postdel() - { - if (m_next != NULL) { - pitem *temp = m_next->m_next; - temp->m_previous = this; // should work without reallocation - delete m_next; - m_next = temp; // should work without reallocation - } - } - pitem *preins(const T& v) - { - pitem *temp = m_previous; - m_previous = new pitem(&v, temp, this); - temp->m_next = m_previous; // should work without reallocation - return m_previous; - } - pitem *postins(const T& v) - { - pitem *temp = m_next; - m_next = new pitem(&v, this, temp); - temp->m_previous = m_next; // should work without reallocation - return m_next; - } - T& data() const - { - if (!m_data) { - throw 1; - } - return *m_data; - } - }; -protected: - pitem m_head; - pitem m_tail; - mutable pitem *m_current; -public: - bool empty() const - { - return (m_head.m_next == &m_tail); // or v.v. - } - void pop_back() - { - m_tail.predel(); // i.e., delete the one before the tail - } - void pop_front() - { - m_head.postdel(); // i.e., delete the one after the head - } - void push_back(const T& v) - { - m_tail.preins(v); // i.e., add before the tail - } - void push_front(const T& v) - { - m_head.postins(v); // i.e., add after the head - } - void first() const - { - m_current = m_head.m_next; - } - void last() const - { - m_current = m_tail.m_previous; - } - bool is_head() const - { - return (m_current == &m_head); - } - bool is_tail() const - { - return (m_current == &m_tail); - } - const plist& operator ++(int) const - { - m_current = m_current->m_next; - return *this; - } - const plist& operator --(int) const - { - m_current = m_current->m_previous; - return *this; - } - T& operator *() const { - return m_current->data(); - }; - void preins(const T& data) { - m_current->preins(data); - } - void postins(const T& data) { - m_current->postins(data); - } - // note pre and post del delete the current item: - void predel() { - m_current = m_current->m_previous; - m_current->postdel(); - } - void postdel() { - m_current = m_current->m_next; - m_current->predel(); - } - void clear() - { - while (!empty()) { - pop_back(); - } - } -public: - plist() - { - m_head.m_next = &m_tail; - m_tail.m_previous = &m_head; - m_current = &m_head; // just so it's somewhere... - } - plist(const plist& list) { - m_head.m_next = &m_tail; - m_tail.m_previous = &m_head; - m_current = list.m_current; - for (list.first(); !list.is_tail(); list++) { - push_back(*list); - } - list.m_current = m_current; // set back original list current to what it was before - } - plist& operator = (const plist& list) { - if (&list != this) { - m_current = list.m_current; - clear(); - for (list.first(); list.is_tail(); list++) { - push_back(*list); - } - list.m_current = m_current; // set back original list current to what it was before - } - return *this; - } - ~plist() - { - // remove contents: - clear(); - } -}; - -/////////////////////////////////////////////////////////////////////////////// - -// ptree: a simple tree class - -// Allows template of a template (recursive) definition for tree -#define ptreeT ptree - -template class ptree -{ -public: - class exception : public pexception - { - public: - enum exception_t { PTREE_UNDEFINED = 0x1000, - UNASSIGNED_DATA = 0x1001 }; - public: - exception(int n_exception = PTREE_UNDEFINED) : pexception( n_exception ) {} - }; - enum base_t { npos = -1 }; -protected: - T *m_data; - ptree *m_parent; - pvector m_children; -public: - ptree() { - m_data = NULL; - m_parent = NULL; - } - ptree(const T& data) { - m_data = new T(data); - m_parent = NULL; - } - ptree(const ptree& tree ) { - m_data = tree.m_data; - for (int i = 0; i < tree.m_children.size(); i++) { - ptree *child = new ptree( *(tree.m_children[i]) ); - m_children.push_back( child ); - m_children.tail()->m_parent = this; - } - } - ptree& operator = (const ptree& tree) { - if (this != &tree) { - m_data = tree.m_data; - for (int i = 0; i < tree.m_children.size(); i++) { - ptree *child = new ptree( *(tree.m_children[i]) ); - m_children.push_back( child ); - m_children.tail()->m_parent = this; - } - } - return *this; - } - ~ptree() { - delete m_data; - m_data = NULL; - while (m_children.size()) { - delete m_children.tail(); - m_children.pop_back(); - } - } - void addChild(const T& data) { - m_children.push_back( new ptree(data) ); - m_children.tail()->m_parent = this; - } - void removeChild(int ref) { - ptree *child = m_children[ref]; - m_children.remove(ref); - delete child; - } - int getChildCount() const { - return m_children.size(); - } - ptree& getChild(int ref) const { - return *(m_children[ref]); - } - ptree& getLastChild() const { - return *(m_children[m_children.size() - 1]); - } - int hasParent() const { - return m_parent ? 1 : 0; - } - ptree& getParent() const { - return *m_parent; - } - void setParent(ptree& parent) { - if (m_parent) { - for (int i = 0; i < m_parent->m_children.size(); i++) { - if (m_parent->m_children[i] == this) { - m_parent->m_children.remove(i); - } - } - } - m_parent = &parent; - } - void setValue(const T& data) { - m_data = new T(data); - } - T& getValue() const { - if (!m_data) - throw exception( exception::UNASSIGNED_DATA ); - return *m_data; - } - pvector getPath() { - pvector path; - getPath(path); - return path; - } - void getPath(pvector& path) { - path.push_back( getValue() ); - if (m_parent) { - m_parent->getPath(path); - } - } -}; - -/////////////////////////////////////////////////////////////////////////////// - -template class pflipper -{ -protected: - T *m_a; - T *m_b; - short parity; -public: - pflipper() { - parity = 0; - m_a = new T; - m_b = new T; - } - pflipper( const T& a, const T& b ) { - parity = 0; - m_a = new T(a); - m_b = new T(b); - } - pflipper( const pflipper& f ) { - parity = f.parity; - m_a = new T(*(f.m_a)); - m_b = new T(*(f.m_b)); - } - ~pflipper() { - if (m_a) { - delete m_a; - m_a = NULL; - } - if (m_b) { - delete m_b; - m_b = NULL; - } - } - pflipper& operator = (const pflipper& f ) { - if (this != &f) { - if (m_a) - delete m_a; - if (m_b) - delete m_b; - parity = f.parity; - m_a = new T(*(f.m_a)); - m_b = new T(*(f.m_b)); - } - return *this; - } - void flip() { - parity = ~parity; - } - T& a() const { - if (parity) - return *m_a; - else - return *m_b; - } - T& b() const { - if (parity) - return *m_b; - else - return *m_a; - } -}; - -/////////////////////////////////////////////////////////////////////////////// - -// pstring: a simple string class - -class pstring -{ -public: - class exception : public pexception - { - public: - enum exception_t { PSTRING_UNDEFINED = 0x1000, - BAD_STRING = 0x1001, - OUT_OF_RANGE = 0x1002, - UNABLE_TO_CONVERT = 0x1003 }; - public: - exception(int n_exception = PSTRING_UNDEFINED) : pexception( n_exception ) {} - }; - - enum base_t { npos = -1 }; - -protected: - int m_alloc; - int m_start; - int m_end; - char *m_data; - -public: - pstring(const char *data = NULL) - { - if (!data || (m_end = strlen(data)) < 1) { - m_data = NULL; - m_start = 0; - m_end = 0; - m_alloc = 0; - } - else { - m_start = 0; - m_alloc = m_end + 1; - m_data = new char [m_alloc]; - if (!m_data) - throw pexception( pexception::MEMORY_ALLOCATION ); - for (int i = m_start; i < m_end; i++) m_data[i] = data[i]; - m_data[m_end] = '\0'; - } - } - pstring(const char c) - { - m_start = 0; - m_end = 1; - m_alloc = m_end + 1; - m_data = new char [m_alloc]; - m_data[0] = c; - m_data[m_end] = '\0'; - } - pstring(const int length) - { - if (length < 1) { - m_data = NULL; - m_start = 0; - m_end = 0; - m_alloc = 0; - } - else { - m_start = length; - m_end = length; - m_alloc = length + 1; - m_data = new char [m_alloc]; - if (!m_data) { - throw pexception( pexception::MEMORY_ALLOCATION ); - } - m_data[m_end] = '\0'; - } - } - // Added V1.6 to allow initialisation from long / double - // (due to the phasing out of the pdata class) - friend pstring pstringify(const char c); - friend pstring pstringify(const int val, const pstring& format); - friend pstring pstringify(const double& val, const pstring& format); - // - pstring(const pstring& s) - { - if (s.m_alloc == 0) { - m_data = NULL; - m_start = 0; - m_end = 0; - m_alloc = 0; - } - else if (!s.m_data) - throw exception( exception::BAD_STRING ); - else { - m_start = 0; - m_end = s.m_end - s.m_start; - m_alloc = m_end + 1; - m_data = new char [m_alloc]; - if (!m_data) - throw pexception( pexception::MEMORY_ALLOCATION ); - for (int i = 0; i < m_end; i++) { - m_data[i] = s.m_data[i + s.m_start]; - } - m_data[m_end] = '\0'; - } - } - virtual ~pstring() - { - if (m_data) { - delete [] m_data; m_data = NULL; m_start = 0; m_end = 0; m_alloc = 0; - } - } - pstring& operator = (const pstring& s) - { - if (&s != this) { - if (m_alloc < s.m_end - s.m_start + 1) { - if (m_data) { - delete [] m_data; - } - if (s.m_end - s.m_start) { - m_alloc = s.m_end - s.m_start + 1; - m_data = new char [s.m_alloc]; - if (!m_data) - throw pexception( pexception::MEMORY_ALLOCATION ); - } - else { - m_alloc = 0; - m_data = NULL; - } - } - m_start = 0; - m_end = s.m_end - s.m_start; - if (s.m_end - s.m_start) { - if (!s.m_data) - throw exception( exception::BAD_STRING ); - for (int i = 0; i < m_end; i++) - m_data[i] = s.m_data[i + s.m_start]; - m_data[m_end] = '\0'; - } - } - return *this; - } - const char *c_str() const - { - return m_data + m_start; // Note! Not persistent: do not pass this but c_strcpy()! - } - char *c_strcpy(char *str) const - { - return strcpy( str, (m_data + m_start) ); - } - // Three simple conversions - int c_int() const; - double c_double() const; - - char& operator [] (int i) const - { - if (i >= (m_end - m_start) || i < 0) - throw exception( exception::OUT_OF_RANGE ); - return m_data[i + m_start]; - } - void clear() - { m_start = 0; m_end = 0; } // Note: no deallocation - bool empty() const - { return (m_end == m_start) ? true : false; } - int size() const - { return m_alloc; } - int length() const - { return m_end - m_start; } - - pstring substr( int start = 0, int length = -1 ) const; - - int findindex( char c, int start = 0, int end = npos ) const; - int findindexreverse( char c, int start = npos, int end = 0 ) const; - int findindex( const pstring& str, int start = 0, int end = npos ) const; - - // Full tokenizer: - pvecstring tokenize( char delim = ' ', bool ignorenulls = false ); - - pstring splice( char delim = ' ' ); - pstring splice( const pstring& delim ); - - pstring& ltrim( char c = ' '); - pstring& ltrim( const pstring& str ); - - pstring& replace( char a ); // simply remove all instances of char a - pstring& replace( char a, char b ); - - pstring& makelower(); - pstring& makeupper(); - - friend bool compare(const pstring& a, const pstring& b, int n); - friend bool operator == (const pstring& a, const pstring& b); - friend bool operator != (const pstring& a, const pstring& b); - friend bool operator < (const pstring& a, const pstring& b); // for storing in hash tables etc - friend bool operator > (const pstring& a, const pstring& b); - - friend pstring operator + (const pstring& a, const pstring& b); - - friend ostream& operator << (ostream& stream, const pstring& str); - friend istream& operator >> (istream& stream, pstring& str); - - friend pstring readtoken(istream& stream, - const pstring& delim_list = pstring(" ")); - - char *raw() const - { return m_data; } - - // binary read/write - bool read(istream& stream); - bool write(ostream& stream); -}; - -inline pstring pstringify(const char val) -{ - pstring str(1); - str[0] = val; - return str; -} - -inline pstring pstringify(const int val, const pstring& format = "% 16d") -{ - pstring str; - str.m_start = 0; - str.m_alloc = 16 + format.length(); - str.m_data = new char [str.m_alloc]; - if (!str.m_data) { - throw pexception( pexception::MEMORY_ALLOCATION ); - } - sprintf( str.m_data, format.c_str(), val ); - str.m_end = strlen(str.m_data); - return str; -} - -inline pstring pstringify(const double& val, const pstring& format = "%+.16le") -{ - pstring str; - str.m_start = 0; - str.m_alloc = 24 + format.length(); - str.m_data = new char [str.m_alloc]; - if (!str.m_data) { - throw pexception( pexception::MEMORY_ALLOCATION ); - } - sprintf( str.m_data, format.c_str(), val ); - str.m_end = strlen(str.m_data); - return str; -} - -inline pstring pstring::substr(int start, int length) const -{ - if (length < 0 || length > (m_end - m_start - start)) - length = m_end - m_start - start; - pstring sub; - sub.m_start = 0; - sub.m_end = length; - sub.m_alloc = length + 1; - sub.m_data = new char [sub.m_alloc]; - for (int i = 0; i < sub.m_end; i++) - sub.m_data[i] = m_data[i + m_start + start]; - sub.m_data[length] = '\0'; - return sub; -} - -inline int pstring::findindex( char c, int start, int end ) const -{ - if (end == pstring::npos || end > m_end - m_start) { - end = m_end - m_start; - } - for (int pos = start; pos < end; pos++) { - if (m_data[pos + m_start] == c) { - return pos; - } - } - return pstring::npos; -} - -inline int pstring::findindexreverse( char c, int start, int end ) const -{ - if (start == pstring::npos || start > m_end - m_start) { - start = m_end - m_start; - } - for (int pos = start - 1; pos >= end; pos--) { - if (m_data[pos + m_start] == c) { - return pos; - } - } - return pstring::npos; -} - -inline int pstring::findindex( const pstring& str, int start, int end ) const -{ - if (end == pstring::npos) { - end = m_end - m_start; - } - for (int pos = start; pos < end; pos++) { - if (m_data[pos + m_start] == str.m_data[str.m_start]) { - int mark = pos, remark = pstring::npos; - while (mark != pstring::npos && ++pos < str.m_end - str.m_start + mark) { - if (pos >= end) { - return pstring::npos; - } - else if (m_data[pos+m_start] != str.m_data[pos-mark+str.m_start]) { - mark = pstring::npos; - } - else if (m_data[pos+str.m_start] == str.m_data[str.m_start] - && remark == pstring::npos) { - remark = pos; - } - } - if (mark != pstring::npos) { - return mark; - } - else if (remark != pstring::npos) { - return findindex( str, remark ); - } - } - } - return pstring::npos; -} - -inline pstring& pstring::ltrim( char c ) -{ - int pos = m_start; - while (pos < m_end && m_data[pos] == c) - pos++; - m_start = pos; - return *this; -} - -inline pstring& pstring::ltrim( const pstring& str ) -{ - int pos = m_start; - while (pos < m_end && str.findindex(m_data[pos]) != npos ) - pos++; - m_start = pos; - return *this; -} - -// tokenize: going beyond splice... - -inline pvecstring pstring::tokenize( char delim, bool ignorenulls ) -{ - pvecstring tokens; - int first, last = 0; - while (last + m_start < m_end) { - first = last; - last = findindex(delim, first); - if (last == npos) - last = m_end - m_start; - tokens.push_back( substr(first, last - first) ); - if (ignorenulls) { - while (last + m_start < m_end && m_data[last+m_start] == delim) - last++; // Lose consecutive delimeters - } - else { - last++; // Lose delimiter - } - } - return tokens; -} - -// splice: kind of combined substr, find operation: - -// returns the head, the tail is kept, the delimiter is destroyed -// (the leading whitespace destroy is no longer used: use x.ltrim().splice() ) - -inline pstring pstring::splice( char delim ) -{ - int pos = 0; - pos = findindex(delim, pos); - if (pos == npos) - pos = m_end - m_start; - pstring str = substr(0, pos); - pos++; // Lose delimiter - m_start = m_end > pos + m_start ? pos + m_start : m_end; - return str; -} - -// returns the head, the tail is kept, the delimiter is destroyed - -inline pstring pstring::splice( const pstring& delim ) -{ - int pos = findindex(delim); - if (pos == npos) - pos = m_end - m_start; - pstring str = substr(0, pos); - pos += delim.m_end; // Lose delimiter - m_start = m_end > pos + m_start ? pos + m_start : m_end; - return str; -} - -// Conversion - -inline int pstring::c_int() const -{ - int out = 0; - if (m_start != m_end) { - char *endptr = m_data + m_start; - out = (int) strtol( m_data + m_start, &endptr, 10 ); - if (endptr == m_data + m_start) { - throw exception( exception::UNABLE_TO_CONVERT ); - } - } - return out; -} - -inline double pstring::c_double() const -{ - double out = 0.0; - if (m_start != m_end) { - char *endptr = m_data + m_start; - out = strtod( m_data + m_start, &endptr ); - if (endptr == m_data + m_start) { - throw exception( exception::UNABLE_TO_CONVERT ); - } - } - return out; -} - -// Comparison - -inline bool compare(const pstring& a, const pstring& b, int n) -{ - if (n > a.length() || n > b.length()) { - false; - //throw pstring::exception( pstring::exception::OUT_OF_RANGE ); - } - for (int i = 0; i < n; i++) { - if ( a.m_data[i+a.m_start] != b.m_data[i+b.m_start] ) { - return false; - } - } - return true; -} - -inline bool operator != (const pstring& a, const pstring& b) -{ - if (a.length() != b.length()) { - return true; - } - for (int i = 0; i < a.length(); i++) - { - if (a.m_data[i+a.m_start] != b.m_data[i+b.m_start]) { - return true; - } - } - return false; -} - -inline bool operator == (const pstring& a, const pstring& b) -{ - return !(a != b); -} - -inline bool operator < (const pstring& a, const pstring& b) // for storing in hash tables etc -{ - for (int i = 0; i < b.length(); i++) { - if (i == a.length()) { - return true; // <- if all characters are the same, but b is longer than a, then a < b - } - else if (a.m_data[i+a.m_start] < b.m_data[i+b.m_start]) { - return true; - } - else if (a.m_data[i+a.m_start] > b.m_data[i+b.m_start]) { - return false; - } - } - return false; -} - -inline bool operator > (const pstring& a, const pstring& b) // for storing in hash tables etc -{ - for (int i = 0; i < a.length(); i++) { - if (i == b.length()) { - return true; // <- if all characters are the same, but a is longer than b, then a > b - } - else if (a.m_data[i+a.m_start] > b.m_data[i+b.m_start]) { - return true; - } - else if (a.m_data[i+a.m_start] < b.m_data[i+b.m_start]) { - return false; - } - } - return false; -} - -inline pstring operator + (const pstring& a, const pstring& b) -{ - pstring str(a.length() + b.length()); - str.m_start = 0; - for (int i = 0; i < str.m_end; i++) - { - str.m_data[i] = (i < a.length()) ? a.m_data[i+a.m_start] : - b.m_data[i+b.m_start - a.length()]; - } - return str; -} - -inline ostream& operator << (ostream& stream, const pstring& str) -{ - if (str.empty()) { - return stream; - } - return ( stream << str.c_str() ); -} - -inline istream& operator >> (istream& stream, pstring& str) -{ - // default is 128, but grows upto required length - if (str.m_alloc < 128) { - str.m_alloc = 128; - delete [] str.m_data; - str.m_data = new char [str.m_alloc]; - if (!str.m_data) - throw pexception( pexception::MEMORY_ALLOCATION ); - } - for (int i = 0; ; i++) { - if (i + 1 == str.m_alloc) { - char *old_data = str.m_data; - str.m_data = new char[str.m_alloc * 2]; - for (int j = 0; j < str.m_alloc; j++) - str.m_data[j] = old_data[j]; - delete [] old_data; - str.m_alloc *= 2; - } - stream.get( str.m_data[i] ); - // cross platform --- just do this yourself: \n is for MAC = 13, UNIX = 10, MS = 13,10 - if (str.m_data[i] == 10 || stream.eof() || stream.fail()) { - str.m_data[i] = '\0'; - break; - } - else if (str.m_data[i] == 13) { - if (stream.peek() == 10) - stream.get( str.m_data[i] ); - str.m_data[i] = '\0'; - break; - } - } - str.m_start = 0; - str.m_end = strlen(str.m_data); - return stream; -} - -// binary read / write - -inline bool pstring::read(istream& stream) -{ - // actually, required alloc is 1 less than required alloc due to null terminator - int required_alloc; - stream.read( (char *) &required_alloc, sizeof(int) ); - if (required_alloc > 0 && m_alloc < required_alloc + 1) { - m_alloc = required_alloc + 1; - delete [] m_data; - m_data = new char [m_alloc]; - if (!m_data) - throw pexception( pexception::MEMORY_ALLOCATION ); - } - if (required_alloc > 0) { - stream.read(m_data, required_alloc); - m_data[required_alloc] = '\0'; - } - m_start = 0; - m_end = required_alloc; - - return true; -} - -inline bool pstring::write(ostream& stream) -{ - int required_alloc = 0; - if (m_data) - required_alloc = m_end - m_start; - stream.write( (char *) &required_alloc, sizeof(int) ); - if (required_alloc > 0) - stream.write( m_data + m_start, required_alloc ); - return true; -} - -// Okay, I give up, here you are, a token reader - -inline pstring readtoken(istream& stream, const pstring& delim_list) -{ - pstring str; - str.m_start = 0; - str.m_end = 0; - str.m_alloc = 128; - str.m_data = new char [str.m_alloc]; - - char single_char; - int here = -1; - - while ( !stream.eof() && str.m_end < 128 ) { - single_char = stream.get(); - if (here == -1) { - if (isprint(single_char) && delim_list.findindex(single_char) == pstring::npos) { - here = 0; - str.m_data[ 0 ] = single_char; - str.m_end++; - } - } - else { - here++; - if (!isprint(single_char) || delim_list.findindex(single_char) != pstring::npos) { - str.m_data[ str.m_end ] = '\0'; - return str; - } - else { - str.m_data[ str.m_end ] = single_char; - str.m_end++; - } - } - } - str.m_data[ str.m_end ] = '\0'; - return str; -} - -inline pstring& pstring::replace(char a) -{ - int i = m_start; - for (int j = m_start; j < m_end; i++, j++) { - if (a == m_data[j]) { - j++; - if (j == m_end) { - break; - } - } - m_data[i] = m_data[j]; - } - m_end = i; - m_data[ i ] = '\0'; - return *this; -} - -inline pstring& pstring::replace(char a, char b) -{ - for (int i = m_start; i < m_end; i++) { - if (a == m_data[i]) { - m_data[i] = b; - } - } - return *this; -} - -inline pstring& pstring::makelower() -{ - for (int i = m_start; i < m_end; i++) { - // ASCII caps - if (m_data[i] > 64 && m_data[i] < 91) { - m_data[i] += 32; - } - } - return *this; -} -inline pstring& pstring::makeupper() -{ - for (int i = m_start; i < m_end; i++) { - // ASCII lower - if (m_data[i] > 96 && m_data[i] < 123) { - m_data[i] -= 32; - } - } - return *this; -} - - -/////////////////////////////////////////////////////////////////////////////// - -// Read and write runlength encoded vectors, with byte alignment through T - -// note: vector must have been allocated to accept stream -template -istream& read_rle( istream& stream, T *vector, int length ) -{ - unsigned char *data = (unsigned char *) vector; - for (int i = 0; i < sizeof(T); i++) { - unsigned char runlength = 0, current, last; - int count = 0; - while (count < length) { - stream.get(current); - if (count && current == last) { - stream.get(runlength); - } - else { - last = current; - runlength = 1; - } - for (int i = count; i < count + runlength; i++) { - data[i + sizeof(T) * count] = current; - } - count += (int) runlength; - } - } - return stream; -} - -template ostream& write_rle( ostream& stream, T *vector, int length ) -{ - unsigned char *data = (unsigned char *) vector; - for (int i = 0; i < sizeof(T); i++) { - unsigned char runlength = 0, current; - int count = 0; - while (count < length) { - do { - current = data[i + sizeof(T) * count]; - runlength++; - count++; - } while (count < length && current == data[i + sizeof(T) * count] && runlength < 255); - if (runlength == 1) { - stream.put(current); - } - else { - stream.put(current); - stream.put(current); - runlength -= 1; // since we've written current twice anyway to mark the run - stream.put(runlength); - } - runlength = 0; - } - } - return stream; -} - -/////////////////////////////////////////////////////////////////////////////// - -// Hashing for LZW compression - -const int HASHBITSIZE = 12; -const int HASHTABLESIZE = 5021; // n.b., prime > 4096 -//const int HASHTABLESIZE = 65983; // n.b., prime > 65536 -const int HASHMAXVALUE = (1 << HASHBITSIZE) - 1; -const int HASHMAXCODE = HASHMAXVALUE - 1; - -struct phash -{ - int code; - unsigned int prefix; - unsigned char character; -}; - -class phashtable -{ -protected: - mutable int m_current; - int m_nextcode; - phash m_table[HASHTABLESIZE]; -public: - phashtable(); - void add_encode(unsigned int prefix, unsigned char character); - void add_decode(unsigned int prefix, unsigned char character); - int search(unsigned int prefix, unsigned char character) const; - unsigned char *decode(unsigned char *buffer, unsigned int code); - int getnextcode() - { return m_nextcode; } -}; - -inline phashtable::phashtable() -{ - for (int i = 0; i < HASHTABLESIZE; i++) { - m_table[i].code = -1; - } - m_nextcode = 256; // 0-255 for standard characters -} - -inline void phashtable::add_encode(unsigned int prefix, unsigned char character) -{ - if (m_nextcode <= HASHMAXCODE) { - m_table[m_current].code = m_nextcode; - m_table[m_current].prefix = prefix; - m_table[m_current].character = character; - m_nextcode++; - } -} - -inline void phashtable::add_decode(unsigned int prefix, unsigned char character) -{ - if (m_nextcode <= HASHMAXCODE) { - m_table[m_nextcode].prefix = prefix; - m_table[m_nextcode].character = character; - m_nextcode++; - } -} - -inline int phashtable::search(unsigned int prefix, unsigned char character) const -{ - // the bracket overkill on the following line ensures paftl.h compiles on a GNU compiler - m_current = (((unsigned int) character) << (HASHBITSIZE-8)) ^ prefix; - int offset; - if (m_current == 0) { - offset = 1; - } - else { - offset = HASHTABLESIZE - m_current; - } - while ( m_table[m_current].code != -1 && - (m_table[m_current].prefix != prefix || m_table[m_current].character != character)) - { - m_current -= offset; - if (m_current < 0) - m_current += HASHTABLESIZE; - } - return m_table[m_current].code; -} - -inline unsigned char *phashtable::decode(unsigned char *buffer, unsigned int code) -{ - int i = 0; - while (code > 255) - { - *buffer++ = m_table[code].character; - code = m_table[code].prefix; - } - *buffer = code; - return buffer; -} - -/////////////////////////////////////////////////////////////////////////////// - -// LZW as of June 2003 US patent has expired -// as of June 2004 the European patent expires - -// Note to paftl users: ensure that you meet patent requirements for your usage - -// LZW uses a class so that the hash table may be retained over multiple -// vector read / writes, as well as holding a read buffer - -// 12 bit, 4096 pattern holder - -// Note: you must *flush* after writing -- the idea is you can write several -// vectors before a flush - -template class plzw -{ -protected: - // read / write buffering - unsigned long m_bitbuffer; - bool m_bitswaiting; -protected: - bool m_firstever; - unsigned char m_character; - unsigned int m_prefix; - phashtable m_hashtable; - unsigned char m_decodedstring[HASHTABLESIZE]; // <- impossible that the decode string is ever as long as the hash table size -public: - plzw(); - istream& read( istream& stream, T *vector, int length ); - ostream& write( ostream& stream, T *vector, int length ); -protected: - istream& get(istream& stream, unsigned int& code); - ostream& put(ostream& stream, const unsigned int code); -}; - -template -plzw::plzw() -{ - m_firstever = true; - m_bitswaiting = false; -} - -template -istream& plzw::read(istream& stream, T *vector, int length ) -{ - unsigned char *data = (unsigned char *) vector; - unsigned char *string; - - if (m_firstever) { - get(stream, m_prefix); - m_character = m_prefix; - data[0] = m_character; - } - - // T is sequenced, as we assume that patterns will recur through aligned bytes of T - for (unsigned int i = (m_firstever ? 1 : 0); i < sizeof(T) * length;) { - unsigned int nextcode; - get(stream, nextcode); - if (nextcode >= (unsigned int) m_hashtable.getnextcode()) { - *m_decodedstring = m_character; - string = m_hashtable.decode(m_decodedstring + 1, m_prefix); - } - else { - string = m_hashtable.decode(m_decodedstring, nextcode); - } - m_character = *string; - if (i != 0) { - // this should be skipped on initial read - m_hashtable.add_decode(m_prefix,m_character); - } - while (string >= m_decodedstring && i < sizeof(T) * length) { - data[i] = *string--; - i++; - } - m_prefix = nextcode; - } - - // skip to next byte boundary for next read... (and retain context) - m_bitswaiting = false; - m_firstever = false; - - return stream; -} - -template -ostream& plzw::write(ostream& stream, T *vector, int length ) -{ - unsigned char *data = (unsigned char *) vector; - - m_prefix = data[0]; - - for (unsigned int i = 0; i < sizeof(T) * length; i++) { - m_character = data[i]; - int code = m_hashtable.search(m_prefix, m_character); - if (code != -1) { - m_prefix = code; - } - else { - m_hashtable.add_encode(m_prefix, m_character); - put(stream, m_prefix); - m_prefix = m_character; - } - } - - // skip to next byte boundary - put(stream, m_prefix); - if (m_bitswaiting) { - stream.put((unsigned char)(m_bitbuffer & 0xFF)); - m_bitswaiting = false; - } - - return stream; -} - -// stored, 1 and 2 are the 12-bit codes, -// a b & c are first 4 bits, second 4 bits and third four bits respectively -// b1 a1 -// c2 c1 -// b2 a2 - -template -istream& plzw::get(istream& stream, unsigned int& code) -{ - unsigned char bits; - if (!m_bitswaiting) { - stream.get(bits); - code = bits; - stream.get(bits); - code |= (bits & 0x0F) << 8; - m_bitbuffer = bits & 0xF0; - m_bitswaiting = true; - } - else { - stream.get(bits); - code = ((unsigned int)bits) | (m_bitbuffer << 4); - m_bitswaiting = false; - } - - return stream; -} - -template -ostream& plzw::put(ostream& stream, const unsigned int code) -{ - if (!m_bitswaiting) { - stream.put((unsigned char)(code & 0xFF)); - m_bitbuffer = code >> 8; - m_bitswaiting = true; - } - else { - unsigned char bits; - bits = ((code >> 4) & 0xF0) | m_bitbuffer; - stream.put(bits); - stream.put((unsigned char)(code & 0xFF)); - m_bitswaiting = false; - } - - return stream; -} - -/////////////////////////////////////////////////////////////////////////////// - -// } // namespace paftl - -#endif diff --git a/genlib/pflipper.h b/genlib/pflipper.h new file mode 100644 index 00000000..593f4071 --- /dev/null +++ b/genlib/pflipper.h @@ -0,0 +1,54 @@ +// Copyright (c) 1996-2011 Alasdair Turner (a.turner@ucl.ac.uk) +// +//----------------------------------------------------------------------------- +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// +// See the lgpl.txt file for details +//----------------------------------------------------------------------------- + +#pragma once + +template class pflipper { + protected: + T m_contents[2]; + short parity; + + public: + pflipper() { parity = 0; } + pflipper(const T &a, const T &b) { + parity = 0; + m_contents[0] = a; + m_contents[1] = b; + } + pflipper(const pflipper &f) { + parity = f.parity; + m_contents[0] = f.m_contents[0]; + m_contents[1] = f.m_contents[1]; + } + virtual ~pflipper() {} + pflipper &operator=(const pflipper &f) { + if (this != &f) { + parity = f.parity; + m_contents[0] = f.m_contents[0]; + m_contents[1] = f.m_contents[1]; + } + return *this; + } + void flip() { parity = (parity == 0) ? 1 : 0; } + T &a() { return m_contents[parity]; } + T &b() { return m_contents[(parity == 0) ? 1 : 0]; } + const T &a() const { return m_contents[parity]; } + const T &b() const { return m_contents[(parity == 0) ? 1 : 0]; } +}; diff --git a/genlib/readwritehelpers.h b/genlib/readwritehelpers.h new file mode 100644 index 00000000..eb355fc7 --- /dev/null +++ b/genlib/readwritehelpers.h @@ -0,0 +1,93 @@ +// Copyright (C) 2017 Christian Sailer +// Copyright (C) 2018 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "genlib/exceptions.h" + +#include +#include +#include + +namespace dXreadwrite { + // The read/write methods can only be used for vectors of stack allocated types (basic data, POD) + // read in vector data and write to an existing vector (overwriting its previous contents) + template size_t readIntoVector(std::istream &stream, std::vector &vec) { + vec.clear(); + unsigned int size; + stream.read(reinterpret_cast(&size), sizeof(size)); + if (size > 0) { + vec.resize(size); + stream.read(reinterpret_cast(vec.data()), sizeof(T) * std::streamsize(size)); + } + return size; + } + // read in a vector into a new vector + template std::vector readVector(std::istream &stream) { + std::vector vec; + readIntoVector(stream, vec); + return vec; + } + + template void writeVector(std::ostream &stream, const std::vector &vec) { + // READ / WRITE USES 32-bit LENGTHS (number of elements) for compatibility reasons + + if (vec.size() > size_t(static_cast(-1))) { + throw new depthmapX::RuntimeException("Vector exceeded max size for streaming"); + } + const unsigned int length = static_cast(vec.size()); + stream.write(reinterpret_cast(&length), sizeof(length)); + if (length > 0) { + stream.write(reinterpret_cast(vec.data()), sizeof(T) * std::streamsize(length)); + } + } + + // read in map data and write to an existing map (overwriting its previous contents) + template size_t readIntoMap(std::istream &stream, std::map &map) { + map.clear(); + unsigned int size; + stream.read(reinterpret_cast(&size), sizeof(size)); + for (size_t i = 0; i < size; ++i) { + K key; + V value; + stream.read(reinterpret_cast(&key), sizeof(K)); + stream.read(reinterpret_cast(&value), sizeof(V)); + map.insert(std::make_pair(key, value)); + } + return size; + } + // read in a map into a new map + template std::map readMap(std::istream &stream) { + std::map map; + readIntoMap(stream, map); + return map; + } + + template void writeMap(std::ostream &stream, const std::map &map) { + // READ / WRITE USES 32-bit LENGTHS (number of elements) for compatibility reasons + + if (map.size() > size_t(static_cast(-1))) { + throw new depthmapX::RuntimeException("Map exceeded max size for streaming"); + } + const unsigned int length = static_cast(map.size()); + stream.write(reinterpret_cast(&length), sizeof(length)); + for (auto &pair : map) { + stream.write(reinterpret_cast(&pair.first), sizeof(K)); + stream.write(reinterpret_cast(&pair.second), sizeof(V)); + } + } + +} // namespace dXreadwrite diff --git a/genlib/simplematrix.h b/genlib/simplematrix.h new file mode 100644 index 00000000..4e5fb05a --- /dev/null +++ b/genlib/simplematrix.h @@ -0,0 +1,221 @@ +// genlib - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2018, Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include +#include + +namespace depthmapX { + + /** + * Base class for 2 dimensional matrices. This can be used as reference/pointer, but you cannot + * create this directly - you need to create either a row or a column matrix (the difference + * being the memory layout either, contiguous rows, or contiguous columns. + * Which layout to choose depends on the underlying data - if the data layout is given, it should be + * simple to find the matching implementation. To choose a new data layout, think about access patterns. + * If it is more likely to process several values from one row in one got, choose a row matrix. If processing + * is more likely to be by column, choose a column matrix. If access is truly random, it makes no difference. + */ + template class BaseMatrix { + protected: + BaseMatrix(size_t rows, size_t columns) { + m_data = new T[rows * columns]; + m_rows = rows; + m_columns = columns; + } + + BaseMatrix(const BaseMatrix &other) : BaseMatrix(other.m_rows, other.m_columns) { + std::copy(other.begin(), other.end(), m_data); + } + + BaseMatrix(BaseMatrix &&other) : m_data(other.m_data), m_rows(other.m_rows), m_columns(other.m_columns) { + other.m_data = nullptr; + other.m_rows = 0; + other.m_columns = 0; + } + + public: + virtual ~BaseMatrix() { delete[] m_data; } + + /** + * @brief Fill all values of the matrix with a default value + * @param value default value + */ + virtual void initialiseValues(T const &value) { std::fill(begin(), end(), value); } + + /** + * @brief Resets the matrix to a new size - this deletes all contents. + * This method provides a strong exception guarantee - if the new statement throws, + * the old state will be preserved. + * @param rows new number of rows + * @param columns new number of columns + */ + virtual void reset(size_t rows, size_t columns) { + // allocate new memory first - if this throws, the old matrix is still intact. + T *tmp = new T[rows * columns]; + delete[] m_data; + m_data = tmp; + + m_rows = rows; + m_columns = columns; + } + + /** + * @brief operator () access operator uses () instead of [] to allow giving two coordinates + * @param row row to access + * @param column column to access + * @return non-const reference to the data + */ + virtual T &operator()(size_t row, size_t column) = 0; + + /** + * @brief operator () access operator uses () instead of [] to allow giving two coordinates + * @param row row to access + * @param column column to access + * @return const reference to the data + */ + virtual T const &operator()(size_t row, size_t column) const = 0; + + /** + * @brief begin get a pointer to the data array (complies with std::iterator definitions) + * @return pointer to the first element + */ + T *begin() { return m_data; } + + /** + * @brief end pointer marking the end of the data array + * @return pointer behind the last element of the data array + */ + T *end() { return m_data + size(); } + + /** + * @brief begin get a pointer to the data array (complies with std::iterator definitions) + * @return const pointer to the first element + */ + T const *begin() const { return m_data; } + + /** + * @brief end pointer marking the end of the data array + * @return const pointer behind the last element of the data array + */ + T const *end() const { return m_data + size(); } + + /** + * @brief size + * @return size of the data array in elements + */ + size_t size() const { return m_rows * m_columns; } + + /** + * @brief rows + * @return number of rows + */ + size_t rows() const { return m_rows; } + + /** + * @brief columns + * @return number of columns + */ + size_t columns() const { return m_columns; } + + protected: + T *m_data; + size_t m_rows; + size_t m_columns; + + void access_check(size_t row, size_t column) const { + if (row >= m_rows) { + throw std::out_of_range("row out of range"); + } + if (column >= m_columns) { + throw std::out_of_range("column out of range"); + } + } + + void swap(BaseMatrix &other) { + std::swap(m_data, other.m_data); + std::swap(m_rows, other.m_rows); + std::swap(m_columns, other.m_columns); + } + }; + + /** + * Row matrix implementation - the data for each row is contiguous in memory, columns jump by the + * number of rows. + */ + template class RowMatrix : public BaseMatrix { + public: + RowMatrix(size_t rows, size_t columns) : BaseMatrix(rows, columns) {} + RowMatrix(RowMatrix const &other) : BaseMatrix(other) {} + RowMatrix(RowMatrix &&other) : BaseMatrix(std::move(other)) {} + + RowMatrix &operator=(RowMatrix const &other) { + RowMatrix tmp(other); + this->swap(tmp); + return *this; + } + + RowMatrix &operator=(RowMatrix &&other) { + RowMatrix tmp(std::move(other)); + this->swap(tmp); + return *this; + } + + T &operator()(size_t row, size_t column) { + this->access_check(row, column); + return this->m_data[column + row * this->m_columns]; + } + + T const &operator()(size_t row, size_t column) const { + this->access_check(row, column); + return this->m_data[column + row * this->m_columns]; + } + }; + + /** + * Column matrix implementation - the data for each column is contiguous in memory, rows jump by the + * number of columns. + */ + template class ColumnMatrix : public BaseMatrix { + public: + ColumnMatrix(size_t rows, size_t columns) : BaseMatrix(rows, columns) {} + ColumnMatrix(ColumnMatrix const &other) : BaseMatrix(other) {} + ColumnMatrix(ColumnMatrix &&other) : BaseMatrix(std::move(other)) {} + + ColumnMatrix &operator=(ColumnMatrix const &other) { + ColumnMatrix tmp(other); + this->swap(tmp); + return *this; + } + + ColumnMatrix &operator=(ColumnMatrix &&other) { + ColumnMatrix tmp(std::move(other)); + this->swap(tmp); + return *this; + } + + T &operator()(size_t row, size_t column) { + this->access_check(row, column); + return this->m_data[row + column * this->m_rows]; + } + + T const &operator()(size_t row, size_t column) const { + this->access_check(row, column); + return this->m_data[row + column * this->m_rows]; + } + }; +} // namespace depthmapX diff --git a/genlib/stringutils.cpp b/genlib/stringutils.cpp new file mode 100644 index 00000000..cd2bd786 --- /dev/null +++ b/genlib/stringutils.cpp @@ -0,0 +1,151 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "stringutils.h" + +#include +#include +#include +#include +#include + +namespace dXstring { + std::vector split(const std::string &s, char delim, bool skipEmptyTokens) { + std::vector elems; + std::stringstream ss; + ss.str(s); + std::string item; + while (std::getline(ss, item, delim)) { + if (skipEmptyTokens && item.empty()) { + continue; + } + elems.push_back(item); + } + + return elems; + } + + std::string readString(std::istream &stream) { + unsigned int length; + stream.read(reinterpret_cast(&length), sizeof(length)); + if (length == 0) { + return std::string(); + } + std::string result(length, '\0'); + char *ptr = &result[0]; + stream.read(ptr, length); + return result; + } + + void writeString(std::ostream &stream, const std::string &s) { + unsigned int length = static_cast(s.length()); + stream.write(reinterpret_cast(&length), sizeof(unsigned int)); + if (length > 0) { + stream.write(s.data(), length); + } + } + + std::string formatString(double value, const std::string &format) { + size_t bufferLength = 24 + format.length(); + std::vector buffer(bufferLength, '\0'); + snprintf(&buffer[0], bufferLength, format.c_str(), value); + return std::string(&buffer[0]); + } + + std::string formatString(int value, const std::string &format) { + size_t bufferLength = 24 + format.length(); + std::vector buffer(bufferLength, '\0'); + snprintf(&buffer[0], bufferLength, format.c_str(), value); + return std::string(&buffer[0]); + } + + std::string &toLower(std::string &str) { + std::transform(str.begin(), str.end(), str.begin(), tolower); + return str; + } + + // trim from start (in place) + void ltrim(std::string &s, char c) { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [&c](int ch) { return ch != c; })); + } + + // trim from end (in place) + void rtrim(std::string &s, char c) { + s.erase(std::find_if(s.rbegin(), s.rend(), [&c](int ch) { return ch != c; }).base(), s.end()); + } + + void makeInitCaps(std::string &s) { + bool literal = false; + bool reset = true; + for (auto &c : s) { + if (!isalpha(c)) { + if (c == '"') { + literal = !literal; + } + reset = true; + } else { + if (!literal) { + if (reset) { + c = static_cast(toupper(c)); + } else { + c = static_cast(tolower(c)); + } + } + reset = false; + } + } + } + + bool isDouble(const std::string &s) { + // nasty const cast to satisfy the function signature - we will not change the value of endPtr + char *endPtr = const_cast(&s[0]); + strtod(s.c_str(), &endPtr); + return endPtr != &s[0]; + } + + // handles all three line endings ("\r", "\n" and "\r\n"). taken from: + // https://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf + std::istream &safeGetline(std::istream &is, std::string &t) { + t.clear(); + + // The characters in the stream are read one-by-one using a std::streambuf. + // That is faster than reading them one-by-one using the std::istream. + // Code that uses streambuf this way must be guarded by a sentry object. + // The sentry object performs various tasks, + // such as thread synchronization and updating the stream state. + + std::istream::sentry se(is, true); + std::streambuf *sb = is.rdbuf(); + + for (;;) { + int c = sb->sbumpc(); + switch (c) { + case '\n': + return is; + case '\r': + if (sb->sgetc() == '\n') + sb->sbumpc(); + return is; + case std::streambuf::traits_type::eof(): + // Also handle the case when the last line has no line ending + if (t.empty()) + is.setstate(std::ios::eofbit); + return is; + default: + t += (char)c; + } + } + } +} // namespace dXstring diff --git a/genlib/stringutils.h b/genlib/stringutils.h new file mode 100644 index 00000000..1f4325c9 --- /dev/null +++ b/genlib/stringutils.h @@ -0,0 +1,43 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// Collection of utility functions that are required to add pstring functionality +// to std::strings (i.e. splitting and compatible serialisation/deserialisation) + +#pragma once + +#include +#include +#include +#include + +namespace dXstring { + std::vector split(const std::string &s, char delim, bool skipEmptyTokens = false); + std::string readString(std::istream &stream); + void writeString(std::ostream &stream, const std::string &s); + std::string formatString(double value, const std::string &format = "%+.16le"); + std::string formatString(int value, const std::string &format = "% 16d"); + /// Inplace conversion to lower case + std::string &toLower(std::string &str); + void ltrim(std::string &s, char c = ' '); + void rtrim(std::string &s, char c = ' '); + void makeInitCaps(std::string &s); + bool isDouble(const std::string &s); + template bool beginsWith(const T &input, const T match) { + return input.size() >= match.size() && equal(match.begin(), match.end(), input.begin()); + } + std::istream &safeGetline(std::istream &is, std::string &t); + +} // namespace dXstring diff --git a/genlib/xmlparse.cpp b/genlib/xmlparse.cpp index 322ca4b8..87063fd1 100644 --- a/genlib/xmlparse.cpp +++ b/genlib/xmlparse.cpp @@ -15,9 +15,7 @@ // along with this program. If not, see . -#include - -using namespace std; +#include "xmlparse.h" enum { STEP_START, STEP_ELEMENT_NAME, STEP_ATTRIBUTE_NAME, @@ -30,16 +28,16 @@ bool iscrlf(char c) return (c == 10 || c == 13); } -bool xmlelement::parse(ifstream& stream, bool parsesubelements) +bool xmlelement::parse(std::ifstream& stream, bool parsesubelements) { bool closed = false; bool complete = false; int step = STEP_START; - string buffer; - string attribute; - string value; + std::string buffer; + std::string attribute; + std::string value; while (!complete && stream) { - char c = stream.get(); + char c = static_cast(stream.get()); if (stream) { switch (step) { case STEP_START: @@ -158,30 +156,30 @@ bool xmlelement::parse(ifstream& stream, bool parsesubelements) } } if (!complete && step != STEP_START) { - throw xmlerror(string("Unexpected end of element ") + name); + throw xmlerror(std::string("Unexpected end of element ") + name); } return closed; } -void xmlelement::badcharacter(char c, const string& location) +void xmlelement::badcharacter(char c, const std::string& location) { if (isprint(c)) { - throw (string("Found '") + c + string("' while ") + location); + throw (std::string("Found '") + c + std::string("' while ") + location); } else { - stringstream s; + std::stringstream s; s << "Found character " << int(c) << " while " << location; throw (s.str()); } } -bool xmlelement::subparse(ifstream& stream) +bool xmlelement::subparse(std::ifstream& stream) { bool complete = false; while (!complete && stream) { subelements.push_back(xmlelement()); if (!subelements.back().parse(stream,true)) { - throw xmlerror(string("Unexplained error")); + throw xmlerror(std::string("Unexplained error")); } if (subelements.back().closetag) { if (subelements.back().name == name) { @@ -189,32 +187,32 @@ bool xmlelement::subparse(ifstream& stream) complete = true; } else { - throw xmlerror(string("Element <") + name + string("> closed with ")); + throw xmlerror(std::string("Element <") + name + std::string("> closed with ")); } } } if (!complete) { - throw xmlerror(string("Unexpected end of element ") + name); + throw xmlerror(std::string("Unexpected end of element ") + name); } return true; } -ostream& operator << (ostream& stream, const xmlelement& elem) +std::ostream& operator << (std::ostream& stream, const xmlelement& elem) { stream << "<" << elem.name; - map::const_iterator it; + std::map::const_iterator it; for (it = elem.attributes.begin(); it != elem.attributes.end(); it++) { stream << " " << it->first << "=\"" << it->second << "\" "; } if (elem.subelements.size() == 0) { - stream << " />" << endl; + stream << " />" << std::endl; } else { - stream << ">" << endl; + stream << ">" << std::endl; for (size_t i = 0; i < elem.subelements.size(); i++) { stream << elem.subelements[i]; } - stream << "" << endl; + stream << "" << std::endl; } return stream; } diff --git a/genlib/xmlparse.h b/genlib/xmlparse.h index 8a41c17a..a6ca26ed 100644 --- a/genlib/xmlparse.h +++ b/genlib/xmlparse.h @@ -23,37 +23,27 @@ #include #include #include - -using namespace std; - -inline string tolower(const string& str) -{ - string s = str; - for (size_t i = 0; i < s.length(); i++) { - s[i] = tolower(s[i]); - } - return s; -} +#include struct xmlelement { - string name; + std::string name; bool closetag; - map attributes; - vector subelements; + std::map attributes; + std::vector subelements; xmlelement() { closetag = false;} - bool parse(ifstream& stream, bool parsesubelements = false); - friend ostream& operator << (ostream& stream, const xmlelement& elem); + bool parse(std::ifstream& stream, bool parsesubelements = false); + friend std::ostream& operator << (std::ostream& stream, const xmlelement& elem); protected: - bool subparse(ifstream& stream); - void badcharacter(char c, const string& location); + bool subparse(std::ifstream& stream); + void badcharacter(char c, const std::string& location); }; struct xmlerror { - string error; - xmlerror(const string& e = string()) + std::string error; + xmlerror(const std::string& e = std::string()) { error = e; } }; diff --git a/genlibTest/CMakeLists.txt b/genlibTest/CMakeLists.txt new file mode 100644 index 00000000..92a87dc0 --- /dev/null +++ b/genlibTest/CMakeLists.txt @@ -0,0 +1,17 @@ +set(genlibtest genlibTest) +set(genlibTest_SRCS + testreadwritehelpers.cpp + main.cpp + testsimplematrix.cpp + testbspnode.cpp + teststringutils.cpp + testcontainerutils.cpp) + +set(LINK_LIBS + genlib) + +include_directories("../ThirdParty/Catch") + +add_executable(${genlibtest} ${genlibTest_SRCS}) +target_link_libraries(${genlibtest} ${LINK_LIBS}) + diff --git a/genlibTest/main.cpp b/genlibTest/main.cpp new file mode 100644 index 00000000..b17dd431 --- /dev/null +++ b/genlibTest/main.cpp @@ -0,0 +1,18 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#define CATCH_CONFIG_MAIN +#include "catch.hpp" diff --git a/genlibTest/testbspnode.cpp b/genlibTest/testbspnode.cpp new file mode 100644 index 00000000..b42d9346 --- /dev/null +++ b/genlibTest/testbspnode.cpp @@ -0,0 +1,219 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "genlib/comm.h" +#include "genlib/p2dpoly.h" +#include "genlib/bsptree.h" + +TEST_CASE("BSPTree::pickMidpointLine") +{ + std::vector lines; + lines.push_back(TaggedLine(Line(Point2f(1, 2), Point2f(2, 2)), 0)); + lines.push_back(TaggedLine(Line(Point2f(2, 2), Point2f(3, 2)), 0)); + lines.push_back(TaggedLine(Line(Point2f(3, 2), Point2f(4, 2)), 0)); + + BSPNode node; + + REQUIRE(BSPTree::pickMidpointLine(lines, 0) == 1); + + SECTION("Additional lines") { + lines.push_back(TaggedLine(Line(Point2f(4, 2), Point2f(5, 2)), 0)); + REQUIRE(BSPTree::pickMidpointLine(lines, 0) == 1); + + lines.push_back(TaggedLine(Line(Point2f(5, 1), Point2f(6, 1)), 0)); + REQUIRE(BSPTree::pickMidpointLine(lines, 0) == 2); + + // the only line with height > width becomes chosen + lines.push_back(TaggedLine(Line(Point2f(15, 4), Point2f(15, 0)), 0)); + REQUIRE(BSPTree::pickMidpointLine(lines, 0) == 5); + } + SECTION("rotated middle") { + + // height > width, rotated, close to midpoint + lines.push_back(TaggedLine(Line(Point2f(4.5, 1), Point2f(4.5, 3)), 0)); + + lines.push_back(TaggedLine(Line(Point2f(5, 2), Point2f(6, 2)), 0)); + lines.push_back(TaggedLine(Line(Point2f(6, 2), Point2f(7, 2)), 0)); + + // height > width, rotated, not close to midpoint + lines.push_back(TaggedLine(Line(Point2f(6.5, 1), Point2f(6.5, 3)), 0)); + + REQUIRE(BSPTree::pickMidpointLine(lines, 0) == 3); + } +} + +void compareLines(Line l1, Line l2, float EPSILON) { + REQUIRE(l1.start().x == Approx(l2.start().x).epsilon(EPSILON)); + REQUIRE(l1.start().y == Approx(l2.start().y).epsilon(EPSILON)); + REQUIRE(l1.end().x == Approx(l2.end().x).epsilon(EPSILON)); + REQUIRE(l1.end().y == Approx(l2.end().y).epsilon(EPSILON)); +} + +TEST_CASE("BSPTree::makeLines") +{ + const float EPSILON = 0.001f; + typedef std::pair, std::vector > TagLineVecPair; + + std::vector lines; + lines.push_back(TaggedLine(Line(Point2f(1, 2), Point2f(2, 2)), 0)); + lines.push_back(TaggedLine(Line(Point2f(2, 2), Point2f(3, 2)), 0)); + lines.push_back(TaggedLine(Line(Point2f(3, 2), Point2f(4, 2)), 0)); + lines.push_back(TaggedLine(Line(Point2f(4, 2), Point2f(5, 2)), 0)); + + std::unique_ptr node(new BSPNode()); + + TagLineVecPair result = BSPTree::makeLines(0, 0, lines, node.get()); + + REQUIRE(result.first.size() == 3); + REQUIRE(result.second.size() == 0); + + compareLines(result.first[0].line, lines[0].line, EPSILON); + compareLines(result.first[1].line, lines[2].line, EPSILON); + compareLines(result.first[2].line, lines[3].line, EPSILON); + + + SECTION("One on the right") + { + lines.push_back(TaggedLine(Line(Point2f(5, 1), Point2f(6, 1)), 0)); + + result = BSPTree::makeLines(0, 0, lines, node.get()); + + REQUIRE(result.first.size() == 3); + REQUIRE(result.second.size() == 1); + + compareLines(result.second[0].line, lines[4].line, EPSILON); + } + SECTION("One line with height > width becomes chosen") + { + // height > width, rotated, not close to midpoint + lines.push_back(TaggedLine(Line(Point2f(5.5, 1), Point2f(5.5, 3)), 0)); + + lines.push_back(TaggedLine(Line(Point2f(6, 2), Point2f(7, 2)), 0)); + + result = BSPTree::makeLines(0, 0, lines, node.get()); + + REQUIRE(result.first.size() == 4); + REQUIRE(result.second.size() == 1); + + compareLines(result.first[0].line, lines[0].line, EPSILON); + compareLines(result.first[1].line, lines[1].line, EPSILON); + compareLines(result.first[2].line, lines[2].line, EPSILON); + compareLines(result.first[3].line, lines[3].line, EPSILON); + compareLines(result.second[0].line, lines[5].line, EPSILON); + } + + SECTION("One broken between") + { + // height > width, rotated, close to midpoint + lines.push_back(TaggedLine(Line(Point2f(5.5, 1), Point2f(5.5, 3)), 0)); + + lines.push_back(TaggedLine(Line(Point2f(6, 2), Point2f(7, 2)), 0)); + lines.push_back(TaggedLine(Line(Point2f(7, 2), Point2f(8, 2)), 0)); + lines.push_back(TaggedLine(Line(Point2f(8, 2), Point2f(9, 2)), 0)); + lines.push_back(TaggedLine(Line(Point2f(9, 2), Point2f(10, 2)), 0)); + + // line with two points at different sides of chosen + lines.push_back(TaggedLine(Line(Point2f(3, -2), Point2f(6, -2)), 0)); + + result = BSPTree::makeLines(0, 0, lines, node.get()); + + // adds one on each side + REQUIRE(result.first.size() == 5); + REQUIRE(result.second.size() == 5); + + compareLines(result.first[0].line, lines[0].line, EPSILON); + compareLines(result.first[1].line, lines[1].line, EPSILON); + compareLines(result.first[2].line, lines[2].line, EPSILON); + compareLines(result.first[3].line, lines[3].line, EPSILON); + + compareLines(result.second[0].line, lines[5].line, EPSILON); + compareLines(result.second[1].line, lines[6].line, EPSILON); + compareLines(result.second[2].line, lines[7].line, EPSILON); + compareLines(result.second[3].line, lines[8].line, EPSILON); + + compareLines(result.first[4].line, Line(Point2f(3, -2), Point2f(5.5, -2)), EPSILON); + compareLines(result.second[4].line, Line(Point2f(5.5, -2), Point2f(6, -2)), EPSILON); + } +} + +TEST_CASE("BSPTree::make (all horizontal lines)", "all-left tree") +{ + const float EPSILON = 0.001f; + + std::vector lines; + lines.push_back(TaggedLine(Line(Point2f(1, 2), Point2f(2, 2)), 0)); + lines.push_back(TaggedLine(Line(Point2f(2, 2), Point2f(3, 2)), 0)); + lines.push_back(TaggedLine(Line(Point2f(3, 2), Point2f(4, 2)), 0)); + lines.push_back(TaggedLine(Line(Point2f(4, 2), Point2f(5, 2)), 0)); + + std::unique_ptr node(new BSPNode()); + + BSPTree::make(0, 0, lines, node.get()); + + compareLines(node->getLine(), lines[1].line, EPSILON); + + REQUIRE(node->m_left != nullptr); + REQUIRE(node->m_right == nullptr); + + compareLines(node->m_left->getLine(), lines[2].line, EPSILON); + + REQUIRE(node->m_left->m_left != nullptr); + REQUIRE(node->m_left->m_right == nullptr); + + compareLines(node->m_left->m_left->getLine(), lines[3].line, EPSILON); + + REQUIRE(node->m_left->m_left->m_left != nullptr); + REQUIRE(node->m_left->m_left->m_right == nullptr); + + compareLines(node->m_left->m_left->m_left->getLine(), lines[0].line, EPSILON); + + REQUIRE(node->m_left->m_left->m_left->m_left == nullptr); + REQUIRE(node->m_left->m_left->m_left->m_right == nullptr); +} + +TEST_CASE("BSPTree::make (all vertical lines)", "split tree") +{ + const float EPSILON = 0.001f; + + std::vector lines; + lines.push_back(TaggedLine(Line(Point2f(1.5, 1), Point2f(1.5, 3)), 0)); + lines.push_back(TaggedLine(Line(Point2f(2.5, 1), Point2f(2.5, 3)), 0)); + lines.push_back(TaggedLine(Line(Point2f(3.5, 1), Point2f(3.5, 3)), 0)); + lines.push_back(TaggedLine(Line(Point2f(4.5, 1), Point2f(4.5, 3)), 0)); + + std::unique_ptr node(new BSPNode()); + + BSPTree::make(0, 0, lines, node.get()); + + compareLines(node->getLine(), lines[1].line, EPSILON); + + REQUIRE(node->m_left != nullptr); + REQUIRE(node->m_right != nullptr); + + compareLines(node->m_left->getLine(), lines[0].line, EPSILON); + compareLines(node->m_right->getLine(), lines[3].line, EPSILON); + + REQUIRE(node->m_left->m_left == nullptr); + REQUIRE(node->m_left->m_right == nullptr); + + REQUIRE(node->m_right->m_left != nullptr); + REQUIRE(node->m_right->m_right == nullptr); + + compareLines(node->m_right->m_left->getLine(), lines[2].line, EPSILON); + + REQUIRE(node->m_right->m_left->m_left == nullptr); + REQUIRE(node->m_right->m_left->m_right == nullptr); +} diff --git a/genlibTest/testcontainerutils.cpp b/genlibTest/testcontainerutils.cpp new file mode 100644 index 00000000..d24f35f1 --- /dev/null +++ b/genlibTest/testcontainerutils.cpp @@ -0,0 +1,35 @@ +// Copyright (C) 2018 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include +#include + + +TEST_CASE("Test binary search helper with container", ""){ + std::vector testVec{ 1, 2, 4, 5}; + + REQUIRE(*depthmapX::findBinary(testVec, 2) == 2); + REQUIRE(depthmapX::findBinary(testVec, 3) == testVec.end()); + REQUIRE(depthmapX::findBinary(testVec, 6) == testVec.end()); + auto iter = depthmapX::findBinary(testVec, 2); + *iter = 3; + REQUIRE(*depthmapX::findBinary(testVec, 3) == 3); + + const std::vector& constVec = testVec; + REQUIRE(*depthmapX::findBinary(constVec, 3) == 3); + REQUIRE(depthmapX::findBinary(constVec, 2) == testVec.end()); + REQUIRE(depthmapX::findBinary(constVec, 6) == testVec.end()); +} diff --git a/genlibTest/testreadwritehelpers.cpp b/genlibTest/testreadwritehelpers.cpp new file mode 100644 index 00000000..694eba27 --- /dev/null +++ b/genlibTest/testreadwritehelpers.cpp @@ -0,0 +1,79 @@ +// Copyright (C) 2017 Christian Sailer +// Copyright (C) 2018 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include + +#include "cliTest/selfcleaningfile.h" + +#include "genlib/readwritehelpers.h" +#include "genlib/containerutils.h" + +#include + +TEST_CASE("vector reading and writing") +{ + using namespace dXreadwrite; + std::vector intVec{1, 5, 34, -2, 5}; + SelfCleaningFile intFile("integers.bin"); + { + std::ofstream outfile(intFile.Filename()); + writeVector(outfile, intVec); + } + + { + std::ifstream infile(intFile.Filename()); + auto copy = readVector(infile); + REQUIRE(copy == intVec); + } + + std::vector intCopy; + { + std::ifstream infile(intFile.Filename()); + readIntoVector(infile, intCopy); + } + REQUIRE(intCopy == intVec); + +} + +TEST_CASE("map reading and writing") +{ + using namespace dXreadwrite; + std::map intFloatMap; + intFloatMap.insert(std::make_pair(1,0.1f)); + intFloatMap.insert(std::make_pair(5,5000.0f)); + intFloatMap.insert(std::make_pair(34,-3.4f)); + intFloatMap.insert(std::make_pair(-2,0.2f)); + intFloatMap.insert(std::make_pair(6,0.6f)); + SelfCleaningFile intFloatFile("intFloatMap.bin"); + { + std::ofstream outfile(intFloatFile.Filename()); + writeMap(outfile, intFloatMap); + } + + { + std::ifstream infile(intFloatFile.Filename()); + auto copy = readMap(infile); + REQUIRE(copy == intFloatMap); + } + + std::map intCopy; + { + std::ifstream infile(intFloatFile.Filename()); + readIntoMap(infile, intCopy); + } + REQUIRE(intCopy == intFloatMap); + +} diff --git a/genlibTest/testsimplematrix.cpp b/genlibTest/testsimplematrix.cpp new file mode 100644 index 00000000..654c3d57 --- /dev/null +++ b/genlibTest/testsimplematrix.cpp @@ -0,0 +1,138 @@ +// Copyright (C) 2018 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "../genlib/simplematrix.h" +#include +#include + +template void compareMatrixContent( depthmapX::BaseMatrix const & matrix, std::vector const & expected ){ + REQUIRE(matrix.size() == expected.size()); + std::vector result(matrix.size()); + std::copy(matrix.begin(), matrix.end(), result.begin()); + REQUIRE(result == expected); +} + +TEST_CASE("Row matrix test assignemnt copy and move"){ + depthmapX::RowMatrix matrix(2,3); + matrix(0,0) = "0,0"; + matrix(1,0) = "1,0"; + matrix(0,1) = "0,1"; + matrix(1,1) = "1,1"; + matrix(1,2) = "1,2"; + matrix(0,2) = "0,2"; + + std::vector expected{"0,0", "0,1", "0,2", "1,0", "1,1", "1,2"}; + compareMatrixContent(matrix, expected); + + depthmapX::RowMatrix copy(matrix); + compareMatrixContent(matrix, expected); + compareMatrixContent(copy, expected); + + depthmapX::RowMatrix clone(std::move(copy)); + compareMatrixContent(clone, expected); + REQUIRE(copy.size() == 0); + + copy = clone; + compareMatrixContent(copy, expected); + REQUIRE(copy.columns() == 3); + REQUIRE(copy.rows() == 2); + compareMatrixContent(clone, expected); + + depthmapX::RowMatrix assignMove(1,1); + assignMove = std::move(copy); + compareMatrixContent(assignMove, expected); + REQUIRE(copy.size() == 0); +} + +TEST_CASE("Row matrix test exceptions"){ + depthmapX::RowMatrix matrix(2, 3); + matrix(0,0) = 1; + matrix(1,2) = -1; + matrix(0,1) = 2; + matrix(0,2) = 3; + matrix(1,0) = -23; + matrix(1,1) = 0; + + REQUIRE(matrix(1,2) == -1); + + compareMatrixContent(matrix, std::vector{1, 2, 3, -23, 0, -1}); + + REQUIRE_THROWS_WITH(matrix(5, 0), Catch::Contains("row out of range")); + REQUIRE_THROWS_WITH(matrix(0, 5), Catch::Contains("column out of range")); +} + +TEST_CASE("Column matrix test assignemnt copy and move"){ + depthmapX::ColumnMatrix matrix(2,3); + matrix(0,0) = "0,0"; + matrix(1,0) = "1,0"; + matrix(0,1) = "0,1"; + matrix(1,1) = "1,1"; + matrix(1,2) = "1,2"; + matrix(0,2) = "0,2"; + + std::vector expected{"0,0", "1,0", "0,1", "1,1", "0,2", "1,2"}; + compareMatrixContent(matrix, expected); + + depthmapX::ColumnMatrix copy(matrix); + compareMatrixContent(matrix, expected); + compareMatrixContent(copy, expected); + + depthmapX::ColumnMatrix clone(std::move(copy)); + compareMatrixContent(clone, expected); + REQUIRE(copy.size() == 0); + + copy = clone; + compareMatrixContent(copy, expected); + REQUIRE(copy.columns() == 3); + REQUIRE(copy.rows() == 2); + compareMatrixContent(clone, expected); + + depthmapX::ColumnMatrix assignMove(1,1); + assignMove = std::move(copy); + compareMatrixContent(assignMove, expected); + REQUIRE(copy.size() == 0); + +} + +TEST_CASE("Column matrix test exceptions"){ + depthmapX::ColumnMatrix matrix(2, 3); + matrix(0,0) = 1; + matrix(1,2) = -1; + matrix(0,1) = 2; + matrix(0,2) = 3; + matrix(1,0) = -23; + matrix(1,1) = 0; + + REQUIRE(matrix(1,2) == -1); + + compareMatrixContent(matrix, std::vector{1, -23, 2, 0, 3, -1}); + + REQUIRE_THROWS_WITH(matrix(5, 0), Catch::Contains("row out of range")); + REQUIRE_THROWS_WITH(matrix(0, 5), Catch::Contains("column out of range")); +} + +TEST_CASE("Fill and reset"){ + depthmapX::ColumnMatrix matrix(2,3); + matrix.initialiseValues(-42); + compareMatrixContent(matrix, std::vector(6, -42)); + + matrix.reset(3,4); + REQUIRE(matrix.rows() == 3); + REQUIRE(matrix.columns() == 4); + + matrix.initialiseValues(12); + compareMatrixContent(matrix, std::vector(12, 12)); +} diff --git a/genlibTest/teststringutils.cpp b/genlibTest/teststringutils.cpp new file mode 100644 index 00000000..c17c8b8a --- /dev/null +++ b/genlibTest/teststringutils.cpp @@ -0,0 +1,230 @@ +// Copyright (C) 2017-2018 Christian Sailer +// Copyright (C) 2017-2018 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "../genlib/stringutils.h" +#include "../cliTest/selfcleaningfile.h" +#include + +TEST_CASE("Tests for split function", "") +{ + { + std::vector stringParts = dXstring::split("foo,bar",','); + REQUIRE(stringParts.size() == 2); + REQUIRE(stringParts[0] == "foo"); + REQUIRE(stringParts[1] == "bar"); + } + + { + std::vector stringParts = dXstring::split("0.5,1.2",','); + REQUIRE(stringParts.size() == 2); + REQUIRE(stringParts[0] == "0.5"); + REQUIRE(stringParts[1] == "1.2"); + } + + { + std::vector stringParts = dXstring::split("0.5\t1.2",'\t'); + REQUIRE(stringParts.size() == 2); + REQUIRE(stringParts[0] == "0.5"); + REQUIRE(stringParts[1] == "1.2"); + } + + { + std::vector stringParts = dXstring::split("0.5\t1.2\tfoo",'\t'); + REQUIRE(stringParts.size() == 3); + REQUIRE(stringParts[0] == "0.5"); + REQUIRE(stringParts[1] == "1.2"); + REQUIRE(stringParts[2] == "foo"); + } + + { + // skip last blank element + std::vector stringParts = dXstring::split("foo,bar,",','); + REQUIRE(stringParts.size() == 2); + } + + { + // do not skip middle blank element + std::vector stringParts = dXstring::split("foo,,bar",','); + REQUIRE(stringParts.size() == 3); + } + + { + // do skip any empty elements when flag is set + // do not skip middle blank element + std::vector stringParts = dXstring::split("foo,,bar",',', true); + REQUIRE(stringParts.size() == 2); + } +} + +TEST_CASE("Read String") +{ + { + // case empty string - just read 0 length and return new string object + SelfCleaningFile f("test.bin"); + { + std::ofstream fs(f.Filename()); + unsigned int length = 0; + fs.write(reinterpret_cast(&length), sizeof(unsigned int)); + } + std::ifstream fs(f.Filename()); + auto result = dXstring::readString(fs); + REQUIRE(result.empty()); + } + + // case non empty string - read length and then beam data into the string + { + SelfCleaningFile f("test.bin"); + { + std::ofstream fs(f.Filename()); + unsigned int length = 5; + const char *payload = "abcde"; + fs.write(reinterpret_cast(&length), sizeof(unsigned int)); + fs.write(payload, 5); + } + std::ifstream fs(f.Filename()); + std::string result = dXstring::readString(fs); + REQUIRE(result == "abcde"); + } +} + +TEST_CASE("Write String") +{ + { + // case empty string - just write 0 length + std::string testString; + SelfCleaningFile f("test.bin"); + { + std::ofstream fs(f.Filename()); + dXstring::writeString(fs, testString); + } + std::ifstream fs(f.Filename()); + unsigned int length; + fs.read(reinterpret_cast(&length), sizeof(unsigned int)); + REQUIRE(length == 0); + char dummy[1]; + REQUIRE_FALSE(fs.read(dummy, 1)); + REQUIRE(fs.eof()); + } + + { + // case non empty string - just write length plus content + std::string testString("cdfe"); + SelfCleaningFile f("test.bin"); + { + std::ofstream fs(f.Filename()); + dXstring::writeString(fs, testString); + } + std::ifstream fs(f.Filename()); + unsigned int length; + fs.read(reinterpret_cast(&length), sizeof(unsigned int)); + REQUIRE(length == testString.length()); + char buffer[5]; + buffer[4] = '\0'; + fs.read(buffer, length); + REQUIRE(testString == buffer); + char dummy[1]; + REQUIRE_FALSE(fs.read(dummy, 1)); + REQUIRE(fs.eof()); + } +} + + +TEST_CASE("test string format") +{ + REQUIRE(dXstring::formatString(1.0, "foo") == "foo"); + REQUIRE(dXstring::formatString(1.0, "%+.16le") == "+1.0000000000000000e+00"); + REQUIRE(dXstring::formatString(1.0) == "+1.0000000000000000e+00"); + REQUIRE(dXstring::formatString(1.0, "%+.8le") == "+1.00000000e+00"); + REQUIRE(dXstring::formatString(1 ) == " 1"); +} + +TEST_CASE("test tolower") +{ + std::string tstr = "AbdUgs24*hHÜ"; + auto result = dXstring::toLower(tstr); + REQUIRE(tstr == "abdugs24*hhÜ"); + REQUIRE(result == "abdugs24*hhÜ"); +} + +TEST_CASE("test ltrim") +{ + std::string normal = " fo o "; + dXstring::ltrim(normal); + REQUIRE( normal == "fo o "); + std::string empty = ""; + dXstring::ltrim(empty); + REQUIRE( empty == "" ); + std::string justBlanks = " "; + dXstring::ltrim(justBlanks); + REQUIRE( justBlanks == ""); + std::string noBlanks = "foo "; + dXstring::ltrim(noBlanks); + REQUIRE(noBlanks == "foo "); +} + +TEST_CASE("test rtrim") +{ + std::string normal = " fo o "; + dXstring::rtrim(normal); + REQUIRE( normal == " fo o"); + std::string empty = ""; + dXstring::rtrim(empty); + REQUIRE( empty == "" ); + std::string justBlanks = " "; + dXstring::rtrim(justBlanks); + REQUIRE( justBlanks == ""); + std::string noBlanks = "foo "; + dXstring::rtrim(noBlanks); + REQUIRE(noBlanks == "foo"); +} + +TEST_CASE("test makeInitCaps") +{ + std::string tstr = "abC DEf dEf \"fOO Bar\" blah bLuB"; + dXstring::makeInitCaps(tstr); + REQUIRE(tstr == "Abc Def Def \"fOO Bar\" Blah Blub"); +} + +TEST_CASE("test isDouble") +{ + REQUIRE(dXstring::isDouble("0")); + REQUIRE(dXstring::isDouble(" 1.345e23.1")); + REQUIRE_FALSE(dXstring::isDouble("")); + REQUIRE_FALSE(dXstring::isDouble("foo1234")); +} + +TEST_CASE("test begins with") +{ + REQUIRE(dXstring::beginsWith("abcd", "abcd")); + REQUIRE(dXstring::beginsWith("abcde", "abcd")); + REQUIRE_FALSE(dXstring::beginsWith("abcd", "abcde")); + REQUIRE_FALSE(dXstring::beginsWith("abcd", "ef")); + REQUIRE_FALSE(dXstring::beginsWith("abcd", "aec")); +} + +TEST_CASE("test safeGetline") +{ + std::stringstream stream; + std::string out; + + SECTION("Windows") { stream << "Test\r"; } + SECTION("Unix") { stream << "Test\n"; } + SECTION("Mixed") { stream << "Test\r\n"; } + + dXstring::safeGetline(stream, out); + REQUIRE(out == "Test"); +} diff --git a/mgraph440/CMakeLists.txt b/mgraph440/CMakeLists.txt new file mode 100644 index 00000000..e17945c8 --- /dev/null +++ b/mgraph440/CMakeLists.txt @@ -0,0 +1,30 @@ +set(mgraph440 mgraph440) +set(mgraph440_SRCS + pafcolor.cpp + attr.cpp + ngraph.cpp + datalayer.cpp + pointmap.cpp + attributes.cpp + connector.cpp + mgraph.cpp + axialmap.cpp + shapemap.cpp + pixelbase.cpp + spacepix.cpp + point.cpp + stringutils.cpp + p2dpoly.cpp + salaprogram.cpp + pafmath.cpp) + +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR + "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set(warnings "-Wnone") +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + set(warnings "/W0 /EHsc /wd4800") +endif() + +add_compile_definitions(MGRAPH440_LIBRARY) + +add_library(${mgraph440} ${mgraph440_SRCS}) diff --git a/salalib/vertex.cpp b/mgraph440/attr.cpp similarity index 58% rename from salalib/vertex.cpp rename to mgraph440/attr.cpp index 10d070e6..6510a13c 100644 --- a/salalib/vertex.cpp +++ b/mgraph440/attr.cpp @@ -1,657 +1,422 @@ -// sala - a component of the depthmapX - spatial network analysis platform -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// This is my code to make a set of axial lines from a set of boundary lines - -#include -#include // _finite support - -#include // <- sala actually includes vertex.h for us - -////////////////////////////////////////////////////////////////////////////// - -static unsigned int g_nicecolor[] = { - 0x003333DD, // 0 blue - 0x003388DD, // 1 - 0x0022CCDD, // 2 - 0x0022CCBB, // 3 - 0x0022DD88, // 4 - 0x0088DD22, // 5 - 0x00BBCC22, // 6 - 0x00DDCC22, // 7 - 0x00DD8833, // 8 - 0x00DD3333, // 9 red -}; - -// Test a range designed to try to keep consitent saturation and brightness of g_nicecolor, and only move hue -static unsigned int g_nicecolorhsb[] = { - 0x003333DD, // 0 blue - 0x003377DD, // 1 - 0x0033BBDD, // 2 - 0x0033DDBB, // 3 - 0x0033DD55, // 4 - 0x0055DD33, // 5 - 0x00BBDD33, // 6 - 0x00DDBB33, // 7 - 0x00DD7733, // 8 - 0x00DD3333, // 9 red -}; - - -static unsigned int g_hsbcolor[] = { - 0x003333DD, // 0 blue - 0x003388DD, // 1 - 0x0022CCDD, // 2 - 0x0022CCBB, // 3 - 0x0022DD88, // 4 - 0x0088DD22, // 5 - 0x00BBCC22, // 6 - 0x00DDCC22, // 7 - 0x00DD8833, // 8 - 0x00DD3333, // 9 red -}; - - -static unsigned int g_greyscale[] = { - 0x00000000, // 0 black - 0x00444444, // 1 - 0x00777777, // 2 - 0x00AAAAAA, // 3 - 0x00CCCCCC, // 4 - 0x00EEEEEE, // 5 - 0x00FFFFFF, // 6 white -}; - -static unsigned int g_bluered[] = { - 0x004575B4, // 0 blue - 0x0091BFDB, - 0x00E0F3F8, - 0x00FFFFBF, - 0x00FEE090, - 0x00FC8D59, - 0x00D73027 // 6 red -}; - -static unsigned int g_purpleorange[] = { - 0x00542788, // 0 purple - 0x00998EC3, // 1 - 0x00D8DAEB, // 2 - 0x00F7F7F7, // 3 - 0x00FEE0B6, // 4 - 0x00F1A340, // 5 - 0x00B35806 // 6 orange -}; - -// htmlByte converts a normalised number to an HTML safe byte - -unsigned char htmlByte(double colorByte) -{ - // Quick mod - TV -#if defined(_WIN32) - return (unsigned char((colorByte + 0.0333) * 15.0) * 0x11); -#else - return ((unsigned char)((colorByte + 0.0333) * 15.0) * 0x11); -#endif -} - -PafColor& PafColor::makeColor(double field, DisplayParams dp) -{ - // Quick mod - TV - if (field == -1.0 || std::isnan(field)) { - // -1.0 is (currently) a nan value, set alpha channel to 0 (transparent) - switch (dp.colorscale) { - case DisplayParams::MONOCHROME: - case DisplayParams::GREYSCALE: - m_color = 0x00000000; // <- monochrome and greyscale, simply hide - break; - default: - // if in colour, then show greyed out: - m_color = 0x007f7f7f; // <- grey retained for visibility on certain values - break; - } - return *this; - } - if (dp.blue > dp.red) { - field = 1.0 - field; - dp.blue = 1.0f - dp.blue; - dp.red = 1.0f - dp.red; - } - if (dp.colorscale == DisplayParams::DEPTHMAPCLASSIC) { - makeDepthmapClassic(field, dp.blue, dp.red); - } - else { - field = (field - dp.blue) / (dp.red - dp.blue); - // Quick mod - TV - if (std::isnan(field)) { - field = 0.5; - } - if (field > 1.0) { - field = 1.0; - } - else if (field < 0.0) { - field = 0.0; - } - switch(dp.colorscale) { - case DisplayParams::AXMANESQUE: - makeAxmanesque(field); - break; - case DisplayParams::PURPLEORANGE: - makePurpleOrange(field); - break; - case DisplayParams::BLUERED: - makeBlueRed(field); - break; - case DisplayParams::GREYSCALE: - case DisplayParams::MONOCHROME: - makeGreyScale(field); - break; - } - } - return *this; -} - -// this makes an Axman-like colour range - -PafColor& PafColor::makeAxmanesque( double field ) -{ - m_color = 0xff000000 | g_nicecolor[int((field - 1e-9) * 10.0)]; - return *this; -} - -// this makes a purple-orange scheme that is red-green colour-blind safe - -PafColor& PafColor::makePurpleOrange( double field ) -{ - m_color = 0xff000000 | g_purpleorange[int((field - 1e-9) * 7.0)]; - return *this; -} - -// this makes a blue-red scheme that is red-green colour-blind safe - -PafColor& PafColor::makeBlueRed( double field ) -{ - m_color = 0xff000000 | g_bluered[int((field - 1e-9) * 7.0)]; - return *this; -} - -// this makes a greyscale colour range - -PafColor& PafColor::makeGreyScale( double field ) -{ - m_color = 0xff000000 | g_greyscale[int((field - 1e-9) * 7.0)]; - return *this; -} - -// note, makeDepthmapClassic converts to a safe HTML colour - -PafColor& PafColor::makeDepthmapClassic( double field, double blue, double red ) -{ - m_color = 0xff000000; // set alpha to 255, solid colour - double green = blue + (red-blue) / 10.0; - // NB previously included colour muting: the 1.0 was originally 0.9 to mute the colours slightly - if (field >= 0.0 && field < blue) { - setr(htmlByte(0.5 * (blue - field)/blue * 1.0)); - // Quick mod - TV -#if defined(_WIN32) - setb(unsigned char(0xFF)); -#else - setb((unsigned char)(0xFF)); -#endif - } - else if (field >= blue && field < (green+blue)/2.0) { - // Quick mod - TV -#if defined(_WIN32) - setb(unsigned char(0xFF)); -#else - setb((unsigned char)(0xFF)); -#endif - setg(htmlByte((2.0*(field - blue)/(green-blue)) * 1.0)); - } - else if (field >= (green+blue)/2.0 && field < green) { - setb(htmlByte((2.0*(green - field)/(green-blue)) * 1.0)); - // Quick mod - TV -#if defined(_WIN32) - setg(unsigned char(0xFF)); -#else - setg((unsigned char)(0xFF)); -#endif - } - else if (field >= green && field < (green+red)/2.0 ) { - // Quick mod - TV -#if defined(_WIN32) - setg(unsigned char(0xFF)); -#else - setg((unsigned char)(0xFF)); -#endif - setr(htmlByte((2.0*(field - green)/(red-green)) * 1.0)); - } - else if (field >= (green+red)/2.0 && field < red) { - setg(htmlByte((2.0*(red - field)/(red-green)) * 1.0)); - // Quick mod - TV -#if defined(_WIN32) - setr(unsigned char(0xFF)); -#else - setr((unsigned char)(0xFF)); -#endif - } - else if (field >= red) { - // Quick mod - TV -#if defined(_WIN32) - setr(unsigned char(0xFF)); -#else - setr((unsigned char)(0xFF)); -#endif - setb(htmlByte(0.5 * (field - red)/(1.0 - red) * 1.0)); - } - return *this; -} - - -////////////////////////////////////////////////////////////////////////////// - -void AttrHeader::reset(AttrVal attributes[]) -{ - attributes[NEIGHBOURHOOD_SIZE].intval = -1; - attributes[GRAPH_SIZE].intval = -1; - attributes[KERNEL_SIZE].intval = -1; - attributes[CLIQUE_SIZE].intval = -1; - attributes[TOTAL_DEPTH].intval = -1; - attributes[ENTROPY].floatval = -1.0f; - attributes[REL_ENTROPY].floatval = -1.0f; - attributes[CLUSTER].floatval = -1.0f; - attributes[UNUSED].floatval = -1.0f; - attributes[POINT_DEPTH].intval = -1; - attributes[CONTROL_HILL].floatval = -1.0f; - attributes[CONTROL_TURN].floatval = -1.0f; - attributes[MEDIAN_ANGLE].floatval = -1.0f; - attributes[FAR_NODE].intval = -1; - attributes[FAR_DIST].floatval = -1.0f; - attributes[TOTAL_DIST].floatval = -1.0f; - attributes[AGENT_COUNT].intval = -1; - attributes[AGENT_COLL_COUNT].intval = -1; - attributes[TOTAL_METRIC_DEPTH].floatval = -1.0f; - attributes[METRIC_GRAPH_SIZE].intval = -1; - attributes[METRIC_POINT_DEPTH].floatval = -1.0f; - attributes[TOTAL_EUCLID_DIST].floatval = -1.0f; - attributes[POINT_EUCLID_DIST].floatval = -1.0f; - attributes[TOTAL_METRIC_ANGLE].floatval = -1.0f; - attributes[METRIC_POINT_ANGLE].floatval = -1.0f; -} - -#define QUICK_MD (double(attributes[TOTAL_DEPTH].intval) / double(attributes[GRAPH_SIZE].intval - 1)) -#define QUICK_METRIC_MD (double(attributes[TOTAL_METRIC_DEPTH].floatval) / double(attributes[METRIC_GRAPH_SIZE].intval - 1)) -#define QUICK_METRIC_AMD (double(attributes[TOTAL_METRIC_ANGLE].floatval) / double(attributes[METRIC_GRAPH_SIZE].intval - 1)) - -double AttrHeader::getAttr(int attr, const AttrVal attributes[]) const -{ - double val; - // will eventually put the attributes in a table - switch (attr) { - case NEIGHBOURHOOD_SIZE: - val = double(attributes[NEIGHBOURHOOD_SIZE].intval); - break; - case GRAPH_SIZE: - val = double(attributes[GRAPH_SIZE].intval); - break; - case MEAN_DEPTH: - if (attributes[GRAPH_SIZE].intval > 1) { - val = QUICK_MD; - } - else { - val = -1.0; - } - break; - case INTEGRATION_RA: - if (attributes[GRAPH_SIZE].intval > 2) { - val = 2.0 * (QUICK_MD - 1.0) / double(attributes[GRAPH_SIZE].intval - 2); - } - else { - val = -1.0; - } - break; - case INTEGRATION_RRA: - if (attributes[GRAPH_SIZE].intval > 2) { - val = (2.0 * (QUICK_MD - 1.0)) / (double(attributes[GRAPH_SIZE].intval - 2) * dvalue(attributes[GRAPH_SIZE].intval)); - } - else { - val = -1.0; - } - break; - case INTEGRATION_HILL: - if (attributes[GRAPH_SIZE].intval > 2 && attributes[TOTAL_DEPTH].intval > attributes[GRAPH_SIZE].intval) { - val = (double(attributes[GRAPH_SIZE].intval - 2) * dvalue(attributes[GRAPH_SIZE].intval)) / (2.0 * (QUICK_MD - 1.0)); - } - else { - val = -1.0; - } - break; - case INTEGRATION_TEKL: - if (attributes[GRAPH_SIZE].intval > 2 && attributes[TOTAL_DEPTH].intval > attributes[GRAPH_SIZE].intval) { - val = ln(double(attributes[GRAPH_SIZE].intval - 2)/2.0) / - ln(double(attributes[TOTAL_DEPTH].intval - attributes[GRAPH_SIZE].intval + 1)); - } - else { - val = -1.0; - } - break; - case POINT_DEPTH: - val = attributes[POINT_DEPTH].intval; - break; - case AVG_DIST: - if (attributes[NEIGHBOURHOOD_SIZE].intval > 0) { - val = attributes[TOTAL_DIST].floatval / double(attributes[NEIGHBOURHOOD_SIZE].intval); - } - else { - val = -1.0; - } - break; - case AGENT_COUNT: - val = attributes[attr].intval; - break; - case AGENT_COLL_COUNT: - val = attributes[attr].intval; - break; - case METRIC_MEAN_DEPTH: - if (attributes[METRIC_GRAPH_SIZE].intval > 1) { - val = QUICK_METRIC_MD; - } - else { - val = -1.0; - } - break; - case METRIC_MEAN_ANGLE: - if (attributes[METRIC_GRAPH_SIZE].intval > 1) { - val = QUICK_METRIC_AMD; - } - else { - val = -1.0; - } - break; - case DECENTRAL_INTEG: - if (attributes[TOTAL_METRIC_DEPTH].floatval >= 0.0 && attributes[TOTAL_DEPTH].intval > 0) { - val = ln(attributes[TOTAL_METRIC_DEPTH].floatval+1.0) / double(attributes[TOTAL_DEPTH].intval); - } - else { - val = -1.0; - } - break; - case MEAN_PENN_DIST: - if (attributes[METRIC_GRAPH_SIZE].intval > 1) { - if (attributes[TOTAL_METRIC_DEPTH].floatval > attributes[TOTAL_EUCLID_DIST].floatval) { - val = double(attributes[TOTAL_METRIC_DEPTH].floatval - attributes[TOTAL_EUCLID_DIST].floatval) - / double(attributes[METRIC_GRAPH_SIZE].intval); - } - else { - val = 0.0f; - } - } - else { - val = -1.0f; - } - break; - case POINT_PENN_DIST: - if (attributes[METRIC_POINT_DEPTH].floatval >= 0.0) { - if (attributes[METRIC_POINT_DEPTH].floatval > attributes[POINT_EUCLID_DIST].floatval) { - val = attributes[METRIC_POINT_DEPTH].floatval - attributes[POINT_EUCLID_DIST].floatval; - } - else { - val = 0.0f; - } - } - else { - val = -1.0f; - } - break; - default: - val = attributes[attr].floatval; - break; - } - return val; -} - -/////////////////////////////////////////////////////////////////////////////////// - -AttrBody::AttrBody( streampos p, const AttrHeader& h ) -{ - pos = p; - ref = -1; - header = (AttrHeader *) &h; - - color = 0.5; - highlight = false; - myagent = NULL; - - attributes = new AttrVal[header->m_attr_count]; - - header->reset(attributes); -} - -AttrBody::AttrBody(const AttrBody& attr) -{ - pos = attr.pos; - ref = attr.ref; - origin = attr.origin; - header = attr.header; - - color = attr.color; - highlight = attr.highlight; - myagent = attr.myagent; - - if (attr.attributes) { - attributes = new AttrVal[header->m_attr_count]; - // fill in with original attributes: - for (int i = 0; i < header->m_attr_count; i++) { - attributes[i] = attr.attributes[i]; - } - } -} - -AttrBody::~AttrBody() -{ - if (attributes) { - delete [] attributes; - attributes = NULL; - } -} - -ostream& operator << (ostream& stream, const AttrBody& attr) -{ - stream << attr.ref << "\t"; - stream << attr.origin.x << "\t" << attr.origin.y << "\t" << attr.origin.z; - - for (int i = 0; i < NUM_SUMMARISABLE_ATTRIBUTES; i++) { - if (g_attr_summary_map[i].usable()) { - if (g_attr_summary_map[i].intval()) { - stream << "\t" << attr.attributes[g_attr_summary_map[i].ref].intval; - } - else { - stream << "\t" << attr.attributes[g_attr_summary_map[i].ref].floatval; - } - } - } - - return stream; -} - -void AttrBody::write( ofstream& stream ) const -{ - stream.write( (char *) &pos, sizeof(pos) ); - stream.write( (char *) &ref, sizeof(ref) ); - stream.write( (char *) &origin, sizeof(origin) ); - if (attributes) { - stream.write( (char *) attributes, sizeof(AttrVal) * (header->m_attr_count) ); - } -} - -void AttrBody::read( ifstream& stream, int attr_count ) -{ - stream.read( (char *) &pos, sizeof(pos) ); - stream.read( (char *) &ref, sizeof(ref) ); - stream.read( (char *) &origin, sizeof(origin) ); - if (attributes) { - stream.read( (char *) attributes, sizeof(AttrVal) * attr_count ); - } -} - -/////////////////////////////////////////////////////////////////////////////////// - -bool ArVertexList::openwrite( int nodes ) -{ -#ifdef _WIN32 - m_stream = new fstream( m_filename.c_str(), ios::binary | ios::out | ios::trunc ); -#else - m_stream = new fstream( m_filename.c_str(), ios::out | ios::trunc ); -#endif - - if (m_stream->fail()) { - if (m_stream->rdbuf()->is_open()) { - remove(); - } - if (m_stream) { - delete m_stream; - m_stream = NULL; - } - return false; - } - - m_stream->write( "grf", 3 ); - int version = METAGRAPH_VERSION; - m_stream->write( (char *) &version, sizeof(int) ); - m_stream->write( "v", 1 ); // <- signifies virtual memory section - m_stream->write( (char *) &nodes, sizeof(nodes) ); - - return true; -} - -void ArVertexList::openread() -{ -#ifdef _WIN32 - m_stream = new fstream( m_filename.c_str(), ios::binary | ios::in ); -#else - m_stream = new fstream( m_filename.c_str(), ios::in ); -#endif -} - -void ArVertexList::close() -{ - if (m_stream) { - if (m_stream->rdbuf()->is_open()) { - m_stream->close(); - } - delete m_stream; m_stream = NULL; - } -} - -void ArVertexList::remove() -{ - close(); - if (!m_filename.empty()) { - // Quick mod - TV -#if defined(_WIN32) - _unlink(m_filename.c_str()); -#else - unlink(m_filename.c_str()); -#endif - m_filename = pstring(); - } -} - -void ArVertexList::add( int ref, const ArVertex& node ) -{ - m_cache_ref = ref; - m_cache_data = node; -} - -void ArVertexList::commit() // Copy -{ - if (m_cache_ref != -1) { - streampos pos = m_stream->tellp(); - m_attributes[m_cache_ref].pos = pos; - m_cache_data.write( (ofstream&) *m_stream ); - m_cache_data.clear(); - m_stream->flush(); - } - m_cache_ref = -1; -} - -void ArVertexList::commit(const Point2f& p, int far_node, float far_dist, float total_dist) // Add -{ - if (m_cache_ref != -1) { - streampos pos = m_stream->tellp(); - AttrBody attr(pos, m_attr_header); - { - // a few values we know - attr.ref = m_cache_ref; - attr.origin.x = p.x; - attr.origin.y = p.y; - attr.intval(AttrHeader::NEIGHBOURHOOD_SIZE) = m_cache_data.size(); - attr.intval(AttrHeader::FAR_NODE) = far_node; - attr.floatval(AttrHeader::FAR_DIST) = far_dist; - attr.floatval(AttrHeader::TOTAL_DIST) = total_dist; - } - m_attributes.push_back( attr ); - m_cache_data.write( (ofstream&) *m_stream ); - m_cache_data.clear(); - m_stream->flush(); - } - m_cache_ref = -1; -} - - -// NOTE: ONLY READ AND WRITE ATTRIBUTES! -// (At the moment, complex virtual mem stuff is handled at the meta graph level) - -bool ArVertexList::read( ifstream& stream, int metagraph_version ) -{ - m_metagraph_version = metagraph_version; - - int attr_count; - stream.read( (char *) &m_which_attributes, sizeof(m_which_attributes) ); - stream.read( (char *) &attr_count, sizeof(int) ); - - int size; - stream.read( (char *) &size, sizeof(int) ); - - m_attributes.clear(); - for (int i = 0; i < size; i++) { - AttrBody attr(-1, m_attr_header); - attr.read(stream, attr_count); // <- only write in saved attributes - m_attributes.push_back( attr ); - } - - m_cache_ref = -1; // just in case... should really set this with virtual mem stuff... - - return true; -} - -bool ArVertexList::write( ofstream& stream ) -{ - stream.write( (char *) &m_which_attributes, sizeof(m_which_attributes) ); - // I'm phasing this out again for now (attribute header), - // I'm thinking the map should really be stored rather than the header, - // in any case, the only important think about the header is the number of - // attributes... - stream.write( (char *) &m_attr_header.m_attr_count, sizeof(int) ); - - int size = m_attributes.size(); - stream.write( (char *) &size, sizeof(int) ); - - for (size_t i = 0; i < m_attributes.size(); i++) { - m_attributes[i].write( stream ); - } - - return true; -} +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// This is my code to make a set of axial lines from a set of boundary lines + +#include "mgraph440/attr.h" + +#include +#include // _finite support + +////////////////////////////////////////////////////////////////////////////// + +namespace mgraph440 { + +void AttrHeader::reset(AttrVal attributes[]) +{ + attributes[NEIGHBOURHOOD_SIZE].intval = -1; + attributes[GRAPH_SIZE].intval = -1; + attributes[KERNEL_SIZE].intval = -1; + attributes[CLIQUE_SIZE].intval = -1; + attributes[TOTAL_DEPTH].intval = -1; + attributes[ENTROPY].floatval = -1.0f; + attributes[REL_ENTROPY].floatval = -1.0f; + attributes[CLUSTER].floatval = -1.0f; + attributes[UNUSED].floatval = -1.0f; + attributes[POINT_DEPTH].intval = -1; + attributes[CONTROL_HILL].floatval = -1.0f; + attributes[CONTROL_TURN].floatval = -1.0f; + attributes[MEDIAN_ANGLE].floatval = -1.0f; + attributes[FAR_NODE].intval = -1; + attributes[FAR_DIST].floatval = -1.0f; + attributes[TOTAL_DIST].floatval = -1.0f; + attributes[AGENT_COUNT].intval = -1; + attributes[AGENT_COLL_COUNT].intval = -1; + attributes[TOTAL_METRIC_DEPTH].floatval = -1.0f; + attributes[METRIC_GRAPH_SIZE].intval = -1; + attributes[METRIC_POINT_DEPTH].floatval = -1.0f; + attributes[TOTAL_EUCLID_DIST].floatval = -1.0f; + attributes[POINT_EUCLID_DIST].floatval = -1.0f; + attributes[TOTAL_METRIC_ANGLE].floatval = -1.0f; + attributes[METRIC_POINT_ANGLE].floatval = -1.0f; +} + +#define QUICK_MD (double(attributes[TOTAL_DEPTH].intval) / double(attributes[GRAPH_SIZE].intval - 1)) +#define QUICK_METRIC_MD (double(attributes[TOTAL_METRIC_DEPTH].floatval) / double(attributes[METRIC_GRAPH_SIZE].intval - 1)) +#define QUICK_METRIC_AMD (double(attributes[TOTAL_METRIC_ANGLE].floatval) / double(attributes[METRIC_GRAPH_SIZE].intval - 1)) + +double AttrHeader::getAttr(int attr, const AttrVal attributes[]) const +{ + double val; + // will eventually put the attributes in a table + switch (attr) { + case NEIGHBOURHOOD_SIZE: + val = double(attributes[NEIGHBOURHOOD_SIZE].intval); + break; + case GRAPH_SIZE: + val = double(attributes[GRAPH_SIZE].intval); + break; + case MEAN_DEPTH: + if (attributes[GRAPH_SIZE].intval > 1) { + val = QUICK_MD; + } + else { + val = -1.0; + } + break; + case INTEGRATION_RA: + if (attributes[GRAPH_SIZE].intval > 2) { + val = 2.0 * (QUICK_MD - 1.0) / double(attributes[GRAPH_SIZE].intval - 2); + } + else { + val = -1.0; + } + break; + case INTEGRATION_RRA: + if (attributes[GRAPH_SIZE].intval > 2) { + val = (2.0 * (QUICK_MD - 1.0)) / (double(attributes[GRAPH_SIZE].intval - 2) * dvalue(attributes[GRAPH_SIZE].intval)); + } + else { + val = -1.0; + } + break; + case INTEGRATION_HILL: + if (attributes[GRAPH_SIZE].intval > 2 && attributes[TOTAL_DEPTH].intval > attributes[GRAPH_SIZE].intval) { + val = (double(attributes[GRAPH_SIZE].intval - 2) * dvalue(attributes[GRAPH_SIZE].intval)) / (2.0 * (QUICK_MD - 1.0)); + } + else { + val = -1.0; + } + break; + case INTEGRATION_TEKL: + if (attributes[GRAPH_SIZE].intval > 2 && attributes[TOTAL_DEPTH].intval > attributes[GRAPH_SIZE].intval) { + val = ln(double(attributes[GRAPH_SIZE].intval - 2)/2.0) / + ln(double(attributes[TOTAL_DEPTH].intval - attributes[GRAPH_SIZE].intval + 1)); + } + else { + val = -1.0; + } + break; + case POINT_DEPTH: + val = attributes[POINT_DEPTH].intval; + break; + case AVG_DIST: + if (attributes[NEIGHBOURHOOD_SIZE].intval > 0) { + val = attributes[TOTAL_DIST].floatval / double(attributes[NEIGHBOURHOOD_SIZE].intval); + } + else { + val = -1.0; + } + break; + case AGENT_COUNT: + val = attributes[attr].intval; + break; + case AGENT_COLL_COUNT: + val = attributes[attr].intval; + break; + case METRIC_MEAN_DEPTH: + if (attributes[METRIC_GRAPH_SIZE].intval > 1) { + val = QUICK_METRIC_MD; + } + else { + val = -1.0; + } + break; + case METRIC_MEAN_ANGLE: + if (attributes[METRIC_GRAPH_SIZE].intval > 1) { + val = QUICK_METRIC_AMD; + } + else { + val = -1.0; + } + break; + case DECENTRAL_INTEG: + if (attributes[TOTAL_METRIC_DEPTH].floatval >= 0.0 && attributes[TOTAL_DEPTH].intval > 0) { + val = ln(attributes[TOTAL_METRIC_DEPTH].floatval+1.0) / double(attributes[TOTAL_DEPTH].intval); + } + else { + val = -1.0; + } + break; + case MEAN_PENN_DIST: + if (attributes[METRIC_GRAPH_SIZE].intval > 1) { + if (attributes[TOTAL_METRIC_DEPTH].floatval > attributes[TOTAL_EUCLID_DIST].floatval) { + val = double(attributes[TOTAL_METRIC_DEPTH].floatval - attributes[TOTAL_EUCLID_DIST].floatval) + / double(attributes[METRIC_GRAPH_SIZE].intval); + } + else { + val = 0.0f; + } + } + else { + val = -1.0f; + } + break; + case POINT_PENN_DIST: + if (attributes[METRIC_POINT_DEPTH].floatval >= 0.0) { + if (attributes[METRIC_POINT_DEPTH].floatval > attributes[POINT_EUCLID_DIST].floatval) { + val = attributes[METRIC_POINT_DEPTH].floatval - attributes[POINT_EUCLID_DIST].floatval; + } + else { + val = 0.0f; + } + } + else { + val = -1.0f; + } + break; + default: + val = attributes[attr].floatval; + break; + } + return val; +} + +/////////////////////////////////////////////////////////////////////////////////// + +AttrBody::AttrBody( std::streampos p, const AttrHeader& h ) +{ + pos = p; + ref = -1; + header = (AttrHeader *) &h; + + color = 0.5; + highlight = false; + myagent = NULL; + + attributes = new AttrVal[header->m_attr_count]; + + header->reset(attributes); +} + +AttrBody::AttrBody(const AttrBody& attr) +{ + pos = attr.pos; + ref = attr.ref; + origin = attr.origin; + header = attr.header; + + color = attr.color; + highlight = attr.highlight; + myagent = attr.myagent; + + if (attr.attributes) { + attributes = new AttrVal[header->m_attr_count]; + // fill in with original attributes: + for (int i = 0; i < header->m_attr_count; i++) { + attributes[i] = attr.attributes[i]; + } + } +} + +AttrBody::~AttrBody() +{ + if (attributes) { + delete [] attributes; + attributes = NULL; + } +} + +std::ostream& operator << (std::ostream& stream, const AttrBody& attr) +{ + stream << attr.ref << "\t"; + stream << attr.origin.x << "\t" << attr.origin.y << "\t" << attr.origin.z; + + for (int i = 0; i < NUM_SUMMARISABLE_ATTRIBUTES; i++) { + if (g_attr_summary_map[i].usable()) { + if (g_attr_summary_map[i].intval()) { + stream << "\t" << attr.attributes[g_attr_summary_map[i].ref].intval; + } + else { + stream << "\t" << attr.attributes[g_attr_summary_map[i].ref].floatval; + } + } + } + + return stream; +} + +void AttrBody::write( std::ostream& stream ) const +{ + stream.write( (char *) &pos, sizeof(pos) ); + stream.write( (char *) &ref, sizeof(ref) ); + stream.write( (char *) &origin, sizeof(origin) ); + if (attributes) { + stream.write( (char *) attributes, sizeof(AttrVal) * (header->m_attr_count) ); + } +} + +void AttrBody::read( std::ifstream& stream, int attr_count ) +{ + stream.read( (char *) &pos, sizeof(pos) ); + stream.read( (char *) &ref, sizeof(ref) ); + stream.read( (char *) &origin, sizeof(origin) ); + if (attributes) { + stream.read( (char *) attributes, sizeof(AttrVal) * attr_count ); + } +} + +/////////////////////////////////////////////////////////////////////////////////// + +bool ArVertexList::openwrite( int nodes ) +{ +#ifdef _WIN32 + m_stream = new std::fstream( m_filename.c_str(), std::ios::binary | std::ios::out | std::ios::trunc ); +#else + m_stream = new std::fstream( m_filename.c_str(), std::ios::out | std::ios::trunc ); +#endif + + if (m_stream->fail()) { + if (m_stream->rdbuf()->is_open()) { + remove(); + } + if (m_stream) { + delete m_stream; + m_stream = NULL; + } + return false; + } + + m_stream->write( "grf", 3 ); + int version = METAGRAPH_VERSION; + m_stream->write( (char *) &version, sizeof(int) ); + m_stream->write( "v", 1 ); // <- signifies virtual memory section + m_stream->write( (char *) &nodes, sizeof(nodes) ); + + return true; +} + +void ArVertexList::openread() +{ +#ifdef _WIN32 + m_stream = new std::fstream( m_filename.c_str(), std::ios::binary | std::ios::in ); +#else + m_stream = new std::fstream( m_filename.c_str(), std::ios::in ); +#endif +} + +void ArVertexList::close() +{ + if (m_stream) { + if (m_stream->rdbuf()->is_open()) { + m_stream->close(); + } + delete m_stream; m_stream = NULL; + } +} + +void ArVertexList::remove() +{ + close(); + if (!m_filename.empty()) { + // Quick mod - TV +#if defined(_MSC_VER) + _unlink(m_filename.c_str()); +#else + unlink(m_filename.c_str()); +#endif + m_filename = ""; + } +} + +void ArVertexList::add( int ref, const ArVertex& node ) +{ + m_cache_ref = ref; + m_cache_data = node; +} + +void ArVertexList::commit() // Copy +{ + if (m_cache_ref != -1) { + std::streampos pos = m_stream->tellp(); + m_attributes[m_cache_ref].pos = pos; + m_cache_data.write( (std::ofstream&) *m_stream ); + m_cache_data.clear(); + m_stream->flush(); + } + m_cache_ref = -1; +} + +void ArVertexList::commit(const Point2f& p, int far_node, float far_dist, float total_dist) // Add +{ + if (m_cache_ref != -1) { + std::streampos pos = m_stream->tellp(); + AttrBody attr(pos, m_attr_header); + { + // a few values we know + attr.ref = m_cache_ref; + attr.origin.x = p.x; + attr.origin.y = p.y; + attr.intval(AttrHeader::NEIGHBOURHOOD_SIZE) = m_cache_data.size(); + attr.intval(AttrHeader::FAR_NODE) = far_node; + attr.floatval(AttrHeader::FAR_DIST) = far_dist; + attr.floatval(AttrHeader::TOTAL_DIST) = total_dist; + } + m_attributes.push_back( attr ); + m_cache_data.write( (std::ofstream&) *m_stream ); + m_cache_data.clear(); + m_stream->flush(); + } + m_cache_ref = -1; +} + + +// NOTE: ONLY READ AND WRITE ATTRIBUTES! +// (At the moment, complex virtual mem stuff is handled at the meta graph level) + +bool ArVertexList::read( std::ifstream& stream, int metagraph_version ) +{ + m_metagraph_version = metagraph_version; + + int attr_count; + stream.read( (char *) &m_which_attributes, sizeof(m_which_attributes) ); + stream.read( (char *) &attr_count, sizeof(int) ); + + int size; + stream.read( (char *) &size, sizeof(int) ); + + m_attributes.clear(); + for (int i = 0; i < size; i++) { + AttrBody attr(-1, m_attr_header); + attr.read(stream, attr_count); // <- only write in saved attributes + m_attributes.push_back( attr ); + } + + m_cache_ref = -1; // just in case... should really set this with virtual mem stuff... + + return true; +} + +bool ArVertexList::write( std::ostream& stream ) +{ + stream.write( (char *) &m_which_attributes, sizeof(m_which_attributes) ); + // I'm phasing this out again for now (attribute header), + // I'm thinking the map should really be stored rather than the header, + // in any case, the only important think about the header is the number of + // attributes... + stream.write( (char *) &m_attr_header.m_attr_count, sizeof(int) ); + + int size = m_attributes.size(); + stream.write( (char *) &size, sizeof(int) ); + + for (size_t i = 0; i < m_attributes.size(); i++) { + m_attributes[i].write( stream ); + } + + return true; +} + +} diff --git a/salalib/vertex.h b/mgraph440/attr.h similarity index 72% rename from salalib/vertex.h rename to mgraph440/attr.h index 06b9b47c..8c41f869 100644 --- a/salalib/vertex.h +++ b/mgraph440/attr.h @@ -1,721 +1,589 @@ -// sala - a component of the depthmapX - spatial network analysis platform -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - - -// This is my code to make a set of axial lines from a set of boundary lines - -#ifndef __VERTEX_H__ -#define __VERTEX_H__ - -// Modifed by Dream -#if defined(_WIN32) -#include -#else -#include -#endif -#include - -using namespace std; - -#include - -// Pretty much all of this is now deprecated... -// the attrs will be replaced by the easier to use AttributeTables in the future... - -// ...and so it now is: - -// THIS ENTIRE FILE IS DEPRECATED *APART FROM* THE COLOR and OPTIONS CODE BELOW -// ATTRIBUTE TABLES ARE USED INSTEAD - -// For my colour scheme... some parameters to pass, and my own colour class - -struct DisplayParams -{ - enum { AXMANESQUE = 0, GREYSCALE = 1, MONOCHROME = 2, DEPTHMAPCLASSIC = 3, PURPLEORANGE = 4, BLUERED = 5 }; - float blue; - float red; - int colorscale; - DisplayParams() - { blue = 0.0f; red = 1.0f; colorscale = 0; } -}; - -// Converts everything to safe HTML colours - -struct PafColor -{ - unsigned int m_color; - unsigned char redb() - { return (unsigned char) (m_color >> 16); } - unsigned char greenb() - { return (unsigned char) (m_color >> 8); } - unsigned char blueb() - { return (unsigned char) (m_color); } - unsigned char alphab() - { return (unsigned char) (m_color >> 24); } - // Quick mod - TV - void setr(unsigned char r) - { m_color &= 0xff00ffff; m_color |= (((unsigned int)r) << 16);} - // Quick mod - TV - void setg(unsigned char g) - { m_color &= 0xffff00ff; m_color |= (((unsigned int)g) << 8);} - // Quick mod - TV - void setb(unsigned char b) - { m_color &= 0xffffff00; m_color |= ((unsigned int)b);} - float redf() - { return float(redb()) / 255.0f; } - float greenf() - { return float(greenb()) / 255.0f; } - float bluef() - { return float(blueb()) / 255.0f; } - PafColor() - { m_color = 0x00000000; } - PafColor(unsigned int rgb) // color in 0x00rrggbb format - { m_color = 0xff000000 | rgb; } - PafColor( double r, double g, double b, double a = 1.0 ) - { m_color = 0x00000000 | - (((unsigned char) (a * 255.0)) << 24) | - (((unsigned char) (r * 255.0)) << 16) | - (((unsigned char) (g * 255.0)) << 8) | - (((unsigned char) (b * 255.0))); } - PafColor( const Point2f& vec, double a = 1.0 ) - { m_color = 0x00000000 | - (((unsigned char) (a * 255.0)) << 24) | - (((unsigned char) (dot(vec,Point2f(1.0, 0.0)) * 255.0)) << 16) | - (((unsigned char) (dot(vec,Point2f(-0.5,0.86602540378443864676372317075294)) * 255.0)) << 8) | - (((unsigned char) (dot(vec,Point2f(-0.5,-0.86602540378443864676372317075294)) * 255.0))); } - operator unsigned int () - { return m_color & 0x00ffffff; } - friend bool operator == (const PafColor& a, const PafColor& b); - friend bool operator != (const PafColor& a, const PafColor& b); - PafColor& makeAxmanesque( double field); - PafColor& makePurpleOrange( double field ); - PafColor& makeBlueRed( double field ); - PafColor& makeGreyScale( double field ); - PafColor& makeMonochrome( double field ); - PafColor& makeDepthmapClassic( double field, double blue, double red ); - PafColor& makeColor(double field, DisplayParams dp); // <- note, make copy to play around with -}; -inline bool operator == (const PafColor& a, const PafColor& b) -{ - return (a.m_color == b.m_color); -} -inline bool operator != (const PafColor& a, const PafColor& b) -{ - return (a.m_color != b.m_color); -} - -// Options for mean depth calculations -struct Options -{ - enum output_t { OUTPUT_ISOVIST, OUTPUT_VISUAL, OUTPUT_METRIC, OUTPUT_ANGULAR, OUTPUT_THRU_VISION, OUTPUT_CLIQUE_GRAPH, - OUTPUT_KERNEL_GRAPH, OUTPUT_MATRIX_REDUCTION }; - // Output type, see above - int output_type; - // Options for the summary type: - int local; - int global; - int cliques; - // - bool choice; - // include measures that can be derived: RA, RRA and total depth - bool fulloutput; - // - enum { RADIUS_STEPS, RADIUS_METRIC, RADIUS_ANGULAR }; - int radius_type; - double radius; // <- n.b. for metric integ radius is floating point - // radius has to go up to a list (phase out radius as is) - pvecdouble radius_list; - // - int point_depth_selection; - int tulip_bins; - bool process_in_memory; - bool sel_only; - bool gates_only; - // for pushing to a gates layer - int gatelayer; - // a column to weight measures by: - int weighted_measure_col; - int weighted_measure_col2; //EFEF - int routeweight_col; //EFEF - pstring output_file; // To save an output graph (for example) - // default values - Options() - { local = 0; global = 1; cliques = 0; - choice = false; fulloutput = false; point_depth_selection = 0; - tulip_bins = 1024; - radius = -1; radius_type = 0; - output_type = OUTPUT_ISOVIST; process_in_memory = false; gates_only = false; sel_only = false; - gatelayer = -1; - weighted_measure_col = -1;} -}; - -//////////////////////////////////////////////////////////////////////////////////////// - -// THIS ENTIRE FILE IS DEPRECATED APART FROM THE COLOR and OPTIONS CODE ABOVE -// ATTRIBUTE TABLES ARE USED INSTEAD - -union AttrVal { - int intval; - float floatval; -}; - -const int NUM_PHYSICAL_ATTRIBUTES = 25; // 25 physical attributes: see below - -// Note: also see AttrMap at bottom of file. - -// THIS ENTIRE FILE IS DEPRECATED -// ATTRIBUTE TABLES ARE USED INSTEAD - -struct AttrHeader { - enum { NEIGHBOURHOOD_SIZE = 0, - GRAPH_SIZE = 1, - KERNEL_SIZE = 2, - CLIQUE_SIZE = 3, - TOTAL_DEPTH = 4, - MEAN_DEPTH = 101, - INTEGRATION_RA = 102, - INTEGRATION_RRA = 103, - INTEGRATION_HILL = 104, - INTEGRATION_TEKL = 105, - ENTROPY = 5, - REL_ENTROPY = 6, - CLUSTER = 7, - UNUSED = 8, - POINT_DEPTH = 9, - CONTROL_HILL = 10, - CONTROL_TURN = 11, - MEDIAN_ANGLE = 12, - FAR_NODE = 13, // not output in text file - FAR_DIST = 14, - AGENT_COUNT = 15, - AGENT_COLL_COUNT = 16, // collisions - TOTAL_DIST = 17, - AVG_DIST = 107, // derived - TOTAL_METRIC_DEPTH = 18, - METRIC_GRAPH_SIZE = 19, - METRIC_MEAN_DEPTH = 108, // derived - DECENTRAL_INTEG = 109, // derived - METRIC_POINT_DEPTH = 20, - TOTAL_EUCLID_DIST = 21, - POINT_EUCLID_DIST = 22, - MEAN_PENN_DIST = 110, // derived - POINT_PENN_DIST = 111, // derived - TOTAL_METRIC_ANGLE = 23, - METRIC_POINT_ANGLE = 24, - METRIC_MEAN_ANGLE = 112 // derived - }; - - int m_attr_count; // number of attributes: for storage - - AttrHeader(int n = NUM_PHYSICAL_ATTRIBUTES) - { m_attr_count = n; } - void reset(AttrVal attributes[]); - double getAttr(int attr, const AttrVal attributes[]) const; -}; - -const AttrHeader g_attr_header; - -class PafAgent; - -// THIS PART OF THE FILE IS DEPRECATED -// ATTRIBUTE TABLES ARE USED INSTEAD - -struct AttrBody { - // - // stored values - int pos; - int ref; - Point3f origin; // storing origin unnecessary, may revise later - AttrHeader *header; - AttrVal *attributes; - // colour and highlight are not stored - float color; - bool highlight; - // - // you can have agents *in* the graph too (helps with looking them up!) - PafAgent *myagent; - // - AttrBody(streampos p = -1, const AttrHeader& h = AttrHeader() ); - AttrBody(const AttrBody& attr); - ~AttrBody(); - void reset(); - // - double getAttr(int attr) const - { return header->getAttr(attr, attributes); } - // - void write( ofstream& stream ) const; - void read( ifstream& stream, int attr_count ); - // - // Save a bit of memory, use integer / floating as appropriate - int& intval(int i) - { return attributes[i].intval; } - float& floatval(int i) - { return attributes[i].floatval; } - // - friend ostream& operator << (ostream& stream, const AttrBody& attr); - // - friend bool operator == (const AttrBody& a, const AttrBody& b); - friend bool operator != (const AttrBody& a, const AttrBody& b); - friend bool operator < (const AttrBody& a, const AttrBody& b); - friend bool operator > (const AttrBody& a, const AttrBody& b); -}; - -// These allow an order list of attributes (used by the conversion routine) -inline bool operator == (const AttrBody& a, const AttrBody& b) -{ - return a.ref == b.ref; -} -inline bool operator != (const AttrBody& a, const AttrBody& b) -{ - return a.ref != b.ref; -} -inline bool operator > (const AttrBody& a, const AttrBody& b) -{ - return a.ref > b.ref; -} -inline bool operator < (const AttrBody& a, const AttrBody& b) -{ - return a.ref < b.ref; -} - -/////////////////////////////////////////////////////////////////////////////// - -// a graph vertex - -/* -class GraphVertex { - friend class ArVertexList; -protected: - pvecint m_connections; -public: - GraphVertex() - {} - ~GraphVertex() - {} -public: - pvecint& get_connections() { - return m_connections; - } - int count_connections() { - return m_connections.size(); - } - int& operator [] (int index) { - return m_connections[index]; - } - void add_connection(int index) { -#ifdef _DEBUG - if (m_connections.findindex(index) != paftl::npos) { - cerr << "oops" << endl; - } -#endif - m_connections.push_back(index); - } -}; -*/ - -/////////////////////////////////////////////////////////////////////////////// - -// new angular member - -// THIS PART OF THE FILE IS DEPRECATED -// ATTRIBUTE TABLES ARE USED INSTEAD - -inline short& loword(int& a) {return (short&) *((short *)&a);} -inline short& hiword(int& a) {return (short&) *((short *)&a + 1); } - -class ArVertex { - friend class ArVertexList; -protected: - pvecint m_nodes; - pvecint m_bins; -public: - class Iterator { - protected: - ArVertex *m_vertex; - short m_current; - short m_last; - short m_top; - public: - Iterator() { - m_vertex = NULL; - } - Iterator(ArVertex *vertex, int bin) { - m_vertex = vertex; - m_current = loword(m_vertex->m_bins[bin]); - m_last = hiword(m_vertex->m_bins[bin]); - m_top = (short)m_vertex->m_nodes.size(); - if (m_current == m_last) - m_current = -1; - } - Iterator(ArVertex *vertex, short current, short last) { - m_vertex = vertex; - m_current = current; - m_last = last; - m_top = (short)m_vertex->m_nodes.size(); - if (m_current == m_last) - m_current = -1; - else if (m_current == m_top) - m_current = 0; - } - int& operator *() { return m_vertex->m_nodes[m_current]; } - operator short() { return m_current; } - virtual Iterator& operator ++(int) { - if ((++m_current) - m_last == 0) // <- might jump, and then whoops - m_current = -1; - else if (m_current >= m_top) // <- although this just loops back - m_current = 0; - return *this; - } - }; - friend class Iterator; - Iterator fovealView(int bin) { - Iterator i( this, loword(m_bins[(bin+30)%32]), hiword(m_bins[(bin+2)%32]) ); - return i; - } - Iterator peripheralViewFemale(int bin) { - // a fudge follows... - // essentially, the iterator can't determine the difference between 6,6 and 6,7...5,6 - bool found = false; - for (int i = bin - 8; i <= bin + 8; i++) { - if (loword(m_bins[(i+32)%32]) != hiword(m_bins[(i+32)%32])) - found = true; - } - if (loword(m_bins[(bin+24)%32]) == hiword(m_bins[(bin+8)%32]) && found) - return Iterator( this, 0, (short)m_nodes.size() ); - else - return Iterator( this, loword(m_bins[(bin+24)%32]), hiword(m_bins[(bin+8)%32]) ); - } - Iterator peripheralViewMale(int bin) { - Iterator i( this, loword(m_bins[(bin+25)%32]), hiword(m_bins[(bin+7)%32]) ); - return i; - } -public: - enum { bin_count = 32 }; - ArVertex( const pvecint& nodes = pvecint(), const pvecint& bins = pvecint() ) - { m_nodes = nodes; m_bins = bins; } - ArVertex( const ArVertex& v ) - { m_nodes = v.m_nodes; m_bins = v.m_bins; } - ArVertex& operator = (const ArVertex& v ) - { if (&v != this) { - m_nodes = v.m_nodes; m_bins = v.m_bins; - } - return *this; } - void make( pvecint *bin_list ) { - // If you're a clever bunny using the sparkGraph algorithm, the bins come presorted - // ...this code is the same as the one below... tidy at some point! - int bin_marker; - loword(bin_marker) = 0; - hiword(bin_marker) = 0; - for (int i = 0; i < bin_count; i++) { - for (size_t j = 0; j < bin_list[i].size(); j++) { - m_nodes.push_back( bin_list[i][j] ); - } - hiword(bin_marker) += (short)bin_list[i].size(); - m_bins.push_back( bin_marker ); - loword(bin_marker) = hiword(bin_marker); - bin_list[i].clear(); // <- NOTE: useful to clear this here - } - } - void make( pqmap *bin_list ) { - // Same as above - int bin_marker; - loword(bin_marker) = 0; - hiword(bin_marker) = 0; - for (int i = 0; i < bin_count; i++) { - for (size_t j = 0; j < bin_list[i].size(); j++) { - m_nodes.push_back( bin_list[i][j] ); - } - hiword(bin_marker) += (short)bin_list[i].size(); - m_bins.push_back( bin_marker ); - loword(bin_marker) = hiword(bin_marker); - bin_list[i].clear(); // <- NOTE: useful to clear this here - } - } - void clear() - { - m_nodes.clear(); - m_bins.clear(); - } - // Old version compatibility: - int& operator [] (int i) { return m_nodes[i]; } - int size() const { return (int)m_nodes.size(); } - // - // All connected vertices - pvecint& edgeset() { return m_nodes; } - // Edges from a particular bin - Iterator binset(int binnum) { - return Iterator( this, binnum ); - } - int binsize(int bin) { - // NB --- bin with all nodes will give erroneous zero! - return (int)((m_nodes.size() + hiword(m_bins[bin]) - loword(m_bins[bin])) % m_nodes.size()); - } - // - ifstream& read( ifstream& stream, streampos offset, int metagraph_version ) - { - if (metagraph_version >= VERSION_BINS_INTROD) { - m_nodes.read(stream,offset); // read from offset... - m_bins.read(stream); // <- and now read bins straight away - } - else { - m_nodes.read(stream,offset); // no angular before version 30 - } - return stream; - } - ofstream& write(ofstream& stream ) - { - m_nodes.write(stream); - m_bins.write(stream); - return stream; - } -}; - -// THIS PART OF THE FILE IS DEPRECATED -// ATTRIBUTE TABLES ARE USED INSTEAD - -class ArVertexList { -public: - enum { NONE = 0x0000, - BASIC = 0x0001, - LOCAL = 0x0002, - GLOBAL = 0x0004, - POINTDEPTH = 0x0008, - ANGULAR = 0x0010, - METRIC = 0x0020, - METRICPOINTDEPTH = 0x0040, - ANGULARPOINTDEPTH = 0x0080 // for historical reasons (which was implemented when) these are in a strange order - }; // which attributes have been calculated -protected: - // stored here for ease of use - int m_metagraph_version; - pstring m_filename; - fstream *m_stream; - AttrHeader m_attr_header; - prefvec m_attributes; - int m_cache_ref; - ArVertex m_cache_data; // either cached... - bool m_mem_loaded; - prefvec m_mem_data; // ...or all in memory - int m_which_attributes; -public: - ArVertexList( const pstring& filename = pstring() ) { - m_metagraph_version = METAGRAPH_VERSION; - m_filename = filename; - m_stream = NULL; - m_cache_ref = -1; - m_mem_loaded = false; - m_which_attributes = ArVertexList::NONE; - } - virtual ~ArVertexList() { - close(); // <-- used to be remove: ensure MetaGraph removes if a temporary file - } - int size() const { - return (int)m_attributes.size(); - } - ArVertex& operator [] (int i) { - if (m_mem_loaded) { - return m_mem_data[i]; - } - else if (i != m_cache_ref && m_stream) { // <- just make sure this doesn't crash - m_cache_data.read( (ifstream&) *m_stream, m_attributes[i].pos, m_metagraph_version ); - m_cache_ref = i; - } - return m_cache_data; - } - // - long memsize() const { - return (m_attributes.tail().pos ); // roughly right : excludes final node - } - // file must be open to do this - void loadmem() { - for (size_t i = 0; i < m_attributes.size(); i++) { - m_mem_data.push_back( ArVertex() ); - m_mem_data.tail().read( (ifstream&) *m_stream, m_attributes[i].pos, m_metagraph_version ); - } - m_mem_loaded = true; - } - void unloadmem() { - m_mem_data.clear(); - m_mem_loaded = false; - } - // - void setFilename( const pstring& filename ) { - m_filename = filename; - } - const pstring& getFilename() const { - return m_filename; - } - // - void setWhichAttributes(int which_attributes) { - m_which_attributes |= which_attributes; - } - int getWhichAttributes() const { - return m_which_attributes; - } - void clearAttributes() { - m_attributes.clear(); - m_which_attributes = ArVertexList::NONE; - } - // - bool openwrite(int nodes); - void openread(); - void close(); - void remove(); - void add( int ref, const ArVertex& node ); - void commit(); // when copying - void commit( const Point2f& p, int far_node, float far_dist, float total_dist ); // when creating new node - // - bool read( ifstream& stream, int metagraph_version ); - bool write( ofstream& stream ); - // - const AttrBody& getAttributes(int i) const { - return m_attributes[i]; - } - AttrBody& getAttributes(int i) { - return m_attributes[i]; - } -}; - -// THIS PART OF THE FILE IS DEPRECATED -// ATTRIBUTE TABLES ARE USED INSTEAD - -/////////////////////////////////////////////////////////////////////////////// - -// depthmap: file based graph vertex lists: -typedef ArVertex GraphVertex; -typedef ArVertexList GraphVertexList; - -// standard: memory resident graph vertex lists: -// typedef Vertex GraphVertex; -// typedef pqmap GraphVertexList; -// --- now sadly dead and buried -/////////////////////////////////////////////////////////////////////////////// - - - -// Exception to be thrown if the thread is cancelled -/* -class thread_cancelled_exception { -public: - thread_cancelled_exception() - {;} -}; -*/ - - -// Attribute map is for choosing attributes by description - -// THIS PART OF THE FILE IS DEPRECATED -// ATTRIBUTE TABLES ARE USED INSTEAD - -struct AttrMap { - enum { ATTR_INT, ATTR_FLOAT }; - int ref; - char *desc; - int attr_set; - int modules_req; - int type; - AttrMap(int r, char *d, int a, int m, int t) { ref = r; desc = d; attr_set = a; modules_req = m; type = t; } - int usable(int which_attrs = 1) const {return true; } - bool intval() const {return type == ATTR_INT;} - bool floatval() const {return type == ATTR_FLOAT;} -}; - -// THIS PART OF THE FILE IS DEPRECATED -// ATTRIBUTE TABLES ARE USED INSTEAD - -// This *must* match number of attributes listed below! -const int NUM_DISPLAYABLE_ATTRIBUTES = 26; - -// THIS PART OF THE FILE IS DEPRECATED -// ATTRIBUTE TABLES ARE USED INSTEAD - -const AttrMap g_attr_display_map[] = { - // 0 - AttrMap(AttrHeader::NEIGHBOURHOOD_SIZE, (char *)"Neighbourhood Size", GraphVertexList::BASIC, 0, AttrMap::ATTR_INT), - AttrMap(AttrHeader::MEAN_DEPTH, (char *)"Mean Depth", GraphVertexList::GLOBAL, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::INTEGRATION_RA, (char *)"Relative Asymmetry", GraphVertexList::GLOBAL, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::INTEGRATION_RRA, (char *)"Real Relative Asymmetry*", GraphVertexList::GLOBAL,0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::INTEGRATION_HILL, (char *)"Integration (Hillier/Hanson)*", GraphVertexList::GLOBAL, 0, AttrMap::ATTR_FLOAT), - // 5 - AttrMap(AttrHeader::INTEGRATION_TEKL, (char *)"Integration (Teklenburg et al.)", GraphVertexList::GLOBAL, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::GRAPH_SIZE, (char *)"Graph Size", GraphVertexList::GLOBAL, 0, AttrMap::ATTR_INT), - AttrMap(AttrHeader::ENTROPY, (char *)"Entropy", GraphVertexList::GLOBAL, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::REL_ENTROPY, (char *)"Relativised Entropy", GraphVertexList::GLOBAL, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::CLUSTER, (char *)"Clustering Coefficient", GraphVertexList::LOCAL, 0, AttrMap::ATTR_FLOAT), - // 10 - AttrMap(AttrHeader::CONTROL_HILL, (char *)"Control (Hillier/Hanson)", GraphVertexList::LOCAL, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::CONTROL_TURN, (char *)"Control (Turner)", GraphVertexList::LOCAL, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::POINT_DEPTH, (char *)"Point Depth", GraphVertexList::POINTDEPTH, 0, AttrMap::ATTR_INT), - AttrMap(AttrHeader::MEDIAN_ANGLE, (char *)"Mean Angle", GraphVertexList::ANGULAR, 0,AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::FAR_DIST, (char *)"Far Neighbour Distance", GraphVertexList::BASIC, 0, AttrMap::ATTR_FLOAT), - // 15 - AttrMap(AttrHeader::TOTAL_DIST, (char *)"Total Neighbour Distance", GraphVertexList::BASIC, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::AVG_DIST, (char *)"Average Neighbour Distance", GraphVertexList::BASIC, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::AGENT_COUNT, (char *)"Agent Trails", GraphVertexList::BASIC, 0, AttrMap::ATTR_INT), - AttrMap(AttrHeader::AGENT_COLL_COUNT, (char *)"Agent Collisions", GraphVertexList::BASIC, 0, AttrMap::ATTR_INT), - AttrMap(AttrHeader::METRIC_MEAN_DEPTH, (char *)"Metric Mean Depth", GraphVertexList::METRIC, 0, AttrMap::ATTR_FLOAT), - // 20 - AttrMap(AttrHeader::METRIC_MEAN_ANGLE, (char *)"Metric Mean Angle", GraphVertexList::METRIC, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::MEAN_PENN_DIST, (char *)"Mean Penn Distance", GraphVertexList::METRIC, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::DECENTRAL_INTEG, (char *)"Decentralised Integration", GraphVertexList::METRIC, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::METRIC_POINT_DEPTH, (char *)"Metric Point Depth", GraphVertexList::METRICPOINTDEPTH, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::METRIC_POINT_ANGLE, (char *)"Metric Point Angle", GraphVertexList::METRICPOINTDEPTH, 0, AttrMap::ATTR_FLOAT), - // 25 - AttrMap(AttrHeader::POINT_PENN_DIST, (char *)"Point Penn Distance", GraphVertexList::METRICPOINTDEPTH, 0, AttrMap::ATTR_FLOAT) -}; - -// THIS PART OF THE FILE IS DEPRECATED -// ATTRIBUTE TABLES ARE USED INSTEAD - -// This *must* match number of attributes listed below! -const int NUM_SUMMARISABLE_ATTRIBUTES = 23; - -// THIS PART OF THE FILE IS DEPRECATED -// ATTRIBUTE TABLES ARE USED INSTEAD - -const AttrMap g_attr_summary_map[] = { - // 0 - AttrMap(AttrHeader::NEIGHBOURHOOD_SIZE, (char *)"Neighbourhood Size", 1, 0, AttrMap::ATTR_INT), - AttrMap(AttrHeader::FAR_DIST, (char *)"Far Neighbour Distance", 1, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::TOTAL_DIST, (char *)"Total Neighbour Distance", 1, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::GRAPH_SIZE, (char *)"Graph Size", 1, 0, AttrMap::ATTR_INT), - AttrMap(AttrHeader::KERNEL_SIZE, (char *)"Kernel Size", 1, 0, AttrMap::ATTR_INT), - // 5 - AttrMap(AttrHeader::CLIQUE_SIZE, (char *)"Clique Size", 1, 0, AttrMap::ATTR_INT), - AttrMap(AttrHeader::TOTAL_DEPTH, (char *)"Total Visual Depth", 1, 0, AttrMap::ATTR_INT), - AttrMap(AttrHeader::ENTROPY, (char *)"Entropy", 1, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::REL_ENTROPY, (char *)"Relativised Entropy", 1, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::CLUSTER, (char *)"Clustering Coefficient", 1, 0, AttrMap::ATTR_FLOAT), - // 10 - AttrMap(AttrHeader::POINT_DEPTH, (char *)"Point Depth", 1, 0, AttrMap::ATTR_INT), - AttrMap(AttrHeader::CONTROL_HILL, (char *)"Control (Hillier/Hanson)", 1, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::CONTROL_TURN, (char *)"Control (Turner)", 1, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::MEDIAN_ANGLE, (char *)"Mean Angle", 1, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::AGENT_COUNT, (char *)"Agent Trails", 1, 0, AttrMap::ATTR_INT), - // 15 - AttrMap(AttrHeader::AGENT_COLL_COUNT, (char *)"Agent Collisions", 1, 0, AttrMap::ATTR_INT), - AttrMap(AttrHeader::TOTAL_METRIC_DEPTH, (char *)"Total Metric Depth", 1, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::TOTAL_METRIC_ANGLE, (char *)"Total Metric Angle", 1, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::TOTAL_EUCLID_DIST, (char *)"Total Euclidean Distance", 1, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::METRIC_GRAPH_SIZE, (char *)"Metric Graph Size", 1, 0, AttrMap::ATTR_INT), - // 20 - AttrMap(AttrHeader::METRIC_POINT_DEPTH, (char *)"Metric Point Depth", 1, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::METRIC_POINT_ANGLE, (char *)"Metric Point Angle", 1, 0, AttrMap::ATTR_FLOAT), - AttrMap(AttrHeader::POINT_EUCLID_DIST, (char *)"Euclidean Point Depth", 1, 0, AttrMap::ATTR_FLOAT) -}; - -#endif +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +// Modifed by Dream +#if defined(_MSC_VER) +#include +#else +#include +#endif +#include + +#include "mgraph440/paftl.h" +#include "mgraph440/p2dpoly.h" +#include "mgraph440/mgraph_consts.h" + +namespace mgraph440 { + +// Pretty much all of this is now deprecated... +// the attrs will be replaced by the easier to use AttributeTables in the future... + +// ...and so it now is: + +union AttrVal { + int intval; + float floatval; +}; + +const int NUM_PHYSICAL_ATTRIBUTES = 25; // 25 physical attributes: see below + +// Note: also see AttrMap at bottom of file. + +// THIS ENTIRE FILE IS DEPRECATED +// ATTRIBUTE TABLES ARE USED INSTEAD + +struct AttrHeader { + enum { NEIGHBOURHOOD_SIZE = 0, + GRAPH_SIZE = 1, + KERNEL_SIZE = 2, + CLIQUE_SIZE = 3, + TOTAL_DEPTH = 4, + MEAN_DEPTH = 101, + INTEGRATION_RA = 102, + INTEGRATION_RRA = 103, + INTEGRATION_HILL = 104, + INTEGRATION_TEKL = 105, + ENTROPY = 5, + REL_ENTROPY = 6, + CLUSTER = 7, + UNUSED = 8, + POINT_DEPTH = 9, + CONTROL_HILL = 10, + CONTROL_TURN = 11, + MEDIAN_ANGLE = 12, + FAR_NODE = 13, // not output in text file + FAR_DIST = 14, + AGENT_COUNT = 15, + AGENT_COLL_COUNT = 16, // collisions + TOTAL_DIST = 17, + AVG_DIST = 107, // derived + TOTAL_METRIC_DEPTH = 18, + METRIC_GRAPH_SIZE = 19, + METRIC_MEAN_DEPTH = 108, // derived + DECENTRAL_INTEG = 109, // derived + METRIC_POINT_DEPTH = 20, + TOTAL_EUCLID_DIST = 21, + POINT_EUCLID_DIST = 22, + MEAN_PENN_DIST = 110, // derived + POINT_PENN_DIST = 111, // derived + TOTAL_METRIC_ANGLE = 23, + METRIC_POINT_ANGLE = 24, + METRIC_MEAN_ANGLE = 112 // derived + }; + + int m_attr_count; // number of attributes: for storage + + AttrHeader(int n = NUM_PHYSICAL_ATTRIBUTES) + { m_attr_count = n; } + void reset(AttrVal attributes[]); + double getAttr(int attr, const AttrVal attributes[]) const; +}; + +const AttrHeader g_attr_header; + +class PafAgent; + +// THIS PART OF THE FILE IS DEPRECATED +// ATTRIBUTE TABLES ARE USED INSTEAD + +struct AttrBody { + // + // stored values + int pos; + int ref; + Point3f origin; // storing origin unnecessary, may revise later + AttrHeader *header; + AttrVal *attributes; + // colour and highlight are not stored + float color; + bool highlight; + // + // you can have agents *in* the graph too (helps with looking them up!) + PafAgent *myagent; + // + AttrBody(std::streampos p = -1, const AttrHeader& h = AttrHeader() ); + AttrBody(const AttrBody& attr); + ~AttrBody(); + void reset(); + // + double getAttr(int attr) const + { return header->getAttr(attr, attributes); } + // + void write(std::ostream &stream ) const; + void read( std::ifstream& stream, int attr_count ); + // + // Save a bit of memory, use integer / floating as appropriate + int& intval(int i) + { return attributes[i].intval; } + float& floatval(int i) + { return attributes[i].floatval; } + // + friend std::ostream& operator << (std::ostream& stream, const AttrBody& attr); + // + friend bool operator == (const AttrBody& a, const AttrBody& b); + friend bool operator != (const AttrBody& a, const AttrBody& b); + friend bool operator < (const AttrBody& a, const AttrBody& b); + friend bool operator > (const AttrBody& a, const AttrBody& b); +}; + +// These allow an order list of attributes (used by the conversion routine) +inline bool operator == (const AttrBody& a, const AttrBody& b) +{ + return a.ref == b.ref; +} +inline bool operator != (const AttrBody& a, const AttrBody& b) +{ + return a.ref != b.ref; +} +inline bool operator > (const AttrBody& a, const AttrBody& b) +{ + return a.ref > b.ref; +} +inline bool operator < (const AttrBody& a, const AttrBody& b) +{ + return a.ref < b.ref; +} + +/////////////////////////////////////////////////////////////////////////////// + +// a graph vertex + +/* +class GraphVertex { + friend class ArVertexList; +protected: + pvecint m_connections; +public: + GraphVertex() + {} + ~GraphVertex() + {} +public: + pvecint& get_connections() { + return m_connections; + } + int count_connections() { + return m_connections.size(); + } + int& operator [] (int index) { + return m_connections[index]; + } + void add_connection(int index) { +#ifdef _DEBUG + if (m_connections.findindex(index) != paftl::npos) { + cerr << "oops" << endl; + } +#endif + m_connections.push_back(index); + } +}; +*/ + +/////////////////////////////////////////////////////////////////////////////// + +// new angular member + +// THIS PART OF THE FILE IS DEPRECATED +// ATTRIBUTE TABLES ARE USED INSTEAD + +inline short& loword(int& a) {return (short&) *((short *)&a);} +inline short& hiword(int& a) {return (short&) *((short *)&a + 1); } + +class ArVertex { + friend class ArVertexList; +protected: + pvecint m_nodes; + pvecint m_bins; +public: + class Iterator { + protected: + ArVertex *m_vertex; + short m_current; + short m_last; + short m_top; + public: + Iterator() { + m_vertex = NULL; + } + Iterator(ArVertex *vertex, int bin) { + m_vertex = vertex; + m_current = loword(m_vertex->m_bins[bin]); + m_last = hiword(m_vertex->m_bins[bin]); + m_top = (short)m_vertex->m_nodes.size(); + if (m_current == m_last) + m_current = -1; + } + Iterator(ArVertex *vertex, short current, short last) { + m_vertex = vertex; + m_current = current; + m_last = last; + m_top = (short)m_vertex->m_nodes.size(); + if (m_current == m_last) + m_current = -1; + else if (m_current == m_top) + m_current = 0; + } + int& operator *() { return m_vertex->m_nodes[m_current]; } + operator short() { return m_current; } + virtual Iterator& operator ++(int) { + if ((++m_current) - m_last == 0) // <- might jump, and then whoops + m_current = -1; + else if (m_current >= m_top) // <- although this just loops back + m_current = 0; + return *this; + } + }; + friend class Iterator; + Iterator fovealView(int bin) { + Iterator i( this, loword(m_bins[(bin+30)%32]), hiword(m_bins[(bin+2)%32]) ); + return i; + } + Iterator peripheralViewFemale(int bin) { + // a fudge follows... + // essentially, the iterator can't determine the difference between 6,6 and 6,7...5,6 + bool found = false; + for (int i = bin - 8; i <= bin + 8; i++) { + if (loword(m_bins[(i+32)%32]) != hiword(m_bins[(i+32)%32])) + found = true; + } + if (loword(m_bins[(bin+24)%32]) == hiword(m_bins[(bin+8)%32]) && found) + return Iterator( this, 0, (short)m_nodes.size() ); + else + return Iterator( this, loword(m_bins[(bin+24)%32]), hiword(m_bins[(bin+8)%32]) ); + } + Iterator peripheralViewMale(int bin) { + Iterator i( this, loword(m_bins[(bin+25)%32]), hiword(m_bins[(bin+7)%32]) ); + return i; + } +public: + enum { bin_count = 32 }; + ArVertex( const pvecint& nodes = pvecint(), const pvecint& bins = pvecint() ) + { m_nodes = nodes; m_bins = bins; } + ArVertex( const ArVertex& v ) + { m_nodes = v.m_nodes; m_bins = v.m_bins; } + ArVertex& operator = (const ArVertex& v ) + { if (&v != this) { + m_nodes = v.m_nodes; m_bins = v.m_bins; + } + return *this; } + void make( pvecint *bin_list ) { + // If you're a clever bunny using the sparkGraph algorithm, the bins come presorted + // ...this code is the same as the one below... tidy at some point! + int bin_marker; + loword(bin_marker) = 0; + hiword(bin_marker) = 0; + for (int i = 0; i < bin_count; i++) { + for (size_t j = 0; j < bin_list[i].size(); j++) { + m_nodes.push_back( bin_list[i][j] ); + } + hiword(bin_marker) += (short)bin_list[i].size(); + m_bins.push_back( bin_marker ); + loword(bin_marker) = hiword(bin_marker); + bin_list[i].clear(); // <- NOTE: useful to clear this here + } + } + void make( pqmap *bin_list ) { + // Same as above + int bin_marker; + loword(bin_marker) = 0; + hiword(bin_marker) = 0; + for (int i = 0; i < bin_count; i++) { + for (size_t j = 0; j < bin_list[i].size(); j++) { + m_nodes.push_back( bin_list[i][j] ); + } + hiword(bin_marker) += (short)bin_list[i].size(); + m_bins.push_back( bin_marker ); + loword(bin_marker) = hiword(bin_marker); + bin_list[i].clear(); // <- NOTE: useful to clear this here + } + } + void clear() + { + m_nodes.clear(); + m_bins.clear(); + } + // Old version compatibility: + int& operator [] (int i) { return m_nodes[i]; } + int size() const { return (int)m_nodes.size(); } + // + // All connected vertices + pvecint& edgeset() { return m_nodes; } + // Edges from a particular bin + Iterator binset(int binnum) { + return Iterator( this, binnum ); + } + int binsize(int bin) { + // NB --- bin with all nodes will give erroneous zero! + return (int)((m_nodes.size() + hiword(m_bins[bin]) - loword(m_bins[bin])) % m_nodes.size()); + } + // + std::ifstream& read( std::ifstream& stream, std::streampos offset, int metagraph_version ) + { + if (metagraph_version >= mgraph440::VERSION_BINS_INTROD) { + m_nodes.read(stream,offset); // read from offset... + m_bins.read(stream); // <- and now read bins straight away + } + else { + m_nodes.read(stream,offset); // no angular before version 30 + } + return stream; + } + std::ofstream& write(std::ofstream& stream ) + { + m_nodes.write(stream); + m_bins.write(stream); + return stream; + } +}; + +// THIS PART OF THE FILE IS DEPRECATED +// ATTRIBUTE TABLES ARE USED INSTEAD + +class ArVertexList { +public: + enum { NONE = 0x0000, + BASIC = 0x0001, + LOCAL = 0x0002, + GLOBAL = 0x0004, + POINTDEPTH = 0x0008, + ANGULAR = 0x0010, + METRIC = 0x0020, + METRICPOINTDEPTH = 0x0040, + ANGULARPOINTDEPTH = 0x0080 // for historical reasons (which was implemented when) these are in a strange order + }; // which attributes have been calculated +protected: + // stored here for ease of use + int m_metagraph_version; + ::std::string m_filename; + std::fstream *m_stream; + AttrHeader m_attr_header; + prefvec m_attributes; + int m_cache_ref; + ArVertex m_cache_data; // either cached... + bool m_mem_loaded; + prefvec m_mem_data; // ...or all in memory + int m_which_attributes; +public: + ArVertexList( const ::std::string& filename = ::std::string() ) { + m_metagraph_version = mgraph440::METAGRAPH_VERSION; + m_filename = filename; + m_stream = NULL; + m_cache_ref = -1; + m_mem_loaded = false; + m_which_attributes = ArVertexList::NONE; + } + virtual ~ArVertexList() { + close(); // <-- used to be remove: ensure MetaGraph removes if a temporary file + } + int size() const { + return (int)m_attributes.size(); + } + ArVertex& operator [] (int i) { + if (m_mem_loaded) { + return m_mem_data[i]; + } + else if (i != m_cache_ref && m_stream) { // <- just make sure this doesn't crash + m_cache_data.read( (std::ifstream&) *m_stream, m_attributes[i].pos, m_metagraph_version ); + m_cache_ref = i; + } + return m_cache_data; + } + // + long memsize() const { + return (m_attributes.tail().pos ); // roughly right : excludes final node + } + // file must be open to do this + void loadmem() { + for (size_t i = 0; i < m_attributes.size(); i++) { + m_mem_data.push_back( ArVertex() ); + m_mem_data.tail().read( (std::ifstream&) *m_stream, m_attributes[i].pos, m_metagraph_version ); + } + m_mem_loaded = true; + } + void unloadmem() { + m_mem_data.clear(); + m_mem_loaded = false; + } + // + void setFilename( const std::string& filename ) { + m_filename = filename; + } + const std::string& getFilename() const { + return m_filename; + } + // + void setWhichAttributes(int which_attributes) { + m_which_attributes |= which_attributes; + } + int getWhichAttributes() const { + return m_which_attributes; + } + void clearAttributes() { + m_attributes.clear(); + m_which_attributes = ArVertexList::NONE; + } + // + bool openwrite(int nodes); + void openread(); + void close(); + void remove(); + void add( int ref, const ArVertex& node ); + void commit(); // when copying + void commit( const Point2f& p, int far_node, float far_dist, float total_dist ); // when creating new node + // + bool read( std::ifstream& stream, int metagraph_version ); + bool write(std::ostream &stream ); + // + const AttrBody& getAttributes(int i) const { + return m_attributes[i]; + } + AttrBody& getAttributes(int i) { + return m_attributes[i]; + } +}; + +// THIS PART OF THE FILE IS DEPRECATED +// ATTRIBUTE TABLES ARE USED INSTEAD + +/////////////////////////////////////////////////////////////////////////////// + +// depthmap: file based graph vertex lists: +typedef ArVertex GraphVertex; +typedef ArVertexList GraphVertexList; + +// standard: memory resident graph vertex lists: +// typedef Vertex GraphVertex; +// typedef pqmap GraphVertexList; +// --- now sadly dead and buried +/////////////////////////////////////////////////////////////////////////////// + + + +// Exception to be thrown if the thread is cancelled +/* +class thread_cancelled_exception { +public: + thread_cancelled_exception() + {;} +}; +*/ + + +// Attribute map is for choosing attributes by description + +// THIS PART OF THE FILE IS DEPRECATED +// ATTRIBUTE TABLES ARE USED INSTEAD + +struct AttrMap { + enum { ATTR_INT, ATTR_FLOAT }; + int ref; + char *desc; + int attr_set; + int modules_req; + int type; + AttrMap(int r, char *d, int a, int m, int t) { ref = r; desc = d; attr_set = a; modules_req = m; type = t; } + int usable() const {return true; } + bool intval() const {return type == ATTR_INT;} + bool floatval() const {return type == ATTR_FLOAT;} +}; + +// THIS PART OF THE FILE IS DEPRECATED +// ATTRIBUTE TABLES ARE USED INSTEAD + +// This *must* match number of attributes listed below! +const int NUM_DISPLAYABLE_ATTRIBUTES = 26; + +// THIS PART OF THE FILE IS DEPRECATED +// ATTRIBUTE TABLES ARE USED INSTEAD + +const AttrMap g_attr_display_map[] = { + // 0 + AttrMap(AttrHeader::NEIGHBOURHOOD_SIZE, (char *)"Neighbourhood Size", GraphVertexList::BASIC, 0, AttrMap::ATTR_INT), + AttrMap(AttrHeader::MEAN_DEPTH, (char *)"Mean Depth", GraphVertexList::GLOBAL, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::INTEGRATION_RA, (char *)"Relative Asymmetry", GraphVertexList::GLOBAL, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::INTEGRATION_RRA, (char *)"Real Relative Asymmetry*", GraphVertexList::GLOBAL,0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::INTEGRATION_HILL, (char *)"Integration (Hillier/Hanson)*", GraphVertexList::GLOBAL, 0, AttrMap::ATTR_FLOAT), + // 5 + AttrMap(AttrHeader::INTEGRATION_TEKL, (char *)"Integration (Teklenburg et al.)", GraphVertexList::GLOBAL, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::GRAPH_SIZE, (char *)"Graph Size", GraphVertexList::GLOBAL, 0, AttrMap::ATTR_INT), + AttrMap(AttrHeader::ENTROPY, (char *)"Entropy", GraphVertexList::GLOBAL, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::REL_ENTROPY, (char *)"Relativised Entropy", GraphVertexList::GLOBAL, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::CLUSTER, (char *)"Clustering Coefficient", GraphVertexList::LOCAL, 0, AttrMap::ATTR_FLOAT), + // 10 + AttrMap(AttrHeader::CONTROL_HILL, (char *)"Control (Hillier/Hanson)", GraphVertexList::LOCAL, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::CONTROL_TURN, (char *)"Control (Turner)", GraphVertexList::LOCAL, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::POINT_DEPTH, (char *)"Point Depth", GraphVertexList::POINTDEPTH, 0, AttrMap::ATTR_INT), + AttrMap(AttrHeader::MEDIAN_ANGLE, (char *)"Mean Angle", GraphVertexList::ANGULAR, 0,AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::FAR_DIST, (char *)"Far Neighbour Distance", GraphVertexList::BASIC, 0, AttrMap::ATTR_FLOAT), + // 15 + AttrMap(AttrHeader::TOTAL_DIST, (char *)"Total Neighbour Distance", GraphVertexList::BASIC, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::AVG_DIST, (char *)"Average Neighbour Distance", GraphVertexList::BASIC, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::AGENT_COUNT, (char *)"Agent Trails", GraphVertexList::BASIC, 0, AttrMap::ATTR_INT), + AttrMap(AttrHeader::AGENT_COLL_COUNT, (char *)"Agent Collisions", GraphVertexList::BASIC, 0, AttrMap::ATTR_INT), + AttrMap(AttrHeader::METRIC_MEAN_DEPTH, (char *)"Metric Mean Depth", GraphVertexList::METRIC, 0, AttrMap::ATTR_FLOAT), + // 20 + AttrMap(AttrHeader::METRIC_MEAN_ANGLE, (char *)"Metric Mean Angle", GraphVertexList::METRIC, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::MEAN_PENN_DIST, (char *)"Mean Penn Distance", GraphVertexList::METRIC, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::DECENTRAL_INTEG, (char *)"Decentralised Integration", GraphVertexList::METRIC, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::METRIC_POINT_DEPTH, (char *)"Metric Point Depth", GraphVertexList::METRICPOINTDEPTH, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::METRIC_POINT_ANGLE, (char *)"Metric Point Angle", GraphVertexList::METRICPOINTDEPTH, 0, AttrMap::ATTR_FLOAT), + // 25 + AttrMap(AttrHeader::POINT_PENN_DIST, (char *)"Point Penn Distance", GraphVertexList::METRICPOINTDEPTH, 0, AttrMap::ATTR_FLOAT) +}; + +// THIS PART OF THE FILE IS DEPRECATED +// ATTRIBUTE TABLES ARE USED INSTEAD + +// This *must* match number of attributes listed below! +const int NUM_SUMMARISABLE_ATTRIBUTES = 23; + +// THIS PART OF THE FILE IS DEPRECATED +// ATTRIBUTE TABLES ARE USED INSTEAD + +const AttrMap g_attr_summary_map[] = { + // 0 + AttrMap(AttrHeader::NEIGHBOURHOOD_SIZE, (char *)"Neighbourhood Size", 1, 0, AttrMap::ATTR_INT), + AttrMap(AttrHeader::FAR_DIST, (char *)"Far Neighbour Distance", 1, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::TOTAL_DIST, (char *)"Total Neighbour Distance", 1, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::GRAPH_SIZE, (char *)"Graph Size", 1, 0, AttrMap::ATTR_INT), + AttrMap(AttrHeader::KERNEL_SIZE, (char *)"Kernel Size", 1, 0, AttrMap::ATTR_INT), + // 5 + AttrMap(AttrHeader::CLIQUE_SIZE, (char *)"Clique Size", 1, 0, AttrMap::ATTR_INT), + AttrMap(AttrHeader::TOTAL_DEPTH, (char *)"Total Visual Depth", 1, 0, AttrMap::ATTR_INT), + AttrMap(AttrHeader::ENTROPY, (char *)"Entropy", 1, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::REL_ENTROPY, (char *)"Relativised Entropy", 1, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::CLUSTER, (char *)"Clustering Coefficient", 1, 0, AttrMap::ATTR_FLOAT), + // 10 + AttrMap(AttrHeader::POINT_DEPTH, (char *)"Point Depth", 1, 0, AttrMap::ATTR_INT), + AttrMap(AttrHeader::CONTROL_HILL, (char *)"Control (Hillier/Hanson)", 1, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::CONTROL_TURN, (char *)"Control (Turner)", 1, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::MEDIAN_ANGLE, (char *)"Mean Angle", 1, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::AGENT_COUNT, (char *)"Agent Trails", 1, 0, AttrMap::ATTR_INT), + // 15 + AttrMap(AttrHeader::AGENT_COLL_COUNT, (char *)"Agent Collisions", 1, 0, AttrMap::ATTR_INT), + AttrMap(AttrHeader::TOTAL_METRIC_DEPTH, (char *)"Total Metric Depth", 1, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::TOTAL_METRIC_ANGLE, (char *)"Total Metric Angle", 1, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::TOTAL_EUCLID_DIST, (char *)"Total Euclidean Distance", 1, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::METRIC_GRAPH_SIZE, (char *)"Metric Graph Size", 1, 0, AttrMap::ATTR_INT), + // 20 + AttrMap(AttrHeader::METRIC_POINT_DEPTH, (char *)"Metric Point Depth", 1, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::METRIC_POINT_ANGLE, (char *)"Metric Point Angle", 1, 0, AttrMap::ATTR_FLOAT), + AttrMap(AttrHeader::POINT_EUCLID_DIST, (char *)"Euclidean Point Depth", 1, 0, AttrMap::ATTR_FLOAT) +}; + +} diff --git a/salalib/attributes.cpp b/mgraph440/attributes.cpp similarity index 50% rename from salalib/attributes.cpp rename to mgraph440/attributes.cpp index edd590b2..8af1e323 100644 --- a/salalib/attributes.cpp +++ b/mgraph440/attributes.cpp @@ -1,684 +1,382 @@ -// sala - a component of the depthmapX - spatial network analysis platform -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - - - -#include -#include - -#include -#include - -//////////////////////////////////////////////////////////////////////////////////// - -// helpers: local sorting routines - -int compareValuePair(const void *p1, const void *p2) -{ - double v = (((ValuePair *)p1)->value - ((ValuePair *)p2)->value); - return (v > 0.0 ? 1 : v < 0.0 ? -1 : 0); -} - -//////////////////////////////////////////////////////////////////////////////////// - -AttributeTable::AttributeTable(const pstring& name) -{ - // need memory initialised somewhere for these... - g_ref_number_name = pstring("Ref Number"); - g_ref_number_formula = pstring(); - // - m_name = name; - // initially not showing any column: - m_display_column = -2; - // initially no selection: - m_sel_count = 0; - m_sel_value = 0.0; - // - // everything apart from the default layer is available for use: - // Quick mod - TV - m_available_layers = 0xffffffff << 32 + 0xfffffffe; - // display the default layer only (everything): - m_visible_layers = 0x1; - m_layers.add(1,"Everything"); - m_visible_size = 0; -} - -int AttributeTable::insertColumn(const pstring& name) -{ - size_t index = m_columns.searchindex(AttributeColumn(name)); - if (index != paftl::npos) { - m_columns[index].reset(); - int phys_col = m_columns[index].m_physical_col; - for (size_t i = 0; i < size(); i++) { - at(i)[phys_col] = -1.0f; - } - } - else { - index = m_columns.add(AttributeColumn(name)); - for (size_t i = 0; i < size(); i++) { - at(i).push_back(-1.0f); - } - m_columns[index].m_physical_col = m_columns.size() - 1; - } - return index; -} - -void AttributeTable::removeColumn(int col) -{ - int phys_col = m_columns[col].m_physical_col; - // remove data: - for (size_t i = 0; i < size(); i++) { - at(i).remove_at(phys_col); - } - // remove column head: - m_columns.remove_at(col); - // adjust other columns: - for (size_t j = 0; j < m_columns.size(); j++) { - if (m_columns[j].m_physical_col > phys_col) { - m_columns[j].m_physical_col -= 1; - } - } - // done -} - - -// note: returns new column id and may reorder the name columns -int AttributeTable::renameColumn(int col, const pstring& name) -{ - size_t index = m_columns.searchindex(name); - if (index == col) { - // no change in name - return col; - } - else if (index != paftl::npos) { - // column name already exists! - return -1; - } - // a little slow, but it shouldn't happen that often: - // switch round the column names and re-add. - // Copy column exactly (with same physical_col id) - AttributeColumn newcolumn(m_columns[col]); - m_columns.remove_at(col); - newcolumn.m_name = name; - index = m_columns.add(newcolumn); - // you will now have to alter the displayed attribute accordingly... - return index; -} - -int AttributeTable::insertRow(int key) -{ - int index = add(key,AttributeRow()); - value(index).init(m_columns.size()); - return index; -} - -void AttributeTable::removeRow(int key) -{ - size_t index = searchindex(key); - if (index != paftl::npos) { - remove_at(index); - } -} - -void AttributeTable::setColumnValue(int col, float val) -{ - int phys_col = m_columns[col].m_physical_col; - m_columns[col].m_tot = 0.0; - m_columns[col].m_min = val; - m_columns[col].m_max = val; - for (size_t i = 0; i < size(); i++) { - value(i).at(phys_col) = val; - m_columns[col].m_tot += val; - } -} - -////////////////////////////////////////////////////////////////////////////////////// - -// selection feature: - -bool AttributeTable::selectRowByKey(int key) const -{ - size_t index = searchindex(key); - if (index != paftl::npos) { - if ((m_visible_layers & value(index).m_layers) != 0 && !value(index).m_selected) { - value(index).m_selected = true; - m_sel_count++; - addSelValue(getValue(index,m_display_column)); - } - else { - // already selected or not visible - index = -1; - } - } - return index != -1; -} - -bool AttributeTable::selectRowByIndex(int index) const -{ - if (index != -1) { - if ((m_visible_layers & value(index).m_layers) != 0 && !value(index).m_selected) { - value(index).m_selected = true; - m_sel_count++; - addSelValue(getValue(index,m_display_column)); - } - else { - // already selected - index = -1; - } - } - return index != -1; -} - -void AttributeTable::deselectAll() const -{ - m_sel_count = 0; - m_sel_value = 0.0; - for (size_t i = 0; i < size(); i++) { - value(i).m_selected = false; - } -} - -////////////////////////////////////////////////////////////////////////////////////// - -// display features: - -void AttributeTable::setDisplayParams(const DisplayParams& dp) -{ - m_ref_display_params = dp; - for (unsigned int i = 0; i < m_columns.size(); i++) { - m_columns[i].setDisplayParams(dp); - } - m_display_params = dp; -} - -void AttributeTable::setDisplayParams(int col, const DisplayParams& dp) -{ - if (col != -1) - m_columns[col].setDisplayParams(dp); - else - m_ref_display_params = dp; - - if (col == m_display_column) { - m_display_params = dp; - } -} - -void AttributeTable::setVisibleLayers(int64 layers, bool override) -{ - if (layers != m_visible_layers || override) { - m_visible_layers = layers; - // will need to recalculate display information - setDisplayColumn(m_display_column,true); - } -} - -void AttributeTable::setLayerVisible(int layer, bool show) -{ - int64 showlayers = 0; - int64 key = m_layers.key(layer); - bool on = (key & m_visible_layers) != 0; - if (key == 0x1) { - if (show && !on) { - // show just the everything layer - showlayers = 0x1; - } - else if (!show && on) { - // turn everything off - showlayers = 0x0; - } - } - else { - if (show && !on) { - // turn on this layer, but also turn off "everything" layer is it's displayed - showlayers = (key | m_visible_layers) & (~0x1); - } - if (!show && on) { - // simply turn this individual layer off - showlayers = m_visible_layers & (~key); - } - } - setVisibleLayers(showlayers); -} - -bool AttributeTable::selectionToLayer(const pstring& name) -{ - // this slight messing selects the next available layer - int loc = 1; - while (loc < 64 && ((m_available_layers>>loc) & 0x1) == 0) { - loc++; - } - if (loc == 64) { - // too many layers -- maximum 64 - return false; - } - int64 newlayer = 0x1 << loc; - // now layer has been found, eliminate from available layers - // and add a lookup for the name - m_available_layers = (m_available_layers & (~newlayer)); - m_layers.add(newlayer,name); - - // convert everything in the selection to the new layer - for (size_t i = 0; i < size(); i++) { - if (isVisible(i) && isSelected(i)) { - at(i).m_layers |= newlayer; - } - } - - // set so just this layer is displayed... - setVisibleLayers(newlayer); - - return true; -} - -void AttributeTable::setDisplayColumn(int col, bool override) const -{ - if (col != m_display_column || override) { - if (col != -2) { - m_sel_value = 0.0; // reset selection total for new column - // note, visible size is actually picked up by the display index - m_visible_size = m_display_index.makeIndex(*this, col, true); - if (col == -1) - m_display_params = m_ref_display_params; - else - m_display_params = m_columns[col].getDisplayParams(); - } - m_display_column = col; - } -} - -////////////////////////////////////////////////////////////////////////////////////// - -bool AttributeTable::read( ifstream& stream, int version ) -{ - if (version >= VERSION_MAP_LAYERS) { - m_layers.clear(); - stream.read((char *)&m_available_layers,sizeof(int64)); - stream.read((char *)&m_visible_layers,sizeof(int64)); - int count; - stream.read((char *)&count,sizeof(int)); - for (int i = 0; i < count; i++) { - int64 key; - pstring value; - stream.read((char *)&key,sizeof(key)); - value.read(stream); - m_layers.add(key,value); - } - } - int colcount; - stream.read((char *)&colcount, sizeof(colcount)); - for (int j = 0; j < colcount; j++) { - m_columns.push_back(AttributeColumn()); - m_columns.tail().read(stream, version); - // this may need a bit of reordering, as the reader can chop up names: - m_columns.sort(); - } - int rowcount, rowkey; - stream.read((char *)&rowcount, sizeof(rowcount)); - for (int i = 0; i < rowcount; i++) { - stream.read((char *)&rowkey, sizeof(rowkey)); - int index = add(rowkey,AttributeRow()); - if (version >= VERSION_MAP_LAYERS) { - stream.read((char *)&(value(index).m_layers),sizeof(int64)); - } - value(index).read(stream); - } - if (version >= VERSION_GATE_MAPS) { - // ref column display params - stream.read((char *)&m_display_params,sizeof(m_display_params)); - } - return true; -} - -bool AttributeTable::write( ofstream& stream, int version ) -{ - if (version >= VERSION_MAP_LAYERS) { - stream.write((char *)&m_available_layers,sizeof(int64)); - stream.write((char *)&m_visible_layers,sizeof(int64)); - int count = m_layers.size(); - stream.write((char *)&count,sizeof(int)); - for (size_t i = 0; i < m_layers.size(); i++) { - int64 key = m_layers.key(i); - stream.write((char *)&key,sizeof(key)); - m_layers.value(i).write(stream); - } - } - int colcount = m_columns.size(); - stream.write((char *)&colcount, sizeof(colcount)); - for (int j = 0; j < colcount; j++) { - m_columns[j].write(stream,version); - } - int rowcount = size(), rowkey; - stream.write((char *)&rowcount, sizeof(rowcount)); - for (int i = 0; i < rowcount; i++) { - rowkey = key(i); - stream.write((char *)&rowkey, sizeof(rowkey)); - if (version >= VERSION_MAP_LAYERS) { - stream.write((char *)&(value(i).m_layers),sizeof(int64)); - } - value(i).write(stream); - } - // ref column display params - stream.write((char *)&m_display_params,sizeof(m_display_params)); - return true; -} - -bool AttributeTable::outputHeader( ostream& stream, char delimiter, bool updated_only ) const -{ - for (size_t i = 0; i < m_columns.size(); i++) { - if (!updated_only || m_columns[i].m_updated) { - stream << delimiter << m_columns[i].m_name; - } - } - stream << endl; - - return true; -} - -bool AttributeTable::outputRow( int row, ostream& stream, char delim, bool updated_only ) const -{ - int prec = stream.precision(8); - - for (size_t i = 0; i < m_columns.size(); i++) { - if (!updated_only || m_columns[i].m_updated) { - stream << delim << value(row).at(m_columns[i].m_physical_col); - } - } - stream << endl; - - stream.precision(prec); - - return true; -} - -// note, export is a keyword, so use exportTable as function name, -// similar convention for importTable -bool AttributeTable::exportTable(ostream& stream, bool updated_only) -{ - stream << "Ref"; - outputHeader(stream,'\t',updated_only); - for (int i = 0; i < getRowCount(); i++) { - if (isVisible(i)) { - stream << getRowKey(i); - outputRow(i,stream,'\t',updated_only); - } - } - return true; -} - -// From UrbanBuzz I-VALUL project (c) SSL licensed to UCL (written by Alasdair) -// import values imports columns into an attribute tables -// uses ref numbers, does not overwrite geom locations -// if "merge" is selected, column values are added together, -// otherwise the columns are cleared -bool AttributeTable::importTable(istream& stream, bool merge) -{ - pstring inputline; - stream >> inputline; - - // check for a tab delimited header line... - pvecstring strings = inputline.tokenize('\t'); - if (strings.size() < 1) { - return false; - } - // the first column *must* be "Ref" - if (strings[0] != "Ref" && strings[0] != "ref") { //EF replace || with && - return false; - } - - pvecint colrefs; - - for (size_t i = 1; i < strings.size(); i++) { - int col = getOrInsertColumnIndex(strings[i]); - colrefs.push_back( col ); - } - - // check no columns to import (note, this is not necessarily an error, there may - // simply be no columns to import) -- handle false return appropriately - if (colrefs.size() == 0) { - return false; - } - - while (!stream.eof()) { - stream >> inputline; - if (!inputline.empty()) { - pvecstring strings = inputline.tokenize('\t'); - if (!strings.size()) { - continue; - } - if (strings.size() != 1 + colrefs.size()) { - return false; - } - try { - int ref = strings[0].c_int(); - int rowid = getRowid(ref); - if (rowid != -1) { - for (size_t i = 1; i < strings.size(); i++) { - if (merge) { //EF setValue only if not merge - if (strings[i].c_double() != -1.0) { // only add the value if not -1.0 - incrValue(rowid,colrefs[i-1],(float)strings[i].c_double()); - } - } - else { - setValue(rowid,colrefs[i-1],(float)strings[i].c_double()); - } - } - } - else { - // major problem -- row doesn't exist in attribute table - return false; - } - } - catch (pstring::exception) { - return false; - } - } - } - // note: there's no test to check all rowids have been updated - return true; -} - -//////////////////////////////////////////////////////////////////////// - -void AttributeRow::init(size_t length) -{ - if (m_data) { - delete [] m_data; - m_data = NULL; - } - while (length >= storage_size()) - m_shift++; - m_data = new float [storage_size()]; - m_length = length; - - for (size_t i = 0; i < m_length; i++) { - at(i) = -1.0; - } -} - -//////////////////////////////////////////////////////////////////////// - -void AttributeColumn::reset() -{ - m_min = -1.0; - m_max = 0.0; - m_tot = 0.0; - m_visible_min = -1.0; - m_visible_max = 0.0; - m_visible_tot = 0.0; -} - -bool AttributeColumn::read( ifstream& stream, int version ) -{ - m_updated = false; - m_name.read(stream); - float min, max; - stream.read((char *)&min, sizeof(min)); - stream.read((char *)&max, sizeof(max)); - m_min = min; - m_max = max; - if (version >= VERSION_ATTRIBUTES_TABLE) // m_tot has always been a double - stream.read((char *)&m_tot, sizeof(m_tot)); - else - m_tot = 0.0; - stream.read((char *)&m_physical_col, sizeof(m_physical_col)); - stream.read((char *)&m_hidden, sizeof(m_hidden)); - if (version >= VERSION_ATTRIBUTE_LOCKING) { - stream.read((char *)&m_locked, sizeof(m_locked)); - } - else { - if (m_name == "Connectivity" || m_name == "Connectivity (Degree)" || m_name == "Axial Line Ref" || m_name == "Segment Length" || m_name == "Line Length") { - m_locked = true; - } - else { - m_locked = false; - } - } - if (version >= VERSION_STORE_COLOR) { - stream.read((char*)&m_display_params,sizeof(m_display_params)); - } - if (version >= VERSION_STORE_FORMULA) { - m_formula.read(stream); - } - if (version >= VERSION_STORE_COLUMN_CREATOR && version < VERSION_FORGET_COLUMN_CREATOR) { - pstring dummy_creator; - dummy_creator.read(stream); - } - return true; -} - -bool AttributeColumn::write( ofstream& stream, int version ) -{ - m_updated = false; - m_name.write(stream); - float min = (float) m_min; - float max = (float) m_max; - stream.write((char *)&min, sizeof(min)); - stream.write((char *)&max, sizeof(max)); - stream.write((char *)&m_tot, sizeof(m_tot)); - stream.write((char *)&m_physical_col, sizeof(m_physical_col)); - stream.write((char *)&m_hidden, sizeof(m_hidden)); - stream.write((char *)&m_locked, sizeof(m_locked)); - stream.write((char *)&m_display_params,sizeof(m_display_params)); - m_formula.write(stream); - return true; -} - -//////////////////////////////////////////////////////////////////////// - -AttributeIndex::AttributeIndex() -{ - m_col = -1; - m_data = NULL; -} - -void AttributeIndex::clear() -{ - m_col = -1; - pvector::clear(); -} - -int AttributeIndex::makeIndex(const AttributeTable& table, int col, bool setdisplayinfo) -{ - // clear contents: - clear(); - - // local copy since this will be reused a lot - size_t rowcount = table.getRowCount(); - - // preallocate vector: - while (rowcount >= storage_size()) - m_shift++; - m_data = new ValuePair[storage_size()]; - m_length = rowcount; - // - m_col = col; - // - double min = -1.0f, max = -1.0f, vismin = -1.0f, vismax = -1.0f; - double total = 0.0f, vistotal = 0.0; - // note that, for safety, *everything* is always indexed, - // viscount is simply a count of everything that is visible - int viscount = 0; - // n.b., attributes, axial lines and line refs must match - size_t i; - for (i = 0; i < rowcount; i++) - { - at(i).index = i; - if (col != -1) { - at(i).value = double(table.getValue(i,col)); - if (at(i).value != -1) { - if (min == -1.0f || at(i).value < min) { - min = (double) at(i).value; - } - if (max == -1.0f || at(i).value > max) { - max = (double) at(i).value; - } - total += at(i).value; - if (table.isVisible(i)) { - // note, this may be useful -- the visible count does not include nulls - viscount++; - if (vismin == -1.0f || at(i).value < vismin) { - vismin = (double) at(i).value; - } - if (vismax == -1.0f || at(i).value > vismax) { - vismax = (double) at(i).value; - } - vistotal += at(i).value; - } - } - // note: qsort is slow when many values are the same -- so these values are perturbed - // -> perturbation used to be random, but now sub sort by ref number - // note: value needs to be double to work out in large tables - // (note also, max may build up through table, causing some disturbance to order) - at(i).value += (max * 1e-9 * double(i)) / table.getRowCount(); - } - else { - if (table.isVisible(i)) { - // note, viscount is used by scatterplots at least - viscount++; - // eventually there should be a colour override on the ref column as well as any other) - vismax = i; - if (vismin == -1) { - vismin = i; - } - } - at(i).value = double(table.getRowKey(i))/table.getMaxRowKey(); - } - } - - // mutable override: - if (col != -1) { - table.setColumnInfo(col,min,max,total,vismin,vismax,vistotal); - } - - qsort(m_data,rowcount,sizeof(ValuePair),compareValuePair); - - for (i = 0; i < rowcount; i++) { - // note: this is to ensure we have save settings for the table ranges where data has been overwritten: - if (setdisplayinfo) { - at(i).value = (col != -1) ? table.getNormValue(at(i).index,col) : double(table.getRowKey(at(i).index))/table.getMaxRowKey(); - // be able to lookup index pos from row: - ValuePair vp2; - vp2.index = i; - vp2.value = at(i).value; - table.setDisplayInfo(at(i).index,vp2); - } - else { - // don't normalise: you want the exact value for this row - at(i).value = (col != -1) ? table.getValue(at(i).index,col) : double(table.getRowKey(at(i).index)); - } - } - return viscount; -} +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#include +#include + +#include +#include + +#include "mgraph440/stringutils.h" + +#include + +namespace mgraph440 { + +//////////////////////////////////////////////////////////////////////////////////// + +// helpers: local sorting routines + +int compareValuePair(const void *p1, const void *p2) +{ + double v = (((ValuePair *)p1)->value - ((ValuePair *)p2)->value); + return (v > 0.0 ? 1 : v < 0.0 ? -1 : 0); +} + +//////////////////////////////////////////////////////////////////////////////////// + +AttributeTable::AttributeTable(const std::string& name) +{ + // need memory initialised somewhere for these... + g_ref_number_name = std::string("Ref Number"); + g_ref_number_formula = std::string(); + // + m_name = name; + // initially not showing any column: + m_display_column = -2; + // initially no selection: + m_sel_count = 0; + m_sel_value = 0.0; + // + // everything apart from the default layer is available for use: + // Quick mod - TV + m_available_layers = 0xffffffff << (32 + 0xfffffffe); + // display the default layer only (everything): + m_visible_layers = 0x1; + m_layers.add(1,"Everything"); + m_visible_size = 0; +} + +int AttributeTable::insertColumn(const std::string& name) +{ + size_t index = m_columns.searchindex(AttributeColumn(name)); + if (index != paftl::npos) { + m_columns[index].reset(); + int phys_col = m_columns[index].m_physical_col; + for (size_t i = 0; i < size(); i++) { + at(i)[phys_col] = -1.0f; + } + } + else { + index = m_columns.add(AttributeColumn(name)); + for (size_t i = 0; i < size(); i++) { + at(i).push_back(-1.0f); + } + m_columns[index].m_physical_col = m_columns.size() - 1; + } + return index; +} + +int AttributeTable::insertRow(int key) +{ + int index = add(key,AttributeRow()); + value(index).init(m_columns.size()); + return index; +} + +void AttributeTable::deselectAll() const +{ + m_sel_count = 0; + m_sel_value = 0.0; + for (size_t i = 0; i < size(); i++) { + value(i).m_selected = false; + } +} + +////////////////////////////////////////////////////////////////////////////////////// + +void AttributeTable::setDisplayColumn(int col, bool override) const +{ + if (col != m_display_column || override) { + if (col != -2) { + m_sel_value = 0.0; // reset selection total for new column + // note, visible size is actually picked up by the display index + m_visible_size = m_display_index.makeIndex(*this, col, true); + if (col == -1) + m_display_params = m_ref_display_params; + else + m_display_params = m_columns[col].getDisplayParams(); + } + m_display_column = col; + } +} + +////////////////////////////////////////////////////////////////////////////////////// + +bool AttributeTable::read( std::ifstream& stream, int version ) +{ + if (version >= VERSION_MAP_LAYERS) { + m_layers.clear(); + stream.read((char *)&m_available_layers,sizeof(int64)); + stream.read((char *)&m_visible_layers,sizeof(int64)); + int count; + stream.read((char *)&count,sizeof(int)); + for (int i = 0; i < count; i++) { + int64 key; + stream.read((char *)&key,sizeof(key)); + m_layers.add(key,dXstring440::readString(stream)); + } + } + int colcount; + stream.read((char *)&colcount, sizeof(colcount)); + for (int j = 0; j < colcount; j++) { + m_columns.push_back(AttributeColumn()); + m_columns.tail().read(stream, version); + // this may need a bit of reordering, as the reader can chop up names: + m_columns.sort(); + } + int rowcount, rowkey; + stream.read((char *)&rowcount, sizeof(rowcount)); + for (int i = 0; i < rowcount; i++) { + stream.read((char *)&rowkey, sizeof(rowkey)); + int index = add(rowkey,AttributeRow()); + if (version >= VERSION_MAP_LAYERS) { + stream.read((char *)&(value(index).m_layers),sizeof(int64)); + } + value(index).read(stream); + } + if (version >= VERSION_GATE_MAPS) { + // ref column display params + stream.read((char *)&m_display_params,sizeof(m_display_params)); + } + return true; +} + +//////////////////////////////////////////////////////////////////////// + +void AttributeRow::init(size_t length) +{ + if (m_data) { + delete [] m_data; + m_data = NULL; + } + while (length >= storage_size()) + m_shift++; + m_data = new float [storage_size()]; + m_length = length; + + for (size_t i = 0; i < m_length; i++) { + at(i) = -1.0; + } +} + +//////////////////////////////////////////////////////////////////////// + +void AttributeColumn::reset() +{ + m_min = -1.0; + m_max = 0.0; + m_tot = 0.0; + m_visible_min = -1.0; + m_visible_max = 0.0; + m_visible_tot = 0.0; +} + +bool AttributeColumn::read( std::ifstream& stream, int version ) +{ + m_updated = false; + m_name = dXstring440::readString(stream); + float min, max; + stream.read((char *)&min, sizeof(min)); + stream.read((char *)&max, sizeof(max)); + m_min = min; + m_max = max; + if (version >= VERSION_ATTRIBUTES_TABLE) // m_tot has always been a double + stream.read((char *)&m_tot, sizeof(m_tot)); + else + m_tot = 0.0; + stream.read((char *)&m_physical_col, sizeof(m_physical_col)); + stream.read((char *)&m_hidden, sizeof(m_hidden)); + if (version >= VERSION_ATTRIBUTE_LOCKING) { + stream.read((char *)&m_locked, sizeof(m_locked)); + } + else { + if (m_name == "Connectivity" || m_name == "Connectivity (Degree)" || m_name == "Axial Line Ref" || m_name == "Segment Length" || m_name == "Line Length") { + m_locked = true; + } + else { + m_locked = false; + } + } + if (version >= VERSION_STORE_COLOR) { + stream.read((char*)&m_display_params,sizeof(m_display_params)); + } + if (version >= VERSION_STORE_FORMULA) { + m_formula = dXstring440::readString(stream); + } + if (version >= VERSION_STORE_COLUMN_CREATOR && version < VERSION_FORGET_COLUMN_CREATOR) { + std::string dummy_creator = dXstring440::readString(stream); + } + return true; +} + +//////////////////////////////////////////////////////////////////////// + +AttributeIndex::AttributeIndex() +{ + m_col = -1; + m_data = NULL; +} + +void AttributeIndex::clear() +{ + m_col = -1; + pvector::clear(); +} + +int AttributeIndex::makeIndex(const AttributeTable& table, int col, bool setdisplayinfo) +{ + // clear contents: + clear(); + + // local copy since this will be reused a lot + size_t rowcount = table.getRowCount(); + + // preallocate vector: + while (rowcount >= storage_size()) + m_shift++; + m_data = new ValuePair[storage_size()]; + m_length = rowcount; + // + m_col = col; + // + double min = -1.0f, max = -1.0f, vismin = -1.0f, vismax = -1.0f; + double total = 0.0f, vistotal = 0.0; + // note that, for safety, *everything* is always indexed, + // viscount is simply a count of everything that is visible + int viscount = 0; + // n.b., attributes, axial lines and line refs must match + size_t i; + for (i = 0; i < rowcount; i++) + { + at(i).index = i; + if (col != -1) { + at(i).value = double(table.getValue(i,col)); + if (at(i).value != -1) { + if (min == -1.0f || at(i).value < min) { + min = (double) at(i).value; + } + if (max == -1.0f || at(i).value > max) { + max = (double) at(i).value; + } + total += at(i).value; + if (table.isVisible(i)) { + // note, this may be useful -- the visible count does not include nulls + viscount++; + if (vismin == -1.0f || at(i).value < vismin) { + vismin = (double) at(i).value; + } + if (vismax == -1.0f || at(i).value > vismax) { + vismax = (double) at(i).value; + } + vistotal += at(i).value; + } + } + // note: qsort is slow when many values are the same -- so these values are perturbed + // -> perturbation used to be random, but now sub sort by ref number + // note: value needs to be double to work out in large tables + // (note also, max may build up through table, causing some disturbance to order) + at(i).value += (max * 1e-9 * double(i)) / table.getRowCount(); + } + else { + if (table.isVisible(i)) { + // note, viscount is used by scatterplots at least + viscount++; + // eventually there should be a colour override on the ref column as well as any other) + vismax = i; + if (vismin == -1) { + vismin = i; + } + } + at(i).value = double(table.getRowKey(i))/table.getMaxRowKey(); + } + } + + // mutable override: + if (col != -1) { + table.setColumnInfo(col,min,max,total,vismin,vismax,vistotal); + } + + qsort(m_data,rowcount,sizeof(ValuePair),compareValuePair); + + for (i = 0; i < rowcount; i++) { + // note: this is to ensure we have save settings for the table ranges where data has been overwritten: + if (setdisplayinfo) { + at(i).value = (col != -1) ? table.getNormValue(at(i).index,col) : double(table.getRowKey(at(i).index))/table.getMaxRowKey(); + // be able to lookup index pos from row: + ValuePair vp2; + vp2.index = i; + vp2.value = at(i).value; + table.setDisplayInfo(at(i).index,vp2); + } + else { + // don't normalise: you want the exact value for this row + at(i).value = (col != -1) ? table.getValue(at(i).index,col) : double(table.getRowKey(at(i).index)); + } + } + return viscount; +} + +bool AttributeTable::write( std::ostream& stream, int version ) +{ + + stream.write((char *)&m_available_layers,sizeof(int64)); + stream.write((char *)&m_visible_layers,sizeof(int64)); + int count = m_layers.size(); + stream.write((char *)&count,sizeof(int)); + for (size_t i = 0; i < m_layers.size(); i++) { + int64 key = m_layers.key(i); + stream.write((char *)&key,sizeof(key)); + dXstring440::writeString(stream ,m_layers.value(i)); + } + + int colcount = m_columns.size(); + stream.write((char *)&colcount, sizeof(colcount)); + for (int j = 0; j < colcount; j++) { + m_columns[j].write(stream,version); + } + int rowcount = size(), rowkey; + stream.write((char *)&rowcount, sizeof(rowcount)); + for (int i = 0; i < rowcount; i++) { + rowkey = key(i); + stream.write((char *)&rowkey, sizeof(rowkey)); + stream.write((char *)&(value(i).m_layers),sizeof(int64)); + value(i).write(stream); + } + // ref column display params + stream.write((char *)&m_display_params,sizeof(m_display_params)); + return true; +} + +bool AttributeColumn::write( std::ostream& stream, int version ) +{ + m_updated = false; + dXstring440::writeString(stream, m_name); + float min = (float) m_min; + float max = (float) m_max; + stream.write((char *)&min, sizeof(min)); + stream.write((char *)&max, sizeof(max)); + stream.write((char *)&m_tot, sizeof(m_tot)); + stream.write((char *)&m_physical_col, sizeof(m_physical_col)); + stream.write((char *)&m_hidden, sizeof(m_hidden)); + stream.write((char *)&m_locked, sizeof(m_locked)); + stream.write((char *)&m_display_params,sizeof(m_display_params)); + dXstring440::writeString(stream, m_formula); + return true; +} + +} diff --git a/salalib/attributes.h b/mgraph440/attributes.h similarity index 59% rename from salalib/attributes.h rename to mgraph440/attributes.h index 0ed513ad..07a6909c 100644 --- a/salalib/attributes.h +++ b/mgraph440/attributes.h @@ -1,406 +1,293 @@ -// sala - a component of the depthmapX - spatial network analysis platform -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - - -#ifndef __ATTRIBUTES_H__ -#define __ATTRIBUTES_H__ - -// yet another way to do attributes, but one that is easily expandable -// it's slow to look for a column, since you have to find the column -// by name, but other than that it's fairly easy - -// helpers... local sorting routines - -//////////////////////////////////////////////////////////////////////////////// - -struct ValuePair -{ - double value; // needs to be double for sorting in index at higher resolution than the stored data - int index; - ValuePair(int i = -1, double v = -1.0) - { index = i; value = v; } - friend bool operator < (const ValuePair& vp1, const ValuePair& vp2); - friend bool operator > (const ValuePair& vp1, const ValuePair& vp2); - friend bool operator == (const ValuePair& vp1, const ValuePair& vp2); -}; -inline bool operator < (const ValuePair& vp1, const ValuePair& vp2) -{ - return (vp1.value < vp2.value); -} -inline bool operator > (const ValuePair& vp1, const ValuePair& vp2) -{ - return (vp1.value > vp2.value); -} -inline bool operator == (const ValuePair& vp1, const ValuePair& vp2) -{ - return (vp1.value == vp2.value); -} -int compareValuePair(const void *p1, const void *p2); - -//////////////////////////////////////////////////////////////////////////////// - -// These aren't really to do with attributes per se, but helpful to have -// them around ValuePair definition - -// note! unsorted -struct IntPair -{ - int a; - int b; - IntPair(int x = -1, int y = -1) { - a = x; - b = y; - } - // inlined at end of file - friend bool operator == (const IntPair& x, const IntPair& y); - friend bool operator != (const IntPair& x, const IntPair& y); - friend bool operator < (const IntPair& x, const IntPair& y); - friend bool operator > (const IntPair& x, const IntPair& y); -}; - -// note! sorted -struct OrderedIntPair -{ - int a; - int b; - OrderedIntPair(int x = -1, int y = -1) { - a = (int) x < y ? x : y; - b = (int) x < y ? y : x; - } - // inlined at end of file - friend bool operator == (const OrderedIntPair& x, const OrderedIntPair& y); - friend bool operator != (const OrderedIntPair& x, const OrderedIntPair& y); - friend bool operator < (const OrderedIntPair& x, const OrderedIntPair& y); - friend bool operator > (const OrderedIntPair& x, const OrderedIntPair& y); -}; - -//////////////////////////////////////////////////////////////////////////////// - -// for scripting object -#include - -//////////////////////////////////////////////////////////////////////////////// - -class AttributeRow : public pvector -{ - friend class AttributeTable; -protected: - mutable bool m_selected; - mutable ValuePair m_display_info; - // this is for salascripting to allow "checking" a searched node: - mutable SalaObj m_sala_mark; - // this is for recording layers (up to 64 are possible) - int64 m_layers; -public: - AttributeRow() - { m_selected = false; m_layers = 1; } - void init(size_t length); - // - // For SalaScript - void setMark(SalaObj& mark) - { m_sala_mark = mark; } - const SalaObj& getMark() const - { return m_sala_mark; } -}; - -// note pvector: this is stored in order, reorder by qsort -class AttributeIndex : public pvector -{ - friend class AttributeTable; -protected: - int m_col; -public: - AttributeIndex(); - void clear(); - int makeIndex(const AttributeTable& table, int col, bool setdisplayinfo); -}; - -class AttributeColumn -{ -public: - pstring m_name; - bool m_updated; // <- this flag is not saved, and indicates new data in the column (set on insert column etc) - int m_physical_col; - mutable double m_min; - mutable double m_max; - mutable double m_tot; - mutable double m_visible_min; - mutable double m_visible_max; - mutable double m_visible_tot; - bool m_hidden; - bool m_locked; - // display parameters - DisplayParams m_display_params; - // retain formula used to create column - pstring m_formula; -public: - AttributeColumn(const pstring& name = pstring(), int physical_col = -1) - { m_name = name; - m_min = -1.0f; - m_max = 0.0f; - m_tot = 0.0; - m_visible_min = -1.0f; - m_visible_max = 0.0f; - m_visible_tot = 0.0; - m_physical_col = physical_col; - m_hidden = false; - m_locked = false; - m_updated = false; - } - float makeNormValue(float value) const - { return (m_min == m_max) ? 0.5f : (value == -1.0f) ? -1.0f : (float)((value - m_min) / (m_max - m_min)); } - double getMinValue() const - { return m_min; } - double getMaxValue() const - { return m_max; } - double getTotValue() const - { return m_tot; } - double getVisibleMinValue() const - { return m_visible_min; } - double getVisibleMaxValue() const - { return m_visible_max; } - double getVisibleTotValue() const - { return m_visible_tot; } - // - void setValue(float value) - { m_updated = true; m_tot += value; if (m_min == -1.0f || value < m_min) m_min = value; if (value > m_max) m_max = value; } - void changeValue(float oldval, float newval) - { m_updated = true; if (oldval != -1.0f) m_tot -= oldval; if (newval != -1.0f) setValue(newval); } - // - // override (irritatingly needs to be done occassionally) - void setInfo(double min, double max, double tot, double vismin, double vismax, double vistot) const - { m_min = min; m_max = max; m_tot = tot; m_visible_min = vismin; m_visible_max = vismax; m_visible_tot = vistot; } - // - void setDisplayParams(const DisplayParams& dp) - { m_display_params = dp; } - const DisplayParams& getDisplayParams() const - { return m_display_params; } - // - void reset(); - void rename(const pstring& name) { - m_name = name; - } - // user-interface locking unlocking - bool isLocked() const - { return m_locked; } - void setLock(bool lock = true) - { m_locked = lock; } - // - bool read( ifstream& stream, int version ); - bool write( ofstream& stream, int version ); - friend bool operator == (const AttributeColumn& a, const AttributeColumn& b); - friend bool operator < (const AttributeColumn& a, const AttributeColumn& b); - friend bool operator > (const AttributeColumn& a, const AttributeColumn& b); -}; -inline bool operator == (const AttributeColumn& a, const AttributeColumn& b) -{ return a.m_name == b.m_name; } -inline bool operator < (const AttributeColumn& a, const AttributeColumn& b) -{ return a.m_name < b.m_name; } -inline bool operator > (const AttributeColumn& a, const AttributeColumn& b) -{ return a.m_name > b.m_name; } - -class AttributeTable : protected pqmap -{ -protected: - pstring m_name; - pqvector m_columns; - pqmap m_data; - // display parameters for the reference id column - DisplayParams m_ref_display_params; - // - int64 m_available_layers; - pqmap m_layers; - mutable int64 m_visible_layers; - mutable int m_visible_size; - // - pstring g_ref_number_name; // = pstring("Ref Number"); - pstring g_ref_number_formula; // = pstring(""); - // -public: - // - AttributeTable(const pstring& name = pstring()); - // - int insertColumn(const pstring& name = pstring()); - void removeColumn(int col); - int renameColumn(int col, const pstring& name = pstring()); - int insertRow(int key); - void removeRow(int key); - void removeRowids(const pvecint& list) - { remove_at(list); } - // - // note... retrieves from column index (which are sorted by name), not physical column - const pstring& getColumnName(int col) const - { return col != -1 ? m_columns[col].m_name : g_ref_number_name; } - int getColumnIndex(const pstring& name) const - { size_t index = m_columns.searchindex(name); return (index == paftl::npos) ? -1 : int(index);} // note use -1 rather than paftl::npos for return value - int getColumnCount() const - { return (int) m_columns.size(); } - int getOrInsertColumnIndex(const pstring& name) - { size_t col = m_columns.searchindex(name); if (col == paftl::npos) return insertColumn(name); else return (int) col; } - int getOrInsertLockedColumnIndex(const pstring& name) - { size_t col = m_columns.searchindex(name); if (col == paftl::npos) return insertLockedColumn(name); else return (int) col; } - bool isValidColumn(const pstring& name) const - { return m_columns.searchindex(name) != paftl::npos || name == g_ref_number_name; } - // - int getRowKey(int index) const - { return key(index); } - int getRowid(const int key) const - { size_t i = searchindex(key); return (i == paftl::npos) ? -1 : int(i);} // note use -1 rather than paftl::npos for return value - int getRowCount() const - { return (int) size(); } - int getVisibleRowCount() const - { return m_visible_size; } - int getMaxRowKey() const - { return key(size()-1); } - // this version uses known row and col indices - float getValue(int row, int col) const - { return col != -1 ? value(row).at(m_columns[col].m_physical_col) : key(row); } - // this version is meant to use row key and col name - float getValue(int row, const pstring& name) const - { int col = getColumnIndex(name); return col != -1 ? value(row).at(m_columns[col].m_physical_col) : key(row); } - float getNormValue(int row, int col) const - { return col != -1 ? m_columns[col].makeNormValue(value(row).at(m_columns[col].m_physical_col)) : (float) (double(getRowKey(row))/double(getRowKey(int(size()-1)))); } - void setValue(int row, int col, float val) - { value(row).at(m_columns[col].m_physical_col) = val; m_columns[col].setValue(val); } - void setValue(int row, const pstring& name, float val) - { int col = getColumnIndex(name); if (col != -1) setValue(row,col,val); } - void changeValue(int row, int col, float val) - { float& theval = value(row).at(m_columns[col].m_physical_col); m_columns[col].changeValue(theval,val); theval = val; } - void changeValue(int row, const pstring& name, float val) - { int col = getColumnIndex(name); if (col != -1) changeValue(row,col,val); } - void changeSelValues(int col, float val) - { for (size_t i = 0; i < size(); i++) { if (value(i).m_selected) changeValue((int)i,col,val);} } - void incrValue(int row, int col, float amount = 1.0f) - { float& v = value(row).at(m_columns[col].m_physical_col); v = (v == -1.0f) ? amount : v+amount ; m_columns[col].changeValue(v-amount,v); } - void incrValue(int row, const pstring& name, float amount = 1.0f) - { int col = getColumnIndex(name); if (col != -1) incrValue(row,col,amount); } - void decrValue(int row, int col, float amount = 1.0f) - { float& v = value(row).at(m_columns[col].m_physical_col); v = (v != -1.0f) ? v-amount : -1.0f; m_columns[col].changeValue(v+amount,v); } - void decrValue(int row, const pstring& name, float amount = 1.0f) - { int col = getColumnIndex(name); if (col != -1) decrValue(row,col,amount); } - void setColumnValue(int col, float val); - double getMinValue(int col) const - { return col != -1 ? m_columns[col].getMinValue() : key(0); } - double getMaxValue(int col) const - { return col != -1 ? m_columns[col].getMaxValue() : key(size()-1); } - double getAvgValue(int col) const - { return col != -1 ? m_columns[col].getTotValue() / double(getRowCount()) : -1.0; } - // - double getVisibleMinValue(int col) const - { return col != -1 ? m_columns[col].getVisibleMinValue() : key(0); } - double getVisibleMaxValue(int col) const - { return col != -1 ? m_columns[col].getVisibleMaxValue() : key(size()-1); } - double getVisibleAvgValue(int col) const - { return col != -1 ? m_columns[col].getVisibleTotValue() / double(getVisibleRowCount()) : -1.0; } - // - void setColumnInfo(int col, double min, double max, double tot, double vismin, double vismax, double vistot) const - { m_columns[col].setInfo(min,max,tot,vismin,vismax,vistot); } - // - const pstring& getColumnFormula(int col) const - { return col != -1 ? m_columns[col].m_formula : g_ref_number_formula; } - void setColumnFormula(int col, const pstring& formula) - { m_columns[col].m_formula = formula; } - // - // user-interface locking unlocking - bool isColumnLocked(int col) const - { return (col == -1) ? true : m_columns[col].isLocked(); } - void setColumnLock(int col, bool lock = true) - { m_columns[col].setLock(lock); } - int insertLockedColumn(const pstring& name = pstring()) - { int col = insertColumn(name); setColumnLock(col); return col; } - // - // For SalaScript: - void setMark(int row, SalaObj& mark) - { value(row).setMark(mark); } - const SalaObj& getMark(int row) const - { return value(row).getMark(); } -protected: - // Selection: - mutable int m_sel_count; - mutable double m_sel_value; -public: - bool selectRowByIndex(int index) const; - bool selectRowByKey(int key) const; - void deselectAll() const; - void addSelValue(double value) const - { m_sel_value += (value != -1.0f) ? value : 0.0; } - double getSelAvg() const - { return m_sel_value / m_sel_count; } - bool isSelected(int index) const - { return value(index).m_selected; } - // Display: - mutable int m_display_column; - mutable AttributeIndex m_display_index; - mutable DisplayParams m_display_params; - // Underlying layer control: - void setVisibleLayers(int64 layers, bool override = false); - const int64 getVisibleLayers() const - { return m_visible_layers; } - // More user friendly layer control: - bool selectionToLayer(const pstring& name); - int getLayerCount() const - { return (int) m_layers.size(); } - pstring getLayerName(int layer) const - { return m_layers.value(layer); } - bool isLayerVisible(int layer) const - { return ((m_layers.key(layer) & m_visible_layers) != 0); } - void setLayerVisible(int layer, bool show); - // - bool isVisible(int row) const - { return (m_visible_layers & (at(row).m_layers)) != 0; } - // - void setDisplayColumn(int col, bool override = false) const; - const int getDisplayColumn() const - { return m_display_column; } - const int getDisplayPos(int index) const - { return at(index).m_display_info.index; } - const int getDisplayColor(int row) const - { PafColor color; return at(row).m_selected ? PafColor(SALA_SELECTED_COLOR) : color.makeColor(at(row).m_display_info.value,m_display_params); } - const int getDisplayColorByKey(int key) const - { PafColor color; return color.makeColor(search(key).m_display_info.value,m_display_params); } - // this also doubles up to reset the selection total: - void setDisplayInfo(int row, ValuePair vp) const - { at(row).m_display_info = vp; if (at(row).m_selected) addSelValue((double)vp.value); } - // - // set display params for all attributes in table - void setDisplayParams(const DisplayParams& dp); - // set display params for a single column - void setDisplayParams(int col, const DisplayParams& dp); - const DisplayParams& getDisplayParams(int col) const - { return m_display_params; } - // -public: - // misc - void clear() // <- totally destroy, not just clear values - { m_columns.clear(); pqmap::clear(); } - // - void setName(const pstring& name) - { m_name = name; } - const pstring& getName() const - { return m_name; } - // - // read / write - bool read( ifstream& stream, int version ); - bool write( ofstream& stream, int version ); - // - bool outputHeader( ostream& stream, char delim = '\t', bool updated_only = false ) const; - bool outputRow( int row, ostream& stream, char delim = '\t', bool updated_only = false ) const; - // - bool exportTable(ostream& stream, bool updated_only); - bool importTable(istream& stream, bool merge); -}; - -#endif +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#ifndef __ATTRIBUTES_H__ +#define __ATTRIBUTES_H__ + +#include "mgraph440/attr.h" +#include "mgraph440/displayparams.h" +#include "mgraph440/pafcolor.h" +#include // for scripting object +#include + +namespace mgraph440 { + +// yet another way to do attributes, but one that is easily expandable +// it's slow to look for a column, since you have to find the column +// by name, but other than that it's fairly easy + +// helpers... local sorting routines + +//////////////////////////////////////////////////////////////////////////////// + +struct ValuePair +{ + double value; // needs to be double for sorting in index at higher resolution than the stored data + int index; + ValuePair(int i = -1, double v = -1.0) + { index = i; value = v; } + friend bool operator < (const ValuePair& vp1, const ValuePair& vp2); + friend bool operator > (const ValuePair& vp1, const ValuePair& vp2); + friend bool operator == (const ValuePair& vp1, const ValuePair& vp2); +}; +inline bool operator < (const ValuePair& vp1, const ValuePair& vp2) +{ + return (vp1.value < vp2.value); +} +inline bool operator > (const ValuePair& vp1, const ValuePair& vp2) +{ + return (vp1.value > vp2.value); +} +inline bool operator == (const ValuePair& vp1, const ValuePair& vp2) +{ + return (vp1.value == vp2.value); +} +int compareValuePair(const void *p1, const void *p2); + +//////////////////////////////////////////////////////////////////////////////// + +// These aren't really to do with attributes per se, but helpful to have +// them around ValuePair definition + +// note! unsorted +struct IntPair +{ + int a; + int b; + IntPair(int x = -1, int y = -1) { + a = x; + b = y; + } + // inlined at end of file + friend bool operator == (const IntPair& x, const IntPair& y); + friend bool operator != (const IntPair& x, const IntPair& y); + friend bool operator < (const IntPair& x, const IntPair& y); + friend bool operator > (const IntPair& x, const IntPair& y); +}; + +// note! sorted +struct OrderedIntPair +{ + int a; + int b; + OrderedIntPair(int x = -1, int y = -1) { + a = (int) x < y ? x : y; + b = (int) x < y ? y : x; + } + // inlined at end of file + friend bool operator == (const OrderedIntPair& x, const OrderedIntPair& y); + friend bool operator != (const OrderedIntPair& x, const OrderedIntPair& y); + friend bool operator < (const OrderedIntPair& x, const OrderedIntPair& y); + friend bool operator > (const OrderedIntPair& x, const OrderedIntPair& y); +}; + +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// + +class AttributeRow : public pvector +{ + friend class AttributeTable; +protected: + mutable bool m_selected; + mutable ValuePair m_display_info; + // this is for salascripting to allow "checking" a searched node: + mutable SalaObj m_sala_mark; + // this is for recording layers (up to 64 are possible) + int64 m_layers; +public: + AttributeRow() + { m_selected = false; m_layers = 1; } + void init(size_t length); + // + // For SalaScript + void setMark(SalaObj& mark) + { m_sala_mark = mark; } + const SalaObj& getMark() const + { return m_sala_mark; } +}; + +// note pvector: this is stored in order, reorder by qsort +class AttributeIndex : public pvector +{ + friend class AttributeTable; +protected: + int m_col; +public: + AttributeIndex(); + void clear(); + int makeIndex(const AttributeTable& table, int col, bool setdisplayinfo); +}; + +class AttributeColumn +{ +public: + std::string m_name; + bool m_updated; // <- this flag is not saved, and indicates new data in the column (set on insert column etc) + int m_physical_col; + mutable double m_min; + mutable double m_max; + mutable double m_tot; + mutable double m_visible_min; + mutable double m_visible_max; + mutable double m_visible_tot; + bool m_hidden; + bool m_locked; + // display parameters + DisplayParams m_display_params; + // retain formula used to create column + std::string m_formula; + + AttributeColumn(const std::string& name = std::string(), int physical_col = -1) + { m_name = name; + m_min = -1.0f; + m_max = 0.0f; + m_tot = 0.0; + m_visible_min = -1.0f; + m_visible_max = 0.0f; + m_visible_tot = 0.0; + m_physical_col = physical_col; + m_hidden = false; + m_locked = false; + m_updated = false; + } + float makeNormValue(float value) const + { return (m_min == m_max) ? 0.5f : (value == -1.0f) ? -1.0f : (float)((value - m_min) / (m_max - m_min)); } + void setValue(float value) + { m_updated = true; m_tot += value; if (m_min == -1.0f || value < m_min) m_min = value; if (value > m_max) m_max = value; } + void changeValue(float oldval, float newval) + { m_updated = true; if (oldval != -1.0f) m_tot -= oldval; if (newval != -1.0f) setValue(newval); } + void setInfo(double min, double max, double tot, double vismin, double vismax, double vistot) const + { m_min = min; m_max = max; m_tot = tot; m_visible_min = vismin; m_visible_max = vismax; m_visible_tot = vistot; } + const DisplayParams& getDisplayParams() const + { return m_display_params; } + void reset(); + void setLock(bool lock = true) + { m_locked = lock; } + bool read( std::ifstream& stream, int version ); + bool write(std::ostream &stream, int version ); + friend bool operator == (const AttributeColumn& a, const AttributeColumn& b); + friend bool operator < (const AttributeColumn& a, const AttributeColumn& b); + friend bool operator > (const AttributeColumn& a, const AttributeColumn& b); +}; +inline bool operator == (const AttributeColumn& a, const AttributeColumn& b) +{ return a.m_name == b.m_name; } +inline bool operator < (const AttributeColumn& a, const AttributeColumn& b) +{ return a.m_name < b.m_name; } +inline bool operator > (const AttributeColumn& a, const AttributeColumn& b) +{ return a.m_name > b.m_name; } + +class AttributeTable : protected pqmap +{ +public: + std::string m_name; + pqvector m_columns; + mutable int m_sel_count; + mutable double m_sel_value; +// pqmap m_data; +// // display parameters for the reference id column + DisplayParams m_ref_display_params; + int64 m_available_layers; + pqmap m_layers; + mutable int64 m_visible_layers; + mutable int m_visible_size; + mutable int m_display_column; + mutable DisplayParams m_display_params; + // Display: + mutable AttributeIndex m_display_index; + std::string g_ref_number_name; // = std::string("Ref Number"); + std::string g_ref_number_formula; // = std::string(""); + + + AttributeTable(const std::string& name = std::string()); + int insertColumn(const std::string& name = std::string()); + int insertRow(int key); + int getColumnIndex(const std::string& name) const + { size_t index = m_columns.searchindex(name); return (index == paftl::npos) ? -1 : int(index);} // note use -1 rather than paftl::npos for return value + int getOrInsertColumnIndex(const std::string& name) + { size_t col = m_columns.searchindex(name); if (col == paftl::npos) return insertColumn(name); else return (int) col; } + int getOrInsertLockedColumnIndex(const std::string& name) + { size_t col = m_columns.searchindex(name); if (col == paftl::npos) return insertLockedColumn(name); else return (int) col; } + int getRowKey(int index) const + { return key(index); } + int getRowid(const int key) const + { size_t i = searchindex(key); return (i == paftl::npos) ? -1 : int(i);} // note use -1 rather than paftl::npos for return value + int getRowCount() const + { return (int) size(); } + int getMaxRowKey() const + { return key(size()-1); } + // this version uses known row and col indices + float getValue(int row, int col) const + { return col != -1 ? value(row).at(m_columns[col].m_physical_col) : key(row); } + // this version is meant to use row key and col name + float getValue(int row, const std::string& name) const + { int col = getColumnIndex(name); return col != -1 ? value(row).at(m_columns[col].m_physical_col) : key(row); } + float getNormValue(int row, int col) const + { return col != -1 ? m_columns[col].makeNormValue(value(row).at(m_columns[col].m_physical_col)) : (float) (double(getRowKey(row))/double(getRowKey(int(size()-1)))); } + void setValue(int row, int col, float val) + { value(row).at(m_columns[col].m_physical_col) = val; m_columns[col].setValue(val); } + void setValue(int row, const std::string& name, float val) + { int col = getColumnIndex(name); if (col != -1) setValue(row,col,val); } + void changeValue(int row, int col, float val) + { float& theval = value(row).at(m_columns[col].m_physical_col); m_columns[col].changeValue(theval,val); theval = val; } + void changeValue(int row, const std::string& name, float val) + { int col = getColumnIndex(name); if (col != -1) changeValue(row,col,val); } + void changeSelValues(int col, float val) + { for (size_t i = 0; i < size(); i++) { if (value(i).m_selected) changeValue((int)i,col,val);} } + void incrValue(int row, int col, float amount = 1.0f) + { float& v = value(row).at(m_columns[col].m_physical_col); v = (v == -1.0f) ? amount : v+amount ; m_columns[col].changeValue(v-amount,v); } + void incrValue(int row, const std::string& name, float amount = 1.0f) + { int col = getColumnIndex(name); if (col != -1) incrValue(row,col,amount); } + + void setColumnInfo(int col, double min, double max, double tot, double vismin, double vismax, double vistot) const + { m_columns[col].setInfo(min,max,tot,vismin,vismax,vistot); } + + void setColumnLock(int col, bool lock = true) + { m_columns[col].setLock(lock); } + int insertLockedColumn(const std::string& name = std::string()) + { int col = insertColumn(name); setColumnLock(col); return col; } + // For SalaScript: + void setMark(int row, SalaObj& mark) + { value(row).setMark(mark); } + const SalaObj& getMark(int row) const + { return value(row).getMark(); } + void deselectAll() const; + void addSelValue(double value) const + { m_sel_value += (value != -1.0f) ? value : 0.0; } + bool isSelected(int index) const + { return value(index).m_selected; } + + bool isVisible(int row) const + { return (m_visible_layers & (at(row).m_layers)) != 0; } + void setDisplayColumn(int col, bool override = false) const; + int getDisplayColumn() const + { return m_display_column; } + void setDisplayInfo(int row, ValuePair vp) const + { at(row).m_display_info = vp; if (at(row).m_selected) addSelValue((double)vp.value); } + const DisplayParams& getDisplayParams() const + { return m_display_params; } + void clear() // <- totally destroy, not just clear values + { m_columns.clear(); pqmap::clear(); } + + bool read( std::ifstream& stream, int version ); + bool write(std::ostream &stream, int version ); +}; + +} + +#endif diff --git a/mgraph440/axialmap.cpp b/mgraph440/axialmap.cpp new file mode 100644 index 00000000..5ab16fda --- /dev/null +++ b/mgraph440/axialmap.cpp @@ -0,0 +1,232 @@ +#include "mgraph440/mgraph_consts.h" +#include "mgraph440/axialmap.h" +#include "mgraph440/stringutils.h" + +namespace mgraph440 { + +bool ShapeGraph::read( std::ifstream& stream, int version ) +{ + m_attributes.clear(); + m_connectors.clear(); + m_selection = false; + m_map_type = ShapeMap::EMPTYMAP; + + // the old version used SpacePixel as base class + // actually easiest to read and translate, rather than try to use new method + if (version < VERSION_AXIAL_SHAPES) { + readold(stream, version); + } + else { + bool segmentmap = false; + if (version < VERSION_MAP_TYPES) { + // axial specific reads -- segment map flag and keyvertices (part of all line map functionality) + // note, now stored in the "map_type", and read / written with shape map + char segmentmapc = stream.get(); + if (segmentmapc == '1') { + segmentmap = true; + } + } + // note that keyvertexcount and keyvertices are different things! (length keyvertices not the same as keyvertexcount!) + stream.read((char *)&m_keyvertexcount,sizeof(m_keyvertexcount)); + int size; + stream.read((char *)&size,sizeof(size)); + for (int i = 0; i < size; i++) { + m_keyvertices.push_back(pvecint()); + m_keyvertices[i].read(stream); + } + // now base class read: + ShapeMap::read(stream,version); + // + // override shapemap map type designation if necessary: + if (version < VERSION_MAP_TYPES) { + if (segmentmap) { + m_map_type = ShapeMap::SEGMENTMAP; + } + else { + m_map_type = ShapeMap::AXIALMAP; + } + } + } + + return true; +} + +bool ShapeGraph::readold( std::ifstream& stream, int version ) +{ + // read in from old base class + SpacePixel linemap; + linemap.read(stream, version); + const pmap& lines = linemap.getAllLines(); + + m_name = linemap.getName(); + + // now copy to new base class: + init(lines.size(),linemap.getRegion()); + for (size_t i = 0; i < lines.size(); i++) { + makeLineShape(lines[i].line); + } + // n.b., we now have to reclear attributes! + m_attributes.clear(); + + // continue old read: + int pushmap = -1; + if (version >= VERSION_SEGMENT_MAPS) { + char segmentmapc = stream.get(); + if (segmentmapc == '1') { + m_map_type = ShapeMap::SEGMENTMAP; + } + else { + m_map_type = ShapeMap::AXIALMAP; + } + } + if (version >= VERSION_GATE_MAPS) { + char gatemapc = stream.get(); + if (gatemapc == '1') { + m_map_type = ShapeMap::DATAMAP; + } + stream.read((char *)&pushmap,sizeof(pushmap)); + } + + int displayed_attribute; // n.b., temp variable necessary to force recalc below + stream.read((char *)&displayed_attribute,sizeof(displayed_attribute)); + + m_attributes.read(stream,version); + int size; + stream.read((char *)&size,sizeof(size)); + for (int j = 0; j < size; j++) { + m_keyvertices.push_back(pvecint()); // <- these were stored with the connector + int key; + stream.read((char *)&key,sizeof(key)); // <- key deprecated + m_connectors.push_back(Connector()); + m_connectors[j].read(stream,version,&(m_keyvertices[j])); + } + stream.read((char *)&m_keyvertexcount,sizeof(m_keyvertexcount)); + + if (version >= VERSION_AXIAL_LINKS) { + m_links.read(stream); + m_unlinks.read(stream); + } + // some miscellaneous extra data for mapinfo files + if (m_mapinfodata) { + delete m_mapinfodata; + m_mapinfodata = NULL; + } + if (version >= VERSION_MAPINFO_DATA) { + char x = stream.get(); + if (x == 'm') { + m_mapinfodata = new MapInfoData; + m_mapinfodata->read(stream,version); + } + } + + // now, as soon as loaded, must recalculate our screen display: + // note m_displayed_attribute should be -2 in order to force recalc... + m_displayed_attribute = -2; + setDisplayedAttribute(displayed_attribute); + + return true; +} + +bool ShapeGraphs::read( std::ifstream& stream, int version ) +{ + // base class read + if (version >= VERSION_AXIAL_SHAPES) { + ShapeMaps::read(stream,version); + } + else { + readold(stream,version); + } + + // these are additional essentially for all line axial maps + // should probably be kept *with* the all line axial map... + m_poly_connections.clear(); + m_poly_connections.read(stream); + m_radial_lines.clear(); + m_radial_lines.read(stream); + + // this is an index to look up the all line map, used by UI to determine if can make fewest line map + // note: it is not saved for historical reasons + // will get confused by more than one all line map + m_all_line_map = getMapRef("All-Line Map"); + if (m_all_line_map == -1) { + // used to be called All Line Map + m_all_line_map = getMapRef("All Line Map"); + } + if (m_all_line_map != -1) { + at(m_all_line_map).m_map_type = ShapeMap::ALLLINEMAP; + } + + // VERSION_AXIAL_REGION_FIX -- this fix is now deprecated + // some awful things could have gone wrong in the past, but the shapemap read should fix automatically + + return true; +} + +// for backward compatibility only: +bool ShapeGraphs::readold( std::ifstream& stream, int version ) +{ + // this read is based on SpacePixelGroup::read(stream, version); + dXstring440::readString(stream); + QtRegion dummyregion; + stream.read( (char *) &dummyregion, sizeof(dummyregion) ); + int count; + stream.read( (char *) &count, sizeof(count) ); + for (int i = 0; i < count; i++) { + push_back(ShapeGraph()); + tail().read(stream,version); + } + stream.read((char *)&m_displayed_map,sizeof(m_displayed_map)); + + return true; +} + +bool ShapeGraphs::write(std::ostream &stream, int version, bool displayedmaponly ) +{ + // base class write + ShapeMaps::write(stream, version, displayedmaponly); + + m_poly_connections.write(stream); + m_radial_lines.write(stream); + + return true; +} + +bool ShapeGraph::write( std::ostream& stream, int version ) +{ + // note keyvertexcount and keyvertices are different things! (length keyvertices not the same as keyvertexcount!) + stream.write((char *)&m_keyvertexcount,sizeof(m_keyvertexcount)); + int size = m_keyvertices.size(); + stream.write((char *)&size,sizeof(size)); + for (size_t i = 0; i < m_keyvertices.size(); i++) { + m_keyvertices[i].write(stream); + } + + // now simply run base class write: + ShapeMap::write(stream,version); + + return true; +} + +AxialPolygons::AxialPolygons() +{ + m_pixel_polys = NULL; +} + +AxialPolygons::~AxialPolygons() +{ + if (m_pixel_polys) { + for (int i = 0; i < m_cols; i++) { + delete [] m_pixel_polys[i]; + } + delete [] m_pixel_polys; + m_pixel_polys = NULL; + } +} + +ShapeGraph::ShapeGraph(const std::string& name, int type) : ShapeMap(name,type) +{ + m_keyvertexcount = 0; + m_hasgraph = true; +} + +} diff --git a/mgraph440/axialmap.h b/mgraph440/axialmap.h new file mode 100644 index 00000000..b2a11d06 --- /dev/null +++ b/mgraph440/axialmap.h @@ -0,0 +1,146 @@ +#pragma once + +#include "mgraph440/spacepix.h" +#include "mgraph440/shapemap.h" +#include "mgraph440/connector.h" + +namespace mgraph440 { + +struct AxialVertexKey +{ + int m_ref_key; + short m_ref_a; + short m_ref_b; + AxialVertexKey(int ref = -1, short a = -1, short b = -1) + { m_ref_key = ref; m_ref_a = a; m_ref_b = b; } + friend bool operator == (const AxialVertexKey& a, const AxialVertexKey& b); + friend bool operator != (const AxialVertexKey& a, const AxialVertexKey& b); + friend bool operator > (const AxialVertexKey& a, const AxialVertexKey& b); + friend bool operator < (const AxialVertexKey& a, const AxialVertexKey& b); +}; +inline bool operator == (const AxialVertexKey& a, const AxialVertexKey& b) +{ return (a.m_ref_key == b.m_ref_key && a.m_ref_a == b.m_ref_a && a.m_ref_b == b.m_ref_b); } +inline bool operator != (const AxialVertexKey& a, const AxialVertexKey& b) +{ return (a.m_ref_key != b.m_ref_key || a.m_ref_a != b.m_ref_a || a.m_ref_b != b.m_ref_b); } +inline bool operator > (const AxialVertexKey& a, const AxialVertexKey& b) +{ return (a.m_ref_key > b.m_ref_key || (a.m_ref_key == b.m_ref_key && (a.m_ref_a > b.m_ref_a || (a.m_ref_a == b.m_ref_a && a.m_ref_b > b.m_ref_b)))); } +inline bool operator < (const AxialVertexKey& a, const AxialVertexKey& b) +{ return (a.m_ref_key < b.m_ref_key || (a.m_ref_key == b.m_ref_key && (a.m_ref_a < b.m_ref_a || (a.m_ref_a == b.m_ref_a && a.m_ref_b < b.m_ref_b)))); } + +const AxialVertexKey NoVertex(-1,-1,-1); + +struct RadialKey { + AxialVertexKey vertex; + float ang; + bool segend; + // padding the remaining three bytes behind the bool - don't use int : 24 as this will grab the next 4 byte block + char pad1 : 8; + short pad2 : 16; + + RadialKey(const AxialVertexKey& v = NoVertex, float a = -1.0f, bool se = false) : pad1(0), pad2(0) + { vertex = v; ang = a; segend = se; } + RadialKey(const RadialKey& rk) : pad1(0), pad2(0) + { vertex = rk.vertex; ang = rk.ang; segend = rk.segend; } + friend bool operator < (const RadialKey& a, const RadialKey& b); + friend bool operator > (const RadialKey& a, const RadialKey& b); + friend bool operator == (const RadialKey& a, const RadialKey& b); +}; +inline bool operator < (const RadialKey& a, const RadialKey& b) +{ return a.vertex < b.vertex || (a.vertex == b.vertex && (a.ang < b.ang || (a.ang == b.ang && a.segend < b.segend))); } +inline bool operator > (const RadialKey& a, const RadialKey& b) +{ return a.vertex > b.vertex || (a.vertex == b.vertex && (a.ang > b.ang || (a.ang == b.ang && a.segend > b.segend))); } +inline bool operator == (const RadialKey& a, const RadialKey& b) +{ return a.vertex == b.vertex && a.ang == b.ang && a.segend == b.segend; } + +struct RadialLine : public RadialKey +{ + Point2f openspace; + Point2f keyvertex; + Point2f nextvertex; + RadialLine(const RadialKey& rk = RadialKey()) : RadialKey(rk) {;} + RadialLine(const AxialVertexKey& v, bool se, const Point2f& o, const Point2f& k, const Point2f& n) + { vertex = v; ang = (float) angle(o,k,n); segend = se; openspace = o; keyvertex = k; nextvertex = n; } + RadialLine(const RadialLine& rl) : RadialKey(rl) + { openspace = rl.openspace; keyvertex = rl.keyvertex; nextvertex = rl.nextvertex; } + bool cuts(const Line& l) const; +}; +struct PolyConnector { + Line line; + RadialKey key; + PolyConnector(const Line& l = Line(), const RadialKey& k = RadialKey()) + { line = l; key = k; } +}; +struct AxialVertex : public AxialVertexKey +{ + Point2f m_point; + Point2f m_openspace; + Point2f m_a; + Point2f m_b; + bool m_clockwise; + bool m_convex; + bool m_initialised; + bool m_axial; + AxialVertex(const AxialVertexKey& vertex_key = NoVertex, const Point2f& point = Point2f(), const Point2f& openspace = Point2f()) : AxialVertexKey(vertex_key) + { m_point = point; m_openspace = openspace; m_initialised = false; m_axial = false; } +}; + +class AxialPolygons : public SpacePixel +{ + friend class ShapeGraphs; +public: + pqmap> m_vertex_possibles; + pvecint m_vertex_polys; + pvecint **m_pixel_polys; + pqvector m_handled_list; + AxialPolygons(); + virtual ~AxialPolygons(); + + void clear(); + void init(prefvec& lines, const QtRegion& region); + void makeVertexPossibles(const prefvec& lines, const prefvec& connectionset); + void makePixelPolys(); + // + AxialVertex makeVertex(const AxialVertexKey& vertexkey, const Point2f& openspace); + // find a polygon corner visible from seed: + AxialVertexKey seedVertex(const Point2f& seed); + // make axial lines from corner vertices, visible from openspace + void makeAxialLines(pqvector& openvertices, prefvec& lines, prefvec& keyvertices, prefvec& poly_connections, pqvector& radial_lines); + // extra: make all the polygons possible from the set of m_vertex_possibles + void makePolygons(prefvec>& polygons); +}; + +class ShapeGraph : public ShapeMap +{ + friend class ShapeGraphs; + friend class AxialMinimiser; + friend class MapInfoData; +public: + ShapeGraph(const std::string& name = "", int type = ShapeMap::AXIALMAP); + virtual ~ShapeGraph() {;} + + prefvec m_keyvertices; // but still need to return keyvertices here + int m_keyvertexcount; + bool outputMifPolygons(std::ostream& miffile, std::ostream& midfile) const; + void outputNet(std::ostream& netfile) const; + virtual bool read( std::ifstream& stream, int version ); + bool readold( std::ifstream& stream, int version ); + virtual bool write(std::ostream &stream, int version ); +}; + +class ShapeGraphs : public ShapeMaps +{ +public: + // helpful to know this for creating fewest line maps, although has to be reread at input + int m_all_line_map; + // For all line map work: + AxialPolygons m_polygons; + prefvec m_poly_connections; + pqvector m_radial_lines; + ShapeGraphs() { m_all_line_map = -1; } + virtual ~ShapeGraphs() {;} + bool read( std::ifstream& stream, int version ); + bool readold( std::ifstream& stream, int version ); + bool write( std::ostream& stream, int version, bool displayedmaponly = false ); +}; + +} diff --git a/mgraph440/bspnode.h b/mgraph440/bspnode.h new file mode 100644 index 00000000..359d00d9 --- /dev/null +++ b/mgraph440/bspnode.h @@ -0,0 +1,53 @@ +// genlib - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010 University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "mgraph440/paftl.h" +#include "mgraph440/p2dpoly.h" + +// Binary Space Partition + +namespace mgraph440 { + +struct BSPNode +{ +public: + enum { BSPLEFT, BSPRIGHT }; + BSPNode *left; + BSPNode *right; + BSPNode *parent; + Line line; + int m_tag; + int m_count; + // +public: + BSPNode() + { left = NULL; right = NULL; parent = NULL; m_count = 0; m_tag = -1; } + virtual ~BSPNode() + { if (left) delete left; left = NULL; if (right) delete right; right = NULL; } + // + bool isLeaf() { + return left == NULL && right == NULL; + } + void make(Communicator *communicator, time_t atime, const prefvec& lines, BSPNode *par); + int classify(const Point2f& p); + const Line& getLine() const { return line; } + int getTag() const { return m_tag; } +}; + +} diff --git a/mgraph440/comm.h b/mgraph440/comm.h new file mode 100644 index 00000000..22edb369 --- /dev/null +++ b/mgraph440/comm.h @@ -0,0 +1,209 @@ +// genlib - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef __COMM_H__ +#define __COMM_H__ + +//#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +// Quick mod - TV +#pragma warning (disable: 4244) +#pragma warning (disable: 4100) +#else + +#endif + +namespace mgraph440 { + + const char *const g_default_file_set = "File set"; + +struct FilePath { + std::string m_path; + std::string m_name; + std::string m_ext; + FilePath(const std::string& pathname) + { + size_t dot = pathname.find_last_of('.'); +#ifdef _WIN32 + size_t slash = pathname.find_last_of('\\'); // WIN32 +#else + size_t slash = pathname.find_last_of('/'); // Other +#endif + if (slash != std::string::npos) { + m_path = pathname.substr(0,slash+1); + } + if (dot != std::string::npos) { + m_name = pathname.substr(slash+1,dot-slash-1); + m_ext = pathname.substr(dot+1); + } + else { + m_name = pathname.substr(slash+1); + } + } +}; + +class Communicator +{ +public: + class CancelledException // throw from your class + { + public: + CancelledException() {;} + }; + enum { NUM_STEPS, CURRENT_STEP, NUM_RECORDS, CURRENT_RECORD }; +protected: + bool m_cancelled; + bool m_delete_flag; + // nb. converted to Win32 UTF-16 Unicode path (AT 31.01.11) Linux, MacOS use UTF-8 (AT 29.04.11) + std::string m_infilename; + std::ifstream *m_infile; + std::ifstream *m_infile2; // <- MapInfo MIF files come in two parts + std::ofstream *m_outfile; + // nb. converted to Win32 UTF-16 Unicode path (AT 31.01.11) Linux, MacOS use UTF-8 (AT 29.04.11) + std::vector m_fileset; // <- sometimes you want to load a whole set of files +public: + Communicator() + { m_infile = NULL; m_infile2 = NULL; m_outfile = NULL; m_cancelled = false; m_delete_flag = false; } + // + bool GetDeleteFlag() // used by ICommunicator and IComm together + { return m_delete_flag; } + // + virtual ~Communicator() + { if (m_infile) delete m_infile; m_infile = NULL; + if (m_infile2) delete m_infile2; m_infile2 = NULL; + if (m_outfile) delete m_outfile; m_outfile = NULL; } + // + void SetInfile( const char* filename ) + { + m_infile = new std::ifstream( filename ); + FilePath fp(filename); + m_infilename = fp.m_name; + } + void SetInfile2( const char* filename ) + { + m_infile2 = new std::ifstream( filename ); + } + std::string GetInfileName() + { + return m_fileset.size() ? std::string(g_default_file_set) : m_infilename; + } + std::string GetMBInfileName() + { + std::string ret; + if (m_fileset.size()) { + ret = "File set"; + } + else { + ret = std::string(m_infilename.c_str()); + } + return ret; + } + size_t GetInfileSize() + { + if (m_infile) { + m_infile->seekg(0, std::ios::beg); + size_t begin_pos = m_infile->tellg(); + m_infile->seekg(0, std::ios::end); + size_t end_pos = m_infile->tellg(); + m_infile->seekg(0, std::ios::beg); + return size_t(end_pos - begin_pos); + } + return 0; + } + void SetOutfile( const char *filename ) + { m_outfile = new std::ofstream( filename ); } + // + bool IsCancelled() const + { return m_cancelled; } + void Cancel() + { m_cancelled = true; } + // + operator std::ofstream& () + { return *m_outfile; } + operator std::ifstream& () + { return *m_infile; } + std::ifstream& GetInfile2() + { return *m_infile2; } + // + const std::vector& GetFileSet() const + { return m_fileset; } + // + virtual void CommPostMessage(int m, int x, int y = 0) const = 0; // Override for specific operating system +}; + +// this is a simple version of the Communicator which can be used for +// an interface + +class ICommunicator : public Communicator +{ + friend class IComm; // IComm is found in idepthmap.h + // +protected: + mutable int num_steps; + mutable int num_records; + mutable int step; + mutable int record; + // +public: + ICommunicator() { m_delete_flag = true; } // note: an ICommunicator lets IComm know that it should delete it + virtual ~ICommunicator() {;} + virtual void CommPostMessage(int m, int x) const; +}; + +inline void ICommunicator::CommPostMessage(int m, int x) const +{ + switch (m) { + case Communicator::NUM_STEPS: + num_steps = x; + break; + case Communicator::CURRENT_STEP: + step = x; + break; + case Communicator::NUM_RECORDS: + num_records = x; + break; + case Communicator::CURRENT_RECORD: + record = x; + break; + default: + break; + } +} + + +// a helpful little function... + +inline bool qtimer( time_t& t1, time_t timeout ) +{ + /* static */ timeb time2; // static removed for multithreaded usage + ftime( &time2 ); + time_t t2 = (time2.time % 100) * 1000 + time2.millitm; + if ((t2 - t1) > timeout || (t2 - t1) < 0) { // also catch a loop + t1 = t2; + return true; + } + return false; +} + +} + +#endif diff --git a/mgraph440/connector.cpp b/mgraph440/connector.cpp new file mode 100644 index 00000000..eedf2b25 --- /dev/null +++ b/mgraph440/connector.cpp @@ -0,0 +1,170 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#include + +#include "mgraph440/mgraph_consts.h" +#include +#include +#include +#include + +namespace mgraph440 { + +bool Connector::read( ::std::ifstream& stream, int version, pvecint *keyvertices ) +{ + m_connections.clear(); + m_forward_segconns.clear(); + m_back_segconns.clear(); + + // n.b., must set displayed attribute as soon as loaded... + m_connections.read(stream); + + // keyvertices now stored with axial map itself, but need this read for backward compatibility + if (version < VERSION_AXIAL_SHAPES && keyvertices != NULL) { + keyvertices->read(stream); + } + + if (version >= VERSION_SEGMENT_MAPS) { + stream.read((char *)&m_segment_axialref, sizeof(m_segment_axialref)); + m_forward_segconns.read(stream); + } + if (version >= VERSION_SEGMENT_MAPS_FIX) { + m_back_segconns.read(stream); + } + + return true; +} + +bool Connector::write( ::std::ostream& stream ) +{ + // n.b., must set displayed attribute as soon as loaded... + m_connections.write(stream); + // m_keyvertices.write(stream); + stream.write((char *)&m_segment_axialref, sizeof(m_segment_axialref)); + m_forward_segconns.write(stream); + m_back_segconns.write(stream); + + return true; +} + +///////////////////////////////////////////////////////////////////////////////// + +// Cursor extras + +int Connector::count(int mode) const +{ + int c = 0; + switch (mode) { + case CONN_ALL: + c = m_connections.size(); + break; + case SEG_CONN_ALL: + c = m_back_segconns.size() + m_forward_segconns.size(); + break; + case SEG_CONN_FW: + c = m_forward_segconns.size(); + break; + case SEG_CONN_BK: + c = m_back_segconns.size(); + break; + } + return c; +} +int Connector::cursor(int mode) const +{ + int cur = -1; + if (m_cursor != -1) { + switch (mode) { + case CONN_ALL: + if (m_cursor < (int)m_connections.size()) { + cur = m_connections[m_cursor]; + } + break; + case SEG_CONN_ALL: + if (m_cursor < (int)m_back_segconns.size()) { + cur = m_back_segconns.key(m_cursor).ref; + } + else if (m_cursor - m_back_segconns.size() < m_forward_segconns.size()) { + cur = m_forward_segconns.key(m_cursor - m_back_segconns.size()).ref; + } + break; + case SEG_CONN_FW: + if (m_cursor < (int)m_forward_segconns.size()) { + cur = m_forward_segconns.key(m_cursor).ref; + } + break; + case SEG_CONN_BK: + if (m_cursor < (int)m_back_segconns.size()) { + cur = m_back_segconns.key(m_cursor).ref; + } + break; + } + } + if (cur == -1) { + m_cursor = -1; + } + return cur; +} +int Connector::direction(int mode) const +{ + int direction = 0; + if (m_cursor != -1) { + switch (mode) { + case SEG_CONN_ALL: + if (m_cursor < (int)m_back_segconns.size()) { + direction = m_back_segconns.key(m_cursor).dir; + } + else if (m_cursor - m_back_segconns.size() < m_forward_segconns.size()) { + direction = m_forward_segconns.key(m_cursor - m_back_segconns.size()).dir; + } + break; + case SEG_CONN_FW: + direction = m_forward_segconns.key(m_cursor).dir; + break; + case SEG_CONN_BK: + direction = m_back_segconns.key(m_cursor).dir; + break; + } + } + return direction; +} +float Connector::weight(int mode) const +{ + float weight = 0.0f; + if (m_cursor != -1) { + switch (mode) { + case SEG_CONN_ALL: + if (m_cursor < (int)m_back_segconns.size()) { + weight = m_back_segconns.value(m_cursor); + } + else if (m_cursor - m_back_segconns.size() < m_forward_segconns.size()) { + weight = m_forward_segconns.value(m_cursor - m_back_segconns.size()); + } + break; + case SEG_CONN_FW: + weight = m_forward_segconns.value(m_cursor); + break; + case SEG_CONN_BK: + weight = m_back_segconns.value(m_cursor); + break; + } + } + return weight; +} + +} diff --git a/mgraph440/connector.h b/mgraph440/connector.h new file mode 100644 index 00000000..9af0fd31 --- /dev/null +++ b/mgraph440/connector.h @@ -0,0 +1,102 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#ifndef __CONNECTOR_H__ +#define __CONNECTOR_H__ + +#include "mgraph440/paftl.h" +///////////////////////////////////////////////////////////////////////////// + +// Additional for segment analysis + +namespace mgraph440 { + +struct SegmentRef +{ + char dir; int ref; + SegmentRef(char d = 0, int r = -1) + { dir = d; ref = r; } + friend bool operator < (SegmentRef a, SegmentRef b); + friend bool operator > (SegmentRef a, SegmentRef b); + friend bool operator == (SegmentRef a, SegmentRef b); + friend bool operator != (SegmentRef a, SegmentRef b); +}; +// note, the dir is only a direction indicator, the ref should always be unique +inline bool operator < (SegmentRef a, SegmentRef b) { return a.ref < b.ref; } +inline bool operator > (SegmentRef a, SegmentRef b) { return a.ref > b.ref; } +inline bool operator == (SegmentRef a, SegmentRef b) { return a.ref == b.ref; } +inline bool operator != (SegmentRef a, SegmentRef b) { return a.ref != b.ref; } + +// used during angular analysis +struct SegmentData : public SegmentRef +{ + SegmentRef previous; + int segdepth; + float metricdepth; + unsigned int coverage; + SegmentData(char d = 0, int r = -1, SegmentRef p = SegmentRef(), int sd = 0, float md = 0.0f, unsigned int cv = 0xffffffff) + { dir = d; ref = r; previous = p; segdepth = sd; metricdepth = md; coverage = cv; } + SegmentData(SegmentRef ref, SegmentRef p = SegmentRef(), int sd = 0, float md = 0.0f, unsigned int cv = 0xffffffff) : SegmentRef(ref) + { previous = p; segdepth = sd; metricdepth = md; coverage = cv; } + friend bool operator < (SegmentData a, SegmentData b); + friend bool operator > (SegmentData a, SegmentData b); + friend bool operator == (SegmentData a, SegmentData b); + friend bool operator != (SegmentData a, SegmentData b); +}; +// note, these are stored in reverse metric depth order (i.e., metric shorter paths are taken off the end of the list first) +inline bool operator < (SegmentData a, SegmentData b) { return a.metricdepth > b.metricdepth; } +inline bool operator > (SegmentData a, SegmentData b) { return a.metricdepth < b.metricdepth; } +inline bool operator == (SegmentData a, SegmentData b) { return a.metricdepth == b.metricdepth; } +inline bool operator != (SegmentData a, SegmentData b) { return a.metricdepth != b.metricdepth; } + +/////////////////////////////////////////////////////////////////////////// + +// Main connector class for segments, convex spaces or axial lines + +struct Connector +{ + // cursor included purely to make this compatible with DLL functionality + mutable int m_cursor; + // if this is a segment, this is the key for the axial line: + int m_segment_axialref; + // use one or other of these + pvecint m_connections; + // + pmap m_back_segconns; + pmap m_forward_segconns; + // + Connector(int axialref = -1) + { m_segment_axialref = axialref; m_cursor = -1; } + void clear() + { m_connections.clear(); m_back_segconns.clear(); m_forward_segconns.clear(); } + // + bool read( ::std::ifstream& stream, int version, pvecint *keyvertices = NULL ); + bool write(std::ostream &stream ); + // + // Cursor extras + enum { CONN_ALL, SEG_CONN_ALL, SEG_CONN_FW, SEG_CONN_BK }; + int count(int mode = CONN_ALL) const; + int cursor(int mode = CONN_ALL) const; + int direction(int mode = SEG_CONN_ALL) const; + float weight(int mode = SEG_CONN_ALL) const; + void first() const { m_cursor = 0; } + void next() const { m_cursor++; } +}; + +} + +#endif diff --git a/mgraph440/containerutils.h b/mgraph440/containerutils.h new file mode 100644 index 00000000..40a123e8 --- /dev/null +++ b/mgraph440/containerutils.h @@ -0,0 +1,35 @@ +// genlib - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2017, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +namespace depthmapX440 { + +template +void findAndErase(std::vector &vec, T element) { + auto it = std::find(vec.begin(), vec.end(), element); + if(it != vec.end()) + vec.erase(it); +} + +template +void addIfNotExists(std::vector &vec, T element) { + auto it = std::find(vec.begin(), vec.end(), element); + if(it == vec.end()) + vec.push_back(element); +} + +} diff --git a/salalib/datalayer.cpp b/mgraph440/datalayer.cpp similarity index 71% rename from salalib/datalayer.cpp rename to mgraph440/datalayer.cpp index 64207440..4f6b0b44 100644 --- a/salalib/datalayer.cpp +++ b/mgraph440/datalayer.cpp @@ -1,177 +1,150 @@ -// sala - a component of the depthmapX - spatial network analysis platform -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// THIS CODE IS DEPRECATED DO NOT USE: USE SHAPE MAPS INSTEAD 21.08.05 - -// INCLUDED ONLY TO ALLOW COMPATIBILITY WITH OLD VERSIONS - -// DataLayer.cpp: implementation of the DataLayer class. -// -////////////////////////////////////////////////////////////////////// - -#include - -#include -#include - -bool DataLayers::read(ifstream& stream, int version) -{ - m_layers.clear(); - stream.read( (char *) &m_current_layer_index, sizeof(int) ); - int size; - stream.read( (char *) &size, sizeof(int) ); - for (int i = 0; i < size; i++) { - DataLayer data; - m_layers.push_back(data); - m_layers.tail().read(stream, version); - } - return true; -} - -bool DataLayers::write(ofstream& stream) -{ - stream.write( (char *) &m_current_layer_index, sizeof(int) ); - int size = m_layers.size(); - stream.write( (char *) &size, sizeof(int) ); - for (size_t i = 0; i < m_layers.size(); i++) { - m_layers[i].write(stream); - } - return true; -} - -//////////////////////////////////////////////////////// - -void DataLayer::setDisplayColumn(int i) -{ - if (i == 0) { - for (size_t j = 0; j < m_data_objects.size(); j++) { - m_data_objects[j].m_color = float(j + 1) / m_data_objects.size(); - } - m_display_min = 0; - m_display_max = m_data_objects.size(); - } - else if (m_data_objects.size()) { - double max = m_data_objects[0][i-1], min = m_data_objects[0][i-1]; - for (size_t j = 1; j < m_data_objects.size(); j++) { - if (m_data_objects[j][i-1] < min) { - min = m_data_objects[j][i-1]; - } - else if (m_data_objects[j][i-1] > max) { - max = m_data_objects[j][i-1]; - } - } - for (size_t k = 0; k < m_data_objects.size(); k++) { - m_data_objects[k].m_color = (float) ((m_data_objects[k][i-1] - min) / (max - min)); - } - m_display_min = min; - m_display_max = max; - } - m_display_column = i; -} - -bool DataLayer::read(ifstream& stream, int version) -{ - m_data_objects.clear(); - m_column_titles.clear(); - stream.read( (char *) &m_layer_ref, sizeof(int) ); - m_layer_name.read(stream); - stream.read( (char *) &m_next_object_ref, sizeof(int) ); - int rows_size; - stream.read( (char *) &rows_size, sizeof(int) ); - for (int i = 0; i < rows_size; i++) { - DataObject object; - m_data_objects.push_back(object); - m_data_objects.tail().read(stream,version); - } - int columns_size; - stream.read( (char *) &columns_size, sizeof(int) ); - for (int j = 0; j < columns_size; j++) { - pstring title; - m_column_titles.push_back(title); - m_column_titles.tail().read(stream); - } - - // Since it doesn't seem to be recorded, just display the initial column - setDisplayColumn(0); - - return true; -} - -bool DataLayer::write(ofstream& stream) -{ - stream.write( (char *) &m_layer_ref, sizeof(int) ); - m_layer_name.write(stream); - stream.write( (char *) &m_next_object_ref, sizeof(int) ); - int rows_size = m_data_objects.size(); - stream.write( (char *) &rows_size, sizeof(int) ); - for (size_t i = 0; i < m_data_objects.size(); i++) { - m_data_objects[i].write(stream); - } - int columns_size = m_column_titles.size(); - stream.write( (char *) &columns_size, sizeof(int) ); - for (int j = 0; j < columns_size; j++) { - m_column_titles[j].write(stream); - } - return true; -} - -bool DataLayer::output(ofstream& stream) -{ - stream << "Ref" << "\t" << "x" << "\t" << "y" << "\t"; - for (size_t i = 0; i < m_column_titles.size(); i++) { - stream << m_column_titles[i] << "\t"; - } - stream << endl; - - for (size_t j = 0; j < m_data_objects.size(); j++) { - stream.precision(12); - stream << j << "\t" << m_data_objects[j].getCentroid().x << "\t" << m_data_objects[j].getCentroid().y << "\t"; - stream.precision(7); - for (size_t k = 0; k < m_column_titles.size(); k++) { - stream << m_data_objects[j].m_data_cols[k] << "\t"; - } - stream << endl; - } - - return true; -} - -////////////////////////////////////////////////////////////// - -bool DataObject::read(ifstream& stream, int version) -{ - stream.read( (char *) &m_object_ref, sizeof(int) ); - m_object_name.read(stream); - m_data_cols.read(stream); - if (version >= VERSION_LAYERS_CENTROID_INTROD) { - stream.read( (char *) &m_centroid, sizeof(Point2f) ); - } - // default values for selection / output color - m_selected = false; - m_color = 0.0f; - - return true; -} - -bool DataObject::write(ofstream& stream) -{ - stream.write( (char *) &m_object_ref, sizeof(int) ); - m_object_name.write(stream); - m_data_cols.write(stream); - stream.write( (char *) &m_centroid, sizeof(Point2f) ); - return true; -} - +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// THIS CODE IS DEPRECATED DO NOT USE: USE SHAPE MAPS INSTEAD 21.08.05 + +// INCLUDED ONLY TO ALLOW COMPATIBILITY WITH OLD VERSIONS + +// DataLayer.cpp: implementation of the DataLayer class. +// +////////////////////////////////////////////////////////////////////// + +#include + +#include +#include +#include "mgraph440/stringutils.h" + +namespace mgraph440 { + +bool DataLayers::read(std::ifstream& stream, int version) +{ + m_layers.clear(); + stream.read( (char *) &m_current_layer_index, sizeof(int) ); + int size; + stream.read( (char *) &size, sizeof(int) ); + for (int i = 0; i < size; i++) { + DataLayer data; + m_layers.push_back(data); + m_layers.tail().read(stream, version); + } + return true; +} + +//////////////////////////////////////////////////////// + +void DataLayer::setDisplayColumn(int i) +{ + if (i == 0) { + for (size_t j = 0; j < m_data_objects.size(); j++) { + m_data_objects[j].m_color = float(j + 1) / m_data_objects.size(); + } + m_display_min = 0; + m_display_max = m_data_objects.size(); + } + else if (m_data_objects.size()) { + double max = m_data_objects[0][i-1], min = m_data_objects[0][i-1]; + for (size_t j = 1; j < m_data_objects.size(); j++) { + if (m_data_objects[j][i-1] < min) { + min = m_data_objects[j][i-1]; + } + else if (m_data_objects[j][i-1] > max) { + max = m_data_objects[j][i-1]; + } + } + for (size_t k = 0; k < m_data_objects.size(); k++) { + m_data_objects[k].m_color = (float) ((m_data_objects[k][i-1] - min) / (max - min)); + } + m_display_min = min; + m_display_max = max; + } + m_display_column = i; +} + +bool DataLayer::read(std::ifstream& stream, int version) +{ + m_data_objects.clear(); + m_column_titles.clear(); + stream.read( (char *) &m_layer_ref, sizeof(int) ); + m_layer_name = dXstring440::readString(stream); + stream.read( (char *) &m_next_object_ref, sizeof(int) ); + int rows_size; + stream.read( (char *) &rows_size, sizeof(int) ); + for (int i = 0; i < rows_size; i++) { + DataObject object; + m_data_objects.push_back(object); + m_data_objects.tail().read(stream,version); + } + int columns_size; + stream.read( (char *) &columns_size, sizeof(int) ); + for (int j = 0; j < columns_size; j++) { + m_column_titles.push_back(dXstring440::readString(stream)); + } + + // Since it doesn't seem to be recorded, just display the initial column + setDisplayColumn(0); + + return true; +} + +bool DataLayer::output(std::ofstream& stream) +{ + stream << "Ref" << "\t" << "x" << "\t" << "y" << "\t"; + for (size_t i = 0; i < m_column_titles.size(); i++) { + stream << m_column_titles[i] << "\t"; + } + stream << std::endl; + + for (size_t j = 0; j < m_data_objects.size(); j++) { + stream.precision(12); + stream << j << "\t" << m_data_objects[j].getCentroid().x << "\t" << m_data_objects[j].getCentroid().y << "\t"; + stream.precision(7); + for (size_t k = 0; k < m_column_titles.size(); k++) { + stream << m_data_objects[j].m_data_cols[k] << "\t"; + } + stream << std::endl; + } + + return true; +} + +////////////////////////////////////////////////////////////// + +bool DataObject::read(std::ifstream& stream, int version) +{ + stream.read( (char *) &m_object_ref, sizeof(int) ); + m_object_name = dXstring440::readString(stream); + m_data_cols.read(stream); + if (version >= VERSION_LAYERS_CENTROID_INTROD) { + stream.read( (char *) &m_centroid, sizeof(Point2f) ); + } + // default values for selection / output color + m_selected = false; + m_color = 0.0f; + + return true; +} + +bool DataObject::write(std::ostream& stream) +{ + stream.write( (char *) &m_object_ref, sizeof(int) ); + dXstring440::writeString(stream, m_object_name); + m_data_cols.write(stream); + stream.write( (char *) &m_centroid, sizeof(Point2f) ); + return true; +} + +} diff --git a/salalib/datalayer.h b/mgraph440/datalayer.h similarity index 84% rename from salalib/datalayer.h rename to mgraph440/datalayer.h index 88b4aebd..41d4baae 100644 --- a/salalib/datalayer.h +++ b/mgraph440/datalayer.h @@ -1,317 +1,322 @@ -// sala - a component of the depthmapX - spatial network analysis platform -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - - -// THIS CODE IS DEPRECATED DO NOT USE: USE SHAPE MAPS INSTEAD 21.08.05 - -// INCLUDED ONLY TO ALLOW COMPATIBILITY WITH OLD VERSIONS - -// DataLayer.h: interface for the DataLayer class. -// -////////////////////////////////////////////////////////////////////// - -#ifndef __DATA_LAYER_H__ -#define __DATA_LAYER_H__ - -// a layer object, e.g., a gate or a room - -class DataException { -public: - enum {UNDEFINED, LAYER_HAS_COLUMNS}; -protected: - int m_exception; -public: - DataException(int e = 0) { - m_exception = e; - } - int errorCode() { - return m_exception; - } -}; - -class DataObject -{ - friend class DataLayer; -protected: - int m_object_ref; - pstring m_object_name; - Point2f m_centroid; - pvecdouble m_data_cols; - float m_color; - bool m_selected; -public: - DataObject(int ref = 0, const pstring& name = pstring()) { - m_object_ref = ref; - m_object_name = name; - m_selected = false; - m_color = 0.0f; - } - double& operator [] (int i) { - return m_data_cols[i]; - } - const double& operator [] (int i) const { - return m_data_cols[i]; - } - int size() const { - return (int) m_data_cols.size(); - } - void setCentroid(const Point2f& p) { - m_centroid = p; - } - const Point2f& getCentroid() const { - return m_centroid; - } - float getColor() const { - return m_color; - } - bool isSelected() const { - return m_selected; - } - void setSelected(bool on = true) { - m_selected = on; - } - // - friend bool operator == (const DataObject& a, const DataObject& b); - friend bool operator != (const DataObject& a, const DataObject& b); - friend bool operator < (const DataObject& a, const DataObject& b); - friend bool operator > (const DataObject& a, const DataObject& b); - // - bool read( ifstream& stream, int version ); - bool write( ofstream& stream ); -}; - -inline bool operator == (const DataObject& a, const DataObject& b) { - return a.m_object_ref == b.m_object_ref; -} -inline bool operator != (const DataObject& a, const DataObject& b) { - return a.m_object_ref != b.m_object_ref; -} -inline bool operator < (const DataObject& a, const DataObject& b) { - return a.m_object_ref < b.m_object_ref; -} -inline bool operator > (const DataObject& a, const DataObject& b) { - return a.m_object_ref > b.m_object_ref; -} - -class DataLayer -{ -protected: - int m_layer_ref; - pstring m_layer_name; - int m_next_object_ref; - pqvector m_data_objects; - pvecstring m_column_titles; - int m_display_column; -public: - DataLayer(int ref = -1, const pstring& name = pstring()) { - m_layer_ref = ref; - m_layer_name = name; - m_next_object_ref = -1; - m_display_column = 0; // n.b. display column 0 is ref... always present - } - // Display column used to just set a column to display: - // now it recalculates the colours too - void setDisplayColumn(int i); - // - int addObject() { - m_data_objects.push_back(DataObject(++m_next_object_ref)); - for (size_t i = 0; i < m_column_titles.size(); i++) { - // this used to be a problem so I was throwing an exception - // throw LayerException(LayerException::LAYER_HAS_COLUMNS); - // but I decided just to fill the object with blanks instead: - m_data_objects.tail().m_data_cols.push_back(0.0); - m_data_objects.tail().m_color = 0.0; // <- range 0 to 1 - } - setDisplayColumn(m_display_column); - return m_next_object_ref; - } - void clear() { - m_data_objects.clear(); - m_next_object_ref = -1; - m_display_column = 0; - m_column_titles.clear(); - } - void clearSel() { - for (size_t i = 0; i < m_data_objects.size(); i++) { - m_data_objects[i].setSelected(false); - } - } - DataObject& operator [] (size_t i) { - return m_data_objects[i]; - } - const DataObject& operator [] (size_t i) const { - return m_data_objects[i]; - } - int getLayerRef() const - { return m_layer_ref; } - void setLayerName(const pstring& name) - { m_layer_name = name; } - const pstring& getLayerName() const - { return m_layer_name; } - // - int addColumn(pstring title) { - // probably ought to insert -1.0 to be consistent with -1.0 nulls in attributes tables - // but for the time being it's easier to set to 0.0 - // -- and helps as agent trace / collision counts should default to 0.0 - // -- and helps for push column to layer - size_t index = m_column_titles.findindex(title); - if (index != paftl::npos) { - for (size_t i = 0; i < m_data_objects.size(); i++) { - m_data_objects[i][index] = 0.0; - } - return (int) index; - } - m_column_titles.push_back(title); - for (size_t i = 0; i < m_data_objects.size(); i++) { - m_data_objects[i].m_data_cols.push_back(0.0); - } - return (int) m_column_titles.size() - 1; - } - void delColumn(int col) { - m_column_titles.remove_at(col); - for (size_t i = 0; i < m_data_objects.size(); i++) { - m_data_objects[i].m_data_cols.remove_at(col); - } - } - void setColumnTitle(int i, pstring& name) { - m_column_titles[i] = name; - } - pstring& getColumnTitle(int i) { - return m_column_titles[i]; - } - int getColumnIndex(const pstring& title) { - size_t i = m_column_titles.findindex(title); - return (i == paftl::npos ? -1 : int(i)); // note: must convert to -1 - } - int getColumnCount() { - return (int) m_column_titles.size(); - } - int getObjectCount() { - return (int) m_data_objects.size(); - } -public: - // temporarily public! - // min and max values displayed: - double m_display_min; - double m_display_max; - // and the average value displayed: - double m_display_avg; -public: - int getDisplayColumn() { - return m_display_column; // nb, 0 is used for ref... always present - } - float getObjectValue(int object_ref) { - if (m_display_column == 0) return (float)object_ref; - else return (float)m_data_objects[object_ref].m_data_cols[m_display_column-1]; - } - pstring getObjectText(int object_ref) { - char val[16]; - if (m_display_column == 0) sprintf(val,"%d",object_ref); - else sprintf(val,"%g",m_data_objects[object_ref].m_data_cols[m_display_column-1]); - return pstring(val); - } - PafColor getObjectColor(int object_ref) { - PafColor color; - return color.makeColor(m_data_objects[object_ref].m_color, DisplayParams()); - } - // - friend bool operator == (const DataLayer& a, const DataLayer& b); - friend bool operator != (const DataLayer& a, const DataLayer& b); - friend bool operator < (const DataLayer& a, const DataLayer& b); - friend bool operator > (const DataLayer& a, const DataLayer& b); - // - bool read( ifstream& stream, int version ); - bool write( ofstream& stream ); - bool output( ofstream& stream ); -}; - -inline bool operator == (const DataLayer& a, const DataLayer& b) { - return a.m_layer_ref == b.m_layer_ref; -} -inline bool operator != (const DataLayer& a, const DataLayer& b) { - return a.m_layer_ref != b.m_layer_ref; -} -inline bool operator < (const DataLayer& a, const DataLayer& b) { - return a.m_layer_ref < b.m_layer_ref; -} -inline bool operator > (const DataLayer& a, const DataLayer& b) { - return a.m_layer_ref > b.m_layer_ref; -} - -class DataLayers -{ -public: - // standard types I've thought of so far - // Note that BOUNDARIES comprise blocked locations (which may or may not be visibility graph members) - enum { GATES = 0, ATTRACTORS = 1, GENERATORS = 2, BOUNDARIES = 3 }; -protected: - int m_current_layer_index; - pqvector m_layers; -public: - DataLayers() {;} - bool addLayer(int layer_ref, pstring layer_name) { - size_t index = m_layers.searchindex(layer_ref); - if (index != paftl::npos) { - m_layers.remove_at(index); - } - m_current_layer_index = (int) m_layers.add(DataLayer(layer_ref,layer_name)); - return true; - } - bool layerExists(int layer_ref) { - size_t index = m_layers.searchindex(layer_ref); - return (index != paftl::npos); - } - bool setCurrentLayerRef(int ref) { - size_t index = m_layers.searchindex(ref); - if (index == paftl::npos) { - return false; - } - m_current_layer_index = (int) index; - return true; - } - int getCurrentLayerRef() const { - return m_layers[m_current_layer_index].getLayerRef(); - } - int getLayerRef(int i) const { - return m_layers[i].getLayerRef(); - } - DataLayer& getLayer(int layer_ref) { - return m_layers.search(layer_ref); - } - const DataLayer& getLayer(int layer_ref) const { - return m_layers.search(layer_ref); - } - DataLayer& operator [] (int i) { - return m_layers[i]; - } - const DataLayer& operator [] (int i) const { - return m_layers[i]; - } - DataLayer& getCurrentLayer() { - return m_layers[m_current_layer_index]; - } - const DataLayer& getCurrentLayer() const { - return m_layers[m_current_layer_index]; - } - int getLayerCount() const { - return (int) m_layers.size(); - } - // - bool read( ifstream& stream, int version ); - bool write( ofstream& stream ); -}; - -#endif +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +// THIS CODE IS DEPRECATED DO NOT USE: USE SHAPE MAPS INSTEAD 21.08.05 + +// INCLUDED ONLY TO ALLOW COMPATIBILITY WITH OLD VERSIONS + +// DataLayer.h: interface for the DataLayer class. +// +////////////////////////////////////////////////////////////////////// + +#ifndef __DATA_LAYER_H__ +#define __DATA_LAYER_H__ + +namespace mgraph440 { + +// a layer object, e.g., a gate or a room + +class DataException { +public: + enum {UNDEFINED, LAYER_HAS_COLUMNS}; +protected: + int m_exception; +public: + DataException(int e = 0) { + m_exception = e; + } + int errorCode() { + return m_exception; + } +}; + +class DataObject +{ + friend class DataLayer; +protected: + int m_object_ref; + std::string m_object_name; + Point2f m_centroid; + pvecdouble m_data_cols; + float m_color; + bool m_selected; +public: + DataObject(int ref = 0, const std::string& name = std::string()) { + m_object_ref = ref; + m_object_name = name; + m_selected = false; + m_color = 0.0f; + } + double& operator [] (int i) { + return m_data_cols[i]; + } + const double& operator [] (int i) const { + return m_data_cols[i]; + } + int size() const { + return (int) m_data_cols.size(); + } + void setCentroid(const Point2f& p) { + m_centroid = p; + } + const Point2f& getCentroid() const { + return m_centroid; + } + float getColor() const { + return m_color; + } + bool isSelected() const { + return m_selected; + } + void setSelected(bool on = true) { + m_selected = on; + } + // + friend bool operator == (const DataObject& a, const DataObject& b); + friend bool operator != (const DataObject& a, const DataObject& b); + friend bool operator < (const DataObject& a, const DataObject& b); + friend bool operator > (const DataObject& a, const DataObject& b); + // + bool read( std::ifstream& stream, int version ); + bool write(std::ostream &stream ); +}; + +inline bool operator == (const DataObject& a, const DataObject& b) { + return a.m_object_ref == b.m_object_ref; +} +inline bool operator != (const DataObject& a, const DataObject& b) { + return a.m_object_ref != b.m_object_ref; +} +inline bool operator < (const DataObject& a, const DataObject& b) { + return a.m_object_ref < b.m_object_ref; +} +inline bool operator > (const DataObject& a, const DataObject& b) { + return a.m_object_ref > b.m_object_ref; +} + +class DataLayer +{ +protected: + int m_layer_ref; + std::string m_layer_name; + int m_next_object_ref; + pqvector m_data_objects; + std::vector m_column_titles; + int m_display_column; +public: + DataLayer(int ref = -1, const std::string& name = std::string()) { + m_layer_ref = ref; + m_layer_name = name; + m_next_object_ref = -1; + m_display_column = 0; // n.b. display column 0 is ref... always present + } + // Display column used to just set a column to display: + // now it recalculates the colours too + void setDisplayColumn(int i); + // + int addObject() { + m_data_objects.push_back(DataObject(++m_next_object_ref)); + for (size_t i = 0; i < m_column_titles.size(); i++) { + // this used to be a problem so I was throwing an exception + // throw LayerException(LayerException::LAYER_HAS_COLUMNS); + // but I decided just to fill the object with blanks instead: + m_data_objects.tail().m_data_cols.push_back(0.0); + m_data_objects.tail().m_color = 0.0; // <- range 0 to 1 + } + setDisplayColumn(m_display_column); + return m_next_object_ref; + } + void clear() { + m_data_objects.clear(); + m_next_object_ref = -1; + m_display_column = 0; + m_column_titles.clear(); + } + void clearSel() { + for (size_t i = 0; i < m_data_objects.size(); i++) { + m_data_objects[i].setSelected(false); + } + } + DataObject& operator [] (size_t i) { + return m_data_objects[i]; + } + const DataObject& operator [] (size_t i) const { + return m_data_objects[i]; + } + int getLayerRef() const + { return m_layer_ref; } + void setLayerName(const std::string& name) + { m_layer_name = name; } + const std::string& getLayerName() const + { return m_layer_name; } + // + int addColumn(std::string title) { + // probably ought to insert -1.0 to be consistent with -1.0 nulls in attributes tables + // but for the time being it's easier to set to 0.0 + // -- and helps as agent trace / collision counts should default to 0.0 + // -- and helps for push column to layer + auto iter = std::find(m_column_titles.begin(), m_column_titles.end(), title); + if (iter != m_column_titles.end()) { + size_t index = iter - m_column_titles.begin(); + for (size_t i = 0; i < m_data_objects.size(); i++) { + m_data_objects[i][index] = 0.0; + } + return (int) index; + } + m_column_titles.push_back(title); + for (size_t i = 0; i < m_data_objects.size(); i++) { + m_data_objects[i].m_data_cols.push_back(0.0); + } + return (int) m_column_titles.size() - 1; + } + void delColumn(int col) { + m_column_titles.erase(m_column_titles.begin() + col); + for (size_t i = 0; i < m_data_objects.size(); i++) { + m_data_objects[i].m_data_cols.remove_at(col); + } + } + void setColumnTitle(int i, std::string& name) { + m_column_titles[i] = name; + } + std::string& getColumnTitle(int i) { + return m_column_titles[i]; + } + int getColumnIndex(const std::string& title) { + auto iter = std::find(m_column_titles.begin(), m_column_titles.end(), title); + return (iter == m_column_titles.end() ? -1 : int(iter - m_column_titles.begin())); // note: must convert to -1 + } + int getColumnCount() { + return (int) m_column_titles.size(); + } + int getObjectCount() { + return (int) m_data_objects.size(); + } +public: + // temporarily public! + // min and max values displayed: + double m_display_min; + double m_display_max; + // and the average value displayed: + double m_display_avg; +public: + int getDisplayColumn() { + return m_display_column; // nb, 0 is used for ref... always present + } + float getObjectValue(int object_ref) { + if (m_display_column == 0) return (float)object_ref; + else return (float)m_data_objects[object_ref].m_data_cols[m_display_column-1]; + } + std::string getObjectText(int object_ref) { + char val[16]; + if (m_display_column == 0) sprintf(val,"%d",object_ref); + else sprintf(val,"%g",m_data_objects[object_ref].m_data_cols[m_display_column-1]); + return val; + } + PafColor getObjectColor(int object_ref) { + PafColor color; + return color.makeColor(m_data_objects[object_ref].m_color, DisplayParams()); + } + // + friend bool operator == (const DataLayer& a, const DataLayer& b); + friend bool operator != (const DataLayer& a, const DataLayer& b); + friend bool operator < (const DataLayer& a, const DataLayer& b); + friend bool operator > (const DataLayer& a, const DataLayer& b); + // + bool read( std::ifstream& stream, int version ); + bool write( std::ofstream& stream ); + bool output( std::ofstream& stream ); +}; + +inline bool operator == (const DataLayer& a, const DataLayer& b) { + return a.m_layer_ref == b.m_layer_ref; +} +inline bool operator != (const DataLayer& a, const DataLayer& b) { + return a.m_layer_ref != b.m_layer_ref; +} +inline bool operator < (const DataLayer& a, const DataLayer& b) { + return a.m_layer_ref < b.m_layer_ref; +} +inline bool operator > (const DataLayer& a, const DataLayer& b) { + return a.m_layer_ref > b.m_layer_ref; +} + +class DataLayers +{ +public: + // standard types I've thought of so far + // Note that BOUNDARIES comprise blocked locations (which may or may not be visibility graph members) + enum { GATES = 0, ATTRACTORS = 1, GENERATORS = 2, BOUNDARIES = 3 }; +protected: + int m_current_layer_index; + pqvector m_layers; +public: + DataLayers() {;} + bool addLayer(int layer_ref, const std::string& layer_name) { + size_t index = m_layers.searchindex(layer_ref); + if (index != paftl::npos) { + m_layers.remove_at(index); + } + m_current_layer_index = (int) m_layers.add(DataLayer(layer_ref,layer_name)); + return true; + } + bool layerExists(int layer_ref) { + size_t index = m_layers.searchindex(layer_ref); + return (index != paftl::npos); + } + bool setCurrentLayerRef(int ref) { + size_t index = m_layers.searchindex(ref); + if (index == paftl::npos) { + return false; + } + m_current_layer_index = (int) index; + return true; + } + int getCurrentLayerRef() const { + return m_layers[m_current_layer_index].getLayerRef(); + } + int getLayerRef(int i) const { + return m_layers[i].getLayerRef(); + } + DataLayer& getLayer(int layer_ref) { + return m_layers.search(layer_ref); + } + const DataLayer& getLayer(int layer_ref) const { + return m_layers.search(layer_ref); + } + DataLayer& operator [] (int i) { + return m_layers[i]; + } + const DataLayer& operator [] (int i) const { + return m_layers[i]; + } + DataLayer& getCurrentLayer() { + return m_layers[m_current_layer_index]; + } + const DataLayer& getCurrentLayer() const { + return m_layers[m_current_layer_index]; + } + int getLayerCount() const { + return (int) m_layers.size(); + } + // + bool read( std::ifstream& stream, int version ); + bool write( std::ofstream& stream ); +}; + +} + +#endif diff --git a/mgraph440/displayparams.h b/mgraph440/displayparams.h new file mode 100644 index 00000000..0a641dc7 --- /dev/null +++ b/mgraph440/displayparams.h @@ -0,0 +1,17 @@ +#pragma once + +// For my colour scheme... some parameters to pass, and my own colour class + +namespace mgraph440 { + +struct DisplayParams +{ + enum { AXMANESQUE = 0, GREYSCALE = 1, MONOCHROME = 2, DEPTHMAPCLASSIC = 3, PURPLEORANGE = 4, BLUERED = 5 }; + float blue; + float red; + int colorscale; + DisplayParams() + { blue = 0.0f; red = 1.0f; colorscale = 0; } +}; + +} diff --git a/mgraph440/exceptions.h b/mgraph440/exceptions.h new file mode 100644 index 00000000..0d461efb --- /dev/null +++ b/mgraph440/exceptions.h @@ -0,0 +1,45 @@ +// Copyright (C) 2017 Christian Sailer +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef EXCEPTIONS_H +#define EXCEPTIONS_H + +#include + +namespace depthmapX440 +{ + class BaseException : public std::exception + { + public: + BaseException(){} + BaseException(std::string message) : _message(message) + {} + virtual const char * what() const noexcept + { + return _message.c_str(); + } + private: + std::string _message; + }; + + class RuntimeException: public BaseException + { + public: + RuntimeException(std::string message) : BaseException(message) + {} + }; +} +#endif // EXCEPTIONS_H diff --git a/mgraph440/fileproperties.h b/mgraph440/fileproperties.h new file mode 100644 index 00000000..95cfb5d5 --- /dev/null +++ b/mgraph440/fileproperties.h @@ -0,0 +1,96 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#ifndef __FILEPROPERTIES_H__ +#define __FILEPROPERTIES_H__ + +#include "mgraph440/stringutils.h" + +namespace mgraph440 { + +class FileProperties +{ +protected: + std::string m_create_person; + std::string m_create_organization; + std::string m_create_date; + std::string m_create_program; + std::string m_title; + std::string m_location; + std::string m_description; +public: + FileProperties() {;} + virtual ~FileProperties() {;} + // + void setProperties(const std::string& person, const std::string& organization, const std::string& date, const std::string& program) + { m_create_person = person; m_create_organization = organization; m_create_date = date; m_create_program = program; } + void setTitle(const std::string& title) + { m_title = title; } + void setLocation(const std::string& location) + { m_location = location; } + void setDescription(const std::string& description) + { m_description = description; } + // + const std::string& getPerson() const + { return m_create_person; } + const std::string& getOrganization() const + { return m_create_organization; } + const std::string& getDate() const + { return m_create_date; } + const std::string& getProgram() const + { return m_create_program; } + const std::string& getTitle() const + { return m_title; } + const std::string& getLocation() const + { return m_location; } + const std::string& getDescription() const + { return m_description; } + // + bool read( std::ifstream& stream, int version ); + bool write(std::ostream &stream ); +}; + +inline bool FileProperties::read(std::ifstream& stream, int version) +{ + m_create_person=dXstring440::readString(stream); + m_create_organization=dXstring440::readString(stream); + m_create_date=dXstring440::readString(stream); + m_create_program=dXstring440::readString(stream); + m_title=dXstring440::readString(stream); + m_location=dXstring440::readString(stream); + m_description=dXstring440::readString(stream); + + return true; +} + +inline bool FileProperties::write(std::ostream& stream) +{ + dXstring440::writeString(stream, m_create_person); + dXstring440::writeString(stream, m_create_organization); + dXstring440::writeString(stream, m_create_date); + dXstring440::writeString(stream, m_create_program); + dXstring440::writeString(stream, m_title); + dXstring440::writeString(stream, m_location); + dXstring440::writeString(stream, m_description); + + return true; +} + +} + +#endif + diff --git a/mgraph440/legacyconverters.h b/mgraph440/legacyconverters.h new file mode 100644 index 00000000..db6a6c6a --- /dev/null +++ b/mgraph440/legacyconverters.h @@ -0,0 +1,94 @@ +// Copyright (C) 2017 Christian Sailer +// Copyright (C) 2018 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "mgraph440/paftl.h" + +#include +#include +#include + +namespace genshim440 { + using namespace mgraph440; + /** + * Convert a std::vector to a pvec (preserving the order of elements) + * This is expensive as it copies every single element + */ + template pvector toPVector(const std::vector &vec) { + pvector pvec; + std::for_each(vec.begin(), vec.end(), [&pvec](const T &val) -> void { pvec.push_back(val); }); + return pvec; + } + + /** + * Convert a pvec to a std::vector (preserving the order of elements) + * This is expensive as it copies every single element + */ + template std::vector toSTLVector(pvector &pvec) { + std::vector vec; + for (int i = 0; i < pvec.size(); i++) { + vec.push_back(pvec[i]); + } + return vec; + } + + /** + * Convert a std::vector to a pqvector (preserving the order of elements) + * This is expensive as it copies every single element + */ + template pqvector toPQVector(const std::vector &vec) { + pqvector pvec; + std::for_each(vec.begin(), vec.end(), [&pvec](const T &val) -> void { pvec.push_back(val); }); + return pvec; + } + + /** + * Convert a std::vector to a pqvec (preserving the order of elements) + * This is expensive as it copies every single element + */ + template std::vector toSTLVector(pqvector &pqvec) { + std::vector vec; + for (int i = 0; i < pqvec.size(); i++) { + vec.push_back(pqvec[i]); + } + return vec; + } + + /** + * Convert a pmap to a std::map + * This is expensive as it copies every single element + */ + template std::map toSTLMap(pmap &pm) { + std::map m; + for (int i = 0; i < pm.size(); i++) { + m.insert(std::make_pair(pm.key(i), pm.value(i))); + } + return m; + } + + /** + * Convert a std::map to a pmap (preserving the order of elements) + * This is expensive as it copies every single element + */ + template pmap toPMap(const std::map &m) { + pmap pm; + for (auto pair : m) { + pm.add(pair.first, pair.second); + } + return pm; + } +} // namespace genshim440 diff --git a/mgraph440/mapinfodata.h b/mgraph440/mapinfodata.h new file mode 100644 index 00000000..cb4f690f --- /dev/null +++ b/mgraph440/mapinfodata.h @@ -0,0 +1,99 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + + +#ifndef __MAPINFODATA_H__ +#define __MAPINFODATA_H__ + +#include "mgraph440/mgraph_consts.h" +#include "mgraph440/stringutils.h" + +namespace mgraph440 { + +// imported and exported data +// note: this is very basic and designed for axial line import / export only + +// MapInfoData is stored with axial map data + +class MapInfoData +{ + friend class ShapeGraph; + friend class ShapeGraphs; + friend class ShapeMap; + +public: + std::string m_version; + std::string m_charset; + char m_delimiter; + std::string m_index; + std::string m_coordsys; + std::string m_bounds; + + std::istream& read(std::istream& stream, int version) + { + m_version = dXstring440::readString(stream); + m_charset = dXstring440::readString(stream); + m_delimiter = stream.get(); + m_index = dXstring440::readString(stream); + m_coordsys = dXstring440::readString(stream); + m_bounds = dXstring440::readString(stream); + // + // this is no longer used: just a dummy read: + if (version < mgraph440::VERSION_MAPINFO_SHAPES) { + int columns, rows; + std::vector columnheads; + std::vector table; + stream.read((char *) &columns, sizeof(int)); + for (int i = 0; i < columns; i++) { + columnheads.push_back(dXstring440::readString(stream)); + } + stream.read((char *) &rows, sizeof(int)); + for (int j = 0; j < rows; j++) { + table.push_back(dXstring440::readString(stream)); + } + } + + return stream; + } + std::ostream& write(std::ostream& stream) + { + dXstring440::writeString(stream, m_version); + dXstring440::writeString(stream, m_charset); + stream.put(m_delimiter); + dXstring440::writeString(stream, m_index); + dXstring440::writeString(stream, m_coordsys); + dXstring440::writeString(stream, m_bounds); + /* + // No longer used as of VERSION_MAPINFO_SHAPES + int columns = m_columnheads.size(); + int rows = m_table.size(); + stream.write((char *)&columns, sizeof(columns)); + for (int i = 0; i < m_columnheads.size(); i++) { + m_columnheads[i].write(stream); + } + stream.write((char *)&rows, sizeof(rows)); + for (int j = 0; j < m_table.size(); j++) { + m_table[j].write(stream); + } + */ + return stream; + } +}; + +} + +#endif diff --git a/mgraph440/mgraph.cpp b/mgraph440/mgraph.cpp new file mode 100644 index 00000000..1f290208 --- /dev/null +++ b/mgraph440/mgraph.cpp @@ -0,0 +1,598 @@ +#include "mgraph440/mgraph.h" + +namespace mgraph440 { + +MetaGraph::MetaGraph() +{ + m_state = 0; + m_view_class = VIEWNONE; + m_file_version = -1; // <- if unsaved, file version is -1 + + // Standard layers no longer added: the gates layer will be initialised with the first push to layer, + // or when made from axial lines. + + m_attr_conv_table = NULL; + + // whether or not showing text / grid saved with file: + m_showtext = false; + m_showgrid = false; +} + +MetaGraph::~MetaGraph() +{ +} + +int MetaGraph::convertAttributes( std::ifstream& stream, int version ) +{ + int ret = 1; + + // This is adapted from original ArVertexList code: + + int attr_count, which_attributes; + stream.read( (char *) &which_attributes, sizeof(int) ); + stream.read( (char *) &attr_count, sizeof(int) ); + + int size; + stream.read( (char *) &size, sizeof(int) ); + + if (m_attr_conv_table) + delete m_attr_conv_table; + m_attr_conv_table = new pqvector; + pqvector& attrs = *m_attr_conv_table; + + size_t i; + for (i = 0; i < size_t(size); i++) { + AttrBody attr(-1, g_attr_header); + attr.read(stream, attr_count); // <- only write in saved attributes + if (attr.ref != -1) { + attrs.add( attr ); + } + } + + for (size_t ii = 0; ii < attrs.size(); ii++) { + // Check these are numbered 0 to n, and set the pos to be used later: + if (attrs[ii].ref != ii) { + ret = 0; + break; + } + attrs[ii].pos = -1; + } + + if (ret == 0) { + delete m_attr_conv_table; + m_attr_conv_table = NULL; + return 0; + } + + for (i = 0; i < PointMaps::size(); i++) { + PointMap& map = PointMaps::at(i); + for (int j = 0; j < map.m_cols; j++) { + for (int k = 0; k < map.m_rows; k++) { + // Note: block used to be the noderef + if (map.m_points[j][k].filled() && map.m_points[j][k].m_block != -1) { + AttrBody test(-1,g_attr_header); + test.ref = map.m_points[j][k].m_block; + size_t pos = attrs.searchindex(test); + if (pos != paftl::npos) { + map.m_points[j][k].setAttributes(attrs[pos]); + attrs[pos].pos = (int) PixelRef(j,k); // <- note this can be used to convert the virtual mem quickly + } + else { + // oops + ret = 0; + } + } + } + } + } + return ret; +} + +int MetaGraph::convertVirtualMem( std::ifstream& stream, int version ) +{ + if (!m_attr_conv_table) { + return 0; + } + if (~m_state & ANGULARGRAPH) { + // can't convert non-angular graphs: + if (m_attr_conv_table) + delete m_attr_conv_table; + m_attr_conv_table = NULL; + return DEPRECATED_VERSION; + } + + // The attr conv table can help us quickly convert: + pqvector& attrs = *m_attr_conv_table; + + pvecint nodes; + pvecint bins; + + PixelRefVector bins_b[32]; + static float far_bin_dists[32]; + for (int ii = 0; ii < 32; ii++) { + far_bin_dists[ii] = 0.0f; + } + + char header[3]; + stream.read( header, 3 ); // 'grf' + stream.read( (char *) &version, sizeof( version ) ); // version + char type; + stream.read( (char *) &type, sizeof( type ) ); // 'v' + + int size; + stream.read( (char *) &size, sizeof( size ) ); + + PointMap& map = PointMaps::tail(); + for (int i = 0; i < size; i++) { + nodes.read(stream); + bins.read(stream); + if (attrs[i].pos != -1) { + PixelRef curs = (PixelRef) attrs[i].pos; + + for (int j = 0; j < 32; j++) { + for (int k = loword(bins[j]); k < hiword(bins[j]); k++) { + int next = attrs[nodes[k]].pos; + if (next != -1) { + bins_b[j].push_back( (PixelRef) next ); + } + } + } + + Point& pt = map.getPoint( curs ); + pt.m_node = new Node; + pt.m_node->make( curs, bins_b, far_bin_dists, 0x00FF ); + } + nodes.clear(); + bins.clear(); + } + + delete m_attr_conv_table; + m_attr_conv_table = NULL; + + return WARN_CONVERTED; +} + +int MetaGraph::read( const std::string& filename ) +{ + m_state = 0; // <- clear the state out + + if (filename.empty()) { + return NOT_A_GRAPH; + } + +#ifdef _WIN32 + std::ifstream stream( filename.c_str(), std::ios::binary | std::ios::in ); +#else + std::ifstream stream( filename.c_str(), std::ios::in ); +#endif + + char header[3]; + stream.read( header, 3 ); + if (stream.fail() || header[0] != 'g' || header[1] != 'r' || header[2] != 'f') { + stream.close(); + return NOT_A_GRAPH; + } + int version; + stream.read( (char *) &version, sizeof( version ) ); + m_file_version = version; // <- recorded for easy debugging + if (version > METAGRAPH_VERSION) { + stream.close(); + return NEWER_VERSION; + } + if (version == VERSION_VIEW_CLASS_ADDED) { + stream.close(); + return DEPRECATED_VERSION; // trial version no longer supported + } + + // have to use temporary state here as redraw attempt may come too early: + int temp_state = 0; + if (version >= VERSION_STATE_RECORDED) { + stream.read( (char *) &temp_state, sizeof( temp_state ) ); + } + + if (version >= VERSION_VIEW_CLASS_ADDED) { + stream.read( (char *) &m_view_class, sizeof(m_view_class) ); + } + + if (version >= VERSION_STORE_GRIDTEXTINFO) { + stream.read( (char *) &m_showgrid, sizeof(m_showgrid) ); + stream.read( (char *) &m_showtext, sizeof(m_showtext) ); + } + + // type codes: x --- properties + // v --- virtual graph (from versions below 70) + // n --- ngraph format + // l --- layer data + // p --- point data + // d --- data summary layers + + bool conversion_required = false; + + char type; + stream.read( &type, 1 ); + if (type == 'x') { + FileProperties::read(stream,version); + if (stream.eof()) { + // erk... this shouldn't happen + stream.close(); + return DAMAGED_FILE; + } + else if (!stream.eof()) { + stream.read( &type, 1 ); + } + } + else { + FileProperties::setProperties("","","",""); + } + if (stream.eof()) { + // file is still ok, just empty + stream.close(); + return OK; + } + if (type == 'v') { + + conversion_required = true; + + skipVirtualMem(stream,version); + + // and set our filename: + // Graph::m_nodes.setFilename( filename ); + + // and tell everyone it's been archived + // temp_state |= GRAPHARCHIVED; + + if (stream.eof()) { + // erk... this shouldn't happen + stream.close(); + return DAMAGED_FILE; + } + else if (!stream.eof()) { + stream.read( &type, 1 ); + } + } + if (type == 'l') { + try { + SuperSpacePixel::read( stream, version ); + temp_state |= LINEDATA; + if (!stream.eof()) { + stream.read( &type, 1 ); + } + } + catch (pexception) { + // erk... this shouldn't happen + stream.close(); + return DAMAGED_FILE; + } + } + if (type == 'p') { + if (version < VERSION_NGRAPH_INTROD) { + // This hasn't been coded yet + stream.close(); + return DEPRECATED_VERSION; + } + if (version < VERSION_POINT_MAPS) { + PointMaps::push_back(PointMap()); + if (temp_state & 0x0001) { // 0x0001 was "GRAPH" + PointMaps::tail().m_processed = true; + temp_state &= ~0x0001; + } + if (temp_state & 0x0080) { // 0x0080 was "BOUNDARYGRAPH" + PointMaps::tail().m_boundarygraph = true; + temp_state &= ~0x0080; + } + PointMaps::tail().read( stream, version ); + setDisplayedPointMapRef(0); + } + else { + PointMaps::read( stream, version ); + } + PointMaps::setSpacePixel( (SuperSpacePixel *) this ); + temp_state |= POINTMAPS; + if (!stream.eof()) { + stream.read( &type, 1 ); + } + } + if (type == 'g') { + // Note the older version stored its attributes in a different location... + // ...well, actually, now it's been rearranged, pretty similar to the original... + // hasn't been coded yet, though (see above) + if (version < VERSION_NGRAPH_INTROD) { + if (!convertAttributes( stream, version )) { + stream.close(); + return DAMAGED_FILE; + } + } + // record on state of actual point map: + PointMaps::tail().m_processed = true; + + if (!stream.eof()) { + stream.read( &type, 1 ); + } + } + if (type == 'a') { + temp_state |= ANGULARGRAPH; + if (!stream.eof()) { + stream.read( &type, 1 ); + } + } + if (type == 'd') { + // data layers are deprecated: data layers have been replaced by shape maps + // so: first read data layers: + DataLayers dl; + dl.read( stream, version ); + // now replace with shape maps, but only if layer exists: + temp_state &= ~DATAMAPS; + // converter requires a point map to work on: + if (PointMaps::size()) { + // returns 0 if there are actually no objects in the shapemaps to convert, + int conv_ok = convertDataLayersToShapeMap(dl,getDisplayedPointMap()); + if (conv_ok == 1) { + // read objects in: + temp_state |= DATAMAPS; + } + else if (conv_ok == -1) { + // read objects in, but had trouble converting them: + temp_state |= DATAMAPS; + temp_state |= WARN_CONVERTED; + } + } + if (!stream.eof()) { + stream.read( &type, 1 ); + } + } + if (type == 'x') { + m_shape_graphs.read( stream, version ); + temp_state |= SHAPEGRAPHS; + /* + // THIS CODE IS NO LONGER REQUIRED AS AXIAL MAPS *ARE* SHAPE MAPS -- can just be switched to shape map layer + if (version < VERSION_SHAPE_MAPS && m_shape_graphs.m_gate_map != -1) { + // check for a gate map: + convertShapeGraphToShapeMap(m_shape_graphs.at(m_shape_graphs.m_gate_map)); + // delete the gate map: + m_shape_graphs.remove_at(m_shape_graphs.m_gate_map); + if (m_shape_graphs.m_displayed_map >= m_shape_graphs.m_gate_map) { + int map = m_shape_graphs.m_displayed_map; + m_shape_graphs.m_displayed_map = -1; // <- have to do this as setDisplayedShapeGraph clearSels a map that may not exist anymore + setDisplayedShapeGraph(map-1); + } + m_shape_graphs.m_gate_map = -1; + if (m_shape_graphs.size() == 0) { + temp_state &= ~SHAPEGRAPHS; + } + // assume objects read in okay: + temp_state |= DATAMAPS; + } + */ + if (!stream.eof()) { + stream.read( &type, 1 ); + } + } + if (type == 's') { + m_data_maps.read( stream, version ); + temp_state |= DATAMAPS; + if (!stream.eof()) { + stream.read( &type, 1 ); + } + } + + stream.close(); + + m_state = temp_state; + + if (version < VERSION_VIEW_CLASS_ADDED) { + if (m_state & POINTMAPS) { + m_view_class = VIEWVGA; + } + else { + m_view_class = VIEWNONE; + } + } + + // Note, below version 70, the graph data must be reread: + if (version < VERSION_NGRAPH_INTROD && conversion_required) { + // reopen the stream and convert + stream.open(filename.c_str(), std::ios::binary | std::ios::in ); + int ok = convertVirtualMem(stream, version); + stream.close(); + return ok; + } + + if (version == VERSION_EXTRA_POINT_DATA_INTROD || version == VERSION_NGRAPH_INTROD || version == VERSION_SEGMENT_MAPS) { + m_state |= BUGGY; + return WARN_BUGGY_VERSION; + } + + return OK; +} +std::streampos MetaGraph::skipVirtualMem(std::ifstream& stream, int version) +{ + // it's graph virtual memory: skip it + int nodes = -1; + stream.read( (char *) &nodes, sizeof(nodes) ); + + // in angular version, have to skip two pvectors for each node: + if (version >= 30) + nodes *= 2; + + for (int i = 0; i < nodes; i++) { + int connections; + stream.read( (char *) &connections, sizeof(connections) ); + // This relies on the pvecint storage... hope it don't change! + stream.seekg( stream.tellg() + std::streamoff(connections * sizeof(connections)) ); + } + return (stream.tellg()); +} + +int MetaGraph::convertDataLayersToShapeMap(DataLayers& datalayers, PointMap& pointmap) +{ + int retvar = 1; + // check for existence of data: + pmap conversion_lookup; + size_t i; + for (i = 0; i < size_t(datalayers.getLayerCount()); i++) { + if (datalayers[i].getObjectCount()) { + int x = m_data_maps.addMap(datalayers[i].getLayerName(),ShapeMap::DATAMAP); + conversion_lookup.add(i,x); + } + } + // nothing to convert: + if (!conversion_lookup.size()) { + return 0; + } + + for (i = 0; i < conversion_lookup.size(); i++) { + ShapeMap& shapemap = m_data_maps.getMap(conversion_lookup.value(i)); + int layer_ref = datalayers.getLayerRef(conversion_lookup.key(i)); + pvecint *shape_pixel_lists = new pvecint [datalayers[i].getObjectCount()]; + int j; + for (j = 0; j < pointmap.getAttributeTable().getRowCount(); j++) { + PixelRef pix = pointmap.getAttributeTable().getRowKey(j); + int z = pointmap.getPoint(pix).getDataObject(layer_ref); + if (z != -1) { + shape_pixel_lists[z].push_back(pix); + } + } + // add shapes: + pvecint row_lookup; + for (j = 0; j < datalayers[i].getObjectCount(); j++) { + for (size_t k = 0; k < shape_pixel_lists[j].size(); k++) { + pointmap.overrideSelPixel(shape_pixel_lists[j][k]); + } + row_lookup.push_back(shapemap.makeShapeFromPointSet(pointmap)); + pointmap.clearSel(); + } + delete [] shape_pixel_lists; + // now add attributes: + AttributeTable& table = shapemap.getAttributeTable(); + // add columns, note, we'll have to add and then have lookups because not necessarily in alphabetical order: + for (j = 0; j < datalayers[i].getColumnCount(); j++) { + table.insertColumn(datalayers[i].getColumnTitle(j)); + } + pvecint column_lookup; + for (j = 0; j < datalayers[i].getColumnCount(); j++) { + column_lookup.push_back(table.getColumnIndex(datalayers[i].getColumnTitle(j))); + } + + // now we can add the data for this horrible matrix: + for (j = 0; j < datalayers[i].getObjectCount(); j++) { + for (int k = 0; k < datalayers[i].getColumnCount(); k++) { + if (row_lookup[j] != -1) { + int row = table.getRowid(row_lookup[j]); // row lookup should equal j since this is a new shape map, but for safety looked up + table.setValue(row,column_lookup[k],float(datalayers[i][j][k])); + } + else { + // conversion error occurred: + retvar = -1; + } + } + } + + // set the displayed attribute ready for first draw: + shapemap.overrideDisplayedAttribute(-2); + shapemap.setDisplayedAttribute(-1); + } + // the horror is over: + return retvar; +} + +int MetaGraph::writeToFile( const std::string& filename, int version, bool currentlayer ) +{ + std::ofstream stream; + + int oldstate = m_state; + m_state = 0; // <- temporarily clear out state, avoids any potential read / write errors + + // As of MetaGraph version 70 the disk caching has been removed + stream.open( filename.c_str(), std::ios::binary | std::ios::out | std::ios::trunc ); + if (stream.fail()) { + if (stream.rdbuf()->is_open()) { + stream.close(); + } + m_state = oldstate; + return DISK_ERROR; + } + m_state = oldstate; + int result = writeToStream(stream, version, currentlayer); + stream.close(); + return result; +} +int MetaGraph::writeToStream(std::ostream &stream, int version, bool currentlayer) { + int oldstate = m_state; + char type; + + stream.write("grf", 3); + m_file_version = version; // <- note, the file may now have an updated file version + stream.write( (char *) &version, sizeof(version) ); + if (currentlayer) { + int tempstate, tempclass; + if (m_view_class & VIEWVGA) { + tempstate = POINTMAPS; + tempclass = VIEWVGA; + } + else if (m_view_class & MetaGraph::VIEWAXIAL) { + tempstate = SHAPEGRAPHS; + tempclass = VIEWAXIAL; + } + else if (m_view_class & MetaGraph::VIEWDATA) { + tempstate = DATAMAPS; + tempclass = VIEWDATA; + } + stream.write( (char *) &tempstate, sizeof(tempstate) ); + stream.write( (char *) &tempclass, sizeof(tempclass) ); + } + else { + stream.write( (char *) &oldstate, sizeof(oldstate) ); + stream.write( (char *) &m_view_class, sizeof(m_view_class) ); + } + stream.write( (char *) &m_showgrid, sizeof(m_showgrid) ); + stream.write( (char *) &m_showtext, sizeof(m_showtext) ); + + type = 'x'; + stream.write(&type, 1); + FileProperties::write(stream); + + if (currentlayer) { + if (m_view_class & MetaGraph::VIEWVGA) { + type = 'p'; + stream.write(&type, 1); + PointMaps::write( stream, version, true ); + } + else if (m_view_class & MetaGraph::VIEWAXIAL) { + type = 'x'; + stream.write(&type, 1); + m_shape_graphs.write( stream, version, true ); + } + else if (m_view_class & MetaGraph::VIEWDATA) { + type = 's'; + stream.write(&type, 1); + m_data_maps.write( stream, version, true ); + } + } + else { + if (oldstate & LINEDATA) { + type = 'l'; + stream.write(&type, 1); + SuperSpacePixel::write( stream, version ); + } + if (oldstate & POINTMAPS) { + type = 'p'; + stream.write(&type, 1); + PointMaps::write( stream, version ); + } + if (oldstate & SHAPEGRAPHS) { + type = 'x'; + stream.write(&type, 1); + m_shape_graphs.write( stream, version ); + } + if (oldstate & DATAMAPS) { + type = 's'; + stream.write(&type, 1); + m_data_maps.write( stream, version ); + } + } + + m_state = oldstate; + return OK; +} + +} diff --git a/mgraph440/mgraph.h b/mgraph440/mgraph.h new file mode 100644 index 00000000..653c17ed --- /dev/null +++ b/mgraph440/mgraph.h @@ -0,0 +1,48 @@ +#pragma once + +#include "mgraph440/ngraph.h" // for conversion +#include "mgraph440/pointmap.h" +#include "mgraph440/axialmap.h" +#include "mgraph440/shapemap.h" +#include "mgraph440/spacepix.h" +#include "mgraph440/datalayer.h" +#include "mgraph440/fileproperties.h" +#include "mgraph440/bspnode.h" +#include "mgraph440/attr.h" + +namespace mgraph440 { + +class MetaGraph : public SuperSpacePixel, public PointMaps, public FileProperties +{ +public: + MetaGraph(); + ~MetaGraph(); + + enum { ANGULARGRAPH = 0x0010, LINEDATA = 0x0004, POINTMAPS = 0x0002, DATAMAPS = 0x0020, SHAPEGRAPHS = 0x0100, BUGGY = 0x8000 }; + enum { OK, WARN_BUGGY_VERSION, WARN_CONVERTED, NOT_A_GRAPH, DAMAGED_FILE, DISK_ERROR, NEWER_VERSION, DEPRECATED_VERSION }; + enum { VIEWNONE = 0x00, VIEWVGA = 0x01, VIEWAXIAL = 0x04, VIEWDATA = 0x20 }; + + int m_state; + int m_file_version; + int m_view_class; + bool m_showgrid; + bool m_showtext; + + ShapeMaps m_data_maps; + ShapeGraphs m_shape_graphs; + + // Standard layers no longer added: the gates layer will be initialised with the first push to layer, + // or when made from axial lines. + + pqvector *m_attr_conv_table = NULL; + + std::streampos skipVirtualMem(std::ifstream& stream, int version); + int convertDataLayersToShapeMap(DataLayers& datalayers, PointMap& pointmap); + int convertAttributes(std::ifstream &stream, int version); + int convertVirtualMem(std::ifstream &stream, int version); + int read(const std::string &filename); + int writeToFile( const std::string& filename, int version, bool currentlayer = false); + int writeToStream(std::ostream &stream, int version, bool currentlayer = false); +}; + +} diff --git a/mgraph440/mgraph_consts.h b/mgraph440/mgraph_consts.h new file mode 100644 index 00000000..96d0d565 --- /dev/null +++ b/mgraph440/mgraph_consts.h @@ -0,0 +1,129 @@ +#pragma once + +namespace mgraph440 { + +const int METAGRAPH_VERSION = 440; + +// Human readable(ish) metagraph version changes + +const int VERSION_ALWAYS_RECORD_BINDISTANCES = 440; + +// 17-Aug-2010 Version stamp for Depthmap 10.08.00 +const int VERSION_100800 = 430; + +// 12-Jul-2010 Version stamp for Depthmap 10.07.00 +const int VERSION_100700 = 430; + +// 12-Jul-2010 Occlusion distances for agent control test +const int VERSION_OCCDISTANCES = 430; + +// 07-Feb-2010 Axial lines no longer self-connect +const int VERSION_NO_SELF_CONNECTION = 420; + +// 31-Jan-2009 Maps have sublayers +const int VERSION_MAP_LAYERS = 410; +// +// 390 and 400 used only for testing +// +// 31-Jan-2009 this is simply a version stamp for Depthmap 8.14.00 and 8.15.00 +// The idea is that I should start writing code that saves in version 380 format +// as a benchmark "save for older version" +const int VERSION_81500 = 380; +const int VERSION_81400 = 380; +// +// 20-Apr-2008 The shape map name lookup could have been corrupted. In addition it's not that useful (never much to sort through, unique layer names not necessary) +const int VERSION_NO_SHAPEMAP_NAME_LOOKUP = 380; +// 15-Mar-2008 +const int VERSION_SHAPE_AREA_PERIMETER = 370; +const int VERSION_FORGET_COLUMN_CREATOR = 370; +// 04-Oct-2007 +const int VERSION_MAP_TYPES = 360; +// 20-Sep-2007 +const int VERSION_STORE_COLUMN_CREATOR = 350; +const int VERSION_ATTRIBUTE_LOCKING = 350; +// version 340 unused +// 08-Jun-2007: Store all drawing layers as shape maps rather than spacepixels (continued) +const int VERSION_DRAWING_SHAPES_B = 330; +// 27-Nov-2006: Store all drawing layers as shape maps rather than spacepixels +const int VERSION_DRAWING_SHAPES = 320; +// 27-Nov-2006: Store axial maps as children of shape maps rather than spacepixels +const int VERSION_AXIAL_SHAPES = 310; +// 01-Sep-2006: Store formulae for columns +const int VERSION_STORE_FORMULA = 300; +// 14-May-2006: Occlusions with node +const int VERSION_OCCLUSIONS = 290; +// 28-Dec-2005: Polygon shapes have centroids +const int VERSION_SHAPE_CENTROIDS = 280; +// 18-Dec-2005: Mapinfo data read into shape maps instead of axial maps +const int VERSION_MAPINFO_SHAPES = 270; +// 14-Sep-2005: QtRegion bug with segment maps from imported axial maps fixed: +const int VERSION_AXIAL_REGION_FIX = 263; +// 01-Sep-2005: Now Pointmaps really ought to store their names: +const int VERSION_POINT_MAP_NAMES = 262; +// 25-Aug-2005: And an extension to shape maps to make them easier to use as lines or points +const int VERSION_EXTENDED_SHAPE_MAPS = 261; +// 23-Aug-2005: Although in test from 11-Aug-2005, useful to read the testing graphs created: +const int VERSION_SHAPE_MAPS = 260; +// 11-Aug-2005: Also, a set of PointMaps now replace a single instance of PointData +const int VERSION_POINT_MAPS = 251; +// 11-Aug-2005: Location stored with points, not depixelated on the fly +const int VERSION_POINT_LOCATIONS = 250; +// 01-Mar-2005: Quick grid connections +const int VERSION_GRID_CONNECTIONS = 240; +// 02-Dec-2004: Axial map gates +const int VERSION_GATE_MAPS = 230; +// 29-Oct-2004: Store the colour display settings with the graph data +const int VERSION_STORE_GRIDTEXTINFO = 220; +// 29-Oct-2004: Store the colour display settings with the graph data +const int VERSION_STORE_COLOR = 210; +// 16-Jun-2004: New boundary graph (now much simpler: nodes at edge of main graph) +const int VERSION_NEWBOUNDARYGRAPH = 200; +// 20-May-2004: Each segment must have forward and backward connections listed separately! +const int VERSION_SEGMENT_MAPS_FIX = 191; +// 17-May-2004: Axial maps can be either segment or axial maps. Affects ShapeGraph and AxialLine classes +const int VERSION_SEGMENT_MAPS = 190; +// 12-May-2004: Extra Mapinfo table data +const int VERSION_MAPINFO_DATA = 180; +// 06-May-2004: Explicit links and unlinks for axial lines +const int VERSION_AXIAL_LINKS = 170; +// 29-Feb-2004: Attributes table (already used for AxialLines) now used for PointData as well +const int VERSION_ATTRIBUTES_TABLE = 160; +// File compression introduced +const int VERSION_FILE_COMPRESSION = 150; +// Some minor modifications to the axial line format... won't load v.130 files +const int VERSION_REVISED_AXIAL = 140; +// View class specifies whether axial or vga currently viewed +const int VERSION_VIEW_CLASS_ADDED = 130; +// A distance stored in the bin +const int VERSION_BINDISTANCES = 120; +// A set of nodes on the boundaries of the isovist +const int VERSION_BOUNDARYGRAPH = 110; +// Dynamic lines (addable and removable) in the visibility graph +const int VERSION_DYNAMICLINES = 100; +// Line layers are coloured... +const int VERSION_LAYERCOLORS = 91; +// Blocked locations split into 4, replaces m_noderef +const int VERSION_BLOCKEDQUAD = 90; +// Space pixel groups have different space pixels for different layers (at their own resolution!) +const int VERSION_SPACEPIXELGROUPS = 80; +// The graph state is just recorded +const int VERSION_STATE_RECORDED = 72; +// The binsizes weren't included in the metagraph 70 +const int VERSION_NGRAPH_BINCOUNT = 71; +// Major, major changes to the graph format (from now on it will now be held in memory only) +const int VERSION_NGRAPH_INTROD = 70; +// Slight changes to PointData required for the actual implementation of the quick graph +const int VERSION_SPARK_GRAPH_INTROD = 61; +// Quick graph... add underlying info about lines into the pointdata structure +const int VERSION_QUICK_GRAPH_INTROD = 60; +// Layers +const int VERSION_LAYERS_CENTROID_INTROD = 51; +const int VERSION_LAYERS_INTROD = 50; +// version 41 repairs VERSION_EXTRA_POINT_DATA_INTROD bug +const int VERSION_EXTRA_POINT_DATA_INTROD = 40; +const int VERSION_BINS_INTROD = 30; + +const unsigned int SALA_SELECTED_COLOR = 0x00FFFF77; +const unsigned int SALA_HIGHLIGHTED_COLOR = 0x0077FFFF; + +} diff --git a/mgraph440/ngraph.cpp b/mgraph440/ngraph.cpp new file mode 100644 index 00000000..b3bade92 --- /dev/null +++ b/mgraph440/ngraph.cpp @@ -0,0 +1,401 @@ +#include "mgraph440/ngraph.h" +#include "mgraph440/mgraph_consts.h" +#include "mgraph440/legacyconverters.h" + +namespace mgraph440 { + +inline int processoctant(int bin) +{ + int q = -1; + switch (bin) { + case 0: case 1: case 2: case 3: case 4: + q = 1; break; + case 5: case 6: case 7: + q = 7; break; + case 8: case 9: case 10: case 11: + q = 6; break; + case 12: case 13: case 14: case 15: case 16: + q = 0; break; + case 17: case 18: case 19: case 20: + q = 2; break; + case 21: case 22: case 23: + q = 4; break; + case 24: case 25: case 26: case 27: + q = 5; break; + case 28: case 29: case 30: case 31: + q = 3; break; + } + + return (1 << q); +} + +void Node::make(const PixelRef pix, PixelRefVector *bins, float *bin_far_dists, int q_octants) +{ + m_pixel = pix; + + for (int i = 0; i < 32; i++) { + + if (q_octants != 0x00FF) { + // now, an octant filter has been used... note that the exact q-octants that + // will have been processed rely on adjacenies in the q_octants... + if (!(q_octants & processoctant(i))) { + continue; + } + } + + m_bins[i].m_distance = bin_far_dists[i]; + + if (i == 4 || i == 20) { + m_bins[i].make(bins[i], PixelRef::POSDIAGONAL); + } + else if (i == 12 || i == 28) { + m_bins[i].make(bins[i], PixelRef::NEGDIAGONAL); + } + else if ((i > 4 && i < 12) || (i > 20 && i < 28)) { + m_bins[i].make(bins[i], PixelRef::VERTICAL); + } + else { + m_bins[i].make(bins[i], PixelRef::HORIZONTAL); + } + // Now clear the bin! + bins[i].clear(); + } +} + +void Bin::make(const PixelRefVector& pixels, char dir) +{ + if (m_pixel_vecs) { + delete [] m_pixel_vecs; + m_pixel_vecs = NULL; + } + m_length = 0; + m_node_count = 0; + + if (pixels.size()) { + + m_dir = dir; + + if (m_dir & PixelRef::DIAGONAL) { + + PixelVec cur( pixels[0], pixels[0] ); + + // Special, the diagonal should be pixels directly along the diagonal + // Both posdiagonal and negdiagonal are positive in the x direction + // Note that it is ordered anyway, so no need for anything too fancy: + if (pixels.back().x < cur.start().x) { + cur.m_start = pixels.back(); + } + if (pixels.back().x > cur.end().x) { + cur.m_end = pixels.back(); + } + + m_length = 1; + m_pixel_vecs = new PixelVec[1]; + m_pixel_vecs[0] = cur; + m_node_count = pixels.size(); + } + else { + prefvec pixel_vecs; + // Reorder the pixels: + if (m_dir == PixelRef::HORIZONTAL) { + pvector pixels_h; + for (size_t i = 0; i < pixels.size(); i++) { + pixels_h.add(pixels[i]); + } + // this looks like a simple bubble sort + pixel_vecs.push_back(PixelVec(pixels_h[0],pixels_h[0])); + for (size_t j = 1; j < pixels_h.size(); j++) { + if (pixels_h[j-1].y != pixels_h[j].y || pixels_h[j-1].x + 1 != pixels_h[j].x) { + pixel_vecs.tail().m_end = pixels_h[j-1]; + pixel_vecs.push_back(PixelVec(pixels_h[j],pixels_h[j])); + } + } + pixel_vecs.tail().m_end = pixels_h.tail(); + } + if (m_dir == PixelRef::VERTICAL) { + pvector pixels_v; + for (size_t i = 0; i < pixels.size(); i++) { + pixels_v.add(pixels[i]); + } + // this looks like a simple bubble sort + pixel_vecs.push_back(PixelVec(pixels_v[0],pixels_v[0])); + for (size_t j = 1; j < pixels_v.size(); j++) { + if (pixels_v[j-1].x != pixels_v[j].x || pixels_v[j-1].y + 1 != pixels_v[j].y) { + pixel_vecs.tail().m_end = pixels_v[j-1]; + pixel_vecs.push_back(PixelVec(pixels_v[j],pixels_v[j])); + } + } + pixel_vecs.tail().m_end = pixels_v.tail(); + } + + // Now compact the representation: + m_length = pixel_vecs.size(); + m_pixel_vecs = new PixelVec[m_length]; + for (int k = 0; k < m_length; k++) { + m_pixel_vecs[k] = pixel_vecs[k]; + } + m_node_count = pixels.size(); + } + } +} +void Bin::first() const +{ + m_curvec = 0; + if (m_length) + m_curpix = m_pixel_vecs[m_curvec].m_start; +} + +void Bin::next() const +{ + if (m_curpix.move(m_dir).col(m_dir) > m_pixel_vecs[m_curvec].end().col(m_dir)) { + m_curvec++; + if (m_curvec < m_length) + m_curpix = m_pixel_vecs[m_curvec].m_start; + } +} + +bool Bin::is_tail() const +{ + return m_curvec >= m_length; +} + +PixelRef Bin::cursor() const +{ + return (int) m_curpix; +} +::std::ifstream& Node::read(::std::ifstream& stream, int version) +{ + int i; + for (i = 0; i < 32; i++) { + m_bins[i].read(stream, version); + } + if (version >= VERSION_OCCLUSIONS) { + for (i = 0; i < 32; i++) { + pvector tempPvector; + tempPvector.read(stream); + m_occlusion_bins[i] = genshim440::toSTLVector(tempPvector); + } + } + return stream; +} + +std::ostream& Node::write(std::ostream& stream, int version) +{ + int i; + for (i = 0; i < 32; i++) { + m_bins[i].write(stream,version); + } + + for (i = 0; i < 32; i++) { + pvector tempPvector = genshim440::toPVector(m_occlusion_bins[i]); + tempPvector.write(stream); + } + return stream; +} + +::std::ifstream& Bin::read(::std::ifstream& stream, int version) +{ + stream.read( (char *) &m_dir, sizeof(m_dir) ); + stream.read( (char *) &m_node_count, sizeof(m_node_count) ); + if (version >= VERSION_FILE_COMPRESSION) { + if (version >= VERSION_ALWAYS_RECORD_BINDISTANCES) { + stream.read( (char *) &m_distance, sizeof(m_distance) ); + stream.read( (char *) &m_occ_distance, sizeof(m_occ_distance) ); + } + if (m_node_count) { + if (version < VERSION_ALWAYS_RECORD_BINDISTANCES) { + stream.read( (char *) &m_distance, sizeof(m_distance) ); + } + if (m_dir & PixelRef::DIAGONAL) { + m_length = 1; + m_pixel_vecs = new PixelVec [m_length]; + m_pixel_vecs[0].read(stream, version, m_dir); + } + else { + stream.read( (char *) &m_length, sizeof(m_length) ); + m_pixel_vecs = new PixelVec [m_length]; + m_pixel_vecs[0].read(stream, version, m_dir); + for (int i = 1; i < m_length; i++) { + m_pixel_vecs[i].read(stream, version, m_dir,m_pixel_vecs[i-1]); + } + } + if (version < VERSION_ALWAYS_RECORD_BINDISTANCES) { + if (version >= VERSION_OCCDISTANCES) { + stream.read( (char *) &m_occ_distance, sizeof(m_occ_distance) ); + } + else { + m_occ_distance = 0.0f; + } + } + } + else { + m_pixel_vecs = NULL; + m_length = 0; + if (version < VERSION_ALWAYS_RECORD_BINDISTANCES) { + m_distance = 0.0f; + m_occ_distance = 0.0f; + } + } + } + else { + stream.read( (char *) &m_length, sizeof(m_length) ); + if (version >= VERSION_BINDISTANCES) { + stream.read( (char *) &m_distance, sizeof(m_distance) ); + } + else { + m_distance = 0.0f; + } + if (m_pixel_vecs) { + delete m_pixel_vecs; + m_pixel_vecs = NULL; + } + if (m_length) { + m_pixel_vecs = new PixelVec [m_length]; + stream.read( (char *) m_pixel_vecs, sizeof(PixelVec) * m_length); + } + } + + return stream; +} + +std::ostream& Bin::write(std::ostream& stream, int version) +{ + stream.write( (char *) &m_dir, sizeof(m_dir) ); + stream.write( (char *) &m_node_count, sizeof(m_node_count) ); + + stream.write( (char *) &m_distance, sizeof(m_distance) ); + stream.write( (char *) &m_occ_distance, sizeof(m_occ_distance) ); + + if (m_node_count) { + + if (m_dir & PixelRef::DIAGONAL) { + m_pixel_vecs[0].write(stream,m_dir); + } + else { + stream.write( (char *) &m_length, sizeof(m_length) ); + m_pixel_vecs[0].write(stream,m_dir); + for (int i = 1; i < m_length; i++) { + m_pixel_vecs[i].write(stream,m_dir,m_pixel_vecs[i-1]); + } + } + } + + return stream; +} + +::std::ifstream& PixelVec::read(::std::ifstream& stream, int version, const char dir) +{ + unsigned short runlength; + stream.read((char *) &m_start, sizeof(m_start)); + stream.read((char *) &runlength, sizeof(runlength)); + switch (dir) { + case PixelRef::POSDIAGONAL: + m_end.x = m_start.x + runlength; + m_end.y = m_start.y + runlength; + break; + case PixelRef::NEGDIAGONAL: + m_end.x = m_start.x + runlength; + m_end.y = m_start.y - runlength; + break; + case PixelRef::HORIZONTAL: + m_end.x = m_start.x + runlength; + m_end.y = m_start.y; + break; + case PixelRef::VERTICAL: + m_end.x = m_start.x; + m_end.y = m_start.y + runlength; + break; + } + return stream; +} + +struct ShiftLength { + unsigned short shift : 4; + unsigned short runlength : 12; +}; + +::std::ifstream& PixelVec::read(::std::ifstream& stream, int version, const char dir, const PixelVec& context) +{ + short primary; + ShiftLength shiftlength; + stream.read((char *) &primary, sizeof(primary)); + stream.read((char *) &shiftlength, sizeof(shiftlength)); + switch (dir) { + case PixelRef::HORIZONTAL: + m_start.x = primary; + m_start.y = context.m_start.y + shiftlength.shift; + m_end.x = m_start.x + shiftlength.runlength; + m_end.y = m_start.y; + break; + case PixelRef::VERTICAL: + m_start.x = context.m_start.x + shiftlength.shift; + m_start.y = primary; + m_end.x = m_start.x; + m_end.y = m_start.y + shiftlength.runlength; + break; + } + + return stream; +} + +std::ostream& PixelVec::write(std::ostream& stream, const char dir) +{ + stream.write((char *) &m_start, sizeof(m_start)); + unsigned short runlength; + switch (dir) { + case PixelRef::HORIZONTAL: + case PixelRef::POSDIAGONAL: + case PixelRef::NEGDIAGONAL: + runlength = m_end.x - m_start.x; + break; + case PixelRef::VERTICAL: + runlength = m_end.y - m_start.y; + break; + } + stream.write((char *) &runlength, sizeof(runlength)); + + return stream; +} + +std::ostream& PixelVec::write(std::ostream& stream, const char dir, const PixelVec& context) +{ + ShiftLength shiftlength; + switch (dir) { + case PixelRef::HORIZONTAL: + stream.write((char *) &(m_start.x), sizeof(m_start.x)); + shiftlength.runlength = m_end.x - m_start.x; + shiftlength.shift = m_start.y - context.m_start.y; + break; + case PixelRef::VERTICAL: + stream.write((char *) &(m_start.y), sizeof(m_start.y)); + shiftlength.runlength = m_end.y - m_start.y; + shiftlength.shift = m_start.x - context.m_start.x; + break; + } + stream.write((char *) &shiftlength, sizeof(shiftlength)); + + return stream; +} + +void Node::first() const +{ + m_curbin = 0; + do { + m_bins[m_curbin].first(); + } while (m_bins[m_curbin].is_tail() && ++m_curbin < 32); +} + +void Node::next() const +{ + m_bins[m_curbin].next(); + while (m_bins[m_curbin].is_tail() && ++m_curbin < 32) { + m_bins[m_curbin].first(); + } +} + +PixelRef Node::cursor() const +{ + return m_bins[m_curbin].cursor(); +} + +} diff --git a/mgraph440/ngraph.h b/mgraph440/ngraph.h new file mode 100644 index 00000000..9ec1c261 --- /dev/null +++ b/mgraph440/ngraph.h @@ -0,0 +1,178 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +// ngraph.h + +#ifndef __NGRAPH_H__ +#define __NGRAPH_H__ + +#include "mgraph440/pixelref.h" +#include "mgraph440/paftl.h" +#include + +namespace mgraph440 { + +class PointMap; +struct MetricPair; +struct MetricTriple; + +struct PixelVec +{ + PixelRef m_start; + PixelRef m_end; + PixelVec(const PixelRef start = NoPixel, const PixelRef end = NoPixel) + { m_start = (int) start; m_end = (int) end; }; + PixelRef start() const + { return m_start; } + PixelRef end() const + { return m_end; } + // + std::ifstream& read(std::ifstream& stream, int version, const char dir); + std::ifstream& read(std::ifstream& stream, int version, const char dir, const PixelVec& context); + std::ostream &write(std::ostream &stream, const char dir); + std::ostream& write(std::ostream& stream, const char dir, const PixelVec& context); +}; + +class Bin +{ + friend class Node; +protected: + char m_dir; + unsigned short m_length; + unsigned short m_node_count; + float m_distance; + float m_occ_distance; + PixelVec *m_pixel_vecs; +public: + Bin() + { m_dir = PixelRef::NODIR; m_length = 0; m_pixel_vecs = NULL; m_node_count = 0; m_distance = 0.0f; m_occ_distance = 0.0f; } + Bin(const Bin&) + { throw 1; } + Bin& operator = (const Bin&) + { throw 1; } + ~Bin() + { if (m_pixel_vecs) delete [] m_pixel_vecs; m_pixel_vecs = NULL; } + // + void make(const PixelRefVector& pixels, char m_dir); + // + int count() const + { return m_node_count; } + float distance() const + { return m_distance; } + float occdistance() const + { return m_occ_distance; } + // + void setOccDistance(float d) + { m_occ_distance = d; } + // + bool containsPoint(const PixelRef p) const; + // + // Iterator +protected: + // Conversion back to old fashioned schema: + mutable int m_curvec; + mutable PixelRef m_curpix; +public: +// void contents(PixelRefVector& hood); + void first() const; + void next() const; + bool is_tail() const; + PixelRef cursor() const; + // + std::ifstream& read(std::ifstream& stream, int version); + std::ostream &write(std::ostream &stream, int version); +}; + +class Node +{ +protected: + PixelRef m_pixel; + Bin m_bins[32]; +public: + // testing some agent stuff: + std::vector m_occlusion_bins[32]; +public: + Node() + { ; } + Node(const Node&) + { throw 1; } + Node& operator = (const Node&) + { throw 1; } + ~Node() + { ; } + // Conversion back to old fashioned schema: + mutable int m_curbin; + // Note: this function clears the bins as it goes + void make(const PixelRef pix, PixelRefVector *bins, float *bin_far_dists, int q_octants); + // + void setPixel(const PixelRef& pixel) + { m_pixel = pixel; } + Bin& bin(int i) + { return m_bins[i]; } + float occdistance(int i) + { return m_bins[i].occdistance(); } + int count() + { int c = 0; for (int i = 0; i < 32; i++) c += m_bins[i].count(); return c; } + void first() const; + void next() const; + PixelRef cursor() const; + std::ifstream& read(std::ifstream& stream, int version); + std::ostream &write(std::ostream &stream, int version); +}; + +// Two little helpers: + +class PixelRefH : public PixelRef +{ +public: + PixelRefH() : PixelRef() + {;} + PixelRefH(const PixelRef& p) : PixelRef(p) + {;} + friend bool operator > (const PixelRefH& a, const PixelRefH& b); + friend bool operator < (const PixelRefH& a, const PixelRefH& b); +}; +inline bool operator > (const PixelRefH& a, const PixelRefH& b) +{ + return (a.y > b.y || (a.y == b.y && a.x > b.x)); +} +inline bool operator < (const PixelRefH& a, const PixelRefH& b) +{ + return (a.y < b.y || (a.y == b.y && a.x < b.x)); +} +class PixelRefV : public PixelRef +{ +public: + PixelRefV() : PixelRef() + {;} + PixelRefV(const PixelRef& p) : PixelRef(p) + {;} + friend bool operator > (const PixelRefV& a, const PixelRefV& b); + friend bool operator < (const PixelRefV& a, const PixelRefV& b); +}; +inline bool operator > (const PixelRefV& a, const PixelRefV& b) +{ + return (a.x > b.x || (a.x == b.x && a.y > b.y)); +} +inline bool operator < (const PixelRefV& a, const PixelRefV& b) +{ + return (a.x < b.x || (a.x == b.x && a.y < b.y)); +} + +} + +#endif diff --git a/mgraph440/options.h b/mgraph440/options.h new file mode 100644 index 00000000..936a23a0 --- /dev/null +++ b/mgraph440/options.h @@ -0,0 +1,50 @@ +#pragma once + +namespace mgraph440 { + +// Options for mean depth calculations +struct Options +{ + enum output_t { OUTPUT_ISOVIST, OUTPUT_VISUAL, OUTPUT_METRIC, OUTPUT_ANGULAR, OUTPUT_THRU_VISION, OUTPUT_CLIQUE_GRAPH, + OUTPUT_KERNEL_GRAPH, OUTPUT_MATRIX_REDUCTION }; + // Output type, see above + int output_type; + // Options for the summary type: + int local; + int global; + int cliques; + // + bool choice; + // include measures that can be derived: RA, RRA and total depth + bool fulloutput; + // + enum { RADIUS_STEPS, RADIUS_METRIC, RADIUS_ANGULAR }; + int radius_type; + double radius; // <- n.b. for metric integ radius is floating point + // radius has to go up to a list (phase out radius as is) + pvecdouble radius_list; + // + int point_depth_selection; + int tulip_bins; + bool process_in_memory; + bool sel_only; + bool gates_only; + // for pushing to a gates layer + int gatelayer; + // a column to weight measures by: + int weighted_measure_col; + int weighted_measure_col2; //EFEF + int routeweight_col; //EFEF + std::string output_file; // To save an output graph (for example) + // default values + Options() + { local = 0; global = 1; cliques = 0; + choice = false; fulloutput = false; point_depth_selection = 0; + tulip_bins = 1024; + radius = -1; radius_type = 0; + output_type = OUTPUT_ISOVIST; process_in_memory = false; gates_only = false; sel_only = false; + gatelayer = -1; + weighted_measure_col = -1;} +}; + +} diff --git a/mgraph440/p2dpoly.cpp b/mgraph440/p2dpoly.cpp new file mode 100644 index 00000000..03d30a10 --- /dev/null +++ b/mgraph440/p2dpoly.cpp @@ -0,0 +1,1002 @@ +// genlib - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// 2d polygons (and line sets too...) + +#include +#include + +#include +#include + +namespace mgraph440 { + +////////////////////////////////////////////////////////////////////////////////////// + +// gps2os: function to convert long-lat GPS coordinates to OS national grid + +// n.b.: approximation only + +// This algorithm is taken from: + +// "A guide to coordinate systems in Great Britain" +// http://www.ordnancesurvey.co.uk/oswebsite/gps/information/coordinatesystemsinfo/guidecontents/index.html +// (v1.9 Mar 2008 D00659, Crown Copyright) +// Sourced: 21-Mar-08 + +// It's truly ick... and nuts... there must be an easier way... + +// Outline: +// 1. take long-lat on ETRS89 ellipsoid and convert to 3d cartesian coordinates +// 2. shift 3d cartesian coordinates from ETRS89 ellipsoid to OSGB36 ellipsoid +// 3. convert 3d cartesian coordinates to long-lat on OSGB36 ellipsoid +// 4. project onto OSFB36 2d grid using a transverse Mercator projection + +// According to OS, accurate to within about 5 metres + +Point2f gps2os(const Point2f& pt) +{ + // *first*, we have ETRS89 data... + + // Convert it to 3D Cartesian Coordinates + double lambda = M_PI * pt.x / 180.0; + double phi = M_PI * pt.y / 180.0; + + // GRS80 ellipsoid + double a = 6378137.0000; + double b = 6356752.3141; + double e_sq = (sqr(a) - sqr(b)) / sqr(a); + + double nu = a / sqrt(1.0 - e_sq * sqr(sin(phi))); + + double x = nu * cos(phi) * cos(lambda); + double y = nu * cos(phi) * sin(lambda); + double z = (1 - e_sq) * nu * sin(phi); + + // Now we have the ETRS89 location, convert it to a rough OSGB36 location: + + // rough conversion chart + + // t_x (m) t_y (m) t_z (m) s (ppm) r_x (sec) r_y (sec) r_z (sec) + // -446.448 +125.157 -542.060 +20.4894 -0.1502 -0.2470 -0.8421 = (in radians: ) + + // nb, seconds converted to radians: + double r_x = -0.7281901490265230623720509817416e-6; + double r_y = -1.1974897923405539041670878328241e-6; + double r_z = -4.0826160086234026020206666559563e-6; + + x = -446.448 + (1.0 + 2.04894e-5) * x - r_z * y + r_y * z; + y = +125.157 + r_z * x + (1.0 + 2.04894e-5) * y - r_x * z; + z = -542.060 - r_y * x + r_x * y + (1.0 + 2.04894e-5) * z; + + double p = sqrt(sqr(x)+sqr(y)); + + // now place it back in long lat on the OSGB36 ellipsoid: + + // Airy 1830 (OSGB36) ellipsoid + a = 6377563.396; + b = 6356256.910; + e_sq = (sqr(a) - sqr(b)) / sqr(a); + + lambda = atan( y / x ); + phi = atan( z / (p * (1.0 - e_sq)) ); + double lastphi = phi; + + nu = a / sqrt(1.0 - e_sq * sqr(sin(phi))); + do { + phi = atan( (z + e_sq * nu * sin(phi)) / p ); + } while (fabs(lastphi - phi) > 1e-6); + + // now, it's on the ellipsoid, project it onto the OSGB36 grid: + + // E_0 easting of true origin 400 000m + double E_0 = 400000; + // N_0 northing of true origin -100 000m + double N_0 = -100000; + // F_0 scaling factor on central meridian 0.9996012717 + double F_0 = 0.9996012717; + // lambda_0 longitude of true origin -2.0 radians: -0.034906585039886591538473815369772 + double lambda_0 = -0.034906585039886591538473815369772; + // phi_0 latitude of true origin 49.0 radians: + double phi_0 = 0.85521133347722149269260847655942; + + nu = a * F_0 * pow((1 - e_sq * sqr(sin(phi))),-0.5); + + double n = (a-b) / (a+b); + double rho = a * F_0 * (1.0 - e_sq) * pow((1 - e_sq * sqr(sin(phi))),-1.5); + double eta_sq = nu / rho - 1; + + double n_sq = pow(n,2); + double n_cubed = pow(n,3); + double M = b * F_0 * ( (1.0 + n + 0.25 * 5 * (n_sq + n_cubed)) * (phi - phi_0) + -(3.0 * (n + n_sq + 0.125 * 7 * n_cubed)) * sin(phi - phi_0) * cos(phi + phi_0) + +(0.125 * 15.0 * (n_sq + n_cubed)) * sin(2.0 * (phi - phi_0)) * cos(2.0 * (phi + phi_0)) + -(35.0/24.0 * n_cubed) * sin(3.0 * (phi - phi_0)) * cos(3.0 * (phi + phi_0)) + ); + double I = M + N_0; + double II = 0.5 * nu * sin(phi) * cos(phi); + double tanphi = tan(phi); + double III = nu * sin(phi) * pow(cos(phi),3.0) * (5.0 - sqr(tanphi)+ 9.0 * eta_sq) / 24.0; + double IIIA = nu * sin(phi) * pow(cos(phi),5.0) * (61.0 - 58.0 * sqr(tanphi) + pow(tanphi,4.0)) / 720.0; + double IV = nu * cos(phi); + double V = nu * pow(cos(phi),3.0) * (nu/rho - sqr(tanphi)) / 6.0; + double VI = nu * pow(cos(phi),5.0) * (5.0 - 18.0 * sqr(tanphi) + pow(tanphi,4) + 14.0 * eta_sq - 58.0 * sqr(tanphi) * eta_sq) / 120.0; + + double E = E_0 + IV * (lambda - lambda_0) + V * pow((lambda - lambda_0),3) + VI * pow((lambda - lambda_0),5); + double N = I + II * pow((lambda - lambda_0),2) + III * pow((lambda - lambda_0),4) + IIIA * pow((lambda - lambda_0),6); + + return Point2f(E,N); +} + +////////////////////////////////////////////////////////////////////////////////////// + +static long g_count = 0L; + +int bitcount(int a) +{ + int ret = 0; + while (a != 0) { + ret += (a & 1) ? 1 : 0; + a = a >> 1; + } + return ret; +} + +//////////////////////////////////////////////////////////////////////////////////////// + +// EdgeU is used for polygon clipping to viewports + +// are a,b,c in ccw order (true) or cw order (false) +bool ccwEdgeU(const EdgeU& a, const EdgeU& b, const EdgeU& c) +{ + bool ccw = false; + if (c.edge > a.edge || (c.edge == a.edge && c.u > a.u)) { + if (b.edge > a.edge || (b.edge == a.edge && b.u > a.u)) { + if (b.edge < c.edge || (b.edge == c.edge && b.u < c.u)) { + ccw = true; + } + } + } + else { + if (b.edge > a.edge || (b.edge == a.edge && b.u > a.u)) { + ccw = true; + } + else if (b.edge < c.edge || (b.edge == c.edge && b.u < c.u)) { + ccw = true; + } + } + return ccw; +} + +// EdgeU is used for polygon clipping to viewports +// get the actual point from an EdgeU +Point2f QtRegion::getEdgeUPoint(const EdgeU& eu) +{ + switch (eu.edge) { + case 0: + return Point2f(bottom_left.x + (eu.u * width()), bottom_left.y); + case 1: + return Point2f(top_right.x, bottom_left.y + (eu.u * height())); + case 2: + return Point2f(top_right.x - (eu.u * width()), top_right.y); + case 3: + return Point2f(bottom_left.x, top_right.y - (eu.u * height())); + } + return Point2f(); +} + +// EdgeU is used for polygon clipping to viewports +// get where the polygon exits the viewport +EdgeU QtRegion::getCutEdgeU(const Point2f& inside, const Point2f& outside) +{ + EdgeU eu; + if (outside.x < bottom_left.x) { + double y = outside.y + (inside.y - outside.y) * (bottom_left.x - outside.x) / (inside.x-outside.x); + if (y >= bottom_left.y && y <= top_right.y) { + eu.edge = 3; + eu.u = (top_right.y - y) / height(); + } + } + if (eu.edge == -1 && outside.x > top_right.x) { + double y = inside.y + (outside.y - inside.y) * (top_right.x - inside.x) / (outside.x-inside.x); + if (y >= bottom_left.y && y <= top_right.y) { + eu.edge = 1; + eu.u = (y - bottom_left.y) / height(); + } + } + if (eu.edge == -1 && outside.y < bottom_left.y) { + double x = outside.x + (inside.x - outside.x) * (bottom_left.y - outside.y) / (inside.y-outside.y); + if (x >= bottom_left.x && x <= top_right.x) { + eu.edge = 0; + eu.u = (x - bottom_left.x) / width(); + } + } + if (eu.edge == -1 && outside.y > top_right.y) { + double x = inside.x + (outside.x - inside.x) * (top_right.y - inside.y) / (outside.y-inside.y); + if (x >= bottom_left.x && x <= top_right.x) { + eu.edge = 2; + eu.u = (top_right.x - x) / width(); + } + } + // if at this stage eu.edge is still -1 there's a problem! + return eu; +} + +////////////////////////////////////////////////////////////////////////// + +// union of two regions + +QtRegion runion(const QtRegion& a, const QtRegion& b) +{ + QtRegion n; + n.bottom_left.x = a.bottom_left.x < b.bottom_left.x ? + a.bottom_left.x : b.bottom_left.x; + n.bottom_left.y = a.bottom_left.y < b.bottom_left.y ? + a.bottom_left.y : b.bottom_left.y; + n.top_right.x = a.top_right.x > b.top_right.x ? + a.top_right.x : b.top_right.x; + n.top_right.y = a.top_right.y > b.top_right.y ? + a.top_right.y : b.top_right.y; + return n; +} + +// test intersecting regions, touching counts + +bool intersect_region(const QtRegion& a, const QtRegion& b, double tolerance) +{ + if (overlap_x(a,b,tolerance) && overlap_y(a,b,tolerance)) { + return true; + } + else { + return false; + } +} + +bool overlap_x(const QtRegion& a, const QtRegion& b, double tolerance) +{ + if (a.bottom_left.x > b.bottom_left.x) { + if (b.top_right.x >= a.bottom_left.x - tolerance) { + return true; + } + } + else { + if (a.top_right.x >= b.bottom_left.x - tolerance) { + return true; + } + } + return false; +} + +bool overlap_y(const QtRegion& a, const QtRegion& b, double tolerance) +{ + if (a.bottom_left.y > b.bottom_left.y) { + if (b.top_right.y >= a.bottom_left.y - tolerance) { + return true; + } + } + else { + if (a.top_right.y >= b.bottom_left.y - tolerance) { + return true; + } + } + return false; +} + +// line set up + +// default: nothing: + +Line::Line() +{ + bits.parity = 0; + bits.direction = 0; + // Points automatically assigned to 0,0 +} + +Line::Line(const Point2f& a, const Point2f& b) +{ + if (a.x == b.x) { + bottom_left.x = a.x; + top_right.x = b.x; + // vertical lines stored consistently as parity 1 + if (a.y <= b.y) { + bottom_left.y = a.y; + top_right.y = b.y; + bits.parity = 1; + bits.direction = 1; + } + else { + bottom_left.y = b.y; + top_right.y = a.y; + bits.parity = 1; + bits.direction = 0; + } + } + else if (a.x < b.x) { + bottom_left.x = a.x; + top_right.x = b.x; + if (a.y <= b.y) { + bottom_left.y = a.y; + top_right.y = b.y; + bits.parity = 1; + bits.direction = 1; + } + else { + bottom_left.y = b.y; + top_right.y = a.y; + bits.parity = 0; // -1 + bits.direction = 1; + } + } + else { + bottom_left.x = b.x; + top_right.x = a.x; + if (b.y <= a.y) { + bottom_left.y = b.y; + top_right.y = a.y; + bits.parity = 1; + bits.direction = 0; + } + else { + bottom_left.y = a.y; + top_right.y = b.y; + bits.parity = 0; // -1 + bits.direction = 0; + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +double dot(const Line& a, const Line& b) { + return (a.bx() - a.ax()) * (b.bx() - b.ax()) + + (a.by() - a.ay()) * (b.by() - b.ay()); +} + +// intersection test: touching counts as an intersection +// (uses dot product comparison) + +// NB You must MUST check that line *regions do not intersect* before using this test +// By this test, *all parallel lines intersect* + +bool intersect_line(const Line& a, const Line& b, double tolerance) +{ + g_count++; + + if ( ((a.ay() - a.by()) * (b.ax() - a.ax()) + + (a.bx() - a.ax()) * (b.ay() - a.ay())) * + ((a.ay() - a.by()) * (b.bx() - a.ax()) + + (a.bx() - a.ax()) * (b.by() - a.ay())) <= tolerance && + ((b.ay() - b.by()) * (a.ax() - b.ax()) + + (b.bx() - b.ax()) * (a.ay() - b.ay())) * + ((b.ay() - b.by()) * (a.bx() - b.ax()) + + (b.bx() - b.ax()) * (a.by() - b.ay())) <= tolerance) + { + return true; + } + + return false; +} + +// intersection test: touching does not count as an intersection +// (uses dot product comparison) + +bool intersect_line_no_touch(const Line& a, const Line& b, double tolerance) +{ + g_count++; + + if ( ((a.ay() - a.by()) * (b.ax() - a.ax()) + + (a.bx() - a.ax()) * (b.ay() - a.ay())) * + ((a.ay() - a.by()) * (b.bx() - a.ax()) + + (a.bx() - a.ax()) * (b.by() - a.ay())) < -tolerance && + ((b.ay() - b.by()) * (a.ax() - b.ax()) + + (b.bx() - b.ax()) * (a.ay() - b.ay())) * + ((b.ay() - b.by()) * (a.bx() - b.ax()) + + (b.bx() - b.ax()) * (a.by() - b.ay())) < -tolerance) + { + return true; + } + + return false; +} + +// returns 0 for no intersect, 1 for touching and 2 for crossing +int intersect_line_distinguish(const Line& a, const Line& b, double tolerance) +{ + g_count++; + + double alpha = ((a.ay() - a.by()) * (b.ax() - a.ax()) + + (a.bx() - a.ax()) * (b.ay() - a.ay())) * + ((a.ay() - a.by()) * (b.bx() - a.ax()) + + (a.bx() - a.ax()) * (b.by() - a.ay())); + + double beta = ((b.ay() - b.by()) * (a.ax() - b.ax()) + + (b.bx() - b.ax()) * (a.ay() - b.ay())) * + ((b.ay() - b.by()) * (a.bx() - b.ax()) + + (b.bx() - b.ax()) * (a.by() - b.ay())); + + if (alpha <= tolerance && beta <= tolerance) { + if (alpha < -tolerance && beta < -tolerance) { + return 2; + } + else { + return 1; + } + } + + return 0; +} + +// returns 0 for no intersect, 1 for touching and 2 for crossing +// n.b. only used by polygon contains -- throws if the first point of line b is touching line a +// (first point of line b is the point to be tested) -- i.e., throws if point touches polygon +int intersect_line_b(const Line& a, const Line& b, double tolerance) +{ + g_count++; + + double alpha = ((a.ay() - a.by()) * (b.ax() - a.ax()) + + (a.bx() - a.ax()) * (b.ay() - a.ay())); + + double beta = ((a.ay() - a.by()) * (b.bx() - a.ax()) + + (a.bx() - a.ax()) * (b.by() - a.ay())); + + double gamma = ((b.ay() - b.by()) * (a.ax() - b.ax()) + + (b.bx() - b.ax()) * (a.ay() - b.ay())) * + ((b.ay() - b.by()) * (a.bx() - b.ax()) + + (b.bx() - b.ax()) * (a.by() - b.ay())); + + if (alpha * beta <= tolerance && gamma <= tolerance) { + if (alpha * beta < -tolerance && gamma < -tolerance) { + return 2; + } + else { + // this function is only used for poly contains point, + // the throw is defined if the point is *on* the polygon edge + // (within the tolerance) + if (fabs(alpha) <= tolerance) { + throw 1; + } + return 1; + } + } + return 0; +} + +double Line::intersection_point(const Line& l, int axis, double tolerance) const +{ + // use axis = XAXIS for width() > height() + double loc; + if (axis == XAXIS) { + if (l.width() == 0.0) { + loc = l.bottom_left.x; + } + else { + double lg = l.grad(YAXIS); + double g = grad(YAXIS); + if (fabs(lg - g) <= tolerance) { + // these have almost the same gradient, so it's impossible to tell where they intersect: going for midpoint + Point2f p = l.midpoint(); + loc = (p.x > top_right.x) ? top_right.x : ((p.x < bottom_left.x) ? bottom_left.x : p.x); + } + else { + // this is the same as: constant(YAXIS) - l.constant(YAXIS)) / (l.grad(YAXIS) - grad(YAXIS)); + loc = ((ay() - g * ax()) - (l.ay() - lg * l.ax())) / (lg - g); + } + } + } + else { + if (l.height() == 0.0) { + loc = l.bottom_left.y; + } + else { + double lg = l.grad(XAXIS); + double g = grad(XAXIS); + if (fabs(lg - g) <= tolerance) { + // these have almost the same gradient, so it's impossible to tell where they intersect: going for midpoint + Point2f p = l.midpoint(); + loc = (p.y > top_right.y) ? top_right.y : ((p.y < bottom_left.y) ? bottom_left.y : p.y); + } + else { + // this is the same as: constant(XAXIS) - l.constant(XAXIS)) / (l.grad(XAXIS) - grad(XAXIS)); + loc = ((ax() - g * ay()) - (l.ax() - lg * l.ay())) / (lg - g); + } + } + } + return loc; +} + +// intersecting line segments, touching counts +// (uses intersection point comparison) + +bool Line::intersect_line(const Line& l, int axis, double& loc) const +{ + // please be intelligent when passing the axis... + if (axis == XAXIS) { + if (l.width() == 0.0) { + // Special case: + double y = ay() + sign() * (l.ax() - ax()) * height() / width(); + if (y >= bottom_left.y && y <= l.top_right.y) { // <- you must have checked + loc = l.bottom_left.x; // the regions overlap first + return true; + } + return false; + } + else { + // Standard: (note: if m1 == m2, loc is NaN) + loc = (constant(YAXIS) - l.constant(YAXIS)) / (l.grad(YAXIS) - grad(YAXIS)); + if (std::isnan(loc)) { + // lines are parallel --- are they coincident? + // you must have checked the regions overlap first + if (constant(YAXIS) == l.constant(YAXIS)) { + return true; + } + } + else if (loc >= l.bottom_left.x && loc <= l.top_right.x) { + return true; + } + return false; + } + } + else { + if (l.height() == 0.0) { + // Special case: + double x = ax() + sign() * (l.ay() - ay()) * width() / height(); + if (x >= bottom_left.x && x <= top_right.x) { // <- you must have checked + loc = l.bottom_left.y; // the regions overlap first + return true; + } + return false; + } + else { + // Standard: (note: if m1 == m2, loc is NaN) + loc = (constant(XAXIS) - l.constant(XAXIS)) / (l.grad(XAXIS) - grad(XAXIS)); + if (std::isnan(loc)) { + // lines are parallel --- are they coincident? + // you must have checked the regions overlap first + if (constant(XAXIS) == l.constant(XAXIS)) { + return true; + } + } + else if (loc >= l.bottom_left.y && loc <= l.top_right.y) { + return true; + } + return false; + } + } + return false; +} + +// this converts the loc back into a point: + +Point2f Line::point_on_line(double loc, int axis) const +{ + Point2f p; + if (axis == XAXIS) { + p = Point2f(loc, grad(YAXIS) * loc + constant(YAXIS)); + } + else { + p = Point2f(grad(XAXIS) * loc + constant(XAXIS), loc); + } + return p; +} + +////////////////////////////////////////////////////////////////////////////// + +// distance from a point to a line segment + +double dist(const Point2f& point, const Line& line) +{ + double d = 0.0; + + Point2f alpha = line.end() - line.start(); + Point2f beta = point - line.end(); + Point2f gamma = line.start() - line.end(); + Point2f delta = point - line.start(); + + if (dot(alpha,beta) > 0) { + d = beta.length(); + } + else if (dot(gamma,delta) > 0) { + d = delta.length(); + } + else { + if (alpha.length() < 1e-9 * beta.length()) { + // should actually be a user-specified tolerance test + d = beta.length(); + } + else { + d = fabs(det(alpha,beta)) / alpha.length(); + } + } + return d; +} + +/* + // for infinite line rather than line segment + return fabs((line.bx() - line.ax()) * (line.ay() - point.y) - + (line.ax() - point.x) * (line.by() - line.ay())) / line.length(); +*/ + +////////////////////////////////////////////////////////////////////////////// + +// intersection test + +bool intersect(const RegionTree& a, const RegionTree& b) +{ + if (a.is_leaf() && b.is_leaf()) { + if (intersect_region( QtRegion(a), QtRegion(b))) { + return intersect_line( (const Line&) QtRegion(a), (const Line&) QtRegion(b) ); + } + else { + return false; + } + } + else { + if (intersect_region( QtRegion(a), QtRegion(b))) { + return subintersect(a, b); + } + else { + return false; + } + } +} + +bool subintersect(const RegionTree& a, const RegionTree& b) +{ + if (intersect(a.left(),b.left())) { + return true; + } + else if (intersect(a.right(),b.right())) { + return true; + } + else if (intersect(a.left(),b.right())) { + return true; + } + else if (intersect(a.right(),b.left())) { + return true; + } + + return false; +} + +// Intersection count + +int intersections(const RegionTree& a, const Line& b) +{ + int n = 0; + + if (!a.is_leaf()) { + if (intersect_region( QtRegion(a), QtRegion(b))) { + n += intersections(a.left(), b); + n += intersections(a.right(), b); + } + } + else { + // Note: touching lines count 1, non-touching lines count 2, this allows through + // vertex lines (where it touches both vertices) + n += intersect_line_b( (const Line&) a, (const Line&) b ); + } + + return n; +} + +////////////////////////////////////////////////////////////////////////////// + +// crop a line to fit within bounds of region +// if line lies outside region, returns false + +bool Line::crop(const QtRegion& r) +{ + if (bx() >= r.bottom_left.x) { + if (ax() < r.bottom_left.x) { + // crop! + ay() += sign() * (height() * (r.bottom_left.x - ax()) / width()); + ax() = r.bottom_left.x; + } + if (ax() <= r.top_right.x) { + if (bx() > r.top_right.x) { + // crop! + by() -= sign() * height() * (bx() - r.top_right.x) / width(); + bx() = r.top_right.x; + } + if (top_right.y >= r.bottom_left.y) { + if (bottom_left.y < r.bottom_left.y) { + // crop! + if (bits.parity) { + ax() += width() * (r.bottom_left.y - bottom_left.y) / height(); + } + else { + bx() -= width() * (r.bottom_left.y - bottom_left.y) / height(); + } + bottom_left.y = r.bottom_left.y; + } + if (bottom_left.y <= r.top_right.y) { + if (top_right.y > r.top_right.y) { + // crop! + if (bits.parity) { + bx() -= width() * (top_right.y - r.top_right.y) / height(); + } + else { + ax() += width() * (top_right.y - r.top_right.y) / height(); + } + top_right.y = r.top_right.y; + } + // if we got this far, well done, it's in the region: + return true; + } + } + } + } + // returns false if the entire line is outside the region: + return false; +} + +// cast a ray to the edge of a box + +void Line::ray(short dir, const QtRegion& r) +{ + if (dir == bits.direction) { + if (width() >= height()) { + by() = ay() + sign() * height() * (r.top_right.x - ax()) / width(); + bx() = r.top_right.x; + } + else if (bits.parity) { + bx() = ax() + width() * (r.top_right.y - ay()) / height(); + by() = r.top_right.y; + } + else { + bx() = ax() + width() * (ay() - r.bottom_left.y) / height(); + by() = r.bottom_left.y; + } + } + else { + if (width() >= height()) { + ay() = by() - sign() * height() * (bx() - r.bottom_left.x) / width(); + ax() = r.bottom_left.x; + } + else if (bits.parity) { + ax() = bx() - width() * (by() - r.bottom_left.y) / height(); + ay() = r.bottom_left.y; + } + else { + ax() = bx() - width() * (r.top_right.y - by()) / height(); + ay() = r.top_right.y; + } + } + // now fit within bounds... + crop(r); +} + +////////////////////////////////////////////////////////////////////////////// + +// Polygon set up (the hard bit!) + +void Poly::add_line_segment(const Line& l) +{ + m_line_segments++; + RegionTreeLeaf *leaf = new RegionTreeLeaf( l ); + + if (m_p_root == NULL) + { + // first ever node + + m_p_root = (RegionTree *) leaf; + } + else + { + // traverse the tree to the insertion point + // you'll just have to take my word for it that the next line + // gives you the correct position to insert + int cut_level = bitcount(m_line_segments - 1) - 2; + + if (cut_level < 0) + { + // replace the root node + + QtRegion new_region = + runion( QtRegion(*m_p_root), QtRegion(*leaf) ); + RegionTree *new_root = + new RegionTreeBranch( new_region, *m_p_root, *leaf ); + m_p_root = new_root; + } + else + { + RegionTree *here = m_p_root; + for (int i = 0; i < cut_level; i++) { + here = here->m_p_right; + } + + // cut and insert + + RegionTree& insertion_point = here->right(); + + QtRegion new_region = + runion( QtRegion(insertion_point), QtRegion(*leaf) ); + + RegionTree *new_node = + new RegionTreeBranch( new_region, insertion_point, *leaf ); + + here->m_p_right = new_node; + + // traverse up tree unioning regions + // (saving data by not recording parents!) + // Note must be '>=' to catch current root node --- I really stuffed up earlier with '>'! + while (cut_level >= 0) + { + here = m_p_root; + for (int j = 0; j < cut_level; j++) { + here = here->m_p_right; + } + here->m_p_region = new Line( + runion(QtRegion(here->left()), QtRegion(here->right())) ); + cut_level--; + } + } + } +} + +// ...and after all the efficient stuff, we have a really +// inefficient polygon copy... hmm + +RegionTree *Poly::copy_region_tree( const RegionTree* tree ) +{ + if ( !tree ) { + return NULL; + } + + RegionTree *newtree; + + if (tree->is_leaf()) { + newtree = new RegionTreeLeaf(); + newtree->m_p_region = new Line( *(tree->m_p_region) ); + return newtree; + } + else { + newtree = new RegionTreeBranch(); + } + + pvector newlist; + pvector oldlist; + + oldlist.push_back( (RegionTree *) tree ); + newlist.push_back( (RegionTree *) newtree ); + + do { + RegionTree *oldnode = oldlist.tail(); oldlist.pop_back(); + RegionTree *newnode = newlist.tail(); newlist.pop_back(); + + newnode->m_p_region = new Line( *oldnode->m_p_region ); + + if (oldnode->m_p_left) { + if (oldnode->m_p_left->is_leaf()) { + newnode->m_p_left = new RegionTreeLeaf(); + newnode->m_p_left->m_p_region = + new Line( *(oldnode->m_p_left->m_p_region) ); + } + else { + oldlist.push_back( oldnode->m_p_left ); + newnode->m_p_left = new RegionTreeBranch(); + newlist.push_back( newnode->m_p_left ); + } + } + if (oldnode->m_p_right) { + if (oldnode->m_p_right->is_leaf()) { + newnode->m_p_right = new RegionTreeLeaf(); + newnode->m_p_right->m_p_region = + new Line( *(oldnode->m_p_right->m_p_region) ); + } + else { + oldlist.push_back( oldnode->m_p_right ); + newnode->m_p_right = new RegionTreeBranch(); + newlist.push_back( newnode->m_p_right ); + } + } + + } while (oldlist.size() > 0); + + return newtree; +} + +// polygon destruction + +void Poly::destroy_region_tree() +{ + if ( !m_p_root ) { + return; + } + + pvector del_node_list; + pvector del_node_dir; + + del_node_list.push_back( m_p_root ); + + do { + RegionTree *current_node = del_node_list.tail(); + + if (current_node->m_p_left == current_node && + current_node->m_p_right == current_node) { + + delete current_node; + del_node_list.pop_back(); + + if (del_node_list.size() > 0) { + if (del_node_dir.tail() == 0) { + del_node_list.tail()->m_p_left = del_node_list.tail(); + del_node_dir.pop_back(); + } + else { + del_node_list.tail()->m_p_right = del_node_list.tail(); + del_node_dir.pop_back(); + } + } + } + else { + if (current_node->m_p_right == NULL) { + current_node->m_p_right = current_node; + } + else if (current_node->m_p_right != current_node) { + del_node_list.push_back( current_node->m_p_right ); + del_node_dir.push_back( 1 ); + } + else { + del_node_list.push_back( current_node->m_p_left ); + del_node_dir.push_back( 0 ); + } + } + } + while (del_node_list.size() > 0); + + m_p_root = NULL; +} + +// contains? intersects?? + +// Here they are! + +bool Poly::contains( const Point2f& p ) +{ + // n.b., intersections throws on some accidental alignments -- + // we must use a point outside the polygon to extend our test + // line from to prevent them + Line l( p, Point2f( get_bounding_box().top_right.x + get_bounding_box().width(), + get_bounding_box().top_right.y + get_bounding_box().height()) ); + + int double_n; + + // note, touching intersections count 1/2 + try { + double_n = intersections( *(m_p_root), l ); + } + catch (int) { + throw 1; // throws if on edge + } + + if (double_n % 2 == 0 && double_n % 4 != 0) { + return true; + } + + return false; +} + +bool intersect( const Poly& a, const Poly& b ) +{ + if ( intersect( *(a.m_p_root), *(b.m_p_root)) ) { + return true; + } + return false; +} + +} diff --git a/mgraph440/p2dpoly.h b/mgraph440/p2dpoly.h new file mode 100644 index 00000000..a25ebeb7 --- /dev/null +++ b/mgraph440/p2dpoly.h @@ -0,0 +1,648 @@ +// genlib - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +// 2d poly (own format, adapted from the original Sala libraries + +// The idea is that from this format, +// we can read into Cosmo3d as well as Sala based applications + +#pragma once +// Using doubles right the way through can really eat memory for isovist +// polygon files, thus we use a defined type, change as appropriate: + +#include +#include +#include // communicator used in BSP tree construction + +namespace mgraph440 { + +// Note: code depends on XAXIS being 0 and YAXIS being 1 --- do not change +enum { + NOAXIS = -1, XAXIS = 0, YAXIS = 1 +}; + +class Point2f; +bool approxeq(const Point2f& p1, const Point2f& p2, double tolerance = 0.0); +class QtRegion; +bool intersect_region(const QtRegion& a, const QtRegion& b, double tolerance = 0.0); +bool overlap_x(const QtRegion& a, const QtRegion& b, double tolerance = 0.0); +bool overlap_y(const QtRegion& a, const QtRegion& b, double tolerance = 0.0); +class Line; +bool intersect_line(const Line& a, const Line& b, double tolerance = 0.0); +bool intersect_line_no_touch(const Line& a, const Line& b, double tolerance = 0.0); +int intersect_line_distinguish(const Line& a, const Line& b, double tolerance = 0.0); +int intersect_line_b(const Line& a, const Line& b, double tolerance = 0.0); +Point2f intersection_point(const Line& a, const Line& b, double tolerance = 0.0); + +// NaN on Intel: +// Quick mod - TV +// const double P2DNULL = (const double)0xFFFFFFFF7FF7FFFF; +// for non-Intel: 0x7FF7FFFFFFFFFFFF + +// Point + +class Point2f +{ +public: + double x; + double y; + Point2f() +// { x = P2DNULL; y = P2DNULL; } + { x = 0.0; y = 0.0; } + Point2f(double a, double b) + { x = a; y = b; } + bool atZero() const +// { return x == P2DNULL || y == P2DNULL; } + { return x == 0.0 && y == 0.0; } + void normalScale( const QtRegion& ); // inline function: below region + void denormalScale( const QtRegion& ); + void operator += (const Point2f& p) + { x += p.x; y += p.y; } + void operator -= (const Point2f& p) + { x -= p.x; y -= p.y; } + void operator *= (const double s) + { x *= s; y *= s; } + void operator /= (const double s) + { x /= s; y /= s; } + double& operator [] (int i) + { return (i == XAXIS) ? x : y; } + const double& operator [] (int i) const + { return (i == XAXIS) ? x : y; } + friend Point2f operator - (Point2f& p); + friend Point2f operator + (const Point2f& p1, const Point2f& p2); + friend Point2f operator - (const Point2f& p1, const Point2f& p2); + friend bool operator == (const Point2f& p1, const Point2f& p2); + friend bool operator != (const Point2f& p1, const Point2f& p2); + friend bool operator > (const Point2f& a, const Point2f& b); + friend bool operator < (const Point2f& a, const Point2f& b); + friend Point2f operator * (const double s, const Point2f& p); + friend Point2f operator / (const Point2f& p, const double s); + friend double dot(const Point2f& p1, const Point2f& p2); + friend double det(const Point2f& p1, const Point2f& p2); + friend double dist(const Point2f& p1, const Point2f& p2); + friend double dist(const Point2f& point, const Line& line); + friend double angle(const Point2f& p1, const Point2f& p2, const Point2f& p3); + friend bool approxeq(const Point2f& p1, const Point2f& p2, double tolerance); + friend Point2f pointfromangle(double angle); + // a couple of useful tests + bool intriangle(const Point2f& p1, const Point2f& p2, const Point2f& p3); + bool insegment(const Point2f& key, const Point2f& p2, const Point2f& p3, double tolerance = 0.0); + // for OS transformation (note: accurate only to 5 metres according to OS) + Point2f longlat2os(const Point2f& p); +public: + // A few simple vector ops: + double length() const + { return (double) sqrt(x * x + y * y); } + Point2f& scale(const double scalar) + { x *= scalar; y *= scalar; return *this; } + Point2f& scale(const Point2f& scalevec) + { x *= scalevec.x; y *= scalevec.y; return *this; } + Point2f& normalise() + { return scale( 1.0 / length() ); } + Point2f& rotate(const double angle) + { double t = x; + x = x * cos(angle) - y * sin(angle); + y = y * cos(angle) + t * sin(angle); + return *this; } + double angle() const + { return (y < 0) ? (2.0 * M_PI - acos(x)) : acos(x); } +}; + +inline Point2f operator - (Point2f& p) +{ + return Point2f(-p.x, -p.y); +} + +inline Point2f operator + (const Point2f& p1, const Point2f& p2) +{ + return Point2f(p1.x + p2.x, p1.y + p2.y); +} + +inline Point2f operator - (const Point2f& p1, const Point2f& p2) +{ + return Point2f(p1.x - p2.x, p1.y - p2.y); +} + +inline bool operator == (const Point2f& p1, const Point2f& p2) +{ return (p1.x == p2.x && p1.y == p2.y); } +inline bool operator != (const Point2f& p1, const Point2f& p2) +{ return (p1.x != p2.x || p1.y != p2.y); } +inline bool operator > (const Point2f& p1, const Point2f& p2) +{ return (p1.x > p2.x || (p1.x == p2.x && p1.y > p2.y)); } +inline bool operator < (const Point2f& p1, const Point2f& p2) +{ return (p1.x < p2.x || (p1.x == p2.x && p1.y < p2.y)); } + +inline Point2f operator * (const double s, const Point2f& p) +{ + return Point2f(s * p.x, s * p.y); +} + +inline Point2f operator / (const Point2f& p, const double s) +{ + return Point2f(p.x / s, p.y / s); +} + +inline double dot(const Point2f& p1, const Point2f& p2) +{ + return (p1.x * p2.x + p1.y * p2.y); +} + +// greater than 0 => p2 left (anticlockwise) of p1, less than 0 => p2 right (clockwise) of p1 +inline double det(const Point2f& p1, const Point2f& p2) +{ + return (p1.x * p2.y - p1.y * p2.x); +} + +inline double dist(const Point2f& p1, const Point2f& p2) +{ + return sqrt(sqr(p1.x - p2.x) + sqr(p1.y - p2.y)); +} + +inline double angle(const Point2f& p1, const Point2f& p2, const Point2f& p3) +{ + Point2f a = p1 - p2; + Point2f b = p3 - p2; + a.normalise(); + b.normalise(); + // ensure in range (f.p. error can throw out) + double d = std::min(std::max(dot(a,b),-1.0),1.0); + return (sgn(det(a,b)) == 1) ? acos(d) : 2.0 * M_PI - acos(d); +} + +inline bool approxeq(const Point2f& p1, const Point2f& p2, double tolerance) +{ + return (fabs(p1.x - p2.x) <= tolerance && fabs(p1.y - p2.y) <= tolerance); +} + +inline bool Point2f::insegment(const Point2f& key, const Point2f& p2, const Point2f& p3, double tolerance) +{ + Point2f va = p2 - key; + Point2f vb = p3 - key; + Point2f vp = *this - key; + double ap = det(va,vp); + double bp = det(vb,vp); + if ((dot(va,vp) > 0 && dot(vb,vp) > 0) && (sgn(ap) != sgn(bp) || fabs(ap) < tolerance || fabs(bp) < tolerance) ) { + return true; + } + return false; +} + +inline bool Point2f::intriangle(const Point2f& p1, const Point2f& p2, const Point2f& p3) +{ + // touching counts + int test = sgn(det(p2-p1,*this-p1)); + if (test == sgn(det(p3-p2,*this-p2)) && test == sgn(det(p1-p3,*this-p3))) { + return true; + } + return false; +} + +inline Point2f pointfromangle(double angle) +{ + Point2f p; + p.x = cos(angle); + p.y = sin(angle); + return p; +} + +Point2f gps2os(const Point2f& p); + +// an event is a point plus time (as in spacetime technical language) +class Event2f : public Point2f +{ +public: + double t; // time in seconds + Event2f() : Point2f() + { t = 0.0; } + Event2f(double _x, double _y, double _t) : Point2f(_x,_y) + { t = _t; } + Event2f(Point2f& _p) : Point2f(_p) + { t = 0.0; } + Event2f(Point2f& _p, double _t) : Point2f(_p) + { t = _t; } +}; + +/////////////////////////////////////////////////////////////////////////////////////////// + +class Point3f +{ +public: + double x; + double y; + double z; + Point3f(double a = 0.0, double b = 0.0, double c = 0.0) + { x = a; y = b; z = c;} + Point3f(const Point2f& p) + { x = p.x; y = 0.0; z = p.y; } // Note! not z = -y (due to an incosistency earlier...) + bool inside( const Point3f& bl, const Point3f& tr ) // now inclusive (...) + { return (x >= bl.x && y >= bl.y && z >= bl.z && x <= tr.x && y <= tr.y && z <= tr.z); } + operator Point2f() + { return Point2f( x, z ); } // Note! not x, -z (due to an inconsistency earlier...) + Point2f xy() + { return Point2f(x, y); } // From the x, y plane + // A few simple vector ops: + double length() const + { return (double) sqrt(x * x + y * y + z * z); } + Point3f& scale(const double scalar) + { x *= scalar; y *= scalar; z *= scalar; return *this; } + Point3f& normalise() + { return scale( 1.0 / length() ); } + Point3f& rotate(double theta, double phi) + { double t = x; + x = t * cos(theta) - y * sin(theta); + y = y * cos(theta) + t * sin(theta); + t = x; + x = t * cos(phi) - z * sin(phi); + z = z * cos(phi) - t * sin(phi); + return *this; } + // + friend double dot(const Point3f& a, const Point3f& b); + friend Point3f cross(const Point3f& a, const Point3f& b); +}; + +inline double dot(const Point3f& a, const Point3f& b) +{ + return (a.x * b.x + a.y * b.y + a.z * b.z); +} +inline Point3f cross(const Point3f& a, const Point3f& b) +{ + return Point3f( a.y * b.z - b.y * a.z, a.z * b.x - b.z * a.x, a.x * b.y - b.x * a.y ); +} + +// + +////////////////////////////////////////////////////////////////////////////// + +// used for clipping of polygons to regions + +struct EdgeU { + int edge; + double u; + EdgeU(int e = -1, double _u = 0.0) + { edge = e; u = _u; } + EdgeU(const EdgeU& eu) + { edge = eu.edge; u = eu.u; } + friend bool ccwEdgeU(const EdgeU& a, const EdgeU& b, const EdgeU& c); +}; + +// QtRegion + +class QtRegion +{ +public: + Point2f bottom_left; + Point2f top_right; + QtRegion(const Point2f& bl = Point2f(), const Point2f& tr = Point2f()) + { bottom_left = bl; top_right = tr; } + QtRegion(const QtRegion& r) + { bottom_left = r.bottom_left; top_right = r.top_right; } + QtRegion& operator = (const QtRegion& r) + { bottom_left = r.bottom_left; top_right = r.top_right; return *this; } + // + double height() const + { return top_right.y - bottom_left.y; } + double width() const + // The assumption that top_right.x is always > bottom_left.x is not always true. + // Returning a negative value here causes an infinite loop at axialmap.cpp line 3106 + // after overlapdist is assigned a negative value at axialmap.cpp line 3084. + // height() above could also be changed for this reason, but this is a band-aid + // fix for the real problem, which is why the top_right > bottom_left assumption + // is assumed to be 100% valid but is, in some instances, not valid. + // { return top_right.x - bottom_left.x; } + { return fabs(top_right.x - bottom_left.x); } + double area() const + { return height() * width(); } + void normalScale( const QtRegion& r ) + { top_right.normalScale(r); bottom_left.normalScale(r); } + void denormalScale( const QtRegion& r ) + { top_right.denormalScale(r); bottom_left.denormalScale(r); } + void scale( const Point2f& scalevec ) + { top_right.scale(scalevec); bottom_left.scale(scalevec); } + void offset( const Point2f& offset ) + { top_right += offset; bottom_left += offset; } + Point2f getCentre() const + { return Point2f( (bottom_left.x + top_right.x) / 2.0, + (bottom_left.y + top_right.y) / 2.0 ); } + // + bool contains ( const Point2f& p ) const + { return (p.x > bottom_left.x && p.x < top_right.x && p.y > bottom_left.y && p.y < top_right.y); } + bool contains_touch ( const Point2f& p ) const + { return (p.x >= bottom_left.x && p.x <= top_right.x && p.y >= bottom_left.y && p.y <= top_right.y); } + void encompass( const Point2f& p ) + { if (p.x < bottom_left.x) bottom_left.x = p.x; if (p.x > top_right.x) top_right.x = p.x; + if (p.y < bottom_left.y) bottom_left.y = p.y; if (p.y > top_right.y) top_right.y = p.y; } + // + bool atZero() const + { return bottom_left.atZero() || top_right.atZero(); } + // + Point2f getEdgeUPoint(const EdgeU& eu); + EdgeU getCutEdgeU(const Point2f& inside, const Point2f& outside); + // + friend bool intersect_region(const QtRegion& a, const QtRegion& b, double tolerance); + friend bool overlap_x(const QtRegion& a, const QtRegion& b, double tolerance); + friend bool overlap_y(const QtRegion& a, const QtRegion& b, double tolerance); + // + // set functions + friend QtRegion runion(const QtRegion& a, const QtRegion& b); + friend QtRegion rintersect( const QtRegion& a, const QtRegion& b); // undefined? + // + void grow(const double scalar) + { Point2f dim = top_right - bottom_left; + dim.scale(scalar - 1.0); + top_right += dim; + bottom_left -= dim; } +}; + +// First time we have a region available to use... +inline void Point2f::normalScale( const QtRegion& r ) +{ + if(r.width()) x = (x - r.bottom_left.x) / r.width(); + else x = 0.0; + if(r.height()) y = (y - r.bottom_left.y) / r.height(); + else y = 0.0; +} + +inline void Point2f::denormalScale( const QtRegion& r ) +{ + x = x * r.width() + r.bottom_left.x; + y = y * r.height() + r.bottom_left.y; +} + +// Lines are stored left to right as regions, +// the parity tells us whether the region should be inverted +// top to bottom to get the line + +class Line : public QtRegion +{ +protected: + struct Bits { + Bits() : x_dummy(0), y_dummy(0), z_dummy(0){} + char parity : 8; // 1 ... positive, 0 ... negative + char direction : 8; // 1 ... positive, 0 ... negative + + // dummy variables as it seems to be necessary that the width of this struct is 8 bytes + // and I don't want any uninitialised memory that gets written to file accidentally + char x_dummy : 8; + char y_dummy : 8; + int z_dummy : 32; + }; + Bits bits; +public: + Line(); + Line(const Point2f& a, const Point2f& b); + Line(const QtRegion& r) : QtRegion(r) + { bits.parity = 1; bits.direction = 1; } + Line(const Line& l) : QtRegion(l) + { bits = l.bits; } + Line& operator = (const Line& l) + { this->QtRegion::operator = (l); bits = l.bits; return *this; } + // + friend bool intersect_line(const Line& a, const Line& b, double tolerance); + friend bool intersect_line_no_touch(const Line& a, const Line& b, double tolerance); + friend int intersect_line_distinguish(const Line& a, const Line& b, double tolerance); + friend int intersect_line_b(const Line& a, const Line& b, double tolerance); + // + // fills in the location along the axis where the intersection happens + bool intersect_line(const Line& l, int axis, double& loc) const; + double intersection_point(const Line& l, int axis, double tolerance = 0.0) const; + // this converts a loc retrieved from intersect line or intersection point back into a point: + Point2f point_on_line(double loc, int axis) const; + // ...and a quick do it all in one go: + friend Point2f intersection_point(const Line& a, const Line& b, double tolerance); + // + bool crop(const QtRegion& r); + void ray(short dir, const QtRegion& r); + // + friend double dot(const Line& a, const Line& b); + // + double ax() const { return bottom_left.x; } + double& ax() { return bottom_left.x; } + double bx() const { return top_right.x; } + double& bx() { return top_right.x; } + double ay() const { return bits.parity ? bottom_left.y : top_right.y; } + double& ay() { return bits.parity ? bottom_left.y : top_right.y; } + double by() const { return bits.parity ? top_right.y : bottom_left.y; } + double& by() { return bits.parity ? top_right.y : bottom_left.y; } + // + const Point2f start() const + { return Point2f( bottom_left.x, (bits.parity ? bottom_left.y : top_right.y) ); } + const Point2f end() const + { return Point2f( top_right.x, (bits.parity ? top_right.y : bottom_left.y) ); } + const Point2f midpoint() const + { return Point2f( (start() + end()) / 2); } + // + // helpful to have a user friendly indication of direction: + bool rightward() const + { return bits.direction == 1; } + bool upward() const + { return bits.direction == bits.parity; } + // + const Point2f t_start() const + { return Point2f( (rightward() ? bottom_left.x : top_right.x), (upward() ? bottom_left.y : top_right.y) ); } + const Point2f t_end() const + { return Point2f( (rightward() ? top_right.x : bottom_left.x), (upward() ? top_right.y : bottom_left.y) ); } + // + short sign() const + { return bits.parity ? 1 : -1; } + // + double grad(int axis) const { + return (axis == YAXIS) ? sign() * height() / width() : sign() * width() / height(); + } + double constant(int axis) const { + return (axis == YAXIS) ? ay() - grad(axis) * ax() : ax() - grad(axis) * ay(); + } + // + double length() const + { return (double) sqrt((top_right.x - bottom_left.x) * (top_right.x - bottom_left.x) + + (top_right.y - bottom_left.y) * (top_right.y - bottom_left.y)); } + // + short direction() const + { return bits.direction; } + Point2f vector() const + { return t_end() - t_start(); } +}; + +inline Point2f intersection_point(const Line& a, const Line& b, double tolerance) +{ + int axis = (a.width() >= a.height()) ? XAXIS : YAXIS; + return a.point_on_line(a.intersection_point(b,axis,tolerance),axis); +} + +//////////////////////////////////////////////////////////////////////////////////////// + +struct TaggedLine +{ + Line line; + int tag; + TaggedLine(const Line& l = Line(),int t = -1) { line = l; tag = t; } +}; + +// plain 2-point line without regions +struct SimpleLine +{ +public: + SimpleLine(const Line& line) + { + m_start.x = line.start().x; + m_start.y = line.start().y; + m_end.x = line.end().x; + m_end.y = line.end().y; + } + SimpleLine(const Point2f& a, const Point2f& b) + { + m_start.x = a.x; + m_start.y = a.y; + m_end.x = b.x; + m_end.y = b.y; + } + SimpleLine(double x1, double y1, double x2, double y2) + { + m_start.x = x1; + m_start.y = y1; + m_end.x = x2; + m_end.y = y2; + } + const Point2f& start() const { return m_start; } + const Point2f& end() const { return m_end; } +private: + Point2f m_start; + Point2f m_end; +}; + +//////////////////////////////////////////////////////////////////////////////////////// + +// not sure if this code is used any more: + +// Now the difficult bit: making the line segments into polygons... +// The polygons are stored in a tree format so that intersection testing is easier + +class Poly; + +class RegionTree +{ +friend class mgraph440::Poly; +protected: + Line *m_p_region; + RegionTree *m_p_left; + RegionTree *m_p_right; +public: + RegionTree() + { m_p_region = NULL; m_p_left = this; m_p_right = this; } + virtual ~RegionTree() + { if (m_p_region) delete m_p_region; } + // + virtual bool is_leaf() const = 0; + // + RegionTree& left() const + { return *m_p_left; } + RegionTree& right() const + { return *m_p_right; } + // + operator QtRegion() const + { return *(QtRegion *)m_p_region; } + operator Line() const + { return *(Line *)m_p_region; } + // + friend bool intersect(const RegionTree& a, const RegionTree& b); + friend bool subintersect(const RegionTree& a, const RegionTree& b); + friend int intersections(const RegionTree& a, const Line& b); +}; + +// Branch on a region tree... + +class RegionTreeBranch : public RegionTree +{ +public: + RegionTreeBranch() : RegionTree() {;} + RegionTreeBranch( const Line& r, + const RegionTree& a, + const RegionTree& b ) + { + m_p_left = (RegionTree *) &a; + m_p_right = (RegionTree *) &b; + m_p_region = new Line(r); // copy + } + virtual bool is_leaf() const + { return false; } +}; + +// Leaf on a region tree... + +class RegionTreeLeaf : public RegionTree +{ +public: + RegionTreeLeaf() : RegionTree() {;} + RegionTreeLeaf(const Line &l) + { + // no subnodes (but nice recursive properties) + m_p_left = this; + m_p_right = this; + m_p_region = new Line(l); + } + virtual bool is_leaf() const + { return true; } +}; + +class Poly +{ +protected: + int m_line_segments; + RegionTree *m_p_root; +public: + Poly() + { + m_p_root = NULL; m_line_segments = 0; + } + Poly( const Poly& p ) + { + m_line_segments = p.m_line_segments; + m_p_root = copy_region_tree( p.m_p_root ); + } + Poly& operator = (const Poly& p) + { + if (this != &p) { + m_line_segments = p.m_line_segments; + m_p_root = copy_region_tree( p.m_p_root ); + } + return *this; + } + virtual ~Poly() + { + destroy_region_tree(); + } + // essentially, the copy constructor... + RegionTree *copy_region_tree( const RegionTree* tree ); + // essentially, the destructor... + void destroy_region_tree(); + // + RegionTree& get_region_tree() const + { + return *m_p_root; + } + // + void add_line_segment(const Line& l); + // + int get_line_segments() + { return m_line_segments; } + QtRegion get_bounding_box() + { return *(QtRegion *)(m_p_root->m_p_region); } + // + bool contains( const Point2f& p ); + friend bool intersect( const Poly& a, const Poly& b ); +}; + +} diff --git a/mgraph440/pafcolor.cpp b/mgraph440/pafcolor.cpp new file mode 100644 index 00000000..fde7a07f --- /dev/null +++ b/mgraph440/pafcolor.cpp @@ -0,0 +1,241 @@ +#include "mgraph440/pafcolor.h" + +namespace mgraph440 { + +static unsigned int g_nicecolor[] = { + 0x003333DD, // 0 blue + 0x003388DD, // 1 + 0x0022CCDD, // 2 + 0x0022CCBB, // 3 + 0x0022DD88, // 4 + 0x0088DD22, // 5 + 0x00BBCC22, // 6 + 0x00DDCC22, // 7 + 0x00DD8833, // 8 + 0x00DD3333, // 9 red +}; + +// Test a range designed to try to keep consitent saturation and brightness of g_nicecolor, and only move hue +static unsigned int g_nicecolorhsb[] = { + 0x003333DD, // 0 blue + 0x003377DD, // 1 + 0x0033BBDD, // 2 + 0x0033DDBB, // 3 + 0x0033DD55, // 4 + 0x0055DD33, // 5 + 0x00BBDD33, // 6 + 0x00DDBB33, // 7 + 0x00DD7733, // 8 + 0x00DD3333, // 9 red +}; + + +static unsigned int g_hsbcolor[] = { + 0x003333DD, // 0 blue + 0x003388DD, // 1 + 0x0022CCDD, // 2 + 0x0022CCBB, // 3 + 0x0022DD88, // 4 + 0x0088DD22, // 5 + 0x00BBCC22, // 6 + 0x00DDCC22, // 7 + 0x00DD8833, // 8 + 0x00DD3333, // 9 red +}; + + +static unsigned int g_greyscale[] = { + 0x00000000, // 0 black + 0x00444444, // 1 + 0x00777777, // 2 + 0x00AAAAAA, // 3 + 0x00CCCCCC, // 4 + 0x00EEEEEE, // 5 + 0x00FFFFFF, // 6 white +}; + +static unsigned int g_bluered[] = { + 0x004575B4, // 0 blue + 0x0091BFDB, + 0x00E0F3F8, + 0x00FFFFBF, + 0x00FEE090, + 0x00FC8D59, + 0x00D73027 // 6 red +}; + +static unsigned int g_purpleorange[] = { + 0x00542788, // 0 purple + 0x00998EC3, // 1 + 0x00D8DAEB, // 2 + 0x00F7F7F7, // 3 + 0x00FEE0B6, // 4 + 0x00F1A340, // 5 + 0x00B35806 // 6 orange +}; + +// htmlByte converts a normalised number to an HTML safe byte + +unsigned char htmlByte440(double colorByte) +{ + // Quick mod - TV +#if defined(_MSC_VER) + return (unsigned char((colorByte + 0.0333) * 15.0) * 0x11); +#else + return ((unsigned char)((colorByte + 0.0333) * 15.0) * 0x11); +#endif +} + +PafColor& PafColor::makeColor(double field, DisplayParams dp) +{ + // Quick mod - TV + if (field == -1.0 || std::isnan(field)) { + // -1.0 is (currently) a nan value, set alpha channel to 0 (transparent) + switch (dp.colorscale) { + case DisplayParams::MONOCHROME: + case DisplayParams::GREYSCALE: + m_color = 0x00000000; // <- monochrome and greyscale, simply hide + break; + default: + // if in colour, then show greyed out: + m_color = 0x007f7f7f; // <- grey retained for visibility on certain values + break; + } + return *this; + } + if (dp.blue > dp.red) { + field = 1.0 - field; + dp.blue = 1.0f - dp.blue; + dp.red = 1.0f - dp.red; + } + if (dp.colorscale == DisplayParams::DEPTHMAPCLASSIC) { + makeDepthmapClassic(field, dp.blue, dp.red); + } + else { + field = (field - dp.blue) / (dp.red - dp.blue); + // Quick mod - TV + if (std::isnan(field)) { + field = 0.5; + } + if (field > 1.0) { + field = 1.0; + } + else if (field < 0.0) { + field = 0.0; + } + switch(dp.colorscale) { + case DisplayParams::AXMANESQUE: + makeAxmanesque(field); + break; + case DisplayParams::PURPLEORANGE: + makePurpleOrange(field); + break; + case DisplayParams::BLUERED: + makeBlueRed(field); + break; + case DisplayParams::GREYSCALE: + case DisplayParams::MONOCHROME: + makeGreyScale(field); + break; + } + } + return *this; +} + +// this makes an Axman-like colour range + +PafColor& PafColor::makeAxmanesque( double field ) +{ + m_color = 0xff000000 | g_nicecolor[int((field - 1e-9) * 10.0)]; + return *this; +} + +// this makes a purple-orange scheme that is red-green colour-blind safe + +PafColor& PafColor::makePurpleOrange( double field ) +{ + m_color = 0xff000000 | g_purpleorange[int((field - 1e-9) * 7.0)]; + return *this; +} + +// this makes a blue-red scheme that is red-green colour-blind safe + +PafColor& PafColor::makeBlueRed( double field ) +{ + m_color = 0xff000000 | g_bluered[int((field - 1e-9) * 7.0)]; + return *this; +} + +// this makes a greyscale colour range + +PafColor& PafColor::makeGreyScale( double field ) +{ + m_color = 0xff000000 | g_greyscale[int((field - 1e-9) * 7.0)]; + return *this; +} + +// note, makeDepthmapClassic converts to a safe HTML colour + +PafColor& PafColor::makeDepthmapClassic( double field, double blue, double red ) +{ + m_color = 0xff000000; // set alpha to 255, solid colour + double green = blue + (red-blue) / 10.0; + // NB previously included colour muting: the 1.0 was originally 0.9 to mute the colours slightly + if (field >= 0.0 && field < blue) { + setr(htmlByte440(0.5 * (blue - field)/blue * 1.0)); + // Quick mod - TV +#if defined(_MSC_VER) + setb(unsigned char(0xFF)); +#else + setb((unsigned char)(0xFF)); +#endif + } + else if (field >= blue && field < (green+blue)/2.0) { + // Quick mod - TV +#if defined(_MSC_VER) + setb(unsigned char(0xFF)); +#else + setb((unsigned char)(0xFF)); +#endif + setg(htmlByte440((2.0*(field - blue)/(green-blue)) * 1.0)); + } + else if (field >= (green+blue)/2.0 && field < green) { + setb(htmlByte440((2.0*(green - field)/(green-blue)) * 1.0)); + // Quick mod - TV +#if defined(_MSC_VER) + setg(unsigned char(0xFF)); +#else + setg((unsigned char)(0xFF)); +#endif + } + else if (field >= green && field < (green+red)/2.0 ) { + // Quick mod - TV +#if defined(_MSC_VER) + setg(unsigned char(0xFF)); +#else + setg((unsigned char)(0xFF)); +#endif + setr(htmlByte440((2.0*(field - green)/(red-green)) * 1.0)); + } + else if (field >= (green+red)/2.0 && field < red) { + setg(htmlByte440((2.0*(red - field)/(red-green)) * 1.0)); + // Quick mod - TV +#if defined(_MSC_VER) + setr(unsigned char(0xFF)); +#else + setr((unsigned char)(0xFF)); +#endif + } + else if (field >= red) { + // Quick mod - TV +#if defined(_MSC_VER) + setr(unsigned char(0xFF)); +#else + setr((unsigned char)(0xFF)); +#endif + setb(htmlByte440(0.5 * (field - red)/(1.0 - red) * 1.0)); + } + return *this; +} + +} diff --git a/mgraph440/pafcolor.h b/mgraph440/pafcolor.h new file mode 100644 index 00000000..94faa4b3 --- /dev/null +++ b/mgraph440/pafcolor.h @@ -0,0 +1,79 @@ +#pragma once + +#include "mgraph440/displayparams.h" +#include "mgraph440/p2dpoly.h" + +// Converts everything to safe HTML colours + +namespace mgraph440 { + +struct PafColor +{ + unsigned int m_color; + unsigned char redb() const + { return (unsigned char) (m_color >> 16); } + unsigned char greenb() const + { return (unsigned char) (m_color >> 8); } + unsigned char blueb() const + { return (unsigned char) (m_color); } + unsigned char alphab() const + { return (unsigned char) (m_color >> 24); } + // Quick mod - TV + void setr(unsigned char r) + { m_color &= 0xff00ffff; m_color |= (((unsigned int)r) << 16);} + // Quick mod - TV + void setg(unsigned char g) + { m_color &= 0xffff00ff; m_color |= (((unsigned int)g) << 8);} + // Quick mod - TV + void setb(unsigned char b) + { m_color &= 0xffffff00; m_color |= ((unsigned int)b);} + float redf() const + { return float(redb()) / 255.0f; } + float greenf() const + { return float(greenb()) / 255.0f; } + float bluef() const + { return float(blueb()) / 255.0f; } + PafColor() + { m_color = 0x00000000; } + PafColor(unsigned int rgb) // color in 0x00rrggbb format + { m_color = 0xff000000 | rgb; } + PafColor( double r, double g, double b, double a = 1.0 ) + { + m_color = 0x00000000 | + (((unsigned char) (a * 255.0)) << 24) | + (((unsigned char) (r * 255.0)) << 16) | + (((unsigned char) (g * 255.0)) << 8) | + (((unsigned char) (b * 255.0))); + } + + PafColor( const Point2f& vec, double a = 1.0 ) + { + m_color = 0x00000000 | + (((unsigned char) (a * 255.0)) << 24) | + (((unsigned char) (dot(vec,Point2f(1.0, 0.0)) * 255.0)) << 16) | + (((unsigned char) (dot(vec,Point2f(-0.5,0.86602540378443864676372317075294)) * 255.0)) << 8) | + (((unsigned char) (dot(vec,Point2f(-0.5,-0.86602540378443864676372317075294)) * 255.0))); + } + + operator unsigned int () + { return m_color & 0x00ffffff; } + friend bool operator == (const PafColor& a, const PafColor& b); + friend bool operator != (const PafColor& a, const PafColor& b); + PafColor& makeAxmanesque( double field); + PafColor& makePurpleOrange( double field ); + PafColor& makeBlueRed( double field ); + PafColor& makeGreyScale( double field ); + PafColor& makeMonochrome( double field ); + PafColor& makeDepthmapClassic( double field, double blue, double red ); + PafColor& makeColor(double field, DisplayParams dp); // <- note, make copy to play around with +}; +inline bool operator == (const PafColor& a, const PafColor& b) +{ + return (a.m_color == b.m_color); +} +inline bool operator != (const PafColor& a, const PafColor& b) +{ + return (a.m_color != b.m_color); +} + +} diff --git a/mgraph440/pafmath.cpp b/mgraph440/pafmath.cpp new file mode 100644 index 00000000..0f3b24f4 --- /dev/null +++ b/mgraph440/pafmath.cpp @@ -0,0 +1,99 @@ +// genlib - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + + +// a collection of math functions + +#include +#include +#include + +namespace mgraph440 { + +uint64_t g_rand[11] = {1,2,3,5,7,11,13,17,19,23,29}; + +// 25-Jul-2007: changed the g_mult and g_const used for random number generation +// for some reason, there appeared to be a pattern to the numbers + +// Quick mod - TV +const uint64_t g_mult = /*(0xF9561B2E << 32) + */0x71A7FA85; +const uint64_t g_const = /*(0x9BB3920E << 32) + */0xF5E958B9; + +void pafsrand(unsigned int seed, int set) // = 0 +{ + g_rand[set] = seed; +} + +// Pafrand is a Linear Congruential Generator +// After the 25-Jul-2007 changes: +// The current version seems to meet standard randomness conditions +// Tested using Diehard, the 32 bit version ((g_rand[set] >> 32) & 0xffffffff) +// passes all tests for at least the first 5 seeds above +// it is also independent in at least 20 dimensions +// It should not be used for "serious" randomness, but should be fine +// for most things (agents in depthmapX, genetic algorithms, etc) + +// 25-Jul-2007: moved up to take top 32 bits + +unsigned int pafrand(int set) // = 0 +{ + g_rand[set] = g_mult * g_rand[set] + g_const; + + return (unsigned int)((g_rand[set] >> 32) & PAF_RAND_MAX); +} + +/////////////////////////////////////////////////////////////////////////////// + +double poisson(int x, double lambda) +{ + double f = exp(-lambda); + for (int i = 1; i <= x; i++) { + f *= lambda / double(i); + } + return f; +} + +double cumpoisson(int x, double lambda) +{ + double f = exp(-lambda); + double c = f; + for (int i = 1; i <= x; i++) { + f *= lambda / double(i); + c += f; + } + return c; +} + +int invcumpoisson(double p, double lambda) +{ + if (p <= 0) { + return 0; + } + if (p >= 1) { + // passing this 1 will cause an infinite loop, try this instead: + p = 1-1e-9; + } + double f = exp(-lambda); + int i = 0; + for (double c = f; c < p; c += f) { + i++; + f *= lambda / double(i); + } + return i; +} + +} diff --git a/mgraph440/pafmath.h b/mgraph440/pafmath.h new file mode 100644 index 00000000..2c0b974f --- /dev/null +++ b/mgraph440/pafmath.h @@ -0,0 +1,125 @@ +// genlib - a component of the depthmapX - spatial network analysis platform + +// Paf Template Library --- a set of useful C++ templates +// +// Copyright (c) 1996-2011 Alasdair Turner (a.turner@ucl.ac.uk) +// +//----------------------------------------------------------------------------- +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// +// See the lgpl.txt file for details +//----------------------------------------------------------------------------- + +// a collection of math functions + +#ifndef __PAFMATH_H__ +#define __PAFMATH_H__ + +#include + +namespace mgraph440 { + +#ifndef M_PI +#define M_PI 3.1415926535897932384626433832795 +#endif + +inline double sqr(double a) +{ + return (a*a); +} + +inline int sgn(double a) +{ + return (a < 0) ? -1 : 1; +} + +#ifndef M_ROOT_1_2 +#define M_ROOT_1_2 0.70710678118654752440084436210485 +#endif + +#ifndef M_1_LN2 +#define M_1_LN2 1.4426950408889634073599246810019 +#endif + +const unsigned int PAF_RAND_MAX = 0x0FFFFFFF; +void pafsrand(unsigned int seed, int set = 0); +unsigned int pafrand(int set = 0); + +// a random number from 0 to 1 +inline double prandom(int set = 0) +{ + return double(pafrand(set)) / double(PAF_RAND_MAX); +} + +// a random number from 0 to just less than 1 + +inline double prandomr(int set = 0) +{ + return double(pafrand(set)) / double(PAF_RAND_MAX + 1); +} + +// note, in order to stop confusing myself I have ln defined: +#define ln(X) log(X) + +inline double log2(double a) +{ + return (ln(a) * M_1_LN2); +} + +// Hillier Hanson dvalue +/* +inline double dvalue(double k) +{ + return 2.0 * (3.3231 * k * log10(k+2) - 2.5863 * k + 1.0) / ((k - 1.0) * (k - 2.0)); +} +*/ + +// Hillier Hanson dvalue (from Kruger 1989 -- see Teklenburg et al) +inline double dvalue(double k) +{ + return 2.0 * (k * (log2((k+2.0)/3.0) - 1.0) + 1.0) / ((k - 1.0) * (k - 2.0)); +} + +// Hillier Hanson pvalue +inline double pvalue(double k) +{ + return 2.0 * (k - log2(k) - 1.0) / ((k - 1.0) * (k - 2.0)); +} + +// Teklenburg integration (correction 31.01.11 due to Ulrich Thaler +inline double teklinteg(double nodecount, double totaldepth) +{ + return ln(0.5 * (nodecount - 2.0)) / ln(double(totaldepth - nodecount + 1)); +} + +// Penn palmtree + +inline double palmtree(double n, double r) +{ + if (n > r) { + return r * (n - 0.5 * (r+1)); + } + else { + return 0.5 * n * (n - 1); + } +} + +double poisson(int x, double lambda); +double cumpoisson(int x, double lambda); +int invcumpoisson(double p, double lambda); + +} + +#endif diff --git a/genlib/paftl.h b/mgraph440/paftl.h similarity index 64% rename from genlib/paftl.h rename to mgraph440/paftl.h index b490370a..66243912 100644 --- a/genlib/paftl.h +++ b/mgraph440/paftl.h @@ -1,3134 +1,2141 @@ -// Paf Template Library --- a set of useful C++ templates -// -// Copyright (c) 1996-2011 Alasdair Turner (a.turner@ucl.ac.uk) -// -//----------------------------------------------------------------------------- -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -// -// See the lgpl.txt file for details -//----------------------------------------------------------------------------- -// -// Paf's cross platform box of tricks -// Everything you need to write any C++. All in one file! -// -// pstring similar to STL string -// pmemvec base clase for pvector and prefvec -// pvector similar to STL vector -// prefvec pvector with a different allocator (vector of references) -// pqvector searchable prefvec -// pqmap a simple map class, based on a binary tree -// plist a simple list class -// ptree a simple tree template -// pflipper used for flipping between two vectors (or anythings...) -// pexception exception class, base for various exception types -// -// -// A3 eliminates the double referencing used previously in the -// vector classes - -#ifndef __PAFTL_H__ -#define __PAFTL_H__ - -#define PAFTL_DATE "01-FEB-2011" -// 31-jan-2011: unicode constructor for pstring -// 04-aug-2010: fix bug on quicksort to avoid sorting zero length array -// 06-jun-2010: rewrite quicksort to avoid infinite loop -// 31-aug-2009: change pstring constructors to align with STL string -// 28-nov-2007: full implementation for ANSI standards -// 28-nov-2007: minor bug on pvecsub construction: should be 2 << count rather than 1 << count -// 30-aug-2007: make compatible with Unix / MacOS - -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -// Quick mod - TV -#pragma warning (disable: 4996 ) -#pragma warning (disable: 4396 ) -#else - -#endif - -#ifdef _MSC_VER // MSVC compiler - typedef signed __int64 int64; - typedef unsigned __int64 uint64; -#else - #include // not guaranteed to exist, but does in Mac / Ubuntu - typedef int64_t int64; - typedef uint64_t uint64; -#endif - -using namespace std; - -#ifndef bool -// #define bool int -#endif -#ifndef true - #define true 1 -#endif -#ifndef false - #define false 0 -#endif - -/////////////////////////////////////////////////////////////////////////////// - -// namespace paftl { - -class pexception; -class pstring; -template class pvector; -template class prefvec; -template class pqvector; -template class pqmap; -template class plist; -template class ptree; -template class pflipper; - -// a few basic types - -typedef pvector pvecint; -typedef pvector pvecfloat; -typedef pvector pvecdouble; -typedef pqvector pvecstring; - -/////////////////////////////////////////////////////////////////////////////// - -// miscellaneous enums (paftl used as namespace) - -namespace paftl -{ - enum add_t {ADD_UNIQUE, ADD_REPLACE, ADD_DUPLICATE, ADD_HERE}; - const size_t npos = size_t(-1); -} - -/////////////////////////////////////////////////////////////////////////////// - -class pexception -{ -public: - enum exception_t { UNDEFINED = 0x0000, - MEMORY_ALLOCATION = 0x0001, - FILE_ERROR = 0x0002, - MAX_ARRAY_EXCEEDED = 0x0003}; - -protected: - int m_exception; - size_t m_data; -public: - pexception(int n_exception = UNDEFINED, size_t data = 0) - { m_exception = n_exception; m_data = data; } - int error_code() - { return m_exception; } - size_t info() - { return m_data; } -}; - - -/////////////////////////////////////////////////////////////////////////////// - -// pmemvec: base allocation for pvector and prefvec - -template class pmemvec -{ -public: - class exception : public pexception - { - public: - enum exception_t { PVECTOR_UNDEFINED = 0x1000, - EMPTY_VECTOR = 0x1001, - UNASSIGNED_ITERATOR = 0x1002, - OUT_OF_RANGE = 0x1003}; - public: - exception(int n_exception = PVECTOR_UNDEFINED, size_t data = 0) : pexception( n_exception, data ) {} - }; -protected: - T *m_data; - unsigned short m_shift; - size_t m_length; -public: - // redefine - pmemvec(size_t sz = 0); - pmemvec(const pmemvec& ); - virtual ~pmemvec(); - pmemvec& operator = (const pmemvec& ); - // - virtual void push_back(const T& item); - virtual void pop_back(); - virtual void remove_at(size_t pos = 0); - virtual void remove_at(const pvecint& list); - virtual void insert_at(size_t pos, const T& item); - // - virtual void set(size_t count); - virtual void set(const T& item, size_t count); - // - virtual void clear(); - virtual void clearnofree(); -protected: - size_t storage_size() const - { return m_shift ? (2 << m_shift) : 0; } - void grow(size_t pos); - void shrink(); -public: - size_t size() const - { return m_length; } - T& base_at(size_t pos) - { return m_data[pos]; } - const T& base_at(size_t pos) const - { return m_data[pos]; } -public: - istream& read( istream& stream, streampos offset = streampos(-1) ); - ostream& write( ostream& stream ); -}; - -template -pmemvec::pmemvec(size_t sz) -{ - // note: uses same as grow / storage_size, but cannot rely on function existence when calling constructor - if (sz == 0) { - m_data = NULL; - m_shift = 0; - } - else { - do { - m_shift++; - } while ((size_t(2) << m_shift) < sz); - m_data = new T [storage_size()]; - if (m_data == NULL) { - throw pexception(pexception::MEMORY_ALLOCATION, sizeof(T) * storage_size()); - } - } - m_length = 0; -} - -template -pmemvec::pmemvec(const pmemvec& v) -{ - m_shift = v.m_shift; - m_length = v.m_length; - - if (m_shift) { - m_data = new T [storage_size()]; - if (m_data == NULL) - throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * storage_size() ); - - if (m_length) { - for (size_t i = 0; i < m_length; i++) - m_data[i] = v.m_data[i]; - } - } - else { - m_data = NULL; - } -} - -template -pmemvec::~pmemvec() -{ - if (m_data) - { - delete [] m_data; - m_data = NULL; - } -} - -template -pmemvec& pmemvec::operator = (const pmemvec& v) -{ - if (m_shift < v.m_shift) - { - if (m_shift != 0) { - delete [] m_data; - } - m_shift = v.m_shift; - if (m_shift) { - m_data = new T [storage_size()]; - if (!m_data) - throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * storage_size() ); - } - else { - m_data = NULL; - } - } - m_length = v.m_length; - if (m_length) { - for (size_t i = 0; i < m_length; i++) - m_data[i] = v.m_data[i]; - } - return *this; -} - -template -void pmemvec::push_back(const T& item) -{ - if (m_length >= storage_size()) { - grow( m_length ); - } - m_data[m_length] = item; - m_length++; -} - -template -void pmemvec::pop_back() -{ - if (m_length == 0) - throw exception( exception::EMPTY_VECTOR ); - - --m_length; - - // Preferably include shrink code here -} - -template -void pmemvec::insert_at(size_t pos, const T& item) -{ - if (pos == paftl::npos || pos > m_length) { - throw exception( exception::OUT_OF_RANGE ); - } - if (m_length >= storage_size()) { - grow( pos ); - } - else { - for (size_t i = m_length; i > pos; i--) { - m_data[i] = m_data[i - 1]; - } - } - m_data[pos] = item; - m_length++; -} - -template -void pmemvec::remove_at(size_t pos) -{ - // This is a simple but reliable remove item from vector - if (m_length == 0) - throw exception( exception::EMPTY_VECTOR ); - else if (pos == paftl::npos || pos >= m_length) - throw exception( exception::OUT_OF_RANGE ); - - for (size_t i = pos; i < m_length - 1; i++) { - m_data[i] = m_data[i + 1]; - } - --m_length; - - // Preferably include shrink code here -} - -template -void pmemvec::set(size_t count) -{ - clear(); - do { - m_shift++; - } while ((size_t(2) << m_shift) < count); - m_data = new T [storage_size()]; - if (!m_data) - throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * storage_size() ); - m_length = count; -} - -template -void pmemvec::set(const T& item, size_t count) -{ - clear(); - do { - m_shift++; - } while ((size_t(2) << m_shift) < count); - m_data = new T [storage_size()]; - if (!m_data) - throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * storage_size() ); - m_length = count; - for (size_t i = 0; i < m_length; i++) { - m_data[i] = item; - } -} - -template -void pmemvec::clear() -{ - m_length = 0; - m_shift = 0; - if (m_data) - { - delete [] m_data; - m_data = NULL; - } -} - -template -void pmemvec::clearnofree() -{ - m_length = 0; -} - -template -void pmemvec::grow(size_t pos) -{ - m_shift++; - - T *new_data = new T [storage_size()]; - if (!new_data) - throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * storage_size() ); - - if (m_length) { - for (size_t i = 0; i < m_length + 1; i++) - new_data[i] = (i < pos) ? m_data[i] : m_data[i-1]; - } - if (m_data) { - delete [] m_data; - } - m_data = new_data; -} - -template -void pmemvec::shrink() -{ -} - -template -istream& pmemvec::read( istream& stream, streampos offset ) -{ - if (offset != streampos(-1)) { - stream.seekg( offset ); - } - // READ / WRITE USES 32-bit LENGTHS (number of elements) - // n.b., do not change this to size_t as it will cause 32-bit to 64-bit conversion problems - unsigned int length; - stream.read( (char *) &length, sizeof(unsigned int) ); - m_length = size_t(length); - if (m_length >= storage_size()) { - if (m_data) { - delete [] m_data; - m_data = NULL; - } - while (m_length >= storage_size()) - m_shift++; - m_data = new T [storage_size()]; - if (!m_data) - throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * storage_size() ); - } - if (m_length != 0) { - stream.read( (char *) m_data, sizeof(T) * streamsize(m_length) ); - } - return stream; -} - -template -ostream& pmemvec::write( ostream& stream ) -{ - // READ / WRITE USES 32-bit LENGTHS (number of elements) - // n.b., do not change this to size_t as it will cause 32-bit to 64-bit conversion problems - - // check for max unsigned int exceeded - if (m_length > size_t((unsigned int)-1)) { - throw pexception( pexception::MAX_ARRAY_EXCEEDED, m_length ); - } - // n.b., do not change this to size_t as it will cause 32-bit to 64-bit conversion problems - unsigned int length = (unsigned int)(m_length); - stream.write( (char *) &length, sizeof(unsigned int) ); - if (m_length != 0) { - stream.write( (char *) m_data, sizeof(T) * streamsize(m_length) ); - } - return stream; -} - -/////////////////////////////////////////////////////////////////////////////// - -template class pvector : public pmemvec -{ -protected: - mutable size_t m_current; -public: - pvector(size_t sz = 0) : pmemvec(sz) - {m_current = paftl::npos;} - pvector(const pvector& v) : pmemvec(v) - {m_current = v.m_current;} - pvector& operator = (const pvector& ); - virtual ~pvector() - {;} - // - T& at(size_t pos) - { return pmemvec::m_data[pos]; } - const T& at(size_t pos) const - { return pmemvec::m_data[pos]; } - T& operator[](size_t pos) - { return at(pos); } - const T& operator[](size_t pos) const - { return at(pos); } - // - T& head() - { return at(0); } - const T& head() const - { return at(0); } - T& tail() - { return at(pmemvec::m_length-1); } - const T& tail() const - { return at(pmemvec::m_length-1); } - // standard operations (unordered vector) - T& find(const T& item); - const T& find(const T& item) const; - size_t findindex(const T& item) const; - // binary operations (ordered vector) - size_t add(const T& item, int type = paftl::ADD_UNIQUE); // ignored if already exists - T& search(const T& item); - const T& search(const T& item) const; - size_t searchindex(const T& item) const; - size_t searchfloorindex(const T& item) const; - size_t searchceilindex(const T& item) const; - void remove(const T& item) - { pmemvec::remove_at(searchindex(item)); } - // set operations (ordered vector) - void operator += (const pvector& v); - // qsort algo: - void sort(); - void sort(size_t left, size_t right); - // - - // Quick mod - TV -#if defined(_WIN32) - friend pvector intersect(const pvector& a, const pvector& b); -#endif -}; - -template -pvector& pvector::operator = (const pvector& v) -{ - if (&v != this) - { - pmemvec::operator = (v); - } - return *this; -} - -template -T& pvector::find(const T& item) -{ - if (findindex(item) == paftl::npos) { - throw pmemvec::exception::exception(pmemvec::exception::OUT_OF_RANGE); - } - return at(m_current); -} -template -const T& pvector::find(const T& item) const -{ - if (findindex(item) == paftl::npos) { - throw pmemvec::exception(pmemvec::exception::OUT_OF_RANGE); - } - return at(m_current); -} - -template -size_t pvector::findindex(const T& item) const -{ - for (size_t i = 0; i < pmemvec::m_length; i++) { - if (at(i) == item) { - m_current = i; - return i; - } - } - return paftl::npos; -} - -// oops... we need an iterator... add use a current position marker. - -template -T& pvector::search(const T& item) -{ - if (searchindex(item) == paftl::npos) { - throw pmemvec::exception(pmemvec::exception::OUT_OF_RANGE); // Not found - } - return at(m_current); -} -template -const T& pvector::search(const T& item) const -{ - if (searchindex(item) == paftl::npos) { - throw pmemvec::exception(pmemvec::exception::OUT_OF_RANGE); // Not found - } - return at(m_current); -} - -template -size_t pvector::searchindex(const T& item) const -{ - if (pmemvec::m_length != 0) { - size_t ihere, ifloor = 0, itop = pmemvec::m_length - 1; - while (itop != paftl::npos && ifloor <= itop) { - m_current = ihere = (ifloor + itop) / 2; - if (item == at(ihere)) { - return m_current; - } - else if (item > at(ihere)) { - ifloor = ihere + 1; - } - else { - itop = ihere - 1; - } - } - } - return paftl::npos; -} - -template -size_t pvector::searchfloorindex(const T& item) const -{ - searchindex(item); - while (m_current != 0 && at(m_current) > item) { - m_current--; - } - return m_current; -} - -template -size_t pvector::searchceilindex(const T& item) const -{ - searchindex(item); - while (m_current < pmemvec::m_length && at(m_current) < item) { - m_current++; - } - return m_current; -} - - -// Note: uses m_current set by searchindex - -// Really need a list 'merge' function as well... will write this soon! - -template -size_t pvector::add(const T& item, int type) // UNIQUE by default -{ - size_t where = paftl::npos; - if (pmemvec::m_length == 0 || item > pvector::tail()) { // often used for push_back, so handle quickly if so - pmemvec::push_back( item ); - where = pmemvec::m_length - 1; - } - else { - // if you call with ADD_HERE, it is assumed you've just used search or searchindex - // i.e., we don't need to go through the binary search again to find the insert position - if (type != paftl::ADD_HERE) { - searchindex(item); - } - if (item < at(m_current)) { - pmemvec::insert_at( m_current, item ); - where = m_current; - } - else if (item > at(m_current) || type == paftl::ADD_DUPLICATE) { - pmemvec::insert_at( m_current + 1, item ); - where = m_current + 1; - } - else if (type == paftl::ADD_REPLACE || type == paftl::ADD_HERE) { - // relies on good assignment operator - at(m_current) = item; - } - // n.b., type "UNIQUE" does not replace, returns -1 - } - return where; -} - -template -void pvector::operator += (const pvector& v) -{ - if (this != &v && pmemvec::m_length + v.pmemvec::m_length > 0) { - - while (pmemvec::m_length + v.pmemvec::m_length >= pmemvec::storage_size()) - pmemvec::m_shift++; - - T *new_data = new T [pmemvec::storage_size()]; - if (!new_data) - throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * pmemvec::storage_size() ); - - size_t i = 0, j = 0, k = 0; - while (i + j < pmemvec::m_length + v.pmemvec::m_length) { - if ( i < pmemvec::m_length ) { - if (j < v.pmemvec::m_length) { - if (pmemvec::m_data[i] < v.pmemvec::m_data[j]) { - new_data[k++] = pmemvec::m_data[i++]; - } - else if (pmemvec::the_data()[i] > v.pmemvec::the_data()[j]) { - new_data[k++] = v.pmemvec::m_data[j++]; - } - else { - new_data[k++] = pmemvec::m_data[i++]; j++; - } - } - else { - while (i < pmemvec::m_length) { - new_data[k++] = pmemvec::m_data[i++]; - } - } - } - else { - while (j < v.pmemvec::m_length) { - new_data[k++] = v.pmemvec::m_data[j++]; - } - } - } - if (pmemvec::m_data) { - delete [] pmemvec::m_data; - } - pmemvec::m_length = k; - pmemvec::m_data = new_data; - } -} - -template -void pvector::sort() -{ - if (pmemvec::m_length != 0) { - sort(0,pmemvec::m_length-1); - } -} - -// rewrite 6-jun-10 (was entering infinite loop, now appears to work properly) -template -void pvector::sort(size_t left, size_t right) -{ - size_t i = left, j = right; - const T& val = pmemvec::m_data[(left+right)/2]; - while (j != paftl::npos && i <= j) { - while (i <= j && pmemvec::m_data[i] < val) - i++; - while (j != paftl::npos && pmemvec::m_data[j] > val) - j--; - if (j != paftl::npos && i <= j) { - // swap contents - T temp = pmemvec::m_data[i]; - pmemvec::m_data[i] = pmemvec::m_data[j]; - pmemvec::m_data[j] = temp; - i++; j--; - } - } - if (j != paftl::npos && left < j) - sort(left, j); - if (i < right) - sort(i, right); -} - -// requires two sorted lists -template -inline pvector intersect(const pvector& a, const pvector& b) -{ - pvector retvec; - size_t i = 0; - size_t j = 0; - while (i < a.size() && j < b.size()) { - if (a[i] == b[j]) { - retvec.push_back(a[i]); - i++; j++; - } - else { - while (a[i] < b[j] && i < a.size()) { - i++; - } - while (a[i] > b[j] && j < b.size()) { - j++; - } - } - } - return retvec; -} - -/////////////////////////////////////////////////////////////////////////////// - -// this version for bulk deletes: copies over entries to new list -// (first requires pvector to have been defined) - -template -void pmemvec::remove_at(const pvecint& list) -{ - if (m_length == 0) - throw exception( exception::EMPTY_VECTOR ); - if (list.size() >= m_length) { - // if the list does not contain duplicates, then this simply means delete all contents: - clear(); - return; - } - // shrink new vector: - while ((m_length - list.size()) * 2 < storage_size()) { - m_shift--; - } - size_t new_length = 0; - T *new_data = new T [storage_size()]; - bool *rem_flag = new bool [m_length]; - if (!new_data) - throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * storage_size() ); - if (!rem_flag) - throw pexception( pexception::MEMORY_ALLOCATION, sizeof(bool) * storage_size() ); - size_t i; - for (i = 0; i < m_length; i++) { - rem_flag[i] = false; - } - for (i = 0; i < list.size(); i++) { - if (size_t(list[i]) == paftl::npos || size_t(list[i]) >= m_length) - throw exception( exception::OUT_OF_RANGE ); - rem_flag[list[i]] = true; - } - for (i = 0; i < m_length; i++) { - if (!rem_flag[i]) { - new_data[new_length] = m_data[i]; - new_length++; - } - } - m_length = new_length; - delete [] m_data; - delete [] rem_flag; - m_data = new_data; -} - -/////////////////////////////////////////////////////////////////////////////// - -// prefvec: a vector of references (useful for larger objects) -// should be able to use pqvector in most cases - -template class prefvec : public pmemvec -{ -public: - prefvec(size_t sz = 0) : pmemvec(sz) - {;} - prefvec(const prefvec& ); - virtual ~prefvec(); - prefvec& operator = (const prefvec& ); - // - void push_back(const T& item); - void pop_back(); - void remove_at(size_t pos = 0); - void free_at(size_t pos = 0); - void remove_at(const pvecint& list); - void insert_at(size_t pos, const T& item); - // - void set(size_t count); - void set(const T& item, size_t count); - // - void clear(); - void clearnofree(); - // - T& at(size_t pos) - { return *(pmemvec::m_data[pos]); } - const T& at(size_t pos) const - { return *(pmemvec::m_data[pos]); } - T& operator[](size_t pos) - { return at(pos); } - const T& operator[](size_t pos) const - { return at(pos); } - // - T& head() - { return at(0); } - const T& head() const - { return at(0); } - T& tail() - { return at(pmemvec::m_length-1); } - const T& tail() const - { return at(pmemvec::m_length-1); } - // - // NOTE: no find (as often equivalence operator will not be defined) - // - // Override read and write - istream& read( istream& stream ); - ostream& write( ostream& stream ); -}; - -template -prefvec::prefvec(const prefvec& v) : pmemvec(v) -{ - for (size_t i = 0; i < pmemvec::m_length; i++) { - pmemvec::m_data[i] = new T(v.at(i)); - if (pmemvec::m_data[i] == NULL) { - throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) ); - } - } -} - -template -prefvec& prefvec::operator = (const prefvec& v) -{ - if (&v != this) { - for (size_t i = 0; i < pmemvec::m_length; i++) { - delete pmemvec::m_data[i]; - } - pmemvec::operator = (v); - for (size_t j = 0; j < pmemvec::m_length; j++) { - pmemvec::m_data[j] = new T(v.at(j)); - if (pmemvec::m_data[j] == NULL) { - throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) ); - } - } - } - return *this; -} - -template -prefvec::~prefvec() -{ - for (size_t i = 0; i < pmemvec::m_length; i++) { - if (pmemvec::m_data[i]) - delete pmemvec::m_data[i]; - } - // virtual destructor called for pmemvec -} - -template -void prefvec::push_back(const T& item) -{ - T *p = new T(item); - pmemvec::push_back( p ); -} - -template -void prefvec::pop_back() -{ - if (pmemvec::m_data[pmemvec::m_length - 1]) { - delete pmemvec::m_data[pmemvec::m_length - 1]; - pmemvec::m_data[pmemvec::m_length - 1] = NULL; - } - pmemvec::pop_back(); -} - -template -void prefvec::remove_at(size_t pos) -{ - if (pmemvec::m_length == 0) - throw (typename pmemvec::exception)( pmemvec::exception::EMPTY_VECTOR ); - else if (pos == paftl::npos || pos >= pmemvec::m_length) - throw (typename pmemvec::exception)( pmemvec::exception::OUT_OF_RANGE ); - - if (pmemvec::m_data[pos]) { - delete pmemvec::m_data[pos]; - pmemvec::m_data[pos] = NULL; - } - pmemvec::remove_at( pos ); -} - -// just frees the memory at position: does not manipulate vector - -template -void prefvec::free_at(size_t pos) -{ - if (pmemvec::m_length == 0) - throw (typename pmemvec::exception)( pmemvec::exception::EMPTY_VECTOR ); - else if (pos == paftl::npos || pos >= pmemvec::m_length) - throw (typename pmemvec::exception)( pmemvec::exception::OUT_OF_RANGE ); - - delete pmemvec::m_data[pos]; - pmemvec::m_data[pos] = NULL; -} - -// this version for intended for bulk deletes (also retains previous ordering) -template -void prefvec::remove_at(const pvecint& list) -{ - if (pmemvec::m_length == 0) - throw (typename pmemvec::exception)( pmemvec::exception::EMPTY_VECTOR ); - - for (size_t i = 0; i < list.size(); i++) { - if (size_t(list[i]) == paftl::npos || size_t(list[i]) >= pmemvec::m_length) - throw (typename pmemvec::exception)( pmemvec::exception::OUT_OF_RANGE ); - if (pmemvec::m_data[list[i]]) { - delete pmemvec::m_data[list[i]]; - pmemvec::m_data[list[i]] = NULL; - } - } - pmemvec::remove_at( list ); -} - - -template -void prefvec::insert_at(size_t pos, const T& item) -{ - T *p = new T(item); - if (p == NULL) { - throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) ); - } - pmemvec::insert_at(pos, p); -} - -template -void prefvec::set(size_t count) -{ - pmemvec::set(count); - for (size_t i = 0; i < pmemvec::m_length; i++) { - pmemvec::m_data[i] = NULL; - if (pmemvec::m_data[i] == NULL) { - throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) ); - } - } -} - -template -void prefvec::set(const T& item, size_t count) -{ - pmemvec::set(count); - for (size_t i = 0; i < pmemvec::m_length; i++) { - pmemvec::m_data[i] = new T(item); - if (pmemvec::m_data[i] == NULL) { - throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) ); - } - } -} - - -template -void prefvec::clear() -{ - for (size_t i = 0; i < pmemvec::m_length; i++) { - if (pmemvec::m_data[i]) { - delete pmemvec::m_data[i]; - pmemvec::m_data[i] = NULL; - } - } - pmemvec::clear(); -} - -template -void prefvec::clearnofree() -{ - // still have to delete objects pointed to, just doesn't just clear the list of pointers: - for (size_t i = 0; i < pmemvec::m_length; i++) { - if (pmemvec::m_data[i]) { - delete pmemvec::m_data[i]; - pmemvec::m_data[i] = NULL; - } - } - pmemvec::clearnofree(); -} - -// Note: read and write only work for structures without pointers - -template -istream& prefvec::read( istream& stream ) -{ - for (size_t i = 0; i < pmemvec::m_length; i++) { - if (pmemvec::m_data[i]) { - delete pmemvec::m_data[i]; - pmemvec::m_data[i] = NULL; - } - } - // READ / WRITE USES 32-bit LENGTHS (number of elements) - // n.b., do not change this to size_t as it will cause 32-bit to 64-bit conversion problems - unsigned int length; - stream.read( (char *) &length, sizeof(unsigned int) ); - if (stream.fail()) { - throw pexception(pexception::FILE_ERROR); - } - pmemvec::m_length = size_t(length); - if (pmemvec::m_length >= pmemvec::storage_size()) { - if (pmemvec::m_data) { - delete [] pmemvec::m_data; - } - while (pmemvec::m_length >= pmemvec::storage_size()) - pmemvec::m_shift++; - pmemvec::m_data = new T * [pmemvec::storage_size()]; - if (pmemvec::m_data == NULL) { - throw pexception( pexception::MEMORY_ALLOCATION, pmemvec::storage_size() * sizeof(T) ); - } - } - for (size_t j = 0; j < pmemvec::m_length; j++) { - T *p = new T; - if (p == NULL) { - throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) ); - } - stream.read( (char *) p, sizeof(T) ); - if (stream.fail()) { - throw pexception(pexception::FILE_ERROR); - } - pmemvec::m_data[j] = p; - } - return stream; -} - -template -ostream& prefvec::write( ostream& stream ) -{ - // READ / WRITE USES 32-bit LENGTHS (number of elements) - // n.b., do not change this to size_t as it will cause 32-bit to 64-bit conversion problems - - // check for max unsigned int exceeded - if (pmemvec::m_length > size_t((unsigned int)-1)) { - // Quick mod - TV -#if 0 - throw exception( pexception::MAX_ARRAY_EXCEEDED, pmemvec::m_length ); -#else - ; -#endif - } - - // n.b., do not change this to size_t as it will cause 32-bit to 64-bit conversion problems - unsigned int length = (unsigned int)(pmemvec::m_length); - stream.write( (char *) &length, sizeof(unsigned int) ); - - for (size_t i = 0; i < pmemvec::m_length; i++) { - stream.write( (char *) &at(i), sizeof(T) ); - } - return stream; -} - -/////////////////////////////////////////////////////////////////////////////// - -// pqvector... prefvec with the binary addition routine... -// (i.e., almost the hash table...) - -// (so... I think we might replace pqmap with an inherited form of this soon) -// (if MS would oblige...) - -template class pqvector : public prefvec -{ -protected: - mutable size_t m_current; -public: - pqvector(size_t sz = 0) : prefvec(sz) {;} - pqvector(const pqvector& v) : prefvec( v ) {;} - virtual ~pqvector() {;} - pqvector& operator = (const pqvector& v) - { prefvec::operator = (v); return *this; } - // - // at, [] and so on as before - // - // standard operations (unordered vector) - T& find(const T& item); - const T& find(const T& item) const; - size_t findindex(const T& item) const; - // - // binary operations (ordered vector) - T& search(const T& item); - const T& search(const T& item) const; - size_t searchindex(const T& item) const; - void remove(const T& item) - { remove_at(searchindex(item)); } - size_t add(const T& item, int type = paftl::ADD_UNIQUE); - T& current() - { return prefvec::at(m_current); } - const T& current() const - { return pmemvec::at(m_current); } - // qsort algo: - void sort(); - void sort(size_t left, size_t right); -}; - -template -T& pqvector::find(const T& item) -{ - if (findindex(item) == paftl::npos) { - throw pmemvec::exception(pmemvec::exception::OUT_OF_RANGE); - } - return prefvec::at(m_current); -} -template -const T& pqvector::find(const T& item) const -{ - if (findindex(item) == paftl::npos) { - throw pmemvec::exception(pmemvec::exception::OUT_OF_RANGE); - } - return prefvec::at(m_current); -} - -template -size_t pqvector::findindex(const T& item) const -{ - for (size_t i = 0; i < pmemvec::m_length; i++) { - if (prefvec::at(i) == item) { - m_current = i; - return i; - } - } - return paftl::npos; -} - -// oops... we need an iterator... add use a current position marker. - -template -T& pqvector::search(const T& item) -{ - if (searchindex(item) == paftl::npos) { - throw (typename pmemvec::exception)(pmemvec::exception::OUT_OF_RANGE); // Not found - } - return prefvec::at(m_current); -} -template -const T& pqvector::search(const T& item) const -{ - if (searchindex(item) == paftl::npos) { - throw (typename pmemvec::exception)(pmemvec::exception::OUT_OF_RANGE); // Not found - } - return prefvec::at(m_current); -} - -template -size_t pqvector::searchindex(const T& item) const -{ - if (pmemvec::size() != 0) { - size_t ihere, ifloor = 0, itop = pmemvec::size() - 1; - while (itop != paftl::npos && ifloor <= itop) { - m_current = ihere = (ifloor + itop) / 2; - if (item == prefvec::at(ihere)) { - return m_current; - } - else if (item > prefvec::at(ihere)) { - ifloor = ihere + 1; - } - else { - itop = ihere - 1; - } - } - } - return paftl::npos; -} - -// Note: uses m_current set by searchindex - -// Really need a list 'merge' function as well... will write this soon! - -template -size_t pqvector::add(const T& item, int type) // default type UNIQUE -{ - size_t where = paftl::npos; - if (pmemvec::size() == 0 || item > prefvec::tail()) { // often used for push_back, so handle quickly if so - prefvec::push_back( item ); - where = pmemvec::size() - 1; - } - else { - // if you call with ADD_HERE, it is assumed you've just used search or searchindex - // i.e., we don't need to go through the binary search again to find the insert position - if (type != paftl::ADD_HERE) { - searchindex(item); - } - if (item < prefvec::at(m_current)) { - prefvec::insert_at( m_current, item ); - where = m_current; - } - else if (item > prefvec::at(m_current) || type == paftl::ADD_DUPLICATE) { - prefvec::insert_at( m_current + 1, item ); - where = m_current + 1; - } - else if (type == paftl::ADD_REPLACE || type == paftl::ADD_HERE) { - // relies on good assignment operator - prefvec::at(m_current) = item; - } - // n.b., type "UNIQUE" does not replace, returns paftl::npos - } - return where; -} - -template -void pqvector::sort() -{ - if (pmemvec::m_length != 0) { - sort(0,pmemvec::m_length-1); - } -} - -// rewrite 6-jun-10 (was entering infinite loop, now appears to work properly) -template -void pqvector::sort(size_t left, size_t right) -{ - size_t i = left, j = right; - const T& val = prefvec::at((left+right)/2); - while (j != paftl::npos && i <= j) { - while (i <= j && prefvec::at(i) < val) - i++; - while (j != paftl::npos && prefvec::at(j) > val) - j--; - if (j != paftl::npos && i <= j) { - // swap contents (using pointer) - T* temp = pmemvec::m_data[i]; - pmemvec::m_data[i] = pmemvec::m_data[j]; - pmemvec::m_data[j] = temp; - i++; j--; - } - } - if (j != paftl::npos && left < j) - sort(left, j); - if (i < right) - sort(i, right); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// - -// psubvec is based on pvector, designed for arrays of chars or shorts, it subsumes itself -// so can be stored as a single pointer: useful if you have a lot of empty arrays - -template class psubvec -{ -public: - static const T npos = -1; -protected: - T *m_data; -public: - psubvec() - { m_data = NULL; } - psubvec(const psubvec& ); - ~psubvec(); - psubvec& operator = (const psubvec& ); - // - virtual void push_back(const T item); - virtual void clear(); -public: - bool isEmpty() // isEmpty is provided in addition to size as is quicker to test - { return m_data == NULL; } - T size() const - { return m_data ? m_data[0] : 0; } - T& operator [] (T pos) - { return m_data[pos+1]; } - const T& operator [] (T pos) const - { return m_data[pos+1]; } -public: - istream& read( istream& stream, streampos offset = -1 ); - ostream& write( ostream& stream ); -}; - -template -psubvec::psubvec(const psubvec& v) -{ - if (v.m_data) { - T length = v.m_data[0]; - T count = 0; - while (length >>= 1) // find bit length (note: cannot assume int) - count++; - m_data = new T [2 << count]; - if (m_data == NULL) { - throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * size_t(2 << count) ); - } - length = v.m_data[0]; - for (T i = 0; i < length + 1; i++) { - m_data[i] = v.m_data[i]; - } - } - else { - m_data = NULL; - } -} - -template -psubvec::~psubvec() -{ - if (m_data) - { - delete [] m_data; - m_data = NULL; - } -} - -template -psubvec& psubvec::operator = (const psubvec& v) -{ - if (this != &v) { - if (v.m_data) { - T length = v.m_data[0]; - T count = 0; - while (length >>= 1) // find bit length (note: cannot assume int) - count++; - m_data = new T [2 << count]; - if (m_data == NULL) { - throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * size_t(2 << count) ); - } - length = v.m_data[0]; - for (T i = 0; i < length + 1; i++) { - m_data[i] = v.m_data[i]; - } - } - else { - m_data = NULL; - } - } - return *this; -} - -template -void psubvec::push_back(const T item) -{ - if (!m_data) { - m_data = new T [2]; - m_data[0] = 1; - m_data[1] = item; - } - else { - T length = m_data[0] + 1; - if ((length & (length - 1)) == 0) { // determine if next length would be power of 2 - T *new_data = new T [length << 1]; - if (new_data == NULL) { - throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * size_t(length << 1) ); - } - for (T i = 0; i < length; i++) - new_data[i] = m_data[i]; - delete [] m_data; - m_data = new_data; - } - m_data[0] = length; - m_data[length] = item; - } -} - -template -void psubvec::clear() -{ - if (m_data) - { - delete [] m_data; - m_data = NULL; - } -} - -template -istream& psubvec::read( istream& stream, streampos offset ) -{ - if (m_data) { - delete [] m_data; - m_data = NULL; - } - T length; - stream.read( (char *) &length, sizeof(T) ); - if (length) { - T copy = length; - T count = 0; - while (length >>= 1) // find bit length (note: cannot assume int) - count++; - m_data = new T [2 << count]; - if (m_data == NULL) { - throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * size_t(2 << count) ); - } - stream.read((char *) &m_data, sizeof(T)*(copy+1) ); - } - return stream; -} - -template -ostream& psubvec::write( ostream& stream ) -{ - if (m_data) { - stream.write((char *) &m_data, sizeof(T)*(m_data[0]+1)); - } - return stream; -} - - - -/////////////////////////////////////////////////////////////////////////////////////////////// - -// And now the quick mapping routine - -// Helper class keyvaluepair... - -template class keyvaluepair { - // Quick mod - TV -#if defined(_WIN32) -protected: -#else -public: -#endif - T1 m_key; - T2 m_value; -public: - keyvaluepair(const T1 key = T1(), const T2 value = T2()) - { m_key = key; m_value = value; } - T1& key() { return m_key; } - const T1 key() const { return m_key; } - T2& value() { return m_value; } - const T2& value() const { return m_value; } - - // Quick mod - TV -#if defined (_WIN32) - friend bool operator == (const keyvaluepair& a, const keyvaluepair& b); - friend bool operator < (const keyvaluepair& a, const keyvaluepair& b); - friend bool operator > (const keyvaluepair& a, const keyvaluepair& b); -#endif - istream& read( istream& stream ); - ostream& write( ostream& stream ); -}; -template -inline bool operator == (const keyvaluepair& a, const keyvaluepair& b) -{ return (a.m_key == b.m_key); } -template -inline bool operator < (const keyvaluepair& a, const keyvaluepair& b) -{ return (a.m_key < b.m_key); } -template -inline bool operator > (const keyvaluepair& a, const keyvaluepair& b) -{ return (a.m_key > b.m_key); } -// Note: read and write only work for structures without pointers -template -istream& keyvaluepair::read( istream& stream ) -{ - stream.read( (char *) &m_key, sizeof(T1) ); - stream.read( (char *) &m_value, sizeof(T2) ); - return stream; -} -template -ostream& keyvaluepair::write( ostream& stream ) -{ - stream.write( (char *) &m_key, sizeof(T1) ); - stream.write( (char *) &m_value, sizeof(T2) ); - return stream; -} - -template class keyvaluepairref -{ - // Quick mod - TV -#if defined(_WIN32) -protected: -#else -public: -#endif - T1 m_key; - T2 *m_value; -public: - keyvaluepairref(const T1 key = T1()) - { m_key = key; m_value = NULL; } - keyvaluepairref(const T1 key, const T2& value) - { m_key = key; m_value = new T2(value); } - keyvaluepairref(const keyvaluepairref& k) - { m_key = k.m_key; m_value = new T2(*(k.m_value)); } - keyvaluepairref& operator = (const keyvaluepairref& k) - { - if (this != &k) - { - m_key = k.m_key; - m_value = new T2(*(k.m_value)); - } - return *this; - } - ~keyvaluepairref() - { if (m_value) {delete m_value; m_value = NULL;} } - T1& key() { return m_key; } - const T1 key() const { return m_key; } - T2& value() { return *m_value; } - const T2& value() const { return *m_value; } - - // Quick mod - TV -#if defined(_WIN32) - friend bool operator == (const keyvaluepairref& a, const keyvaluepairref& b); - friend bool operator < (const keyvaluepairref& a, const keyvaluepairref& b); - friend bool operator > (const keyvaluepairref& a, const keyvaluepairref& b); -#endif - - // - virtual istream& read( istream& stream ); - virtual ostream& write( ostream& stream ); -}; -template -inline bool operator == (const keyvaluepairref& a, const keyvaluepairref& b) -{ return (a.m_key == b.m_key); } -template -inline bool operator < (const keyvaluepairref& a, const keyvaluepairref& b) -{ return (a.m_key < b.m_key); } -template -inline bool operator > (const keyvaluepairref& a, const keyvaluepairref& b) -{ return (a.m_key > b.m_key); } -// Note: read and write only work for structures without pointers -template -istream& keyvaluepairref::read( istream& stream ) -{ - stream.read( (char *) &m_key, sizeof(T1) ); - -#ifndef _WIN32 - m_value = new T2; -#endif - stream.read( (char *) m_value, sizeof(T2) ); - return stream; -} -template -ostream& keyvaluepairref::write( ostream& stream ) -{ - stream.write( (char *) &m_key, sizeof(T1) ); - stream.write( (char *) m_value, sizeof(T2) ); - return stream; -} - -// ...and yuk! it gets worse... now we have to define a whole new class: - -template class pmemmap -{ -// It looks very similar to a pqvector... -protected: - pqvector m_vector; -public: - pmemmap() {;} - pmemmap(const pmemmap& map ) { m_vector = map.m_vector; } - ~pmemmap() {;} - pmemmap& operator = (const pmemmap& map ) - { if (this != &map) m_vector = map.m_vector; return *this; } - // - // at, [] and so on - T2& at(size_t i) - { return m_vector.at(i).value(); } - const T2& at(size_t i) const - { return m_vector.at(i).value(); } - T2& operator [] (size_t i) - { return m_vector.at(i).value(); } - const T2& operator [] (size_t i) const - { return m_vector.at(i).value(); } - T2& head() - { return m_vector.head().value(); } - const T2& head() const - { return m_vector.head().value(); } - T2& tail() - { return m_vector.tail().value(); } - const T2& tail() const - { return m_vector.tail().value(); } - size_t size() const - { return m_vector.size(); } - void clear() - { m_vector.clear(); } - // - // standard operations (unordered vector) - T2& find(const T1& item) const - { return m_vector.find(Pair(item)).value(); } - size_t findindex(const T1& item) const - { return m_vector.findindex(Pair(item)); } - // - // binary operations (ordered vector) - T2& search(const T1& item) - { return m_vector.search(Pair(item)).value(); } - const T2& search(const T1& item) const - { return m_vector.search(Pair(item)).value(); } - const size_t searchindex(const T1& item) const - { return m_vector.searchindex(Pair(item)); } - void remove_at(size_t i) - { m_vector.remove_at(i); } - void remove_at(const pvecint& list) - { m_vector.remove_at(list); } - void remove(const T1& item) - { remove_at(m_vector.searchindex(item)); } - size_t add(const T1& k, const T2& v, int type = paftl::ADD_UNIQUE) // note: does not replace! - { return m_vector.add( Pair(k,v), type ); } - // extras - T1& key(size_t i) - { return m_vector.at(i).key(); } - const T1 key(size_t i) const - { return m_vector.at(i).key(); } - T2& value(size_t i) - { return m_vector.at(i).value(); } - const T2& value(size_t i) const - { return m_vector.at(i).value(); } - T2& current() - { return m_vector.current().value(); } - const T2& current() const - { return m_vector.current().value(); } - // read and write (structures without pointers *only*) - istream& read( istream& stream ); - ostream& write( ostream& stream ); -}; - -// Note: read and write only work for structures without pointers - -template -istream& pmemmap::read( istream& stream ) -{ - for (size_t i = m_vector.size() - 1; i != paftl::npos; i--) { - m_vector.remove_at(i); - } - // n.b., do not change this to size_t as it will cause 32-bit to 64-bit conversion problems - unsigned int length; - stream.read( (char *) &length, sizeof(unsigned int) ); - for (size_t j = 0; j < size_t(length); j++) { - // these should be in order, so just push them: - Pair p; - p.read(stream); - m_vector.push_back(p); - } - return stream; -} - -template -ostream& pmemmap::write( ostream& stream ) -{ - // check for max unsigned int exceeded - if (m_vector.size() > size_t((unsigned int)-1)) { - throw pexception( pexception::MAX_ARRAY_EXCEEDED, m_vector.size() ); - } - - // n.b., do not change this to size_t as it will cause 32bit to 64bit conversion problems - unsigned int length = (unsigned int)(m_vector.size()); - stream.write( (char *) &length, sizeof(unsigned int) ); - for (size_t i = 0; i < m_vector.size(); i++) { - m_vector[i].write(stream); - } - return stream; -} - -// ...to stop the MS compiler complaining... -#define kvp(T1,T2) keyvaluepair - -template class pmap : public pmemmap -{ -}; - -// ...to stop the MS compiler complaining... -#define kvpr(T1,T2) keyvaluepairref - -template class pqmap : public pmemmap -{ -}; - -/////////////////////////////////////////////////////////////////////////////// - -// and a simple list class... -// (with integrated iterator) - -template class plist -{ -protected: - class pitem - { - protected: - T *m_data; - public: - pitem *m_previous; - pitem *m_next; - pitem(const T *d = NULL, pitem *p = NULL, pitem *n = NULL) - { - if (d) - m_data = new T(*d); - else - m_data = NULL; - m_previous = p; - m_next = n; - } - pitem(const pitem& p) - { - throw 1; - } - pitem& operator = (const pitem& p) - { - throw 1; - } - ~pitem() - { - if (m_data) - delete m_data; - m_data = NULL; - m_previous = NULL; - m_next = NULL; - } - void predel() - { - if (m_previous != NULL) { - pitem *temp = m_previous->m_previous; - temp->m_next = this; // should work without reallocation - delete m_previous; - m_previous = temp; // should work without reallocation - } - } - void postdel() - { - if (m_next != NULL) { - pitem *temp = m_next->m_next; - temp->m_previous = this; // should work without reallocation - delete m_next; - m_next = temp; // should work without reallocation - } - } - pitem *preins(const T& v) - { - pitem *temp = m_previous; - m_previous = new pitem(&v, temp, this); - temp->m_next = m_previous; // should work without reallocation - return m_previous; - } - pitem *postins(const T& v) - { - pitem *temp = m_next; - m_next = new pitem(&v, this, temp); - temp->m_previous = m_next; // should work without reallocation - return m_next; - } - T& data() const - { - if (!m_data) { - throw 1; - } - return *m_data; - } - }; -protected: - pitem m_head; - pitem m_tail; - mutable pitem *m_current; -public: - bool empty() const - { - return (m_head.m_next == &m_tail); // or v.v. - } - void pop_back() - { - m_tail.predel(); // i.e., delete the one before the tail - } - void pop_front() - { - m_head.postdel(); // i.e., delete the one after the head - } - void push_back(const T& v) - { - m_tail.preins(v); // i.e., add before the tail - } - void push_front(const T& v) - { - m_head.postins(v); // i.e., add after the head - } - void first() const - { - m_current = m_head.m_next; - } - void last() const - { - m_current = m_tail.m_previous; - } - bool is_head() const - { - return (m_current == &m_head); - } - bool is_tail() const - { - return (m_current == &m_tail); - } - const plist& operator ++(int) const - { - m_current = m_current->m_next; - return *this; - } - const plist& operator --(int) const - { - m_current = m_current->m_previous; - return *this; - } - T& operator *() const { - return m_current->data(); - }; - void preins(const T& data) { - m_current->preins(data); - } - void postins(const T& data) { - m_current->postins(data); - } - // note pre and post del delete the current item: - void predel() { - m_current = m_current->m_previous; - m_current->postdel(); - } - void postdel() { - m_current = m_current->m_next; - m_current->predel(); - } - void clear() - { - while (!empty()) { - pop_back(); - } - } -public: - plist() - { - m_head.m_next = &m_tail; - m_tail.m_previous = &m_head; - m_current = &m_head; // just so it's somewhere... - } - plist(const plist& list) { - m_head.m_next = &m_tail; - m_tail.m_previous = &m_head; - m_current = list.m_current; - for (list.first(); !list.is_tail(); list++) { - push_back(*list); - } - list.m_current = m_current; // set back original list current to what it was before - } - plist& operator = (const plist& list) { - if (&list != this) { - m_current = list.m_current; - clear(); - for (list.first(); list.is_tail(); list++) { - push_back(*list); - } - list.m_current = m_current; // set back original list current to what it was before - } - return *this; - } - ~plist() - { - // remove contents: - clear(); - } -}; - -/////////////////////////////////////////////////////////////////////////////// - -// ptree: a simple tree class - -// Allows template of a template (recursive) definition for tree -#define ptreeT ptree - -template class ptree -{ -public: - class exception : public pexception - { - public: - enum exception_t { PTREE_UNDEFINED = 0x1000, - UNASSIGNED_DATA = 0x1001 }; - public: - exception(int n_exception = PTREE_UNDEFINED) : pexception( n_exception ) {} - }; -protected: - T *m_data; - ptree *m_parent; - pvector m_children; -public: - ptree() { - m_data = NULL; - m_parent = NULL; - } - ptree(const T& data) { - m_data = new T(data); - m_parent = NULL; - } - ptree(const ptree& tree ) { - m_data = tree.m_data; - for (int i = 0; i < tree.m_children.size(); i++) { - ptree *child = new ptree( *(tree.m_children[i]) ); - m_children.push_back( child ); - m_children.tail()->m_parent = this; - } - } - ptree& operator = (const ptree& tree) { - if (this != &tree) { - m_data = tree.m_data; - for (int i = 0; i < tree.m_children.size(); i++) { - ptree *child = new ptree( *(tree.m_children[i]) ); - m_children.push_back( child ); - m_children.tail()->m_parent = this; - } - } - return *this; - } - ~ptree() { - delete m_data; - m_data = NULL; - while (m_children.size()) { - delete m_children.tail(); - m_children.pop_back(); - } - } - void addChild(const T& data) { - m_children.push_back( new ptree(data) ); - m_children.tail()->m_parent = this; - } - void removeChild(int ref) { - ptree *child = m_children[ref]; - m_children.remove(ref); - delete child; - } - int getChildCount() const { - return m_children.size(); - } - ptree& getChild(int ref) const { - return *(m_children[ref]); - } - ptree& getLastChild() const { - return *(m_children[m_children.size() - 1]); - } - int hasParent() const { - return m_parent ? 1 : 0; - } - ptree& getParent() const { - return *m_parent; - } - void setParent(ptree& parent) { - if (m_parent) { - for (int i = 0; i < m_parent->m_children.size(); i++) { - if (m_parent->m_children[i] == this) { - m_parent->m_children.remove(i); - } - } - } - m_parent = &parent; - } - void setValue(const T& data) { - m_data = new T(data); - } - T& getValue() const { - if (!m_data) - throw exception( exception::UNASSIGNED_DATA ); - return *m_data; - } - pvector getPath() { - pvector path; - getPath(path); - return path; - } - void getPath(pvector& path) { - path.push_back( getValue() ); - if (m_parent) { - m_parent->getPath(path); - } - } -}; - -/////////////////////////////////////////////////////////////////////////////// - -template class pflipper -{ -protected: - T m_contents[2]; - short parity; -public: - pflipper() { - parity = 0; - } - pflipper( const T& a, const T& b ) { - parity = 0; - m_contents[0] = a; - m_contents[1] = b; - } - pflipper( const pflipper& f ) { - parity = f.parity; - m_contents[0] = f.m_contents[0]; - m_contents[1] = f.m_contents[1]; - } - virtual ~pflipper() { - } - pflipper& operator = (const pflipper& f ) { - if (this != &f) { - parity = f.parity; - m_contents[0] = f.m_contents[0]; - m_contents[1] = f.m_contents[1]; - } - return *this; - } - void flip() { - parity = (parity == 0) ? 1 : 0; - } - T& a() { - return m_contents[parity]; - } - T& b() { - return m_contents[(parity == 0) ? 1 : 0]; - } - const T& a() const { - return m_contents[parity]; - } - const T& b() const { - return m_contents[(parity == 0) ? 1 : 0]; - } -}; - -/////////////////////////////////////////////////////////////////////////////// - -// pstring: a simple string class - -class pstring -{ -public: - class exception : public pexception - { - public: - enum exception_t { PSTRING_UNDEFINED = 0x1000, - BAD_STRING = 0x1001, - OUT_OF_RANGE = 0x1002, - UNABLE_TO_CONVERT = 0x1003 }; - public: - exception(int n_exception = PSTRING_UNDEFINED) : pexception( n_exception ) {} - }; - -protected: - size_t m_alloc; - size_t m_start; - size_t m_end; - char *m_data; - -public: - pstring(const char *data = NULL) - { - if (!data || (m_end = strlen(data)) < 1) { - m_data = NULL; - m_start = 0; - m_end = 0; - m_alloc = 0; - } - else { - m_start = 0; - m_alloc = m_end + 1; - m_data = new char [m_alloc]; - if (!m_data) - throw pexception( pexception::MEMORY_ALLOCATION ); - for (size_t i = m_start; i < m_end; i++) m_data[i] = data[i]; - m_data[m_end] = '\0'; - } - } - // AT 31.01.11 -- wchar_t implementation - pstring(const wchar_t *data) - { - size_t len = wcslen(data); - if (!data || len == 0) { - m_data = NULL; - m_start = 0; - m_end = 0; - m_alloc = 0; - } - else { - m_start = 0; - m_end = 0; - m_alloc = len * 2 + 1; // add some redundancy - m_data = new char [m_alloc]; - if (!m_data) - throw pexception( pexception::MEMORY_ALLOCATION ); - m_data[m_end] = '\0'; - char *buf = new char[MB_CUR_MAX]; - for (size_t i = 0; i < len && data[i] != L'\0'; i++) { - int x = wctomb(buf,data[i]); - if (x != -1) { - if (m_end + x >= m_alloc - 1) { - m_alloc += len; - char *temp = new char [m_alloc]; - strcpy(temp,m_data); - delete [] m_data; - m_data = temp; - } - if (x == 1) { - m_data[m_end] = buf[0]; - } - else { - strncat(m_data, buf, x); - } - m_end += x; - m_data[m_end] = '\0'; - } - } - delete buf; - } - } - // Changed 31.08.09 -- pstring no longer has a const char constructor - // this is to avoid accidental construction from an int - // Instead, there is now the following constructor compatible with STL string: - pstring(size_t n, char c) - { - if (n < 1) { - m_data = NULL; - m_start = 0; - m_end = 0; - m_alloc = 0; - } - else { - m_start = 0; - m_end = n; - m_alloc = m_end + 1; - m_data = new char [m_alloc]; - if (!m_data) - throw pexception( pexception::MEMORY_ALLOCATION ); - memset(m_data,c,n); - m_data[m_end] = '\0'; - } - } - // Changed 31.08.09 -- pstring no longer has an int constructor - // this is to avoid accidental construction from an int - // instead, use 'reserve' (as you would for an STL string) - // Added V1.6 to allow initialisation from long / double - // (due to the phasing out of the pdata class) - // - friend pstring pstringify(const char c); - friend pstring pstringify(const int val, const pstring& format); - friend pstring pstringify(const double val, const pstring& format); - // - pstring(const pstring& s) - { - if (s.m_alloc == 0) { - m_data = NULL; - m_start = 0; - m_end = 0; - m_alloc = 0; - } - else if (!s.m_data) - throw exception( exception::BAD_STRING ); - else { - m_start = 0; - m_end = s.m_end - s.m_start; - m_alloc = m_end + 1; - m_data = new char [m_alloc]; - if (!m_data) - throw pexception( pexception::MEMORY_ALLOCATION ); - for (size_t i = 0; i < m_end; i++) { - m_data[i] = s.m_data[i + s.m_start]; - } - m_data[m_end] = '\0'; - } - } - virtual ~pstring() - { - if (m_data) { - delete [] m_data; m_data = NULL; m_start = 0; m_end = 0; m_alloc = 0; - } - } - pstring& operator = (const pstring& s) - { - if (&s != this) { - if (m_alloc < s.m_end - s.m_start + 1) { - if (m_data) { - delete [] m_data; - } - if (s.m_end - s.m_start) { - m_alloc = s.m_end - s.m_start + 1; - m_data = new char [s.m_alloc]; - if (!m_data) - throw pexception( pexception::MEMORY_ALLOCATION ); - } - else { - m_alloc = 0; - m_data = NULL; - } - } - m_start = 0; - m_end = s.m_end - s.m_start; - if (s.m_end - s.m_start) { - if (!s.m_data) - throw exception( exception::BAD_STRING ); - for (size_t i = 0; i < m_end; i++) - m_data[i] = s.m_data[i + s.m_start]; - m_data[m_end] = '\0'; - } - } - return *this; - } - void reserve(const size_t length) - { - if (length < 1) { - if (m_data) - delete m_data; - m_data = NULL; - m_start = 0; - m_end = 0; - m_alloc = 0; - } - else if (m_alloc < length + 1) { - if (m_data) - delete m_data; - m_start = length; - m_end = length; - m_alloc = length + 1; - m_data = new char [m_alloc]; - if (!m_data) { - throw pexception( pexception::MEMORY_ALLOCATION ); - } - m_data[m_end] = '\0'; // ensure terminated, even if contains no real data - } - } - // - const char *c_str() const - { - return m_data + m_start; // Note! Not persistent: do not pass this but c_strcpy()! - } - char *c_strcpy(char *str) const - { - return strcpy( str, (m_data + m_start) ); - } - // Simple conversions (throw exceptions if not valid) - int c_int() const; - double c_double() const; - // Test validity (through attempted conversion) - bool is_int() const; - bool is_double() const; - - char& operator [] (size_t i) const - { - if (i >= (m_end - m_start)) - throw exception( exception::OUT_OF_RANGE ); - return m_data[i + m_start]; - } - void clear() - { m_start = 0; m_end = 0; } // Note: no deallocation - bool empty() const - { return (m_end == m_start) ? true : false; } - size_t size() const - { return m_alloc; } - size_t length() const - { return m_end - m_start; } - - pstring substr( size_t start = 0, size_t length = paftl::npos ) const; - - size_t findindex( char c, size_t start = 0, size_t end = paftl::npos ) const; - size_t findindexreverse( char c, size_t start = paftl::npos, size_t end = 0 ) const; - size_t findindex( const pstring& str, size_t start = 0, size_t end = paftl::npos ) const; - - // Full tokenizer: - pvecstring tokenize( char delim = ' ', bool ignorenulls = false ); - - pstring splice( char delim = ' ' ); - pstring splice( const pstring& delim ); - - pstring& ltrim( char c = ' '); - pstring& rtrim( char c = ' '); - pstring& ltrim( const pstring& str ); - - pstring& replace( char a ); // simply remove all instances of char a - pstring& replace( char a, char b ); - - pstring& makelower(); - pstring& makeupper(); - pstring& makeinitcaps(); - - friend bool compare(const pstring& a, const pstring& b, size_t n); - friend bool operator == (const pstring& a, const pstring& b); - friend bool operator != (const pstring& a, const pstring& b); - friend bool operator < (const pstring& a, const pstring& b); // for storing in hash tables etc - friend bool operator > (const pstring& a, const pstring& b); - - friend pstring operator + (const pstring& a, const pstring& b); - - friend ostream& operator << (ostream& stream, const pstring& str); - friend istream& operator >> (istream& stream, pstring& str); - - char *raw() const - { return m_data; } - - // binary read/write - bool read(istream& stream); - bool write(ostream& stream); -}; - -inline pstring pstringify(const char val) -{ - pstring str(1,val); - return str; -} - -inline pstring pstringify(const int val, const pstring& format = "% 16d") -{ - pstring str; - str.m_start = 0; - str.m_alloc = 16 + format.length(); - str.m_data = new char [str.m_alloc]; - if (!str.m_data) { - throw pexception( pexception::MEMORY_ALLOCATION ); - } - sprintf( str.m_data, format.c_str(), val ); - str.m_end = strlen(str.m_data); - return str; -} - -inline pstring pstringify(const double val, const pstring& format = "%+.16le") -{ - pstring str; - str.m_start = 0; - str.m_alloc = 24 + format.length(); - str.m_data = new char [str.m_alloc]; - if (!str.m_data) { - throw pexception( pexception::MEMORY_ALLOCATION ); - } - sprintf( str.m_data, format.c_str(), val ); - str.m_end = strlen(str.m_data); - return str; -} - -inline pstring pstring::substr(size_t start, size_t length) const -{ - if (length > (m_end - m_start - start)) - length = m_end - m_start - start; - pstring sub; - sub.m_start = 0; - sub.m_end = length; - sub.m_alloc = length + 1; - sub.m_data = new char [sub.m_alloc]; - for (size_t i = 0; i < sub.m_end; i++) - sub.m_data[i] = m_data[i + m_start + start]; - sub.m_data[length] = '\0'; - return sub; -} - -inline size_t pstring::findindex( char c, size_t start, size_t end ) const -{ - if (end == paftl::npos || end > m_end - m_start) { - end = m_end - m_start; - } - for (size_t pos = start; pos < end; pos++) { - if (m_data[pos + m_start] == c) { - return pos; - } - } - return paftl::npos; -} - -inline size_t pstring::findindexreverse( char c, size_t start, size_t end ) const -{ - if (start == paftl::npos || start > m_end - m_start) { - start = m_end - m_start; - } - for (size_t pos = start - 1; pos != paftl::npos && pos >= end; pos--) { - if (m_data[pos + m_start] == c) { - return pos; - } - } - return paftl::npos; -} - -inline size_t pstring::findindex( const pstring& str, size_t start, size_t end ) const -{ - if (end == paftl::npos) { - end = m_end - m_start; - } - for (size_t pos = start; pos < end; pos++) { - if (m_data[pos + m_start] == str.m_data[str.m_start]) { - size_t mark = pos, remark = paftl::npos; - while (mark != paftl::npos && ++pos < str.m_end - str.m_start + mark) { - if (pos >= end) { - return paftl::npos; - } - else if (m_data[pos+m_start] != str.m_data[pos-mark+str.m_start]) { - mark = paftl::npos; - } - else if (m_data[pos+str.m_start] == str.m_data[str.m_start] - && remark == paftl::npos) { - remark = pos; - } - } - if (mark != paftl::npos) { - return mark; - } - else if (remark != paftl::npos) { - return findindex( str, remark ); - } - } - } - return paftl::npos; -} - -inline pstring& pstring::ltrim( char c ) -{ - size_t pos = m_start; - while (pos < m_end && m_data[pos] == c) - pos++; - m_start = pos; - return *this; -} - -inline pstring& pstring::rtrim( char c ) -{ - // this check is necessary, as m_data[m_end] will be reset and could be null - if (m_start != m_end) { - size_t pos = m_end; - while (pos > m_start && m_data[pos-1] == c) - pos--; - m_end = pos; - m_data[m_end] = '\0'; - } - return *this; -} - -inline pstring& pstring::ltrim( const pstring& str ) -{ - size_t pos = m_start; - while (pos < m_end && str.findindex(m_data[pos]) != paftl::npos ) - pos++; - m_start = pos; - return *this; -} - -// tokenize: going beyond splice... - -inline pvecstring pstring::tokenize( char delim, bool ignorenulls ) -{ - pvecstring tokens; - size_t first, last = 0; - while (last + m_start < m_end) { - first = last; - last = findindex(delim, first); - if (last == paftl::npos) - last = m_end - m_start; - tokens.push_back( substr(first, last - first) ); - if (ignorenulls) { - while (last + m_start < m_end && m_data[last+m_start] == delim) - last++; // Lose consecutive delimiters - } - else { - last++; // Lose delimiter - } - } - return tokens; -} - -// splice: kind of combined substr, find operation: - -// returns the head, the tail is kept, the delimiter is destroyed -// (the leading whitespace destroy is no longer used: use x.ltrim().splice() ) - -inline pstring pstring::splice( char delim ) -{ - size_t pos = 0; - pos = findindex(delim, pos); - if (pos == paftl::npos) - pos = m_end - m_start; - pstring str = substr(0, pos); - pos++; // Lose delimiter - m_start = m_end > pos + m_start ? pos + m_start : m_end; - return str; -} - -// returns the head, the tail is kept, the delimiter is destroyed - -inline pstring pstring::splice( const pstring& delim ) -{ - size_t pos = findindex(delim); - if (pos == paftl::npos) - pos = m_end - m_start; - pstring str = substr(0, pos); - pos += delim.m_end; // Lose delimiter - m_start = m_end > pos + m_start ? pos + m_start : m_end; - return str; -} - -// Conversion - -inline int pstring::c_int() const -{ - int out = 0; - if (m_start != m_end) { - char *endptr = m_data + m_start; - out = (int) strtol( m_data + m_start, &endptr, 10 ); - if (endptr == m_data + m_start) { - throw exception( exception::UNABLE_TO_CONVERT ); - } - } - return out; -} - -inline double pstring::c_double() const -{ - double out = 0.0; - if (m_start != m_end) { - char *endptr = m_data + m_start; - out = strtod( m_data + m_start, &endptr ); - if (endptr == m_data + m_start) { - throw exception( exception::UNABLE_TO_CONVERT ); - } - } - return out; -} - -// only way to test is to try it! -inline bool pstring::is_int() const -{ - int out = 0; - if (m_start != m_end) { - char *endptr = m_data + m_start; - out = (int) strtol( m_data + m_start, &endptr, 10 ); // 10 is base 10 - if (endptr != m_data + m_start) { - return true; - } - } - return false; -} - -// only way to test is to try it! -inline bool pstring::is_double() const -{ - double out = 0.0; - if (m_start != m_end) { - char *endptr = m_data + m_start; - out = strtod( m_data + m_start, &endptr ); - if (endptr != m_data + m_start) { - return true; - } - } - return false; -} - -// Comparison - -inline bool compare(const pstring& a, const pstring& b, size_t n) -{ - if (n > a.length() || n > b.length()) { - return false; - //throw pstring::exception( pstring::exception::OUT_OF_RANGE ); - } - for (size_t i = 0; i < n; i++) { - if ( a.m_data[i+a.m_start] != b.m_data[i+b.m_start] ) { - return false; - } - } - return true; -} - -inline bool operator != (const pstring& a, const pstring& b) -{ - if (a.length() != b.length()) { - return true; - } - for (size_t i = 0; i < a.length(); i++) - { - if (a.m_data[i+a.m_start] != b.m_data[i+b.m_start]) { - return true; - } - } - return false; -} - -inline bool operator == (const pstring& a, const pstring& b) -{ - return !(a != b); -} - -inline bool operator < (const pstring& a, const pstring& b) // for storing in hash tables etc -{ - for (size_t i = 0; i < b.length(); i++) { - if (i == a.length()) { - return true; // <- if all characters are the same, but b is longer than a, then a < b - } - else if (a.m_data[i+a.m_start] < b.m_data[i+b.m_start]) { - return true; - } - else if (a.m_data[i+a.m_start] > b.m_data[i+b.m_start]) { - return false; - } - } - return false; -} - -inline bool operator > (const pstring& a, const pstring& b) // for storing in hash tables etc -{ - for (size_t i = 0; i < a.length(); i++) { - if (i == b.length()) { - return true; // <- if all characters are the same, but a is longer than b, then a > b - } - else if (a.m_data[i+a.m_start] > b.m_data[i+b.m_start]) { - return true; - } - else if (a.m_data[i+a.m_start] < b.m_data[i+b.m_start]) { - return false; - } - } - return false; -} - -inline pstring operator + (const pstring& a, const pstring& b) -{ - pstring str; - str.reserve(a.length() + b.length()); - str.m_start = 0; - for (size_t i = 0; i < str.m_end; i++) - { - str.m_data[i] = (i < a.length()) ? a.m_data[i+a.m_start] : - b.m_data[i+b.m_start - a.length()]; - } - return str; -} - -inline ostream& operator << (ostream& stream, const pstring& str) -{ - if (str.empty()) { - return stream; - } - return ( stream << str.c_str() ); -} - -inline istream& operator >> (istream& stream, pstring& str) -{ - // default is 128, but grows upto required length - if (str.m_alloc < 128) { - str.m_alloc = 128; - delete [] str.m_data; - str.m_data = new char [str.m_alloc]; - if (!str.m_data) - throw pexception( pexception::MEMORY_ALLOCATION ); - } - for (size_t i = 0; ; i++) { - if (i + 1 == str.m_alloc) { - char *old_data = str.m_data; - str.m_data = new char[str.m_alloc * 2]; - for (size_t j = 0; j < str.m_alloc; j++) - str.m_data[j] = old_data[j]; - delete [] old_data; - str.m_alloc *= 2; - } - stream.get( str.m_data[i] ); - // cross platform --- just do this yourself: \n is for MAC = 13, UNIX = 10, MS = 13,10 - if (str.m_data[i] == 10 || stream.eof() || stream.fail()) { - str.m_data[i] = '\0'; - break; - } - else if (str.m_data[i] == 13) { - if (stream.peek() == 10) - stream.get( str.m_data[i] ); - str.m_data[i] = '\0'; - break; - } - } - str.m_start = 0; - str.m_end = strlen(str.m_data); - return stream; -} - -// binary read / write - -inline bool pstring::read(istream& stream) -{ - // actually, required alloc is 1 less than required alloc due to null terminator - unsigned int required_alloc; - // n.b., there are 32-bit vs 64-bit size_t differences: you must read this in as an - // unisgned int, or suffer translation problems across platforms - stream.read( (char *) &required_alloc, sizeof(unsigned int) ); // n.b., do not change this to size_t as it will cause 32-bit to 64-bit conversion problems - if (required_alloc > 0 && m_alloc < required_alloc + 1) { - m_alloc = size_t(required_alloc + 1); - delete [] m_data; - m_data = new char [m_alloc]; - if (!m_data) - throw pexception( pexception::MEMORY_ALLOCATION ); - } - if (required_alloc != 0) { - stream.read(m_data, streamsize(required_alloc) * sizeof(char)); - m_data[required_alloc] = '\0'; - } - m_start = 0; - m_end = size_t(required_alloc); - - return true; -} - -inline bool pstring::write(ostream& stream) -{ - // n.b., do not change this to size_t as it will cause 32-bit to 64-bit conversion problems - unsigned int required_alloc = 0; - if (m_data) - required_alloc = (unsigned int)(m_end - m_start); - stream.write( (char *) &required_alloc, sizeof(unsigned int) ); - if (required_alloc > 0) - stream.write( m_data + m_start, required_alloc ); - return true; -} - -/* -// the default delim_list isn't liked in standard C++ -// this function does not appear to be used in depthmapX and has been removed -inline pstring readtoken(istream& stream, const pstring& delim_list) -{ - pstring str; - str.m_start = 0; - str.m_end = 0; - str.m_alloc = 128; - str.m_data = new char [str.m_alloc]; - - char single_char; - size_t here = paftl::npos; - - while ( !stream.eof() && str.m_end < 128 ) { - single_char = stream.get(); - if (here == -1) { - if (isprint(single_char) && delim_list.findindex(single_char) == paftl::npos) { - here = 0; - str.m_data[ 0 ] = single_char; - str.m_end++; - } - } - else { - here++; - if (!isprint(single_char) || delim_list.findindex(single_char) != paftl::npos) { - str.m_data[ str.m_end ] = '\0'; - return str; - } - else { - str.m_data[ str.m_end ] = single_char; - str.m_end++; - } - } - } - str.m_data[ str.m_end ] = '\0'; - return str; -} -*/ - -inline pstring& pstring::replace(char a) -{ - size_t i = m_start; - for (size_t j = m_start; j < m_end; i++, j++) { - if (a == m_data[j]) { - j++; - if (j == m_end) { - break; - } - } - m_data[i] = m_data[j]; - } - m_end = i; - m_data[ i ] = '\0'; - return *this; -} - -inline pstring& pstring::replace(char a, char b) -{ - for (size_t i = m_start; i < m_end; i++) { - if (a == m_data[i]) { - m_data[i] = b; - } - } - return *this; -} - -inline pstring& pstring::makelower() -{ - for (size_t i = m_start; i < m_end; i++) { - // ASCII caps - if (isupper(m_data[i])) { - m_data[i] = tolower(m_data[i]); - } - } - return *this; -} -inline pstring& pstring::makeupper() -{ - for (size_t i = m_start; i < m_end; i++) { - // ASCII lower - if (islower(m_data[i])) { - m_data[i] = toupper(m_data[i]); - } - } - return *this; -} -inline pstring& pstring::makeinitcaps() -{ - bool reset = true; - bool liter = false; - for (size_t i = m_start; i < m_end; i++) { - if (!isalpha(m_data[i])) { - reset = true; - if (m_data[i] == '\"') { - // ignore things within quotation marks - liter = !liter; - } - } - else if (!liter) { - if (reset) { - if (islower(m_data[i])) { - m_data[i] = toupper(m_data[i]); - } - } - else if (isupper(m_data[i])) { - m_data[i] = tolower(m_data[i]); - } - reset = false; - } - } - return *this; -} - - -/////////////////////////////////////////////////////////////////////////////// - -// Read and write runlength encoded vectors, with byte alignment through T - -// note: vector must have been allocated to accept stream -template -istream& read_rle( istream& stream, T *vector, size_t length ) -{ - unsigned char *data = (unsigned char *) vector; - for (size_t i = 0; i < sizeof(T); i++) { - unsigned char runlength = 0, current, last; - size_t count = 0; - while (count < length) { - stream.get((char&)current); - if (count && current == last) { - stream.get((char&)runlength); - } - else { - last = current; - runlength = 1; - } - for (size_t i = count; i < count + runlength; i++) { - data[i + sizeof(T) * count] = current; - } - count += runlength; - } - } - return stream; -} - -template ostream& write_rle( ostream& stream, T *vector, size_t length ) -{ - unsigned char *data = (unsigned char *) vector; - for (size_t i = 0; i < sizeof(T); i++) { - unsigned char runlength = 0, current; - size_t count = 0; - while (count < length) { - do { - current = data[i + sizeof(T) * count]; - runlength++; - count++; - } while (count < length && current == data[i + sizeof(T) * count] && runlength < 255); - if (runlength == 1) { - stream.put(current); - } - else { - stream.put(current); - stream.put(current); - runlength -= 1; // since we've written current twice anyway to mark the run - stream.put(runlength); - } - runlength = 0; - } - } - return stream; -} - -/////////////////////////////////////////////////////////////////////////////// - -// Hashing for LZW compression - -const size_t HASHBITSIZE = 12; -const size_t HASHTABLESIZE = 5021; // n.b., prime > 4096 -//const size_t HASHTABLESIZE = 65983; // n.b., prime > 65536 -const size_t HASHMAXVALUE = (1 << HASHBITSIZE) - 1; -const size_t HASHMAXCODE = HASHMAXVALUE - 1; - -struct phash -{ - unsigned int code; - unsigned int prefix; - unsigned char character; -}; - -class phashtable -{ -protected: - mutable size_t m_current; - unsigned int m_nextcode; - phash m_table[HASHTABLESIZE]; -public: - phashtable(); - void add_encode(unsigned int prefix, unsigned char character); - void add_decode(unsigned int prefix, unsigned char character); - size_t search(unsigned int prefix, unsigned char character) const; - unsigned char *decode(unsigned char *buffer, unsigned int code); - int getnextcode() - { return m_nextcode; } -}; - -inline phashtable::phashtable() -{ - for (size_t i = 0; i < HASHTABLESIZE; i++) { - m_table[i].code = -1; - } - m_nextcode = 256; // 0-255 for standard characters -} - -inline void phashtable::add_encode(unsigned int prefix, unsigned char character) -{ - if (m_nextcode <= HASHMAXCODE) { - m_table[m_current].code = m_nextcode; - m_table[m_current].prefix = prefix; - m_table[m_current].character = character; - m_nextcode++; - } -} - -inline void phashtable::add_decode(unsigned int prefix, unsigned char character) -{ - if (m_nextcode <= HASHMAXCODE) { - m_table[m_nextcode].prefix = prefix; - m_table[m_nextcode].character = character; - m_nextcode++; - } -} - -inline size_t phashtable::search(unsigned int prefix, unsigned char character) const -{ - // the bracket overkill on the following line ensures paftl.h compiles on a GNU compiler - m_current = (((unsigned int) character) << (HASHBITSIZE-8)) ^ prefix; - size_t offset; - if (m_current == 0) { - offset = 1; - } - else { - offset = HASHTABLESIZE - m_current; - } - while ( m_table[m_current].code != (unsigned int) -1 && - (m_table[m_current].prefix != prefix || m_table[m_current].character != character)) - { - if (offset > m_current) - m_current += HASHTABLESIZE; - m_current -= offset; - } - return m_table[m_current].code; -} - -inline unsigned char *phashtable::decode(unsigned char *buffer, unsigned int code) -{ - while (code > 255) - { - *buffer++ = m_table[code].character; - code = m_table[code].prefix; - } - *buffer = code; - return buffer; -} - -/////////////////////////////////////////////////////////////////////////////// - -// LZW as of June 2003 US patent has expired -// as of June 2004 the European patent expires - -// Note to paftl users: ensure that you meet patent requirements for your usage - -// LZW uses a class so that the hash table may be retained over multiple -// vector read / writes, as well as holding a read buffer - -// 12 bit, 4096 pattern holder - -// Note: you must *flush* after writing -- the idea is you can write several -// vectors before a flush - -template class plzw -{ -protected: - // read / write buffering - unsigned long m_bitbuffer; - bool m_bitswaiting; -protected: - bool m_firstever; - unsigned char m_character; - unsigned int m_prefix; - phashtable m_hashtable; - unsigned char m_decodedstring[HASHTABLESIZE]; // <- impossible that the decode string is ever as long as the hash table size -public: - plzw(); - istream& read( istream& stream, T *vector, int length ); - ostream& write( ostream& stream, T *vector, int length ); -protected: - istream& get(istream& stream, unsigned int& code); - ostream& put(ostream& stream, const unsigned int code); -}; - -template -plzw::plzw() -{ - m_firstever = true; - m_bitswaiting = false; -} - -template -istream& plzw::read(istream& stream, T *vector, int length ) -{ - unsigned char *data = (unsigned char *) vector; - unsigned char *string; - - if (m_firstever) { - get(stream, m_prefix); - m_character = m_prefix; - data[0] = m_character; - } - - // T is sequenced, as we assume that patterns will recur through aligned bytes of T - for (unsigned int i = (m_firstever ? 1 : 0); i < sizeof(T) * length;) { - unsigned int nextcode; - get(stream, nextcode); - if (nextcode >= (unsigned int) m_hashtable.getnextcode()) { - *m_decodedstring = m_character; - string = m_hashtable.decode(m_decodedstring + 1, m_prefix); - } - else { - string = m_hashtable.decode(m_decodedstring, nextcode); - } - m_character = *string; - if (i != 0) { - // this should be skipped on initial read - m_hashtable.add_decode(m_prefix,m_character); - } - while (string >= m_decodedstring && i < sizeof(T) * length) { - data[i] = *string--; - i++; - } - m_prefix = nextcode; - } - - // skip to next byte boundary for next read... (and retain context) - m_bitswaiting = false; - m_firstever = false; - - return stream; -} - -template -ostream& plzw::write(ostream& stream, T *vector, int length ) -{ - unsigned char *data = (unsigned char *) vector; - - m_prefix = data[0]; - - for (unsigned int i = 0; i < sizeof(T) * length; i++) { - m_character = data[i]; - int code = m_hashtable.search(m_prefix, m_character); - if (code != -1) { - m_prefix = code; - } - else { - m_hashtable.add_encode(m_prefix, m_character); - put(stream, m_prefix); - m_prefix = m_character; - } - } - - // skip to next byte boundary - put(stream, m_prefix); - if (m_bitswaiting) { - stream.put((unsigned char)(m_bitbuffer & 0xFF)); - m_bitswaiting = false; - } - - return stream; -} - -// stored, 1 and 2 are the 12-bit codes, -// a b & c are first 4 bits, second 4 bits and third four bits respectively -// b1 a1 -// c2 c1 -// b2 a2 - -template -istream& plzw::get(istream& stream, unsigned int& code) -{ - unsigned char bits; - if (!m_bitswaiting) { - stream.get((char&)bits); - code = bits; - stream.get((char&)bits); - code |= (bits & 0x0F) << 8; - m_bitbuffer = bits & 0xF0; - m_bitswaiting = true; - } - else { - stream.get((char&)bits); - code = ((unsigned int)bits) | (m_bitbuffer << 4); - m_bitswaiting = false; - } - - return stream; -} - -template -ostream& plzw::put(ostream& stream, const unsigned int code) -{ - if (!m_bitswaiting) { - stream.put((unsigned char)(code & 0xFF)); - m_bitbuffer = code >> 8; - m_bitswaiting = true; - } - else { - unsigned char bits; - bits = ((code >> 4) & 0xF0) | m_bitbuffer; - stream.put(bits); - stream.put((unsigned char)(code & 0xFF)); - m_bitswaiting = false; - } - - return stream; -} - -/////////////////////////////////////////////////////////////////////////////// - -// } // namespace paftl - -#endif +// Paf Template Library --- a set of useful C++ templates +// +// Copyright (c) 1996-2011 Alasdair Turner (a.turner@ucl.ac.uk) +// +//----------------------------------------------------------------------------- +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// +// See the lgpl.txt file for details +//----------------------------------------------------------------------------- +// +// Paf's cross platform box of tricks +// Everything you need to write any C++. All in one file! +// +// pmemvec base clase for pvector and prefvec +// pvector similar to STL vector +// prefvec pvector with a different allocator (vector of references) +// pqvector searchable prefvec +// pqmap a simple map class, based on a binary tree +// ptree a simple tree template +// pflipper used for flipping between two vectors (or anythings...) +// pexception exception class, base for various exception types +// +// +// A3 eliminates the double referencing used previously in the +// vector classes + +#ifndef __PAFTL_MGRAPH440_H__ +#define __PAFTL_MGRAPH440_H__ + +#include +#include +#include +#include +#include +#include + + +#ifdef _MSC_VER // MSVC compiler +#else + #include // not guaranteed to exist, but does in Mac / Ubuntu +#endif + +namespace mgraph440 { + +#define PAFTL_DATE "01-FEB-2011" +// 31-jan-2011: unicode constructor for pstring +// 04-aug-2010: fix bug on quicksort to avoid sorting zero length array +// 06-jun-2010: rewrite quicksort to avoid infinite loop +// 31-aug-2009: change pstring constructors to align with STL string +// 28-nov-2007: full implementation for ANSI standards +// 28-nov-2007: minor bug on pvecsub construction: should be 2 << count rather than 1 << count +// 30-aug-2007: make compatible with Unix / MacOS + + +#ifdef _WIN32 +// Quick mod - TV +#pragma warning (disable: 4996 ) +#pragma warning (disable: 4396 ) +#else + +#endif + +#ifdef _MSC_VER // MSVC compiler + typedef signed __int64 int64; + typedef unsigned __int64 uint64; +#else + typedef int64_t int64; + typedef uint64_t uint64; +#endif + +#ifndef bool +// #define bool int +#endif +#ifndef true + #define true 1 +#endif +#ifndef false + #define false 0 +#endif + +/////////////////////////////////////////////////////////////////////////////// + +// namespace paftl { + +class pexception; +template class pvector; +template class prefvec; +template class pqvector; +template class pqmap; +template class ptree; +template class pflipper; + +// a few basic types + +typedef pvector pvecint; +typedef pvector pvecfloat; +typedef pvector pvecdouble; + +/////////////////////////////////////////////////////////////////////////////// + +// miscellaneous enums (paftl used as namespace) + +namespace paftl +{ + enum add_t {ADD_UNIQUE, ADD_REPLACE, ADD_DUPLICATE, ADD_HERE}; + const size_t npos = size_t(-1); +} + +/////////////////////////////////////////////////////////////////////////////// + +class pexception +{ +public: + enum exception_t { UNDEFINED = 0x0000, + MEMORY_ALLOCATION = 0x0001, + FILE_ERROR = 0x0002, + MAX_ARRAY_EXCEEDED = 0x0003}; + +protected: + int m_exception; + size_t m_data; +public: + pexception(int n_exception = UNDEFINED, size_t data = 0) + { m_exception = n_exception; m_data = data; } + int error_code() + { return m_exception; } + size_t info() + { return m_data; } +}; + + +/////////////////////////////////////////////////////////////////////////////// + +// pmemvec: base allocation for pvector and prefvec + +template class pmemvec +{ +public: + class exception : public pexception + { + public: + enum exception_t { PVECTOR_UNDEFINED = 0x1000, + EMPTY_VECTOR = 0x1001, + UNASSIGNED_ITERATOR = 0x1002, + OUT_OF_RANGE = 0x1003}; + public: + exception(int n_exception = PVECTOR_UNDEFINED, size_t data = 0) : pexception( n_exception, data ) {} + }; +protected: + T *m_data; + unsigned short m_shift; + size_t m_length; +public: + // redefine + pmemvec(size_t sz = 0); + pmemvec(const pmemvec& ); + virtual ~pmemvec(); + pmemvec& operator = (const pmemvec& ); + // + virtual void push_back(const T& item); + virtual void pop_back(); + virtual void remove_at(size_t pos = 0); + virtual void remove_at(const pvecint& list); + virtual void insert_at(size_t pos, const T& item); + // + virtual void set(size_t count); + virtual void set(const T& item, size_t count); + // + virtual void clear(); + virtual void clearnofree(); +protected: + size_t storage_size() const + { return m_shift ? (2 << m_shift) : 0; } + void grow(size_t pos); + void shrink(); +public: + size_t size() const + { return m_length; } + T& base_at(size_t pos) + { return m_data[pos]; } + const T& base_at(size_t pos) const + { return m_data[pos]; } +public: + ::std::istream& read( ::std::istream& stream, ::std::streampos offset = ::std::streampos(-1) ); + ::std::ostream& write( ::std::ostream& stream ); +}; + +template +pmemvec::pmemvec(size_t sz) +{ + // note: uses same as grow / storage_size, but cannot rely on function existence when calling constructor + if (sz == 0) { + m_data = NULL; + m_shift = 0; + } + else { + do { + m_shift++; + } while ((size_t(2) << m_shift) < sz); + m_data = new T [storage_size()]; + if (m_data == NULL) { + throw pexception(pexception::MEMORY_ALLOCATION, sizeof(T) * storage_size()); + } + } + m_length = 0; +} + +template +pmemvec::pmemvec(const pmemvec& v) +{ + m_shift = v.m_shift; + m_length = v.m_length; + + if (m_shift) { + m_data = new T [storage_size()]; + if (m_data == NULL) + throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * storage_size() ); + + if (m_length) { + for (size_t i = 0; i < m_length; i++) + m_data[i] = v.m_data[i]; + } + } + else { + m_data = NULL; + } +} + +template +pmemvec::~pmemvec() +{ + if (m_data) + { + delete [] m_data; + m_data = NULL; + } +} + +template +pmemvec& pmemvec::operator = (const pmemvec& v) +{ + if (m_shift < v.m_shift) + { + if (m_shift != 0) { + delete [] m_data; + } + m_shift = v.m_shift; + if (m_shift) { + m_data = new T [storage_size()]; + if (!m_data) + throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * storage_size() ); + } + else { + m_data = NULL; + } + } + m_length = v.m_length; + if (m_length) { + for (size_t i = 0; i < m_length; i++) + m_data[i] = v.m_data[i]; + } + return *this; +} + +template +void pmemvec::push_back(const T& item) +{ + if (m_length >= storage_size()) { + grow( m_length ); + } + m_data[m_length] = item; + m_length++; +} + +template +void pmemvec::pop_back() +{ + if (m_length == 0) + throw exception( exception::EMPTY_VECTOR ); + + --m_length; + + // Preferably include shrink code here +} + +template +void pmemvec::insert_at(size_t pos, const T& item) +{ + if (pos == paftl::npos || pos > m_length) { + throw exception( exception::OUT_OF_RANGE ); + } + if (m_length >= storage_size()) { + grow( pos ); + } + else { + for (size_t i = m_length; i > pos; i--) { + m_data[i] = m_data[i - 1]; + } + } + m_data[pos] = item; + m_length++; +} + +template +void pmemvec::remove_at(size_t pos) +{ + // This is a simple but reliable remove item from vector + if (m_length == 0) + throw exception( exception::EMPTY_VECTOR ); + else if (pos == paftl::npos || pos >= m_length) + throw exception( exception::OUT_OF_RANGE ); + + for (size_t i = pos; i < m_length - 1; i++) { + m_data[i] = m_data[i + 1]; + } + --m_length; + + // Preferably include shrink code here +} + +template +void pmemvec::set(size_t count) +{ + clear(); + do { + m_shift++; + } while ((size_t(2) << m_shift) < count); + m_data = new T [storage_size()]; + if (!m_data) + throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * storage_size() ); + m_length = count; +} + +template +void pmemvec::set(const T& item, size_t count) +{ + clear(); + do { + m_shift++; + } while ((size_t(2) << m_shift) < count); + m_data = new T [storage_size()]; + if (!m_data) + throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * storage_size() ); + m_length = count; + for (size_t i = 0; i < m_length; i++) { + m_data[i] = item; + } +} + +template +void pmemvec::clear() +{ + m_length = 0; + m_shift = 0; + if (m_data) + { + delete [] m_data; + m_data = NULL; + } +} + +template +void pmemvec::clearnofree() +{ + m_length = 0; +} + +template +void pmemvec::grow(size_t pos) +{ + m_shift++; + + T *new_data = new T [storage_size()]; + if (!new_data) + throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * storage_size() ); + + if (m_length) { + for (size_t i = 0; i < m_length + 1; i++) + new_data[i] = (i < pos) ? m_data[i] : m_data[i-1]; + } + if (m_data) { + delete [] m_data; + } + m_data = new_data; +} + +template +void pmemvec::shrink() +{ +} + +template +::std::istream& pmemvec::read( ::std::istream& stream, ::std::streampos offset ) +{ + if (offset != ::std::streampos(-1)) { + stream.seekg( offset ); + } + // READ / WRITE USES 32-bit LENGTHS (number of elements) + // n.b., do not change this to size_t as it will cause 32-bit to 64-bit conversion problems + unsigned int length; + stream.read( (char *) &length, sizeof(unsigned int) ); + m_length = size_t(length); + if (m_length >= storage_size()) { + if (m_data) { + delete [] m_data; + m_data = NULL; + } + while (m_length >= storage_size()) + m_shift++; + m_data = new T [storage_size()]; + if (!m_data) + throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * storage_size() ); + } + if (m_length != 0) { + stream.read( (char *) m_data, sizeof(T) * ::std::streamsize(m_length) ); + } + return stream; +} + +template +::std::ostream& pmemvec::write( ::std::ostream& stream ) +{ + // READ / WRITE USES 32-bit LENGTHS (number of elements) + // n.b., do not change this to size_t as it will cause 32-bit to 64-bit conversion problems + + // check for max unsigned int exceeded + if (m_length > size_t((unsigned int)-1)) { + throw pexception( pexception::MAX_ARRAY_EXCEEDED, m_length ); + } + // n.b., do not change this to size_t as it will cause 32-bit to 64-bit conversion problems + unsigned int length = (unsigned int)(m_length); + stream.write( (char *) &length, sizeof(unsigned int) ); + if (m_length != 0) { + stream.write( (char *) m_data, sizeof(T) * ::std::streamsize(m_length) ); + } + return stream; +} + +/////////////////////////////////////////////////////////////////////////////// + +template class pvector : public pmemvec +{ +protected: + mutable size_t m_current; +public: + pvector(size_t sz = 0) : pmemvec(sz) + {m_current = paftl::npos;} + pvector(const pvector& v) : pmemvec(v) + {m_current = v.m_current;} + pvector& operator = (const pvector& ); + virtual ~pvector() + {;} + // + T& at(size_t pos) + { return pmemvec::m_data[pos]; } + const T& at(size_t pos) const + { return pmemvec::m_data[pos]; } + T& operator[](size_t pos) + { return at(pos); } + const T& operator[](size_t pos) const + { return at(pos); } + // + T& head() + { return at(0); } + const T& head() const + { return at(0); } + T& tail() + { return at(pmemvec::m_length-1); } + const T& tail() const + { return at(pmemvec::m_length-1); } + // standard operations (unordered vector) + T& find(const T& item); + const T& find(const T& item) const; + size_t findindex(const T& item) const; + // binary operations (ordered vector) + size_t add(const T& item, int type = paftl::ADD_UNIQUE); // ignored if already exists + T& search(const T& item); + const T& search(const T& item) const; + size_t searchindex(const T& item) const; + size_t searchfloorindex(const T& item) const; + size_t searchceilindex(const T& item) const; + void remove(const T& item) + { pmemvec::remove_at(searchindex(item)); } + // set operations (ordered vector) + void operator += (const pvector& v); + // qsort algo: + void sort(); + void sort(size_t left, size_t right); + // + + // Quick mod - TV +#if defined(_MSC_VER) + friend pvector intersect(const pvector& a, const pvector& b); +#endif +}; + +template +pvector& pvector::operator = (const pvector& v) +{ + if (&v != this) + { + pmemvec::operator = (v); + } + return *this; +} + +template +T& pvector::find(const T& item) +{ + if (findindex(item) == paftl::npos) { + throw pmemvec::exception::exception(pmemvec::exception::OUT_OF_RANGE); + } + return at(m_current); +} +template +const T& pvector::find(const T& item) const +{ + if (findindex(item) == paftl::npos) { + throw pmemvec::exception(pmemvec::exception::OUT_OF_RANGE); + } + return at(m_current); +} + +template +size_t pvector::findindex(const T& item) const +{ + for (size_t i = 0; i < pmemvec::m_length; i++) { + if (at(i) == item) { + m_current = i; + return i; + } + } + return paftl::npos; +} + +// oops... we need an iterator... add use a current position marker. + +template +T& pvector::search(const T& item) +{ + if (searchindex(item) == paftl::npos) { + throw pmemvec::exception(pmemvec::exception::OUT_OF_RANGE); // Not found + } + return at(m_current); +} +template +const T& pvector::search(const T& item) const +{ + if (searchindex(item) == paftl::npos) { + throw pmemvec::exception(pmemvec::exception::OUT_OF_RANGE); // Not found + } + return at(m_current); +} + +template +size_t pvector::searchindex(const T& item) const +{ + if (pmemvec::m_length != 0) { + size_t ihere, ifloor = 0, itop = pmemvec::m_length - 1; + while (itop != paftl::npos && ifloor <= itop) { + m_current = ihere = (ifloor + itop) / 2; + if (item == at(ihere)) { + return m_current; + } + else if (item > at(ihere)) { + ifloor = ihere + 1; + } + else { + itop = ihere - 1; + } + } + } + return paftl::npos; +} + +template +size_t pvector::searchfloorindex(const T& item) const +{ + searchindex(item); + while (m_current != 0 && at(m_current) > item) { + m_current--; + } + return m_current; +} + +template +size_t pvector::searchceilindex(const T& item) const +{ + searchindex(item); + while (m_current < pmemvec::m_length && at(m_current) < item) { + m_current++; + } + return m_current; +} + + +// Note: uses m_current set by searchindex + +// Really need a list 'merge' function as well... will write this soon! + +template +size_t pvector::add(const T& item, int type) // UNIQUE by default +{ + size_t where = paftl::npos; + if (pmemvec::m_length == 0 || item > pvector::tail()) { // often used for push_back, so handle quickly if so + pmemvec::push_back( item ); + where = pmemvec::m_length - 1; + } + else { + // if you call with ADD_HERE, it is assumed you've just used search or searchindex + // i.e., we don't need to go through the binary search again to find the insert position + if (type != paftl::ADD_HERE) { + searchindex(item); + } + if (item < at(m_current)) { + pmemvec::insert_at( m_current, item ); + where = m_current; + } + else if (item > at(m_current) || type == paftl::ADD_DUPLICATE) { + pmemvec::insert_at( m_current + 1, item ); + where = m_current + 1; + } + else if (type == paftl::ADD_REPLACE || type == paftl::ADD_HERE) { + // relies on good assignment operator + at(m_current) = item; + } + // n.b., type "UNIQUE" does not replace, returns -1 + } + return where; +} + +template +void pvector::operator += (const pvector& v) +{ + if (this != &v && pmemvec::m_length + v.pmemvec::m_length > 0) { + + while (pmemvec::m_length + v.pmemvec::m_length >= pmemvec::storage_size()) + pmemvec::m_shift++; + + T *new_data = new T [pmemvec::storage_size()]; + if (!new_data) + throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * pmemvec::storage_size() ); + + size_t i = 0, j = 0, k = 0; + while (i + j < pmemvec::m_length + v.pmemvec::m_length) { + if ( i < pmemvec::m_length ) { + if (j < v.pmemvec::m_length) { + if (pmemvec::m_data[i] < v.pmemvec::m_data[j]) { + new_data[k++] = pmemvec::m_data[i++]; + } + else if (pmemvec::the_data()[i] > v.pmemvec::the_data()[j]) { + new_data[k++] = v.pmemvec::m_data[j++]; + } + else { + new_data[k++] = pmemvec::m_data[i++]; j++; + } + } + else { + while (i < pmemvec::m_length) { + new_data[k++] = pmemvec::m_data[i++]; + } + } + } + else { + while (j < v.pmemvec::m_length) { + new_data[k++] = v.pmemvec::m_data[j++]; + } + } + } + if (pmemvec::m_data) { + delete [] pmemvec::m_data; + } + pmemvec::m_length = k; + pmemvec::m_data = new_data; + } +} + +template +void pvector::sort() +{ + if (pmemvec::m_length != 0) { + sort(0,pmemvec::m_length-1); + } +} + +// rewrite 6-jun-10 (was entering infinite loop, now appears to work properly) +template +void pvector::sort(size_t left, size_t right) +{ + size_t i = left, j = right; + const T& val = pmemvec::m_data[(left+right)/2]; + while (j != paftl::npos && i <= j) { + while (i <= j && pmemvec::m_data[i] < val) + i++; + while (j != paftl::npos && pmemvec::m_data[j] > val) + j--; + if (j != paftl::npos && i <= j) { + // swap contents + T temp = pmemvec::m_data[i]; + pmemvec::m_data[i] = pmemvec::m_data[j]; + pmemvec::m_data[j] = temp; + i++; j--; + } + } + if (j != paftl::npos && left < j) + sort(left, j); + if (i < right) + sort(i, right); +} + +// requires two sorted lists +template +inline pvector intersect(const pvector& a, const pvector& b) +{ + pvector retvec; + size_t i = 0; + size_t j = 0; + while (i < a.size() && j < b.size()) { + if (a[i] == b[j]) { + retvec.push_back(a[i]); + i++; j++; + } + else { + while (a[i] < b[j] && i < a.size()) { + i++; + } + while (a[i] > b[j] && j < b.size()) { + j++; + } + } + } + return retvec; +} + +/////////////////////////////////////////////////////////////////////////////// + +// this version for bulk deletes: copies over entries to new list +// (first requires pvector to have been defined) + +template +void pmemvec::remove_at(const pvecint& list) +{ + if (m_length == 0) + throw exception( exception::EMPTY_VECTOR ); + if (list.size() >= m_length) { + // if the list does not contain duplicates, then this simply means delete all contents: + clear(); + return; + } + // shrink new vector: + while ((m_length - list.size()) * 2 < storage_size()) { + m_shift--; + } + size_t new_length = 0; + T *new_data = new T [storage_size()]; + bool *rem_flag = new bool [m_length]; + if (!new_data) + throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * storage_size() ); + if (!rem_flag) + throw pexception( pexception::MEMORY_ALLOCATION, sizeof(bool) * storage_size() ); + size_t i; + for (i = 0; i < m_length; i++) { + rem_flag[i] = false; + } + for (i = 0; i < list.size(); i++) { + if (size_t(list[i]) == paftl::npos || size_t(list[i]) >= m_length) + throw exception( exception::OUT_OF_RANGE ); + rem_flag[list[i]] = true; + } + for (i = 0; i < m_length; i++) { + if (!rem_flag[i]) { + new_data[new_length] = m_data[i]; + new_length++; + } + } + m_length = new_length; + delete [] m_data; + delete [] rem_flag; + m_data = new_data; +} + +/////////////////////////////////////////////////////////////////////////////// + +// prefvec: a vector of references (useful for larger objects) +// should be able to use pqvector in most cases + +template class prefvec : public pmemvec +{ +public: + prefvec(size_t sz = 0) : pmemvec(sz) + {;} + prefvec(const prefvec& ); + virtual ~prefvec(); + prefvec& operator = (const prefvec& ); + // + void push_back(const T& item); + void pop_back(); + void remove_at(size_t pos = 0); + void free_at(size_t pos = 0); + void remove_at(const pvecint& list); + void insert_at(size_t pos, const T& item); + // + void set(size_t count); + void set(const T& item, size_t count); + // + void clear(); + void clearnofree(); + // + T& at(size_t pos) + { return *(pmemvec::m_data[pos]); } + const T& at(size_t pos) const + { return *(pmemvec::m_data[pos]); } + T& operator[](size_t pos) + { return at(pos); } + const T& operator[](size_t pos) const + { return at(pos); } + // + T& head() + { return at(0); } + const T& head() const + { return at(0); } + T& tail() + { return at(pmemvec::m_length-1); } + const T& tail() const + { return at(pmemvec::m_length-1); } + // + // NOTE: no find (as often equivalence operator will not be defined) + // + // Override read and write + ::std::istream& read( ::std::istream& stream ); + ::std::ostream& write( ::std::ostream& stream ); +}; + +template +prefvec::prefvec(const prefvec& v) : pmemvec(v) +{ + for (size_t i = 0; i < pmemvec::m_length; i++) { + pmemvec::m_data[i] = new T(v.at(i)); + if (pmemvec::m_data[i] == NULL) { + throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) ); + } + } +} + +template +prefvec& prefvec::operator = (const prefvec& v) +{ + if (&v != this) { + for (size_t i = 0; i < pmemvec::m_length; i++) { + delete pmemvec::m_data[i]; + } + pmemvec::operator = (v); + for (size_t j = 0; j < pmemvec::m_length; j++) { + pmemvec::m_data[j] = new T(v.at(j)); + if (pmemvec::m_data[j] == NULL) { + throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) ); + } + } + } + return *this; +} + +template +prefvec::~prefvec() +{ + for (size_t i = 0; i < pmemvec::m_length; i++) { + if (pmemvec::m_data[i]) + delete pmemvec::m_data[i]; + } + // virtual destructor called for pmemvec +} + +template +void prefvec::push_back(const T& item) +{ + T *p = new T(item); + pmemvec::push_back( p ); +} + +template +void prefvec::pop_back() +{ + if (pmemvec::m_data[pmemvec::m_length - 1]) { + delete pmemvec::m_data[pmemvec::m_length - 1]; + pmemvec::m_data[pmemvec::m_length - 1] = NULL; + } + pmemvec::pop_back(); +} + +template +void prefvec::remove_at(size_t pos) +{ + if (pmemvec::m_length == 0) + throw (typename pmemvec::exception)( pmemvec::exception::EMPTY_VECTOR ); + else if (pos == paftl::npos || pos >= pmemvec::m_length) + throw (typename pmemvec::exception)( pmemvec::exception::OUT_OF_RANGE ); + + if (pmemvec::m_data[pos]) { + delete pmemvec::m_data[pos]; + pmemvec::m_data[pos] = NULL; + } + pmemvec::remove_at( pos ); +} + +// just frees the memory at position: does not manipulate vector + +template +void prefvec::free_at(size_t pos) +{ + if (pmemvec::m_length == 0) + throw (typename pmemvec::exception)( pmemvec::exception::EMPTY_VECTOR ); + else if (pos == paftl::npos || pos >= pmemvec::m_length) + throw (typename pmemvec::exception)( pmemvec::exception::OUT_OF_RANGE ); + + delete pmemvec::m_data[pos]; + pmemvec::m_data[pos] = NULL; +} + +// this version for intended for bulk deletes (also retains previous ordering) +template +void prefvec::remove_at(const pvecint& list) +{ + if (pmemvec::m_length == 0) + throw (typename pmemvec::exception)( pmemvec::exception::EMPTY_VECTOR ); + + for (size_t i = 0; i < list.size(); i++) { + if (size_t(list[i]) == paftl::npos || size_t(list[i]) >= pmemvec::m_length) + throw (typename pmemvec::exception)( pmemvec::exception::OUT_OF_RANGE ); + if (pmemvec::m_data[list[i]]) { + delete pmemvec::m_data[list[i]]; + pmemvec::m_data[list[i]] = NULL; + } + } + pmemvec::remove_at( list ); +} + + +template +void prefvec::insert_at(size_t pos, const T& item) +{ + T *p = new T(item); + if (p == NULL) { + throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) ); + } + pmemvec::insert_at(pos, p); +} + +template +void prefvec::set(size_t count) +{ + pmemvec::set(count); + for (size_t i = 0; i < pmemvec::m_length; i++) { + pmemvec::m_data[i] = NULL; + if (pmemvec::m_data[i] == NULL) { + throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) ); + } + } +} + +template +void prefvec::set(const T& item, size_t count) +{ + pmemvec::set(count); + for (size_t i = 0; i < pmemvec::m_length; i++) { + pmemvec::m_data[i] = new T(item); + if (pmemvec::m_data[i] == NULL) { + throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) ); + } + } +} + + +template +void prefvec::clear() +{ + for (size_t i = 0; i < pmemvec::m_length; i++) { + if (pmemvec::m_data[i]) { + delete pmemvec::m_data[i]; + pmemvec::m_data[i] = NULL; + } + } + pmemvec::clear(); +} + +template +void prefvec::clearnofree() +{ + // still have to delete objects pointed to, just doesn't just clear the list of pointers: + for (size_t i = 0; i < pmemvec::m_length; i++) { + if (pmemvec::m_data[i]) { + delete pmemvec::m_data[i]; + pmemvec::m_data[i] = NULL; + } + } + pmemvec::clearnofree(); +} + +// Note: read and write only work for structures without pointers + +template +::std::istream& prefvec::read( ::std::istream& stream ) +{ + for (size_t i = 0; i < pmemvec::m_length; i++) { + if (pmemvec::m_data[i]) { + delete pmemvec::m_data[i]; + pmemvec::m_data[i] = NULL; + } + } + // READ / WRITE USES 32-bit LENGTHS (number of elements) + // n.b., do not change this to size_t as it will cause 32-bit to 64-bit conversion problems + unsigned int length; + stream.read( (char *) &length, sizeof(unsigned int) ); + if (stream.fail()) { + throw pexception(pexception::FILE_ERROR); + } + pmemvec::m_length = size_t(length); + if (pmemvec::m_length >= pmemvec::storage_size()) { + if (pmemvec::m_data) { + delete [] pmemvec::m_data; + } + while (pmemvec::m_length >= pmemvec::storage_size()) + pmemvec::m_shift++; + pmemvec::m_data = new T * [pmemvec::storage_size()]; + if (pmemvec::m_data == NULL) { + throw pexception( pexception::MEMORY_ALLOCATION, pmemvec::storage_size() * sizeof(T) ); + } + } + for (size_t j = 0; j < pmemvec::m_length; j++) { + T *p = new T; + if (p == NULL) { + throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) ); + } + stream.read( (char *) p, sizeof(T) ); + if (stream.fail()) { + throw pexception(pexception::FILE_ERROR); + } + pmemvec::m_data[j] = p; + } + return stream; +} + +template +::std::ostream& prefvec::write( ::std::ostream& stream ) +{ + // READ / WRITE USES 32-bit LENGTHS (number of elements) + // n.b., do not change this to size_t as it will cause 32-bit to 64-bit conversion problems + + // check for max unsigned int exceeded + if (pmemvec::m_length > size_t((unsigned int)-1)) { + // Quick mod - TV +#if 0 + throw exception( pexception::MAX_ARRAY_EXCEEDED, pmemvec::m_length ); +#else + ; +#endif + } + + // n.b., do not change this to size_t as it will cause 32-bit to 64-bit conversion problems + unsigned int length = (unsigned int)(pmemvec::m_length); + stream.write( (char *) &length, sizeof(unsigned int) ); + + for (size_t i = 0; i < pmemvec::m_length; i++) { + stream.write( (char *) &at(i), sizeof(T) ); + } + return stream; +} + +/////////////////////////////////////////////////////////////////////////////// + +// pqvector... prefvec with the binary addition routine... +// (i.e., almost the hash table...) + +// (so... I think we might replace pqmap with an inherited form of this soon) +// (if MS would oblige...) + +template class pqvector : public prefvec +{ +protected: + mutable size_t m_current; +public: + pqvector(size_t sz = 0) : prefvec(sz) {;} + pqvector(const pqvector& v) : prefvec( v ) {;} + virtual ~pqvector() {;} + pqvector& operator = (const pqvector& v) + { prefvec::operator = (v); return *this; } + // + // at, [] and so on as before + // + // standard operations (unordered vector) + T& find(const T& item); + const T& find(const T& item) const; + size_t findindex(const T& item) const; + // + // binary operations (ordered vector) + T& search(const T& item); + const T& search(const T& item) const; + size_t searchindex(const T& item) const; + void remove(const T& item) + { remove_at(searchindex(item)); } + size_t add(const T& item, int type = paftl::ADD_UNIQUE); + T& current() + { return prefvec::at(m_current); } + const T& current() const + { return pmemvec::at(m_current); } + // qsort algo: + void sort(); + void sort(size_t left, size_t right); +}; + +template +T& pqvector::find(const T& item) +{ + if (findindex(item) == paftl::npos) { + throw pmemvec::exception(pmemvec::exception::OUT_OF_RANGE); + } + return prefvec::at(m_current); +} +template +const T& pqvector::find(const T& item) const +{ + if (findindex(item) == paftl::npos) { + throw pmemvec::exception(pmemvec::exception::OUT_OF_RANGE); + } + return prefvec::at(m_current); +} + +template +size_t pqvector::findindex(const T& item) const +{ + for (size_t i = 0; i < pmemvec::m_length; i++) { + if (prefvec::at(i) == item) { + m_current = i; + return i; + } + } + return paftl::npos; +} + +// oops... we need an iterator... add use a current position marker. + +template +T& pqvector::search(const T& item) +{ + if (searchindex(item) == paftl::npos) { + throw (typename pmemvec::exception)(pmemvec::exception::OUT_OF_RANGE); // Not found + } + return prefvec::at(m_current); +} +template +const T& pqvector::search(const T& item) const +{ + if (searchindex(item) == paftl::npos) { + throw (typename pmemvec::exception)(pmemvec::exception::OUT_OF_RANGE); // Not found + } + return prefvec::at(m_current); +} + +template +size_t pqvector::searchindex(const T& item) const +{ + if (pmemvec::size() != 0) { + size_t ihere, ifloor = 0, itop = pmemvec::size() - 1; + while (itop != paftl::npos && ifloor <= itop) { + m_current = ihere = (ifloor + itop) / 2; + if (item == prefvec::at(ihere)) { + return m_current; + } + else if (item > prefvec::at(ihere)) { + ifloor = ihere + 1; + } + else { + itop = ihere - 1; + } + } + } + return paftl::npos; +} + +// Note: uses m_current set by searchindex + +// Really need a list 'merge' function as well... will write this soon! + +template +size_t pqvector::add(const T& item, int type) // default type UNIQUE +{ + size_t where = paftl::npos; + if (pmemvec::size() == 0 || item > prefvec::tail()) { // often used for push_back, so handle quickly if so + prefvec::push_back( item ); + where = pmemvec::size() - 1; + } + else { + // if you call with ADD_HERE, it is assumed you've just used search or searchindex + // i.e., we don't need to go through the binary search again to find the insert position + if (type != paftl::ADD_HERE) { + searchindex(item); + } + if (item < prefvec::at(m_current)) { + prefvec::insert_at( m_current, item ); + where = m_current; + } + else if (item > prefvec::at(m_current) || type == paftl::ADD_DUPLICATE) { + prefvec::insert_at( m_current + 1, item ); + where = m_current + 1; + } + else if (type == paftl::ADD_REPLACE || type == paftl::ADD_HERE) { + // relies on good assignment operator + prefvec::at(m_current) = item; + } + // n.b., type "UNIQUE" does not replace, returns paftl::npos + } + return where; +} + +template +void pqvector::sort() +{ + if (pmemvec::m_length != 0) { + sort(0,pmemvec::m_length-1); + } +} + +// rewrite 6-jun-10 (was entering infinite loop, now appears to work properly) +template +void pqvector::sort(size_t left, size_t right) +{ + size_t i = left, j = right; + const T& val = prefvec::at((left+right)/2); + while (j != paftl::npos && i <= j) { + while (i <= j && prefvec::at(i) < val) + i++; + while (j != paftl::npos && prefvec::at(j) > val) + j--; + if (j != paftl::npos && i <= j) { + // swap contents (using pointer) + T* temp = pmemvec::m_data[i]; + pmemvec::m_data[i] = pmemvec::m_data[j]; + pmemvec::m_data[j] = temp; + i++; j--; + } + } + if (j != paftl::npos && left < j) + sort(left, j); + if (i < right) + sort(i, right); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +// psubvec is based on pvector, designed for arrays of chars or shorts, it subsumes itself +// so can be stored as a single pointer: useful if you have a lot of empty arrays + +template class psubvec +{ +public: + static const T npos = -1; +protected: + T *m_data; +public: + psubvec() + { m_data = NULL; } + psubvec(const psubvec& ); + ~psubvec(); + psubvec& operator = (const psubvec& ); + // + virtual void push_back(const T item); + virtual void clear(); +public: + bool isEmpty() // isEmpty is provided in addition to size as is quicker to test + { return m_data == NULL; } + T size() const + { return m_data ? m_data[0] : 0; } + T& operator [] (T pos) + { return m_data[pos+1]; } + const T& operator [] (T pos) const + { return m_data[pos+1]; } +public: + ::std::istream& read(::std::istream& stream, ::std::streampos = -1); + ::std::ostream& write( ::std::ostream& stream ); +}; + +template +psubvec::psubvec(const psubvec& v) +{ + if (v.m_data) { + T length = v.m_data[0]; + T count = 0; + while (length >>= 1) // find bit length (note: cannot assume int) + count++; + m_data = new T [2 << count]; + if (m_data == NULL) { + throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * size_t(2 << count) ); + } + length = v.m_data[0]; + for (T i = 0; i < length + 1; i++) { + m_data[i] = v.m_data[i]; + } + } + else { + m_data = NULL; + } +} + +template +psubvec::~psubvec() +{ + if (m_data) + { + delete [] m_data; + m_data = NULL; + } +} + +template +psubvec& psubvec::operator = (const psubvec& v) +{ + if (this != &v) { + if (v.m_data) { + T length = v.m_data[0]; + T count = 0; + while (length >>= 1) // find bit length (note: cannot assume int) + count++; + m_data = new T [2 << count]; + if (m_data == NULL) { + throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * size_t(2 << count) ); + } + length = v.m_data[0]; + for (T i = 0; i < length + 1; i++) { + m_data[i] = v.m_data[i]; + } + } + else { + m_data = NULL; + } + } + return *this; +} + +template +void psubvec::push_back(const T item) +{ + if (!m_data) { + m_data = new T [2]; + m_data[0] = 1; + m_data[1] = item; + } + else { + T length = m_data[0] + 1; + if ((length & (length - 1)) == 0) { // determine if next length would be power of 2 + T *new_data = new T [length << 1]; + if (new_data == NULL) { + throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * size_t(length << 1) ); + } + for (T i = 0; i < length; i++) + new_data[i] = m_data[i]; + delete [] m_data; + m_data = new_data; + } + m_data[0] = length; + m_data[length] = item; + } +} + +template +void psubvec::clear() +{ + if (m_data) + { + delete [] m_data; + m_data = NULL; + } +} + +template +::std::istream& psubvec::read( ::std::istream& stream, ::std::streampos ) +{ + if (m_data) { + delete [] m_data; + m_data = NULL; + } + T length; + stream.read( (char *) &length, sizeof(T) ); + if (length) { + T copy = length; + T count = 0; + while (length >>= 1) // find bit length (note: cannot assume int) + count++; + m_data = new T [2 << count]; + if (m_data == NULL) { + throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * size_t(2 << count) ); + } + stream.read((char *) &m_data, sizeof(T)*(copy+1) ); + } + return stream; +} + +template +::std::ostream& psubvec::write( ::std::ostream& stream ) +{ + if (m_data) { + stream.write((char *) &m_data, sizeof(T)*(m_data[0]+1)); + } + return stream; +} + + + +/////////////////////////////////////////////////////////////////////////////////////////////// + +// And now the quick mapping routine + +// Helper class keyvaluepair... + +template class keyvaluepair { +public: + T1 m_key; + T2 m_value; +public: + keyvaluepair(const T1 key = T1(), const T2 value = T2()) + { m_key = key; m_value = value; } + T1& key() { return m_key; } + const T1 key() const { return m_key; } + T2& value() { return m_value; } + const T2& value() const { return m_value; } + + ::std::istream& read( ::std::istream& stream ); + ::std::ostream& write( ::std::ostream& stream ); +}; +template +inline bool operator == (const keyvaluepair& a, const keyvaluepair& b) +{ return (a.m_key == b.m_key); } +template +inline bool operator < (const keyvaluepair& a, const keyvaluepair& b) +{ return (a.m_key < b.m_key); } +template +inline bool operator > (const keyvaluepair& a, const keyvaluepair& b) +{ return (a.m_key > b.m_key); } +// Note: read and write only work for structures without pointers +template +::std::istream& keyvaluepair::read( ::std::istream& stream ) +{ + stream.read( (char *) &m_key, sizeof(T1) ); + stream.read( (char *) &m_value, sizeof(T2) ); + return stream; +} +template +::std::ostream& keyvaluepair::write( ::std::ostream& stream ) +{ + stream.write( (char *) &m_key, sizeof(T1) ); + stream.write( (char *) &m_value, sizeof(T2) ); + return stream; +} + +template class keyvaluepairref +{ + // Quick mod - TV +#if defined(_MSC_VER) +protected: +#else +public: +#endif + T1 m_key; + T2 *m_value; +public: + keyvaluepairref(const T1 key = T1()) + { m_key = key; m_value = NULL; } + keyvaluepairref(const T1 key, const T2& value) + { m_key = key; m_value = new T2(value); } + keyvaluepairref(const keyvaluepairref& k) + { m_key = k.m_key; m_value = new T2(*(k.m_value)); } + keyvaluepairref& operator = (const keyvaluepairref& k) + { + if (this != &k) + { + m_key = k.m_key; + m_value = new T2(*(k.m_value)); + } + return *this; + } + virtual ~keyvaluepairref() + { if (m_value) {delete m_value; m_value = NULL;} } + T1& key() { return m_key; } + const T1 key() const { return m_key; } + T2& value() { return *m_value; } + const T2& value() const { return *m_value; } + + // Quick mod - TV +#if defined(_MSC_VER) + friend bool operator == (const keyvaluepairref& a, const keyvaluepairref& b); + friend bool operator < (const keyvaluepairref& a, const keyvaluepairref& b); + friend bool operator > (const keyvaluepairref& a, const keyvaluepairref& b); +#endif + + // + virtual ::std::istream& read( ::std::istream& stream ); + virtual ::std::ostream& write( ::std::ostream& stream ); +}; +template +inline bool operator == (const keyvaluepairref& a, const keyvaluepairref& b) +{ return (a.m_key == b.m_key); } +template +inline bool operator < (const keyvaluepairref& a, const keyvaluepairref& b) +{ return (a.m_key < b.m_key); } +template +inline bool operator > (const keyvaluepairref& a, const keyvaluepairref& b) +{ return (a.m_key > b.m_key); } +// Note: read and write only work for structures without pointers +template +::std::istream& keyvaluepairref::read( ::std::istream& stream ) +{ + stream.read( (char *) &m_key, sizeof(T1) ); + +#ifndef _WIN32 + m_value = new T2; +#endif + stream.read( (char *) m_value, sizeof(T2) ); + return stream; +} +template +::std::ostream& keyvaluepairref::write( ::std::ostream& stream ) +{ + stream.write( (char *) &m_key, sizeof(T1) ); + stream.write( (char *) m_value, sizeof(T2) ); + return stream; +} + +// ...and yuk! it gets worse... now we have to define a whole new class: + +template class pmemmap +{ +// It looks very similar to a pqvector... +protected: + pqvector m_vector; +public: + pmemmap() {;} + pmemmap(const pmemmap& map ) { m_vector = map.m_vector; } + ~pmemmap() {;} + pmemmap& operator = (const pmemmap& map ) + { if (this != &map) m_vector = map.m_vector; return *this; } + // + // at, [] and so on + T2& at(size_t i) + { return m_vector.at(i).value(); } + const T2& at(size_t i) const + { return m_vector.at(i).value(); } + T2& operator [] (size_t i) + { return m_vector.at(i).value(); } + const T2& operator [] (size_t i) const + { return m_vector.at(i).value(); } + T2& head() + { return m_vector.head().value(); } + const T2& head() const + { return m_vector.head().value(); } + T2& tail() + { return m_vector.tail().value(); } + const T2& tail() const + { return m_vector.tail().value(); } + size_t size() const + { return m_vector.size(); } + void clear() + { m_vector.clear(); } + // + // standard operations (unordered vector) + T2& find(const T1& item) const + { return m_vector.find(Pair(item)).value(); } + size_t findindex(const T1& item) const + { return m_vector.findindex(Pair(item)); } + // + // binary operations (ordered vector) + T2& search(const T1& item) + { return m_vector.search(Pair(item)).value(); } + const T2& search(const T1& item) const + { return m_vector.search(Pair(item)).value(); } + size_t searchindex(const T1& item) const + { return m_vector.searchindex(Pair(item)); } + void remove_at(size_t i) + { m_vector.remove_at(i); } + void remove_at(const pvecint& list) + { m_vector.remove_at(list); } + void remove(const T1& item) + { remove_at(m_vector.searchindex(item)); } + size_t add(const T1& k, const T2& v, int type = paftl::ADD_UNIQUE) // note: does not replace! + { return m_vector.add( Pair(k,v), type ); } + // extras + T1& key(size_t i) + { return m_vector.at(i).key(); } + const T1 key(size_t i) const + { return m_vector.at(i).key(); } + T2& value(size_t i) + { return m_vector.at(i).value(); } + const T2& value(size_t i) const + { return m_vector.at(i).value(); } + T2& current() + { return m_vector.current().value(); } + const T2& current() const + { return m_vector.current().value(); } + // read and write (structures without pointers *only*) + ::std::istream& read( ::std::istream& stream ); + ::std::ostream& write( ::std::ostream& stream ); +}; + +// Note: read and write only work for structures without pointers + +template +::std::istream& pmemmap::read( ::std::istream& stream ) +{ + for (size_t i = m_vector.size() - 1; i != paftl::npos; i--) { + m_vector.remove_at(i); + } + // n.b., do not change this to size_t as it will cause 32-bit to 64-bit conversion problems + unsigned int length; + stream.read( (char *) &length, sizeof(unsigned int) ); + for (size_t j = 0; j < size_t(length); j++) { + // these should be in order, so just push them: + Pair p; + p.read(stream); + m_vector.push_back(p); + } + return stream; +} + +template +::std::ostream& pmemmap::write( ::std::ostream& stream ) +{ + // check for max unsigned int exceeded + if (m_vector.size() > size_t((unsigned int)-1)) { + throw pexception( pexception::MAX_ARRAY_EXCEEDED, m_vector.size() ); + } + + // n.b., do not change this to size_t as it will cause 32bit to 64bit conversion problems + unsigned int length = (unsigned int)(m_vector.size()); + stream.write( (char *) &length, sizeof(unsigned int) ); + for (size_t i = 0; i < m_vector.size(); i++) { + m_vector[i].write(stream); + } + return stream; +} + +// ...to stop the MS compiler complaining... +#define kvp(T1,T2) keyvaluepair + +template class pmap : public pmemmap +{ +}; + +// ...to stop the MS compiler complaining... +#define kvpr(T1,T2) keyvaluepairref + +template class pqmap : public pmemmap +{ +}; + +/////////////////////////////////////////////////////////////////////////////// + +// ptree: a simple tree class + +// Allows template of a template (recursive) definition for tree +#define ptreeT ptree + +template class ptree +{ +public: + class exception : public pexception + { + public: + enum exception_t { PTREE_UNDEFINED = 0x1000, + UNASSIGNED_DATA = 0x1001 }; + public: + exception(int n_exception = PTREE_UNDEFINED) : pexception( n_exception ) {} + }; +protected: + T *m_data; + ptree *m_parent; + pvector m_children; +public: + ptree() { + m_data = NULL; + m_parent = NULL; + } + ptree(const T& data) { + m_data = new T(data); + m_parent = NULL; + } + ptree(const ptree& tree ) { + m_data = tree.m_data; + for (int i = 0; i < tree.m_children.size(); i++) { + ptree *child = new ptree( *(tree.m_children[i]) ); + m_children.push_back( child ); + m_children.tail()->m_parent = this; + } + } + ptree& operator = (const ptree& tree) { + if (this != &tree) { + m_data = tree.m_data; + for (int i = 0; i < tree.m_children.size(); i++) { + ptree *child = new ptree( *(tree.m_children[i]) ); + m_children.push_back( child ); + m_children.tail()->m_parent = this; + } + } + return *this; + } + ~ptree() { + delete m_data; + m_data = NULL; + while (m_children.size()) { + delete m_children.tail(); + m_children.pop_back(); + } + } + void addChild(const T& data) { + m_children.push_back( new ptree(data) ); + m_children.tail()->m_parent = this; + } + void removeChild(int ref) { + ptree *child = m_children[ref]; + m_children.remove(ref); + delete child; + } + int getChildCount() const { + return m_children.size(); + } + ptree& getChild(int ref) const { + return *(m_children[ref]); + } + ptree& getLastChild() const { + return *(m_children[m_children.size() - 1]); + } + int hasParent() const { + return m_parent ? 1 : 0; + } + ptree& getParent() const { + return *m_parent; + } + void setParent(ptree& parent) { + if (m_parent) { + for (int i = 0; i < m_parent->m_children.size(); i++) { + if (m_parent->m_children[i] == this) { + m_parent->m_children.remove(i); + } + } + } + m_parent = &parent; + } + void setValue(const T& data) { + m_data = new T(data); + } + T& getValue() const { + if (!m_data) + throw exception( exception::UNASSIGNED_DATA ); + return *m_data; + } + pvector getPath() { + pvector path; + getPath(path); + return path; + } + void getPath(pvector& path) { + path.push_back( getValue() ); + if (m_parent) { + m_parent->getPath(path); + } + } +}; + +/////////////////////////////////////////////////////////////////////////////// + +template class pflipper +{ +protected: + T m_contents[2]; + short parity; +public: + pflipper() { + parity = 0; + } + pflipper( const T& a, const T& b ) { + parity = 0; + m_contents[0] = a; + m_contents[1] = b; + } + pflipper( const pflipper& f ) { + parity = f.parity; + m_contents[0] = f.m_contents[0]; + m_contents[1] = f.m_contents[1]; + } + virtual ~pflipper() { + } + pflipper& operator = (const pflipper& f ) { + if (this != &f) { + parity = f.parity; + m_contents[0] = f.m_contents[0]; + m_contents[1] = f.m_contents[1]; + } + return *this; + } + void flip() { + parity = (parity == 0) ? 1 : 0; + } + T& a() { + return m_contents[parity]; + } + T& b() { + return m_contents[(parity == 0) ? 1 : 0]; + } + const T& a() const { + return m_contents[parity]; + } + const T& b() const { + return m_contents[(parity == 0) ? 1 : 0]; + } +}; + +/////////////////////////////////////////////////////////////////////////////// + +// Read and write runlength encoded vectors, with byte alignment through T + +// note: vector must have been allocated to accept stream +template +::std::istream& read_rle( ::std::istream& stream, T *vector, size_t length ) +{ + unsigned char *data = (unsigned char *) vector; + for (size_t i = 0; i < sizeof(T); i++) { + unsigned char runlength = 0, current, last; + size_t count = 0; + while (count < length) { + stream.get((char&)current); + if (count && current == last) { + stream.get((char&)runlength); + } + else { + last = current; + runlength = 1; + } + for (size_t i = count; i < count + runlength; i++) { + data[i + sizeof(T) * count] = current; + } + count += runlength; + } + } + return stream; +} + +template ::std::ostream& write_rle( ::std::ostream& stream, T *vector, size_t length ) +{ + unsigned char *data = (unsigned char *) vector; + for (size_t i = 0; i < sizeof(T); i++) { + unsigned char runlength = 0, current; + size_t count = 0; + while (count < length) { + do { + current = data[i + sizeof(T) * count]; + runlength++; + count++; + } while (count < length && current == data[i + sizeof(T) * count] && runlength < 255); + if (runlength == 1) { + stream.put(current); + } + else { + stream.put(current); + stream.put(current); + runlength -= 1; // since we've written current twice anyway to mark the run + stream.put(runlength); + } + runlength = 0; + } + } + return stream; +} + +/////////////////////////////////////////////////////////////////////////////// + +// Hashing for LZW compression + +const size_t HASHBITSIZE = 12; +const size_t HASHTABLESIZE = 5021; // n.b., prime > 4096 +//const size_t HASHTABLESIZE = 65983; // n.b., prime > 65536 +const size_t HASHMAXVALUE = (1 << HASHBITSIZE) - 1; +const size_t HASHMAXCODE = HASHMAXVALUE - 1; + +struct phash +{ + unsigned int code; + unsigned int prefix; + unsigned char character; +}; + +class phashtable +{ +protected: + mutable size_t m_current; + unsigned int m_nextcode; + phash m_table[HASHTABLESIZE]; +public: + phashtable(); + void add_encode(unsigned int prefix, unsigned char character); + void add_decode(unsigned int prefix, unsigned char character); + size_t search(unsigned int prefix, unsigned char character) const; + unsigned char *decode(unsigned char *buffer, unsigned int code); + int getnextcode() + { return m_nextcode; } +}; + +inline phashtable::phashtable() +{ + for (size_t i = 0; i < HASHTABLESIZE; i++) { + m_table[i].code = -1; + } + m_nextcode = 256; // 0-255 for standard characters +} + +inline void phashtable::add_encode(unsigned int prefix, unsigned char character) +{ + if (m_nextcode <= HASHMAXCODE) { + m_table[m_current].code = m_nextcode; + m_table[m_current].prefix = prefix; + m_table[m_current].character = character; + m_nextcode++; + } +} + +inline void phashtable::add_decode(unsigned int prefix, unsigned char character) +{ + if (m_nextcode <= HASHMAXCODE) { + m_table[m_nextcode].prefix = prefix; + m_table[m_nextcode].character = character; + m_nextcode++; + } +} + +inline size_t phashtable::search(unsigned int prefix, unsigned char character) const +{ + // the bracket overkill on the following line ensures paftl.h compiles on a GNU compiler + m_current = (((unsigned int) character) << (HASHBITSIZE-8)) ^ prefix; + size_t offset; + if (m_current == 0) { + offset = 1; + } + else { + offset = HASHTABLESIZE - m_current; + } + while ( m_table[m_current].code != (unsigned int) -1 && + (m_table[m_current].prefix != prefix || m_table[m_current].character != character)) + { + if (offset > m_current) + m_current += HASHTABLESIZE; + m_current -= offset; + } + return m_table[m_current].code; +} + +inline unsigned char *phashtable::decode(unsigned char *buffer, unsigned int code) +{ + while (code > 255) + { + *buffer++ = m_table[code].character; + code = m_table[code].prefix; + } + *buffer = code; + return buffer; +} + +/////////////////////////////////////////////////////////////////////////////// + +// LZW as of June 2003 US patent has expired +// as of June 2004 the European patent expires + +// Note to paftl users: ensure that you meet patent requirements for your usage + +// LZW uses a class so that the hash table may be retained over multiple +// vector read / writes, as well as holding a read buffer + +// 12 bit, 4096 pattern holder + +// Note: you must *flush* after writing -- the idea is you can write several +// vectors before a flush + +template class plzw +{ +protected: + // read / write buffering + unsigned long m_bitbuffer; + bool m_bitswaiting; +protected: + bool m_firstever; + unsigned char m_character; + unsigned int m_prefix; + phashtable m_hashtable; + unsigned char m_decodedstring[HASHTABLESIZE]; // <- impossible that the decode string is ever as long as the hash table size +public: + plzw(); + ::std::istream& read( ::std::istream& stream, T *vector, int length ); + ::std::ostream& write( ::std::ostream& stream, T *vector, int length ); +protected: + ::std::istream& get(::std::istream& stream, unsigned int& code); + ::std::ostream& put(::std::ostream& stream, const unsigned int code); +}; + +template +plzw::plzw() +{ + m_firstever = true; + m_bitswaiting = false; +} + +template +::std::istream& plzw::read(::std::istream& stream, T *vector, int length ) +{ + unsigned char *data = (unsigned char *) vector; + unsigned char *string; + + if (m_firstever) { + get(stream, m_prefix); + m_character = m_prefix; + data[0] = m_character; + } + + // T is sequenced, as we assume that patterns will recur through aligned bytes of T + for (unsigned int i = (m_firstever ? 1 : 0); i < sizeof(T) * length;) { + unsigned int nextcode; + get(stream, nextcode); + if (nextcode >= (unsigned int) m_hashtable.getnextcode()) { + *m_decodedstring = m_character; + string = m_hashtable.decode(m_decodedstring + 1, m_prefix); + } + else { + string = m_hashtable.decode(m_decodedstring, nextcode); + } + m_character = *string; + if (i != 0) { + // this should be skipped on initial read + m_hashtable.add_decode(m_prefix,m_character); + } + while (string >= m_decodedstring && i < sizeof(T) * length) { + data[i] = *string--; + i++; + } + m_prefix = nextcode; + } + + // skip to next byte boundary for next read... (and retain context) + m_bitswaiting = false; + m_firstever = false; + + return stream; +} + +template +::std::ostream& plzw::write(::std::ostream& stream, T *vector, int length ) +{ + unsigned char *data = (unsigned char *) vector; + + m_prefix = data[0]; + + for (unsigned int i = 0; i < sizeof(T) * length; i++) { + m_character = data[i]; + int code = m_hashtable.search(m_prefix, m_character); + if (code != -1) { + m_prefix = code; + } + else { + m_hashtable.add_encode(m_prefix, m_character); + put(stream, m_prefix); + m_prefix = m_character; + } + } + + // skip to next byte boundary + put(stream, m_prefix); + if (m_bitswaiting) { + stream.put((unsigned char)(m_bitbuffer & 0xFF)); + m_bitswaiting = false; + } + + return stream; +} + +// stored, 1 and 2 are the 12-bit codes, +// a b & c are first 4 bits, second 4 bits and third four bits respectively +// b1 a1 +// c2 c1 +// b2 a2 + +template +::std::istream& plzw::get(::std::istream& stream, unsigned int& code) +{ + unsigned char bits; + if (!m_bitswaiting) { + stream.get((char&)bits); + code = bits; + stream.get((char&)bits); + code |= (bits & 0x0F) << 8; + m_bitbuffer = bits & 0xF0; + m_bitswaiting = true; + } + else { + stream.get((char&)bits); + code = ((unsigned int)bits) | (m_bitbuffer << 4); + m_bitswaiting = false; + } + + return stream; +} + +template +::std::ostream& plzw::put(::std::ostream& stream, const unsigned int code) +{ + if (!m_bitswaiting) { + stream.put((unsigned char)(code & 0xFF)); + m_bitbuffer = code >> 8; + m_bitswaiting = true; + } + else { + unsigned char bits; + bits = ((code >> 4) & 0xF0) | m_bitbuffer; + stream.put(bits); + stream.put((unsigned char)(code & 0xFF)); + m_bitswaiting = false; + } + + return stream; +} + +/////////////////////////////////////////////////////////////////////////////// + +// } // namespace paftl + +} + +#endif diff --git a/mgraph440/pixelbase.cpp b/mgraph440/pixelbase.cpp new file mode 100644 index 00000000..a02a3f63 --- /dev/null +++ b/mgraph440/pixelbase.cpp @@ -0,0 +1,96 @@ +#include "mgraph440/pixelbase.h" + +namespace mgraph440 { + +PixelRefVector PixelBase::pixelateLine( Line l, int scalefactor ) const +{ + PixelRefVector pixel_list; + + // this is *not* correct for lines that are off the edge... + // should use non-constrained version (false), and find where line enters the region + PixelRef a = pixelate( l.start(), true, scalefactor ); + PixelRef b = pixelate( l.end(), true, scalefactor ); + + l.normalScale( m_region ); + + pixel_list.push_back( a ); + + int scaledcols = m_cols * scalefactor; + int scaledrows = m_rows * scalefactor; + + int parity = 1; // Line goes upwards + if (a.y > b.y) { + parity = -1; // Line goes downwards + a.y *= -1; + b.y *= -1; // Set ay and by saves work on comparisons later on + } + + // special case 1 + if (a.x == b.x) { + while (a.y < b.y ) { + a.y += 1; + pixel_list.push_back( PixelRef(a.x,parity * a.y) ); + } + } + else if (a.y == b.y) { + while ( a.x < b.x ) { + a.x += 1; + pixel_list.push_back( PixelRef(a.x,parity * a.y) ); // Lines always go left to right + } + } + else { + + double hw_ratio = l.height() / l.width(); // Working all of these out leaves less scope for floating point error + double wh_ratio = l.width() / l.height(); + double x0_const = l.ay() - double(parity) * hw_ratio * l.ax(); + double y0_const = l.ax() - double(parity) * wh_ratio * l.ay(); + + while (a.x < b.x || a.y < b.y) { + PixelRef e; + e.y = parity * int( double(scaledrows) * (x0_const + parity * hw_ratio * (double(a.x + 1) / double(scaledcols))) ); + // Note when decending 1.5 -> 1 and ascending 1.5 -> 2 + if (parity < 0) { + e.x = int( double(scaledcols) * (y0_const + wh_ratio * ( double(a.y) / double(scaledrows))) ); + } + else { + e.x = int( double(scaledcols) * (y0_const + wh_ratio * (double(a.y + 1) / double(scaledrows))) ); + } + + if (a.y < e.y) { + while (a.y < e.y && a.y < b.y) { + a.y += 1; + pixel_list.push_back( PixelRef(a.x,parity * a.y) ); + } + if (a.x < b.x) { + a.x += 1; + pixel_list.push_back( PixelRef(a.x,parity * a.y) ); + } + } + else if (a.x < e.x) { + while (a.x < e.x && a.x < b.x) { + a.x += 1; + pixel_list.push_back( PixelRef(a.x,parity * a.y) ); + } + if (a.y < b.y) { + a.y += 1; + pixel_list.push_back( PixelRef(a.x,parity * a.y) ); + } + } + else { + // Special case: exactly diagonal step (should only require one step): + // (Should actually never happen) (Doesn't: checked with RFH) + if (a.x < b.x) { + a.x += 1; + pixel_list.push_back( PixelRef(a.x,parity * a.y) ); + } + if (a.y < b.y) { + a.y += 1; + pixel_list.push_back( PixelRef(a.x,parity * a.y) ); + } + } + } + } + return pixel_list; +} + +} diff --git a/mgraph440/pixelbase.h b/mgraph440/pixelbase.h new file mode 100644 index 00000000..563a3558 --- /dev/null +++ b/mgraph440/pixelbase.h @@ -0,0 +1,26 @@ +#pragma once + +#include "mgraph440/p2dpoly.h" +#include "mgraph440/pixelref.h" + +namespace mgraph440 { + +class PixelBase +{ +public: + int m_rows; + int m_cols; + QtRegion m_region; + PixelBase() {;} + // constrain is constrain to bounding box (i.e., in row / col bounds) + virtual PixelRef pixelate(const Point2f&, bool constrain = true, int scalefactor = 1 ) const = 0; + PixelRefVector pixelateLine( Line l, int scalefactor = 1 ) const; + bool includes(const PixelRef pix) const { + return (pix.x >= 0 && pix.x < m_cols && pix.y >= 0 && pix.y < m_rows); + } + const QtRegion& getRegion() const { + return m_region; + } +}; + +} diff --git a/mgraph440/pixelref.h b/mgraph440/pixelref.h new file mode 100644 index 00000000..1d18eafd --- /dev/null +++ b/mgraph440/pixelref.h @@ -0,0 +1,134 @@ +#pragma once + +#include "mgraph440/p2dpoly.h" + +namespace mgraph440 { + +class PixelRef +{ +public: + short x = 0; + short y = 0; + PixelRef( short ax = -1, short ay = -1 ) + { x = ax; y = ay; } + PixelRef( int i ) + { x = short(i >> 16); y = short(i & 0xffff); } + bool empty() + { return x == -1 && y == -1; } + PixelRef up() const + { return PixelRef(x, y + 1); } + PixelRef left() const + { return PixelRef(x - 1, y); } + PixelRef right() const + { return PixelRef(x + 1, y); } + PixelRef down() const + { return PixelRef(x, y - 1); } + short& operator [] (int i) + { return (i == XAXIS) ? x : y; } + bool within( const PixelRef bl, const PixelRef tr ) const + { return (x >= bl.x && x <= tr.x && y >= bl.y && y <= tr.y); } + bool encloses( PixelRef testpoint ) const + { return (testpoint.x >= 0 && testpoint.x < x && testpoint.y >= 0 && testpoint.y < y);} + // directions for the ngraph: + enum {NODIR = 0x00, HORIZONTAL = 0x01, VERTICAL = 0x02, POSDIAGONAL = 0x04, NEGDIAGONAL = 0x08, DIAGONAL = 0x0c, NEGHORIZONTAL = 0x10, NEGVERTICAL = 0x20}; + short& row(char dir) + { return (dir & VERTICAL) ? x : y; } + short& col(char dir) + { return (dir & VERTICAL) ? y : x; } + const short& row(char dir) const + { return (dir & VERTICAL) ? x : y; } + const short& col(char dir) const + { return (dir & VERTICAL) ? y : x; } + PixelRef& move(char dir) + { switch (dir) + { + case POSDIAGONAL: x++; y++; break; + case NEGDIAGONAL: x++; y--; break; + case HORIZONTAL: x++; break; + case VERTICAL: y++; break; + case NEGHORIZONTAL: x--; break; + case NEGVERTICAL: y--; break; + } + return *this; } + friend bool operator == (const PixelRef a, const PixelRef b); + friend bool operator != (const PixelRef a, const PixelRef b); + friend bool operator < (const PixelRef a, const PixelRef b); + friend bool operator > (const PixelRef a, const PixelRef b); + friend PixelRef operator + (const PixelRef a, const PixelRef b); + friend PixelRef operator - (const PixelRef a, const PixelRef b); + friend PixelRef operator / (const PixelRef a, const int factor); + friend double dist(const PixelRef a, const PixelRef b); + friend double angle(const PixelRef a, const PixelRef b, const PixelRef c); + operator int() const + { return ((int(x) << 16) + (int(y) & 0xffff)); } +}; + +const PixelRef NoPixel( -1, -1 ); +typedef std::vector PixelRefVector; + + +inline bool operator == (const PixelRef a, const PixelRef b) +{ + return (a.x == b.x) && (a.y == b.y); +} +inline bool operator != (const PixelRef a, const PixelRef b) +{ + return (a.x != b.x) || (a.y != b.y); +} +inline bool operator < (const PixelRef a, const PixelRef b) +{ + return (a.x < b.x) || (a.x == b.x && a.y < b.y); +} +inline bool operator > (const PixelRef a, const PixelRef b) +{ + return (a.x > b.x) || (a.x == b.x && a.y > b.y); +} +inline PixelRef operator + (const PixelRef a, const PixelRef b) +{ + return PixelRef(a.x + b.x, a.y + b.y); +} +inline PixelRef operator - (const PixelRef a, const PixelRef b) +{ + return PixelRef(a.x - b.x, a.y - b.y); +} +inline PixelRef operator / (const PixelRef a, const int factor) +{ + return PixelRef(a.x / factor, a.y / factor); +} + + +struct PixelRefPair +{ + PixelRef a; + PixelRef b; + PixelRefPair(const PixelRef x = NoPixel, const PixelRef y = NoPixel) + { + a = x < y ? x : y; + b = x < y ? y : x; + } + friend bool operator == (const PixelRefPair& x, const PixelRefPair& y); + friend bool operator != (const PixelRefPair& x, const PixelRefPair& y); + friend bool operator < (const PixelRefPair& x, const PixelRefPair& y); + friend bool operator > (const PixelRefPair& x, const PixelRefPair& y); + +}; + +// note: these are made with a is always less than b +inline bool operator == (const PixelRefPair& x, const PixelRefPair& y) +{ + return (x.a == y.a && x.b == y.b); +} +inline bool operator != (const PixelRefPair& x, const PixelRefPair& y) +{ + return (x.a != y.a || x.b != y.b); +} +inline bool operator < (const PixelRefPair& x, const PixelRefPair& y) +{ + return ( (x.a == y.a) ? x.b < y.b : x.a < y.a ); +} +inline bool operator > (const PixelRefPair& x, const PixelRefPair& y) +{ + return ( (x.a == y.a) ? x.b > y.b : x.a > y.a ); +} + +} diff --git a/mgraph440/point.cpp b/mgraph440/point.cpp new file mode 100644 index 00000000..292a7705 --- /dev/null +++ b/mgraph440/point.cpp @@ -0,0 +1,86 @@ +#include "mgraph440/point.h" + +namespace mgraph440 { + +Point::~Point() +{ + if (m_node) { + delete m_node; + m_node = NULL; + delete m_attributes; + m_attributes = NULL; + } +} + +std::ifstream& Point::read(std::ifstream& stream, int version, int attr_count) +{ + if (m_node) { + delete m_node; + m_node = NULL; + delete m_attributes; + m_attributes = NULL; + } + stream.read( (char *) &m_state, sizeof(m_state) ); + // block is the same size as m_noderef used to be for ease of replacement: + // (note block NO LONGER used!) + stream.read( (char *) &m_block, sizeof(m_block) ); + if (version < VERSION_BLOCKEDQUAD) { + m_block = 0; + } + stream.read( (char *) &m_misc, sizeof(m_misc) ); + if (version >= VERSION_GRID_CONNECTIONS) { + stream.read( (char *) &m_grid_connections, sizeof(m_grid_connections) ); + } + if (version >= VERSION_NGRAPH_INTROD) { + stream.read( (char *) &m_merge, sizeof(m_merge) ); + bool ngraph; + stream.read( (char *) &ngraph, sizeof(ngraph) ); + if (ngraph) { + m_node = new Node; + m_node->read(stream, version); + if (version < VERSION_ATTRIBUTES_TABLE) { + // don't deal with this here, just get the attributes into memory + m_attributes = new AttrBody(-1,g_attr_header); + m_attributes->read( stream, attr_count ); + } + } + } + if (version >= VERSION_POINT_LOCATIONS) { + stream.read((char *) &m_location, sizeof(m_location)); + } + if (version < VERSION_SHAPE_MAPS) { + // old layer information + m_data_objects.read(stream); + } + if (version >= VERSION_BOUNDARYGRAPH && version < VERSION_NEWBOUNDARYGRAPH) { + // dummy pvecint to hold old format boundary nodes + pvecint old_boundary_nodes; + old_boundary_nodes.read(stream); + } + return stream; +} + +std::ostream& Point::write(std::ostream& stream, int version) +{ + stream.write( (char *) &m_state, sizeof(m_state) ); + // block is the same size as m_noderef used to be for ease of replacement: + // note block is no longer used at all + stream.write( (char *) &m_block, sizeof(m_block) ); + stream.write( (char *) &m_misc, sizeof(m_misc) ); + stream.write( (char *) &m_grid_connections, sizeof(m_grid_connections) ); + stream.write( (char *) &m_merge, sizeof(m_merge) ); + bool ngraph; + if (m_node) { + ngraph = true; + stream.write( (char *) &ngraph, sizeof(ngraph) ); + m_node->write(stream, version); + } + else { + ngraph = false; + stream.write( (char *) &ngraph, sizeof(ngraph) ); + } + stream.write((char *) &m_location, sizeof(m_location)); + return stream; +} + +} diff --git a/mgraph440/point.h b/mgraph440/point.h new file mode 100644 index 00000000..e3cc0a4d --- /dev/null +++ b/mgraph440/point.h @@ -0,0 +1,94 @@ +#pragma once + +#include "mgraph440/attr.h" +#include "mgraph440/ngraph.h" + +namespace mgraph440 { + +class OldPoint1 { + friend class PointMap; +protected: + int m_noderef; + int m_state; +}; + +class OldPoint2 { + friend class PointMap; +protected: + int m_noderef; + int m_state; + int m_misc; +}; + +class Point { + friend class Bin; + friend class PointMap; + friend class MetaGraph; // <- for file conversion routines + friend class PafAgent; + friend class PafWalker; +public: + enum { EMPTY = 0x0001, FILLED = 0x0002, + BLOCKED = 0x0004, CONTEXTFILLED = 0x0008, // PARTBLOCKED = 0x0008 deprecated + SELECTED = 0x0010, EDGE = 0x0020, MERGED = 0x0040, // PINNED = 0x0020 deprecated + AGENTFILLED = 0x0080, AGENTFADE = 0x0100, AGENTA = 0x0200, AGENTB = 0x0400, AGENTC = 0x0800, + UPDATELINEADDED = 0x1000, UPDATELINEREMOVED = 0x2000, HIGHLIGHT = 0x4000, + AUGMENTED = 0x8000 // AV TV + }; + // note the order of these connections is important and used elsewhere: + enum { CONNECT_E = 0x01, CONNECT_NE = 0x02, CONNECT_N = 0x04, CONNECT_NW = 0x08, + CONNECT_W = 0x10, CONNECT_SW = 0x20, CONNECT_S = 0x40, CONNECT_SE = 0x80 }; + int m_block; // not used, unlikely to be used, but kept for time being + int m_state; + int m_misc; // <- undocounter / point seen register / agent reference number, etc + char m_grid_connections; // this is a standard set of grid connections, with bits set for E,NE,N,NW,W,SW,S,SE + Node *m_node; // graph links + Point2f m_location; // note: this is large, but it helps allow loading of non-standard grid points, + // whilst allowing them to be displayed as a visibility graph, also speeds up time to + // display + float m_color; // although display color for the point now introduced + PixelRef m_merge; // to merge with another point + PixelRef m_extent; // used to speed up graph analysis (not sure whether or not it breaks it!) + float m_dist; // used to speed up metric analysis + float m_cumangle; // cummulative angle -- used in metric analysis and angular analysis + // hmm... this is for my 3rd attempt at a quick line intersect algo: + // every line that goes through the gridsquare -- memory intensive I know, but what can you do: + // accuracy is imperative here! Calculated pre-fillpoints / pre-makegraph, and (importantly) it works. + pqmap m_lines; + // and when dynamic lines are being used, the process flag tells you which q octants to reprocess: + // + // Deprecated, kept for compatibility with previous versions: + AttrBody *m_attributes; // deprecated: now PointMap has an attribute table to handle this + pmap m_data_objects; // deprecated: (first int is data layer -- presumably the KEY not the index, second int is object ref) + // + int m_processflag; +public: + Point() + { m_state = EMPTY; m_block = 0; m_misc = 0; m_grid_connections = 0; m_node = NULL; m_attributes = NULL; m_processflag = 0; m_merge = NoPixel; m_user_data = NULL; } + Point& operator = (const Point&) + { throw 1; } + Point(const Point&) + { throw 1; } + ~Point(); + bool filled() const + { return (m_state & FILLED) == FILLED; } + bool selected() const + { return (m_state & SELECTED) == SELECTED; } + int getDataObject( int layer ) { + size_t var = m_data_objects.searchindex( layer ); + if (var != paftl::npos) + return m_data_objects.at(var); + return -1; // note: not paftl::npos + } + AttrBody& getAttributes() + { return *m_attributes; } + void setAttributes(const AttrBody& attr) + { if (m_attributes) delete m_attributes; + m_attributes = new AttrBody(attr); } + std::ifstream& read(std::ifstream& stream, int version, int attr_count); + std::ostream &write(std::ostream &stream, int version); + void *m_user_data; + Node& getNode() + { return *m_node; } +}; + +} diff --git a/mgraph440/pointmap.cpp b/mgraph440/pointmap.cpp new file mode 100644 index 00000000..402ba420 --- /dev/null +++ b/mgraph440/pointmap.cpp @@ -0,0 +1,434 @@ +#include "mgraph440/pointmap.h" +#include "mgraph440/containerutils.h" + +namespace mgraph440 { + +bool PointMap::read(std::ifstream& stream, int version ) +{ + if (version >= VERSION_POINT_MAP_NAMES) { + m_name = dXstring440::readString(stream); + } + else { + m_name = "VGA Map"; + } + + // NOTE: You MUST set m_spacepix manually! + m_displayed_attribute = -1; + + if (m_points) { + for (int i = 0; i < m_cols; i++) { + delete [] m_points[i]; + } + delete [] m_points; + m_points = NULL; + } + + stream.read( (char *) &m_spacing, sizeof(m_spacing) ); + + if (version < VERSION_STATE_RECORDED) { + if (version >= VERSION_SPARK_GRAPH_INTROD) { + bool redundant; + stream.read( (char *) &redundant, sizeof(redundant) ); + } + else { + double redundant; + stream.read( (char *) &redundant, sizeof(redundant) ); + } + } + + stream.read( (char *) &m_rows, sizeof(m_rows) ); + stream.read( (char *) &m_cols, sizeof(m_cols) ); + + stream.read( (char *) &m_point_count, sizeof(m_point_count) ); + + stream.read( (char *) &m_bottom_left, sizeof(m_bottom_left) ); + + m_region = QtRegion( + Point2f(m_bottom_left.x-m_spacing/2.0, m_bottom_left.y-m_spacing/2.0), + Point2f(m_bottom_left.x+double(m_cols-1)*m_spacing + m_spacing/2.0, + m_bottom_left.y+double(m_rows-1)*m_spacing + m_spacing/2.0) ); + + // for old data versions: + int attr_count = -1, which_attributes = -1; + + int displayed_attribute; // n.b., temp variable necessary to force recalc below + if (version >= VERSION_ATTRIBUTES_TABLE) { + // our data read + stream.read((char *)&displayed_attribute,sizeof(displayed_attribute)); + m_attributes.read( stream, version ); + } + else if (version >= VERSION_NGRAPH_INTROD) { + // ick, a very specific subset have this file format: + stream.read( (char *) &which_attributes, sizeof(which_attributes) ); + stream.read( (char *) &attr_count, sizeof(int) ); + } + + m_points = new Point *[m_cols]; + + for (int j = 0; j < m_cols; j++) { + m_points[j] = new Point [m_rows]; + // ...and read... + if (version >= VERSION_LAYERS_INTROD) { + for (int k = 0; k < m_rows; k++) { + m_points[j][k].read(stream,version,attr_count); + + // check if occdistance of any pixel's bin is set, meaning that + // the isovist analysis was done + if(!m_hasIsovistAnalysis) { + for(int b = 0; b < 32; b++) { + if(m_points[j][k].m_node && m_points[j][k].m_node->occdistance(b) > 0) { + m_hasIsovistAnalysis = true; + break; + } + } + } + } + } + else if (version >= VERSION_EXTRA_POINT_DATA_INTROD) { + // Hmm... more untidiness from a previous incarnation + OldPoint2 *oldpoints = new OldPoint2 [m_rows]; + stream.read( (char *) oldpoints, sizeof(OldPoint2) * m_rows ); + for (int k = 0; k < m_rows; k++) { + m_points[j][k].m_block = oldpoints[k].m_noderef; // <- block is actually for something else! + m_points[j][k].m_state = oldpoints[k].m_state; + m_points[j][k].m_misc = oldpoints[k].m_misc; + } + } + else { + // Hmm... more untidiness from a previous incarnation + OldPoint1 *oldpoints = new OldPoint1 [m_rows]; + stream.read( (char *) oldpoints, sizeof(OldPoint1) * m_rows ); + for (int k = 0; k < m_rows; k++) { + m_points[j][k].m_block= oldpoints[k].m_noderef; // <- block is actually for something else! + m_points[j][k].m_state = oldpoints[k].m_state; + } + } + + for (int k = 0; k < m_rows; k++) { + // Old style point node reffing and also unselects selected nodes which would otherwise be difficult + if (version >= VERSION_QUICK_GRAPH_INTROD) { + // would soon be better simply to turn off the select flag.... + m_points[j][k].m_state &= ( Point::EMPTY | Point::FILLED | Point::MERGED | Point::BLOCKED | Point::CONTEXTFILLED | Point::EDGE); + } + else if (m_points[j][k].m_state == -1) { + m_points[j][k].m_state = Point::EMPTY; + } + else { + m_points[j][k].m_state = Point::FILLED; + } + // Set the node pixel if it exists: + if (m_points[j][k].m_node) { + m_points[j][k].m_node->setPixel(PixelRef(j,k)); + } + // Set the point location if required: + if (version < VERSION_POINT_LOCATIONS) { + m_points[j][k].m_location = depixelate(PixelRef(j,k)); + } + // Add merge line if merged: + if (!m_points[j][k].m_merge.empty()) { + depthmapX440::addIfNotExists(m_merge_lines, PixelRefPair(PixelRef(j,k),m_points[j][k].m_merge)); + } + } + } + + // this is my attempt to enter these into the new attribute table: + if (version >= VERSION_NGRAPH_INTROD && version < VERSION_ATTRIBUTES_TABLE) { + if (which_attributes != GraphVertexList::NONE) { + displayed_attribute = 0; + convertAttributes(which_attributes); + } + else { + displayed_attribute = -1; + } + } + + // and if the attribute tables are ready, calculate the direct grid connections: + if (version >= VERSION_NGRAPH_INTROD && version < VERSION_GRID_CONNECTIONS) { + addGridConnections(); + } + + m_selection = NO_SELECTION; + m_pinned_selection = false; + + m_initialised = true; + m_blockedlines = false; + + if (version >= VERSION_POINT_MAPS) { + stream.read((char *) &m_processed, sizeof(m_processed)); + stream.read((char *) &m_boundarygraph, sizeof(m_boundarygraph)); + } + + // now, as soon as loaded, must recalculate our screen display: + // note m_displayed_attribute should be -2 in order to force recalc... + m_displayed_attribute = -2; + setDisplayedAttribute(displayed_attribute); + + return true; +} + +// A horrible piece of code: this is to convert a file from the old format +// AttrHeader / AttrBody to the new format Attributes Table + +// This code converts attributes for all versions +// between VERSION_NGRAPH_INTROD and VERSION_ATTRIBUTES_TABLE + +void PointMap::convertAttributes(int which_attributes) +{ + if (which_attributes & GraphVertexList::BASIC) { + int connectivity_col = m_attributes.insertLockedColumn("Connectivity"); + for (int i = 0; i < m_cols; i++) { + for (int j = 0; j < m_rows; j++) { + if (m_points[i][j].m_attributes) { + // insert row... + int row = m_attributes.insertRow(PixelRef(i,j)); + float val; + val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::NEIGHBOURHOOD_SIZE); + m_attributes.setValue(row, connectivity_col, val); + } + } + } + } + if (which_attributes & GraphVertexList::LOCAL) { + int cluster_col = m_attributes.insertColumn("Visual Clustering Coefficient"); + int control_col = m_attributes.insertColumn("Visual Control"); + int controllability_col = m_attributes.insertColumn("Visual Controllability"); + for (int i = 0; i < m_cols; i++) { + for (int j = 0; j < m_rows; j++) { + if (m_points[i][j].m_attributes) { + int row = m_attributes.getRowid(PixelRef(i,j)); + float val; + val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::CLUSTER); + m_attributes.setValue(row, cluster_col, val); + val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::CONTROL_HILL); + m_attributes.setValue(row, control_col, val); + val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::CONTROL_TURN); + m_attributes.setValue(row, controllability_col, val); + } + } + } + } + if (which_attributes & GraphVertexList::GLOBAL) { + int entropy_col = m_attributes.insertColumn("Visual Entropy"); + int integ_hh_col = m_attributes.insertColumn("Visual Integration [HH]"); + int integ_tk_col = m_attributes.insertColumn("Visual Integration [Tekl]"); + int depth_col = m_attributes.insertColumn("Visual Mean Depth"); + int count_col = m_attributes.insertColumn("Visual Node Count"); + int rel_entropy_col = m_attributes.insertColumn("Visual Relativised Entropy"); + for (int i = 0; i < m_cols; i++) { + for (int j = 0; j < m_rows; j++) { + if (m_points[i][j].m_attributes) { + int row = m_attributes.getRowid(PixelRef(i,j)); + float val; + val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::ENTROPY); + m_attributes.setValue(row, entropy_col, val); + val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::REL_ENTROPY); + m_attributes.setValue(row, rel_entropy_col, val); + val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::INTEGRATION_HILL); + m_attributes.setValue(row, integ_hh_col, val); + val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::INTEGRATION_TEKL); + m_attributes.setValue(row, integ_tk_col, val); + val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::MEAN_DEPTH); + m_attributes.setValue(row, depth_col, val); + val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::GRAPH_SIZE); + m_attributes.setValue(row, count_col, val); + } + } + } + } + if (which_attributes & GraphVertexList::POINTDEPTH) { + int col = m_attributes.insertColumn("Visual Step Depth"); + for (int i = 0; i < m_cols; i++) { + for (int j = 0; j < m_rows; j++) { + if (m_points[i][j].m_attributes) { + int row = m_attributes.getRowid(PixelRef(i,j)); + float val; + val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::POINT_DEPTH); + m_attributes.setValue(row, col, val); + } + } + } + } + if (which_attributes & GraphVertexList::METRIC) { + int mspa_col = m_attributes.insertColumn("Metric Mean Shortest-Path Angle"); + int mspl_col = m_attributes.insertColumn("Metric Mean Shortest-Path Distance"); + int dist_col = m_attributes.insertColumn("Metric Mean Straight-Line Distance"); + int count_col = m_attributes.insertColumn("Metric Node Count"); + for (int i = 0; i < m_cols; i++) { + for (int j = 0; j < m_rows; j++) { + if (m_points[i][j].m_attributes) { + int row = m_attributes.getRowid(PixelRef(i,j)); + double val, total = m_points[i][j].getAttributes().getAttr(AttrHeader::METRIC_GRAPH_SIZE); + // + val = m_points[i][j].getAttributes().getAttr(AttrHeader::TOTAL_METRIC_ANGLE) / total; + m_attributes.setValue(row, mspa_col, float(val)); + val = m_points[i][j].getAttributes().getAttr(AttrHeader::TOTAL_METRIC_DEPTH) / total; + m_attributes.setValue(row, mspl_col, float(val)); + val = m_points[i][j].getAttributes().getAttr(AttrHeader::TOTAL_EUCLID_DIST) / total; + m_attributes.setValue(row, dist_col, float(val)); + // + m_attributes.setValue(row, count_col, float(total)); + } + } + } + } + for (int i = 0; i < m_cols; i++) { + for (int j = 0; j < m_rows; j++) { + if (m_points[i][j].m_attributes) { + delete m_points[i][j].m_attributes; + m_points[i][j].m_attributes = NULL; + } + } + } +} + +///////////////////////////////////////////////////////////////////////////////// +// Update connections will load an old graph and add char information + +void PointMap::addGridConnections() +{ + for (int i = 0; i < m_attributes.getRowCount(); i++) { + PixelRef curs = m_attributes.getRowKey(i); + PixelRef node = curs.right(); + Point& point = getPoint(curs); + point.m_grid_connections = 0; + for (int i = 0; i < 32; i += 4) { + Bin& bin = point.m_node->bin(i); + bin.first(); + while (!bin.is_tail()) { + if (node == bin.cursor()) { + point.m_grid_connections |= (1 << (i / 4)); + break; + } + bin.next(); + } + char dir; + if (i == 0) { + dir = PixelRef::VERTICAL; + } + else if (i == 4 || i == 8) { + dir = PixelRef::NEGHORIZONTAL; + } + else if (i == 12 || i == 16) { + dir = PixelRef::NEGVERTICAL; + } + else if (i == 20 || i == 24) { + dir = PixelRef::HORIZONTAL; + } + node.move(dir); + } + } +} + +void PointMap::setDisplayedAttribute(int col) +{ + if (m_displayed_attribute == col) { + return; + } + else { + m_displayed_attribute = col; + } + // make a local copy of the display params for access speed: + m_display_params = m_attributes.getDisplayParams(); + + m_attributes.setDisplayColumn(m_displayed_attribute,true); +} + +// constrain is used to constrain to existing rows / cols +// (not quite the same as constraining to bounding box due to spacing offsets) +PixelRef PointMap::pixelate( const Point2f& p, bool constrain, int scalefactor ) const +{ + PixelRef ref; + + double spacing = m_spacing / double(scalefactor); + ref.x = int(floor( (p.x - m_bottom_left.x + (m_spacing / 2.0)) / spacing )); + ref.y = int(floor( (p.y - m_bottom_left.y + (m_spacing / 2.0)) / spacing )); + + if (constrain) { + if (ref.x < 0) + ref.x = 0; + else if (ref.x >= m_cols * scalefactor) + ref.x = (m_cols * scalefactor) - 1; + if (ref.y < 0) + ref.y = 0; + else if (ref.y >= m_rows * scalefactor) + ref.y = (m_rows * scalefactor) - 1; + } + + return ref; +} + +// dangerous: used only for making a false selection set +bool PointMap::overrideSelPixel(PixelRef pix) +{ + m_selection = OVERRIDE_SELECTION; + if (!(m_points[pix.x][pix.y].m_state & Point::SELECTED)) { + m_points[pix.x][pix.y].m_state |= Point::SELECTED; + m_selection_set.insert(pix); + } + return true; +} +bool PointMap::clearSel() +{ + if (m_selection == NO_SELECTION) { + return false; + } + for (auto& sel: m_selection_set) { + getPoint(sel).m_state &= ~Point::SELECTED; + } + m_selection_set.clear(); + m_selection = NO_SELECTION; + m_attributes.deselectAll(); + return true; +} + +bool PointMaps::write(std::ostream& stream, int version, bool displayedmaponly) +{ + if (!displayedmaponly) { + stream.write((char *) &m_displayed_map, sizeof(m_displayed_map)); + int count = size(); + stream.write((char *) &count, sizeof(count)); + for (int i = 0; i < count; i++) { + at(i).write( stream, version ); + } + } + else { + int dummy; + // displayed map is 0: + dummy = 0; + stream.write((char *) &dummy, sizeof(dummy)); + // count is 1 + dummy = 1; + stream.write((char *) &dummy, sizeof(dummy)); + // + at(m_displayed_map).write(stream, version); + } + return true; +} +bool PointMap::write( std::ostream& stream, int version ) +{ + dXstring440::writeString(stream, m_name); + + stream.write( (char *) &m_spacing, sizeof(m_spacing) ); + + stream.write( (char *) &m_rows, sizeof(m_rows) ); + stream.write( (char *) &m_cols, sizeof(m_cols) ); + + stream.write( (char *) &m_point_count, sizeof(m_point_count) ); + + stream.write( (char *) &m_bottom_left, sizeof(m_bottom_left) ); + + stream.write( (char *) &m_displayed_attribute, sizeof(m_displayed_attribute) ); + m_attributes.write( stream, version ); + + for (int j = 0; j < m_cols; j++) { + for (int k = 0; k < m_rows; k++) { + m_points[j][k].write( stream, version ); + } + } + + stream.write((char *) &m_processed, sizeof(m_processed)); + stream.write((char *) &m_boundarygraph, sizeof(m_boundarygraph)); + + return false; +} +} diff --git a/mgraph440/pointmap.h b/mgraph440/pointmap.h new file mode 100644 index 00000000..d7fc52ba --- /dev/null +++ b/mgraph440/pointmap.h @@ -0,0 +1,98 @@ +#pragma once + +#include "mgraph440/spacepix.h" +#include "mgraph440/point.h" +#include "mgraph440/pixelref.h" +#include "mgraph440/attributes.h" + +namespace mgraph440 { + +class PointMap : public PixelBase +{ +public: + enum { NO_SELECTION = 0, SINGLE_SELECTION = 1, COMPOUND_SELECTION = 2, LAYER_SELECTION = 4, OVERRIDE_SELECTION = 8 }; + + bool m_processed; + bool m_boundarygraph; + std::string m_name; + SuperSpacePixel *m_spacepix; + Point2f m_bottom_left; + double m_spacing; + mutable int m_displayed_attribute; + AttributeTable m_attributes; + int m_point_count; + bool m_hasIsovistAnalysis = false; + int m_selection; + bool m_pinned_selection; + bool m_initialised; + bool m_blockedlines; + mutable DisplayParams m_display_params; + std::set m_selection_set; // n.b., m_selection_set stored as int for compatibility with other map layers + + Point **m_points; // will contain the graph reference when created + std::vector m_merge_lines; + + Point& getPoint(const PixelRef& p) const + { return m_points[p.x][p.y]; } + bool setSpacePixel(const SuperSpacePixel *spacepix) + {m_spacepix = (SuperSpacePixel *) spacepix; return true;} + bool read( std::ifstream& stream, int version ); + Point2f depixelate( const PixelRef& p, double scalefactor = 1.0 ) const; // Inlined below + void convertAttributes( int which_attributes ); + void addGridConnections(); // adds grid connections where graph does not include them + void setDisplayedAttribute( int col ); + PixelRef pixelate(const Point2f &p, bool constrain, int scalefactor) const; + AttributeTable& getAttributeTable() + { return m_attributes; } + bool overrideSelPixel(PixelRef pix); + double getSpacing() const + { return m_spacing; } + bool clearSel(); // clear the current selection + // Note: passed by ref, use with care in multi-threaded app + const std::set& getSelSet() const + { return m_selection_set; } + bool write(std::ostream &stream, int version ); +}; + +inline Point2f PointMap::depixelate( const PixelRef& p, double scalefactor ) const +{ + return Point2f( m_bottom_left.x + m_spacing * scalefactor * double(p.x), + m_bottom_left.y + m_spacing * scalefactor * double(p.y) ); +} + +class PointMaps : public prefvec +{ +public: + int m_displayed_map; + SuperSpacePixel *m_spacepix; + pmap m_data_objects; // deprecated: (first int is data layer -- presumably the KEY not the index, second int is object ref) + + void setDisplayedPointMapRef(int i) + { m_displayed_map = i; } + PointMap& getDisplayedPointMap() + { return at(m_displayed_map); } + bool overrideSelPixel(PixelRef pix); // set a pixel to selected: careful! + void setSpacePixel(SuperSpacePixel *spacepix) + { m_spacepix = spacepix; for (size_t i = 0; i < size(); i++) at(i).setSpacePixel(spacepix); } + int getDataObject( int layer ) { + size_t var = m_data_objects.searchindex( layer ); + if (var != paftl::npos) + return m_data_objects.at(var); + return -1; // note: not paftl::npos + } + bool read(std::ifstream& stream, int version) + { + stream.read((char *) &m_displayed_map, sizeof(m_displayed_map)); + int count; + stream.read((char *) &count, sizeof(count)); + for (int i = 0; i < count; i++) { + push_back(PointMap()); + tail().setSpacePixel( (SuperSpacePixel *) this ); + tail().read( stream, version ); + } + return true; + } + bool write(std::ostream &stream, int version, bool displayedmaponly = false ); +}; + +} diff --git a/mgraph440/salaprogram.cpp b/mgraph440/salaprogram.cpp new file mode 100644 index 00000000..5bd0931c --- /dev/null +++ b/mgraph440/salaprogram.cpp @@ -0,0 +1,1739 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// salaprogram.cpp - a component of the depthmapX - spatial network analysis platform +// SalaScripting language + + +///////////////////////////////////////////////////////////////////////// + +// SalaScripting language + +// A "Pythonesque" language, which is pre-interpretted, and thus generally +// should run fairly fast + +// The class implementation is very much hardcoded for built-in classes, +// so user defined classes will be difficult to implement +// (but would you really want classes in an inbuilt scripting language?! -- I guess some people would) + +// User defined functions are not included yet, but should be fairly easy using a global function stack +// alongside the global variable stack + +#include +#include +#include +#include "mgraph440/pafmath.h" + +#include +#include +#include +#include + +namespace mgraph440 { + +/////////////////////////////////////////////////////////////////////////////////////////////// + +// Assign and list access rather incongruently in math ops, but never mind: + +bool g_sala_loaded = false; + +prefvec g_sala_math_ops; +prefvec g_sala_comp_ops; +prefvec g_sala_logical_ops; +prefvec g_sala_global_funcs; +prefvec g_sala_member_funcs; + +void loadSalaProgram() +{ + // math ops + g_sala_math_ops.push_back( SalaFuncLabel( SalaObj::S_ADD, "+", "add" ) ); + g_sala_math_ops.push_back( SalaFuncLabel( SalaObj::S_SUBTRACT, "-", "subtract" ) ); + g_sala_math_ops.push_back( SalaFuncLabel( SalaObj::S_MINUS, "-", "negative" )); + g_sala_math_ops.push_back( SalaFuncLabel( SalaObj::S_PLUS, "+", "positive" )); + g_sala_math_ops.push_back( SalaFuncLabel( SalaObj::S_MULTIPLY, "*", "multiply" )); + g_sala_math_ops.push_back( SalaFuncLabel( SalaObj::S_DIVIDE, "/", "divide" )); + g_sala_math_ops.push_back( SalaFuncLabel( SalaObj::S_MODULO, "%", "modulo" )); + g_sala_math_ops.push_back( SalaFuncLabel( SalaObj::S_POWER, "^", "power" )); + g_sala_math_ops.push_back( SalaFuncLabel( SalaObj::S_ASSIGN, "=", "assignment" )); + g_sala_math_ops.push_back(SalaFuncLabel( SalaObj::S_LIST_ACCESS, "[]", "list access" )); // list access included even though not parsed directly like this + + // comp ops + g_sala_comp_ops.push_back( SalaFuncLabel( SalaObj::S_GT, ">", "greater than" )); + g_sala_comp_ops.push_back(SalaFuncLabel( SalaObj::S_LT, "<", "less than" )); + g_sala_comp_ops.push_back(SalaFuncLabel( SalaObj::S_GEQ, ">=", "greater than or equal to" )); + g_sala_comp_ops.push_back(SalaFuncLabel( SalaObj::S_LEQ, "<=", "less than or equal to" )); + g_sala_comp_ops.push_back(SalaFuncLabel( SalaObj::S_NEQ, "!=", "not equal to" )); + g_sala_comp_ops.push_back(SalaFuncLabel( SalaObj::S_EQ, "==", "equal to" )); + g_sala_comp_ops.push_back(SalaFuncLabel( SalaObj::S_IS, "is", "is the same object as" )); + + // logical ops + g_sala_logical_ops.push_back(SalaFuncLabel( SalaObj::S_NOT, "not", "logical not" )); + g_sala_logical_ops.push_back(SalaFuncLabel( SalaObj::S_NOT, "!", "logical not" )); + g_sala_logical_ops.push_back(SalaFuncLabel( SalaObj::S_AND, "and", "logical and" )); + g_sala_logical_ops.push_back(SalaFuncLabel( SalaObj::S_AND, "&&", "logical and" )); + g_sala_logical_ops.push_back(SalaFuncLabel( SalaObj::S_OR, "or", "logical or" )); + g_sala_logical_ops.push_back(SalaFuncLabel( SalaObj::S_OR, "||", "logical or" )); + + // global functions + g_sala_global_funcs.push_back( SalaFuncLabel( SalaObj::S_SQRT, "sqrt", "square root" )); + g_sala_global_funcs.push_back(SalaFuncLabel( SalaObj::S_LOG, "log", "log base 10" )); + g_sala_global_funcs.push_back(SalaFuncLabel( SalaObj::S_LN, "ln", "natural logarithm" )); + g_sala_global_funcs.push_back(SalaFuncLabel( SalaObj::S_RAND, "random", "random number (0.0 to 1.0)" )); + g_sala_global_funcs.push_back(SalaFuncLabel( SalaObj::S_SIN, "sin", "sine" )); + g_sala_global_funcs.push_back(SalaFuncLabel( SalaObj::S_COS, "cos", "cosine" )); + g_sala_global_funcs.push_back(SalaFuncLabel( SalaObj::S_TAN, "tan", "tangent" )); + g_sala_global_funcs.push_back(SalaFuncLabel( SalaObj::S_ASIN, "asin", "inverse sine" )); + g_sala_global_funcs.push_back(SalaFuncLabel( SalaObj::S_ACOS, "acos", "inverse cosine" )); + g_sala_global_funcs.push_back(SalaFuncLabel( SalaObj::S_ATAN, "atan", "inverse tangent" )); + g_sala_global_funcs.push_back(SalaFuncLabel( SalaObj::S_LEN, "len", "array or string length" )); + g_sala_global_funcs.push_back(SalaFuncLabel( SalaObj::S_RANGE, "range", "set of integers" )); + + // member functions + g_sala_member_funcs.push_back(SalaMemberFuncLabel( SalaObj::S_LIST, SalaObj::S_FAPPEND, "append", "append item" )); + g_sala_member_funcs.push_back(SalaMemberFuncLabel( SalaObj::S_LIST, SalaObj::S_FEXTEND, "extend", "extend by list" )); + g_sala_member_funcs.push_back(SalaMemberFuncLabel( SalaObj::S_LIST, SalaObj::S_FPOP, "pop", "pop (last) item" )); + g_sala_member_funcs.push_back(SalaMemberFuncLabel( SalaObj::S_LIST, SalaObj::S_FCLEAR, "clear", "clear contents" )); + g_sala_member_funcs.push_back(SalaMemberFuncLabel( SalaObj::S_GRAPHOBJ, SalaObj::S_FVALUE, "value", "get attribute value" )); + g_sala_member_funcs.push_back(SalaMemberFuncLabel( SalaObj::S_GRAPHOBJ, SalaObj::S_FSETVALUE, "setvalue", "set attribute value" )); + g_sala_member_funcs.push_back(SalaMemberFuncLabel( SalaObj::S_GRAPHOBJ, SalaObj::S_FMARK, "mark", "get node mark" )); + g_sala_member_funcs.push_back(SalaMemberFuncLabel( SalaObj::S_GRAPHOBJ, SalaObj::S_FSETMARK, "setmark", "set node mark" )); + g_sala_member_funcs.push_back(SalaMemberFuncLabel( SalaObj::S_GRAPHOBJ, SalaObj::S_FCONNECTIONS, "connections", "get list of connections" )); + + g_sala_loaded = true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +SalaProgram::SalaProgram(SalaObj context) +{ + if (!g_sala_loaded) { + loadSalaProgram(); + } + + // col is used when run in update mode, it does not form part of the program: + m_col = -1; + m_thisobj = context; +} + +SalaProgram::~SalaProgram() +{ +} + +// use istrstream to make an istream from a string: +// istrstream file(char *); + +bool SalaProgram::parse(std::istream& program) +{ + m_var_stack.clear(); + m_error_stack.clear(); + + // this ensures wipe of any pre-existing variables in the global context: + m_root_command = SalaCommand(this,NULL,-1,SalaCommand::SC_ROOT); + + int line = 0; + + SalaCommand *parent = &m_root_command; + + while (!program.eof()) { + + // the problem with a language being "Pythonesque" is that the "end" of + // any control is implicit through the amount of indentation + // Thus, the parser eats the white space, only handing of control + // to a function when it is ready to parse, and knows its parent + int indent = 0; + bool endloop = false; + while (!endloop) { + char ch = program.peek(); + switch (ch) { + case ' ': + indent++; break; + case 13: + break; // ignore + case '\n': + line++; indent = 0; break; + case '#': + // hit comment, read to end of line: + while (ch != EOF && ch != '\n') + { program.get(); ch = program.peek(); } + line++; + break; + case '\\': + // hit line continuation, ignore everything after it: + while (ch != EOF && ch != '\n') + { program.get(); ch = program.peek(); } + line++; + break; + case EOF: + program.get(); // actually shift onto the eof character + endloop = true; + break; + default: + endloop = true; + break; + } + if (!endloop) { + program.get(); + } + } + + // okay, we now know indent level, and we are ready to parse: + if (!program.eof()) { + while (indent <= parent->m_indent) { + parent = parent->m_parent; + } + + parent->m_children.push_back(SalaCommand(this,parent,indent)); + + SalaCommand &thiscommand = parent->m_children.tail(); + + try { + line = thiscommand.parse(program,line); + } + catch (SalaError e) { + if (e.lineno == -1) + e.lineno = line; + m_error_stack.push_back(e); + return false; + } + + // sort out commands capable of having children: + if (thiscommand.m_command == SalaCommand::SC_FOR || thiscommand.m_command == SalaCommand::SC_IF || thiscommand.m_command == SalaCommand::SC_WHILE) { + parent = &thiscommand; + } + else if (thiscommand.m_command == SalaCommand::SC_ELSE) { + if (parent->m_children.size() < 2) { + m_error_stack.push_back(SalaError("'Else' must be preceded by an 'if','for' or 'while'", thiscommand.m_line)); + return false; + } + int command = parent->m_children[parent->m_children.size()-2].m_command; + if (command != SalaCommand::SC_IF && command != SalaCommand::SC_ELIF && command != SalaCommand::SC_FOR && command != SalaCommand::SC_WHILE) { + m_error_stack.push_back(SalaError("'Else' must be preceded by an 'if','for' or 'while'", thiscommand.m_line)); + return false; + } + parent = &thiscommand; + } + else if (thiscommand.m_command == SalaCommand::SC_ELIF) { + if (parent->m_children.size() < 2) { + m_error_stack.push_back(SalaError("'Elif' must be preceded by an 'if' condition", thiscommand.m_line)); + return false; + } + int command = parent->m_children[parent->m_children.size()-2].m_command; + if (command != SalaCommand::SC_IF && command != SalaCommand::SC_ELIF) { + m_error_stack.push_back(SalaError("'Elif' must be preceded by an 'if' condition", thiscommand.m_line)); + return false; + } + parent = &thiscommand; + } + } + } + + // do a quick check that all 'for', 'if' and 'elif' have children: + // TO DO! + + return true; +} + +SalaObj SalaProgram::evaluate() +{ + for (size_t i = 0; i < m_var_stack.size(); i++) { + // uninitialise all variables: + m_var_stack[i].uninit(); + } + m_marked = false; + + // run the program + SalaObj obj; + bool ret = false, ifhandled = false; + m_root_command.evaluate(obj,ret,ifhandled); + + // clear marks if they've been used: + if (m_marked) { + AttributeTable *table = m_thisobj.getTable(); + for (int i = 0; i < table->getRowCount(); i++) { + // Quick mod - TV +#if defined(_MSC_VER) + table->setMark(i,SalaObj()); +#else + SalaObj objTmp = SalaObj(); + table->setMark(i,objTmp); +#endif + } + m_marked = false; + } + + return obj; +} + +// this function is called by depthmapX to run a script to update a column +// the operation is on a single node / row of the database combination + +bool SalaProgram::runupdate(int col, const std::set &selset) +{ + AttributeTable *table = m_thisobj.getTable(); + bool pointmap = (m_thisobj.type & SalaObj::S_POINTMAP) ? true : false; + // + // note: reference, will change object directly, which is important for commands running the program + int& row = m_thisobj.data.graph.node; + m_col = col; + if (selset.size()) { + for (auto& sel: selset) { + row = sel; // *** NB! selsets for vga store pixelrefs keys, *all* others use rowids directly *** + try { + SalaObj val = evaluate(); + float v = (float) val.toDouble(); // note, toDouble will type check and throw if there's a problem + if (!std::isfinite(v)) { + v = -1.0f; + } + table->changeValue(pointmap ? table->getRowid(row) : row,m_col,v); + } + catch (SalaError e) { + // error + m_error_stack.push_back(e); + return false; + } + } + } + else { + for (int i = 0; i < table->getRowCount(); i++) { + row = pointmap ? table->getRowKey(i) : i; // *** NB! selsets for vga store pixelrefs keys, *all* others use rowids directly *** + try { + SalaObj val = evaluate(); + float v = (float) val.toDouble(); // note, toDouble will type check and throw if there's a problem + if (!std::isfinite(v)) { + v = -1.0f; + } + table->changeValue(i,m_col,v); + } + catch (SalaError e) { + // error + m_error_stack.push_back(e); + return false; + } + } + } + return true; +} + +// this function is called by depthmapX to run a script to select values +// the operation is on a single node / row of the database combination + +bool SalaProgram::runselect(std::vector &selsetout, const std::set& selsetin) +{ + AttributeTable *table = m_thisobj.getTable(); + bool pointmap = (m_thisobj.type & SalaObj::S_POINTMAP) ? true : false; + // + int& row = m_thisobj.data.graph.node; + if (selsetin.size()) { + for (auto& sel: selsetin) { + row = sel; // *** NB! selsets for vga store pixelrefs keys, *all* others use rowids directly *** + try { + SalaObj val = evaluate(); + bool v = val.toBool(); // note, toBool will type check and throw if there's a problem + if (v) { + selsetout.push_back(sel); + } + } + catch (SalaError e) { + // error + m_error_stack.push_back(e); + return false; + } + } + } + else { + for (int i = 0; i < table->getRowCount(); i++) { + row = pointmap ? table->getRowKey(i) : i; // *** NB! selsets for vga store pixelrefs keys, *all* others use rowids directly *** + try { + SalaObj val = evaluate(); + bool v = val.toBool(); // note, toBool will type check and throw if there's a problem + if (v) { + selsetout.push_back(row); + } + } + catch (SalaError e) { + // error + m_error_stack.push_back(e); + return false; + } + } + } + return true; +} + +std::string SalaProgram::getLastErrorMessage() const +{ + const SalaError& error = m_error_stack.tail(); + if (error.lineno == -1) { + return error.message; + } + else { + return error.message + " on line " + dXstring440::formatString(error.lineno+1,"%d"); + } +} + +//////////////////////////////////////////////////////////////////////////// + +SalaCommand::SalaCommand(SalaProgram *program, SalaCommand *parent, int indent, Command command) +{ + m_program = program; + m_parent = parent; + m_indent = indent; + m_command = command; + m_line = 0; +} + +int SalaCommand::parse(std::istream& program, int line) +{ + m_func_stack.clear(); + m_eval_stack.clear(); + m_var_names.clear(); + + m_command = SC_NONE; + + // useful to know which line the command starts on for debugging purposes + m_line = line; + + int last = SP_FUNCTION; + bool endloop = false; + bool overridecache = false; + bool firstword = true; + SalaBuffer buffer; + char cache = ' '; + // + while (!endloop && !program.eof()) { + char alpha = program.get(); + switch (alpha) { + // string constant + case '\"': case '\'': // variants: either delimit with single or double quotes + if (!buffer.empty()) { + decode(buffer); + buffer.clear(); + } + { + char delim = alpha; + char beta = program.peek(); + while (beta != EOF && beta != '\n' && (beta != delim || alpha == '\\')) { + alpha = program.get(); + beta = program.peek(); + buffer.add(alpha); + } + if (beta == EOF || beta == '\n') { + throw SalaError("No closing quote",m_line); + } + else { + program.get(); // take off closing quote and discard + } + // add even if the string constant is empty: + m_eval_stack.push_back( std::string(buffer) ); + buffer.clear(); + last = SP_DATA; + } + break; + // operator stack + case '+': case '-': + if (!buffer.empty()) { + last = decode(buffer); + if (last & SP_NUMBER && cache == 'e') { + // check for 9.999e+99... + // decode will handle later: + buffer.add(alpha); + break; + } + // otherwise handled, clear the buffer: + buffer.clear(); + } + if (last == SP_FUNCTION || last == SP_COMMAND) { + pushFunc( alpha == '+' ? SalaObj(SalaObj::S_PLUS) : SalaObj(SalaObj::S_MINUS) ); + } + else { + pushFunc( alpha == '+' ? SalaObj(SalaObj::S_ADD) : SalaObj(SalaObj::S_SUBTRACT) ); + } + last = SP_FUNCTION; + break; + case '=': + if (!buffer.empty()) { + // n.b., this will catch '>=', '<=', '==' and '!=' + if (strchr("><=!",cache) != NULL) { + buffer.add(alpha); + last = decode(buffer); + buffer.clear(); + overridecache = true; + // handled next step (see default clause below) + break; + } + else { + last = decode(buffer); + buffer.clear(); + } + } + buffer.add(alpha); // <- '=' decoded later + break; + case '!': case '<': case '>': + if (!buffer.empty()) { + last = decode(buffer); + buffer.clear(); + } + // note: this looks a little odd, simply adding to the buffer, but these + // are handled by the default function next step if still hanging on the buffer + buffer.add(alpha); + break; + case '/': case '*': case '%': case '^': + if (!buffer.empty()) { + last = decode(buffer); + buffer.clear(); + } + last = decode(std::string(1,alpha)); + break; + case '(': + // note: the opening bracket forms a function + if (!buffer.empty()) { + last = decode(buffer); + buffer.clear(); + } + if (last == SP_DATA) { + // whatever that just went onto the eval stack, the user thought it was a function... + // alert them: + throw SalaError(m_last_string + " is not a known function name", m_line); + // (in the future, we may well want to transfer an object hashed function name to the func stack instead) + } + else if (last == SP_NUMBER) { + throw SalaError("Cannot treat a number as if it were a function", m_line); + } + // check for pair of open / close brackets: () or ( ) -- this is a null value + { + char beta = program.peek(); + while (beta != EOF && beta == ' ') { + alpha = program.get(); + beta = program.peek(); + } + if (beta == ')') { + alpha = program.get(); + m_eval_stack.push_back(SalaObj()); + last = SP_DATA; + } + else { + pushFunc( SalaObj::S_OPEN_BRACKET ); + last = SP_FUNCTION; + } + } + break; + case ')': + // note: the closing bracket forms a data packet: + if (!buffer.empty()) { + last = decode(buffer); + buffer.clear(); + } + pushFunc( SalaObj::S_CLOSE_BRACKET ); + last = SP_DATA; + break; + case '[': + if (!buffer.empty()) { + last = decode(buffer); + buffer.clear(); + } + // check for pair of open / close brackets: [] or [ ] -- this is a null value or empty list depending on context + { + char beta = program.peek(); + while (beta != EOF && beta == ' ') { + alpha = program.get(); + beta = program.peek(); + } + if (beta == ']') { + alpha = program.get(); + if (last == SP_DATA) { + throw SalaError("Accessor operator ('[]') requires a parameter", m_line); + } + else { + // put an empty list on the stack + m_eval_stack.push_back( SalaObj(SalaObj::S_CONST_LIST, 0) ); + } + last = SP_DATA; + } + else { + if (last == SP_DATA) { + // list accessor function + pushFunc( SalaObj::S_LIST_ACCESS ); + pushFunc( SalaObj::S_OPEN_SQR_BRACKET_ACCESS ); + } + else { + // making an list... + pushFunc( SalaObj::S_OPEN_SQR_BRACKET_LIST ); + } + last = SP_FUNCTION; + } + } + break; + case ']': + // note: the closing bracket forms a data packet: + if (!buffer.empty()) { + last = decode(buffer); + buffer.clear(); + } + pushFunc( SalaObj::S_CLOSE_SQR_BRACKET ); + last = SP_DATA; + break; + case ',': + if (!buffer.empty()) { + last = decode(buffer); + buffer.clear(); + } + pushFunc( SalaObj::S_COMMA ); + last = SP_FUNCTION; + break; + case ':': + if (!buffer.empty()) { + last = decode(buffer); + buffer.clear(); + } + // end of command (def, if, else, elif and for) + if (m_command == SC_FOR || m_command == SC_WHILE || m_command == SC_IF || m_command == SC_ELIF || m_command == SC_ELSE) { + bool commentfound = false; + alpha = program.get(); + while (!program.eof() && alpha != '\n') { + // continue to end of line, only comments allowed though! + if (!commentfound) { + if (alpha == '#') { + commentfound = true; + } + else if (alpha != ' ' && alpha != 13) { // 13 ignored, as it appears \n is 10 in this stream... (so 13,10 can be found) + throw SalaError("'For', 'if', 'else', etc cannot have execution part on same line; insert a new line after ':'", m_line); + } + } + alpha = program.get(); + } + line++; + endloop = true; + } + else { + throw SalaError("Unexpected colon ':' in expression",m_line); + } + break; + // end of line: + case '\\': + // hit line continuation, read to end of line: + if (!buffer.empty()) { + last = decode(buffer); + buffer.clear(); + } + while (!program.eof() && program.get() != '\n'); + // note, end loop is not set, this is a continuation character + line++; // line is incremented, although it this command will still start on the original line + break; + case '#': + // loop through until hit \n or end + if (!buffer.empty()) { + last = decode(buffer); + buffer.clear(); + } + while (!program.eof() && program.get() != '\n'); + line++; // should have hit a line end (or if it's end of file, it doesn't matter) + endloop = true; + break; + case '\n': + // force end of command parse: + if (!buffer.empty()) { + last = decode(buffer); + buffer.clear(); + } + line++; // hit a line end + endloop = true; + break; + case ' ': + // white space: read word + if (!buffer.empty()) { + last = decode(buffer); + buffer.clear(); + } + break; + case '.': + // currently handled inelegantly through decode for either number (1.002) or member access (blah.x()) + buffer.add('.'); + break; + case '\t': + throw SalaError("Tab character found: please use only spaces to indent lines",m_line); + break; + default: + if (strchr("<>=!",cache)) { + // >, <, = and ! are held as next step operators + last = decode(buffer); + buffer.clear(); + } + if (alpha != EOF && alpha != 13) { // 13 ignored, as it appears \n is 10 in this stream... + if (!isalphanum_(alpha) && alpha != '&' && alpha != '|') { // include & and | for and and or + throw SalaError("Unrecognised symbol ('" + std::string(1,alpha) + "')",m_line); + } + buffer.add(alpha); + } + break; + } + if (overridecache) { + cache = ' '; + overridecache = false; + } + else { + cache = alpha; + } + if (last == SP_COMMAND) { + if (m_command == SC_FOR) { + // check the name of the for variable: + alpha = program.get(); + while (alpha == ' ') { + alpha = program.get(); + } + if (!isalpha_(alpha)) { + throw SalaError("'For' command expecting variable name",m_line); + } + while (isalphanum_(alpha)) { + buffer.add(alpha); + alpha = program.get(); + } + if (alpha != ' ') { + throw SalaError("Command expecting syntax 'for xyz in'...",m_line); + } + // add the for iterator variable: + m_program->m_var_stack.push_back(SalaObj()); + int x = m_program->m_var_stack.size() - 1; + m_var_names.add(buffer,x); + m_for_iter = SalaObj( SalaObj::S_VAR, x); + // now check for 'in' + while (alpha == ' ') { + alpha = program.get(); + } + if (alpha != 'i' || program.get() != 'n') { + throw SalaError("Command expecting syntax 'for xyz in'...",m_line); + } + } + last = SP_FUNCTION; + } + } + if (!buffer.empty()) { + decode(buffer); + buffer.clear(); + last = SP_DATA; + } + // push remaining functions onto eval stack: + while (m_func_stack.size()) { + if (m_func_stack.tail().type & SalaObj::S_BRACKET) { + throw SalaError("Unmatched brackets",m_line); + } + m_eval_stack.push_back(m_func_stack.tail()); + m_func_stack.pop_back(); + } + + if (m_eval_stack.size() == 0 && m_command != SC_ELSE) { // note, else is by definition empty + throw SalaError("Partial or missing command",m_line); + } + return line; +} + +int SalaCommand::decode(std::string string) // string copied as makelower applied +{ + // ideally, some form of hashing the string should be performed so that + // functions can be found quicker than a long list of "else ifs" + int retvar = SP_NONE; + dXstring440::toLower(string); + + if (m_command == SC_NONE) { + if (string == "return") { + m_command = SC_RETURN; + retvar = SP_COMMAND; + } + else if (string == "for") { + m_command = SC_FOR; // n.b. will still need a variable name and "in": for x in ... + retvar = SP_COMMAND; + } + else if (string == "while") { + m_command = SC_WHILE; + retvar = SP_COMMAND; + } + else if (string == "if") { + m_command = SC_IF; + retvar = SP_COMMAND; + } + else if (string == "elif") { + m_command = SC_ELIF; + retvar = SP_COMMAND; + } + else if (string == "else") { + m_command = SC_ELSE; + retvar = SP_COMMAND; + } + } + if (retvar == SP_COMMAND) { + // + m_last_string = string; // make a copy for debugging purposes + return retvar; + } + + // numeric constant + if (isdigit(string[0]) || (string.length() > 1 && string[0] == '.' && isdigit(string[1]))) { + if (string[string.length()-1] == 'e') { + // handle later... at the moment we have hit + or - in 9.999e+99 or 9.999e-99 + m_last_string = string; // make a copy for debugging purposes + return SP_NUMBER; + } + if (string.find_first_of('.') != std::string::npos || string.find_first_of('e') != std::string::npos) { + m_eval_stack.push_back( atof(string.c_str()) ); + } + else { + m_eval_stack.push_back( atoi(string.c_str()) ); + } + retvar = SP_NUMBER; + } + // this is a different 'e' to the 'e' above -> natural logarithm + else if (string == "e") { + m_eval_stack.push_back( 2.7182818284590452353602874713527 ); + retvar = SP_NUMBER; + } + else if (string == "pi") { + m_eval_stack.push_back( 3.1415926535897932384626433832795 ); + retvar = SP_NUMBER; + } + // boolean constants + else if (string == "true") { + m_eval_stack.push_back( bool(true) ); + retvar = SP_NUMBER; + } + else if (string == "false") { + m_eval_stack.push_back( bool(false) ); + retvar = SP_NUMBER; + } + // this + else if (string == "this") { + m_eval_stack.push_back( SalaObj(SalaObj::S_THIS) ); + retvar = SP_DATA; + } + else if (string == "none") { + m_eval_stack.push_back(SalaObj()); + retvar = SP_DATA; + } + else { + // everything else should be in one of the operator / func lists: + size_t i; + if (retvar == SP_NONE) { + // note, math ops include assignment + for (i = 0 ; i < g_sala_math_ops.size(); i++) { + if (string == g_sala_math_ops[i].name) { + pushFunc( g_sala_math_ops[i].func ); + retvar = SP_FUNCTION; + break; + } + } + } + if (retvar == SP_NONE) { + for (i = 0 ; i < g_sala_comp_ops.size(); i++) { + if (string == g_sala_comp_ops[i].name) { + pushFunc( g_sala_comp_ops[i].func ); + retvar = SP_FUNCTION; + break; + } + } + } + if (retvar == SP_NONE) { + for (i = 0 ; i < g_sala_logical_ops.size(); i++) { + if (string == g_sala_logical_ops[i].name) { + pushFunc( g_sala_logical_ops[i].func ); + retvar = SP_FUNCTION; + break; + } + } + } + if (retvar == SP_NONE) { + for (i = 0 ; i < g_sala_global_funcs.size(); i++) { + if (string == g_sala_global_funcs[i].name) { + pushFunc( g_sala_global_funcs[i].func ); + retvar = SP_FUNCTION; + } + } + } + } + + if (retvar == SP_NONE) { + size_t n = string.find_first_of("."); + if (n != std::string::npos) { + if (n > 0) { + decode(string.substr(0,n)); + } + if (decode_member(string.substr(n+1),false) == SP_NONE) { + throw SalaError("There is no known member function called " + string.substr(n+1),m_line); + } + retvar = SP_FUNCTION; + } + else { + // see if it's a member function of 'this': + retvar = decode_member(string,true); + + if (retvar == SP_NONE) { + // see if it exists in the variable stack (walk up scope) + SalaCommand *parent = m_parent; + size_t n = paftl::npos; + int x = -1; + while (parent != NULL && n == -1) { + n = parent->m_var_names.searchindex(string); + if (n != paftl::npos) { + x = parent->m_var_names.value(n); + } + parent = parent->m_parent; + } + if (x != -1) { + m_eval_stack.push_back( SalaObj( SalaObj::S_VAR, x) ); + retvar = SP_DATA; + } + else { + m_program->m_var_stack.push_back(SalaObj()); + x = m_program->m_var_stack.size() - 1; + // note: attach simply to your m_parent, not parent variable, which has walked up the stack + m_parent->m_var_names.add(string,x); + m_eval_stack.push_back( SalaObj( SalaObj::S_VAR, x) ); + retvar = SP_DATA; + } + } + } + } + + if (retvar == SP_NONE) { + // should never reach this point + throw SalaError("There is no known function or variable called " + string,m_line); + } + + + if (m_command == SC_NONE) { + m_command = SC_EXPR; + } + + m_last_string = string; // make a copy for debugging purposes + + return retvar; +} + +// note, thisobj not usually known (type S_NALL), +// but, depending where SalaScript is called from, it may be: +// a graph node / table row (for "select by query" and "edit connections") +// a map (not yet implemented, but intended for scripting agents) + +int SalaCommand::decode_member(const std::string& string, bool apply_to_this) +{ + int retvar = SP_NONE; + + // note, all hardcoded for built in classes: + // string classes: + for (size_t i = 0; i < g_sala_member_funcs.size(); i++) { + // note '&' in the type -- essentially allows for inheritance between objects (tuple is type of list, etc) + if (!apply_to_this || (m_program->m_thisobj.type & g_sala_member_funcs[i].type) != 0) { + if (string == g_sala_member_funcs[i].name) { + pushFunc( g_sala_member_funcs[i].func ); + retvar = SP_FUNCTION; + break; + } + } + } + if (retvar == SP_FUNCTION && apply_to_this) { + m_eval_stack.push_back(SalaObj(SalaObj::S_THIS)); + } + return retvar; +} + +void SalaCommand::pushFunc(const SalaObj& func) +{ + // note comma is part of the "Bracket" class of things: + if (func.type & SalaObj::S_BRACKET) { + if (func.type == SalaObj::S_CLOSE_BRACKET) { + while (m_func_stack.size() && m_func_stack.tail().type != SalaObj::S_OPEN_BRACKET) { + m_eval_stack.push_back(m_func_stack.tail()); + m_func_stack.pop_back(); + } + if (m_func_stack.size()) { + // don't necessarily pop it... if it's a group marker, we want to hang onto it: + if (m_func_stack.tail().data.count > 1) { + m_func_stack.tail().type = SalaObj::S_CONST_TUPLE; + m_eval_stack.push_back(m_func_stack.tail()); + } + m_func_stack.pop_back(); // remove opening bracket + } + } + else if (func.type == SalaObj::S_CLOSE_SQR_BRACKET) { + while (m_func_stack.size() && (m_func_stack.tail().type & SalaObj::S_OPEN_SQR_BRACKET) == 0) { + m_eval_stack.push_back(m_func_stack.tail()); + m_func_stack.pop_back(); + } + if (m_func_stack.size()) { + // don't pop it, always make a list from a make list command, even if it's only one item long: + if (m_func_stack.tail().type == SalaObj::S_OPEN_SQR_BRACKET_LIST || m_func_stack.tail().data.count > 1) { + m_func_stack.tail().type = SalaObj::S_CONST_LIST; + m_eval_stack.push_back(m_func_stack.tail()); + } + m_func_stack.pop_back(); + } + } + else if (func.type == SalaObj::S_COMMA) { + // go and increment your associated group / list + while (m_func_stack.size() && m_func_stack.tail().type != SalaObj::S_OPEN_BRACKET && (m_func_stack.tail().type & SalaObj::S_OPEN_SQR_BRACKET) == 0) { + m_eval_stack.push_back(m_func_stack.tail()); + m_func_stack.pop_back(); + } + if (m_func_stack.size()) { + m_func_stack.tail().data.count++; + } + } + else { + m_func_stack.push_back( func ); + } + } + else if (!m_func_stack.size() || func.precedence() > m_func_stack.tail().precedence()) { // original: > + m_func_stack.push_back(func); + } + else { + while (m_func_stack.size() && func.precedence() <= m_func_stack.tail().precedence()) { // original <= + m_eval_stack.push_back(m_func_stack.tail()); + m_func_stack.pop_back(); + } + m_func_stack.push_back(func); + } +} + +void SalaCommand::evaluate(SalaObj& obj, bool& ret, bool& ifhandled) +{ + int begin = m_eval_stack.size()-1; + SalaObj *p_obj = NULL; + switch (m_command) { + case SC_EXPR: + obj = evaluate(begin,p_obj); + break; + case SC_RETURN: + ret = true; + obj = evaluate(begin,p_obj); + break; + case SC_ROOT: + { + for (size_t i = 0; i < m_children.size(); i++) { + m_children[i].evaluate(obj,ret,ifhandled); + if (ret) + break; + } + } + break; + case SC_IF: + { + SalaObj test = evaluate(begin,p_obj); + if (test.toBool() == true) { + for (size_t i = 0; i < m_children.size(); i++) { + m_children[i].evaluate(obj,ret,ifhandled); + if (ret) + break; + } + ifhandled = true; + } + else { + ifhandled = false; + } + } + break; + case SC_ELIF: + if (!ifhandled) { + SalaObj test = evaluate(begin,p_obj); + if (test.toBool() == true) { + for (size_t i = 0; i < m_children.size(); i++) { + m_children[i].evaluate(obj,ret,ifhandled); + if (ret) + break; + } + ifhandled = true; + } + } + break; + case SC_ELSE: + if (!ifhandled) { + for (size_t i = 0; i < m_children.size(); i++) { + m_children[i].evaluate(obj,ret,ifhandled); + if (ret) + break; + } + } + break; + case SC_FOR: + { + // eventually I'd like to do this with generators / iterators rather than constructing a list each time + SalaObj list = evaluate(begin,p_obj); + if (list.type == SalaObj::S_LIST) { + int len = list.data.list.list->size(); + if (len != 0) { + for (int i = 0; i < len; i++) { + // reset all my stack (actually, all parent functions should do this!) + for (size_t j = 0; j < m_var_names.size(); j++) { + m_program->m_var_stack[m_var_names.value(j)].uninit(); + } + m_program->m_var_stack[m_for_iter.data.var] = list.data.list.list->at(i); + for (size_t k = 0; k < m_children.size(); k++) { + m_children[k].evaluate(obj,ret,ifhandled); + if (ret) + break; + } + if (ret) + break; + } + ifhandled = true; + } + else { + ifhandled = false; + } + } + else { + ifhandled = false; + } + } + break; + case SC_WHILE: + { + int counter = 0; + while (evaluate(begin,p_obj).toBool()) { + for (size_t k = 0; k < m_children.size(); k++) { + m_children[k].evaluate(obj,ret,ifhandled); + if (ret) + break; + } + if (ret) + break; + if (++counter == 0x04000000) { // <- an arbitrary big number + throw SalaError("Infinite loop",m_line); + } + begin = m_eval_stack.size()-1; + } + if (counter) { + ifhandled = true; + } + else { + ifhandled = false; + } + } + break; + default: + throw SalaError("Unknown command",m_line); + break; + } +} + +SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) +{ + if (pointer < 0) { + throw SalaError("Missing argument",m_line); + } + SalaObj data = m_eval_stack[pointer]; + pointer--; + if (data.type == SalaObj::S_FUNCTION) { + SalaObj::Func func = data.data.func; + int group = (func & SalaObj::S_GROUP); + if (group == SalaObj::S_MATH_OPS) { + try { + switch (func) { + case SalaObj::S_ADD: + // Quick mod - TV +#if defined(_MSC_VER) + data = evaluate(pointer,p_obj) + evaluate(pointer,p_obj); +#else + { + SalaObj tmp1 = evaluate(pointer,p_obj); + SalaObj tmp2 = evaluate(pointer,p_obj); + data = tmp1 + tmp2; + } +#endif + break; + case SalaObj::S_SUBTRACT: + // Quick mod - TV +#if defined(_MSC_VER) + data = evaluate(pointer,p_obj) - evaluate(pointer,p_obj); +#else + { + SalaObj tmp1 = evaluate(pointer,p_obj); + SalaObj tmp2 = evaluate(pointer,p_obj); + data = tmp1 - tmp2; + } +#endif + break; + case SalaObj::S_PLUS: + data = evaluate(pointer,p_obj); // just ignore it + break; + case SalaObj::S_MINUS: + // Quick mod - TV +#if defined(_MSC_VER) + data = -evaluate(pointer,p_obj); +#else + { + SalaObj tmp1 = evaluate(pointer,p_obj); + data = -tmp1; + } +#endif + break; + case SalaObj::S_MULTIPLY: + // Quick mod - TV +#if defined(_MSC_VER) + data = evaluate(pointer,p_obj) * evaluate(pointer,p_obj); +#else + { + SalaObj tmp1 = evaluate(pointer,p_obj); + SalaObj tmp2 = evaluate(pointer,p_obj); + data = tmp1 * tmp2; + } +#endif + break; + case SalaObj::S_DIVIDE: + // Quick mod - TV +#if defined(_MSC_VER) + data = evaluate(pointer,p_obj) / evaluate(pointer,p_obj); +#else + { + SalaObj tmp1 = evaluate(pointer,p_obj); + SalaObj tmp2 = evaluate(pointer,p_obj); + data = tmp2 / tmp1; + } +#endif + break; + case SalaObj::S_MODULO: + data = evaluate(pointer,p_obj); + + // Quick mod - TV +#if defined(_MSC_VER) + data = evaluate(pointer,p_obj) % data; // reverse order +#else + { + SalaObj tmp1 = evaluate(pointer, p_obj); + data = tmp1 % data; + } +#endif + break; + case SalaObj::S_POWER: + data = evaluate(pointer,p_obj); // reverse order + data = pow(evaluate(pointer,p_obj).toDouble(),data.toDouble()); + break; + case SalaObj::S_ASSIGN: + data = evaluate(pointer,p_obj); // reverse order + evaluate(pointer,p_obj); + if (p_obj != nullptr) { + *p_obj = data; + } + else { + throw SalaError("Cannot assign to constant, function or none",m_line); + } + data = SalaObj(); // assign returns nil value + break; + case SalaObj::S_LIST_ACCESS: + { + int x = evaluate(pointer,p_obj).toInt(); + data = evaluate(pointer,p_obj); + if (data.type == SalaObj::S_LIST) { + // setting p_obj allows things above this in the stack to modify it + p_obj = &(data.list_at(x)); + return *p_obj; + } + else if (data.type == SalaObj::S_STRING) { + // but n.b., strings cannot be modified, keep p_obj as null + p_obj = NULL; + return data.char_at(x); + } + else + throw SalaError("Cannot be applied to " + data.getTypeIndefArt() + data.getTypeStr(),m_line); + } + break; + default: + break; + } + } + catch (SalaError e) + { + // slow to go through one by one, but this is an exception... + for (size_t i = 0; i < g_sala_math_ops.size(); i++) { + if (g_sala_math_ops[i].func == func) { + e.message = "In '" + g_sala_math_ops[i].name + "' operator: " + e.message; + break; + } + } + e.lineno = m_line; throw e; + } + } + else if (group == SalaObj::S_LOGICAL_OPS) { + try { + switch (func) { + case SalaObj::S_OR: + // note: you cannot simply say evaluate(x) || evaluate(y) because if evaluate(x) is true, + // the in-built || operator will not evaluate(y) + // but... it's on the eval stack... it would be nice simply to pop the eval stack at + // this point if the first half evaluates to true, thus emulating C... but it's in reverse order too! + data = evaluate(pointer,p_obj); + data = evaluate(pointer,p_obj).toBool() || data.toBool(); + break; + case SalaObj::S_AND: + data = evaluate(pointer,p_obj).toBool() && evaluate(pointer,p_obj).toBool(); + break; + case SalaObj::S_NOT: + data = !evaluate(pointer,p_obj).toBool(); + break; + case SalaObj::S_EQ: + // Quick mod - TV +#if defined(_MSC_VER) + data = evaluate(pointer,p_obj) == evaluate(pointer,p_obj); +#else + { + SalaObj tmp1 = evaluate(pointer, p_obj); + SalaObj tmp2 = evaluate(pointer, p_obj); + data = (tmp1 == tmp2); + } +#endif + break; + case SalaObj::S_IS: + // Quick mod - TV +#if defined(_MSC_VER) + data = op_is(evaluate(pointer,p_obj),evaluate(pointer,p_obj)); +#else + { + SalaObj tmp1 = evaluate(pointer, p_obj); + SalaObj tmp2 = evaluate(pointer, p_obj); + data = op_is(tmp1, tmp2); + } +#endif + break; + case SalaObj::S_NEQ: + // Quick mod - TV +#if defined(_MSC_VER) + data = evaluate(pointer,p_obj) != evaluate(pointer,p_obj); +#else + { + SalaObj tmp1 = evaluate(pointer,p_obj); + SalaObj tmp2 = evaluate(pointer,p_obj); + data = (tmp1 != tmp2); + } +#endif + break; + case SalaObj::S_GT: + data = evaluate(pointer,p_obj); + // Quick mod - TV +#if defined(_MSC_VER) + data = evaluate(pointer,p_obj) > data; // revese order +#else + { + SalaObj tmp1 = evaluate(pointer,p_obj); + data = (tmp1 > data); + } +#endif + break; + case SalaObj::S_LT: + data = evaluate(pointer,p_obj); + // Quick mod - TV +#if defined(_MSC_VER) + data = evaluate(pointer,p_obj) < data; // revese order +#else + { + SalaObj tmp1 = evaluate(pointer,p_obj); + data = (tmp1 < data); + } +#endif + break; + case SalaObj::S_GEQ: + data = evaluate(pointer,p_obj); + + // Quick mod - TV +#if defined(_MSC_VER) + data = evaluate(pointer,p_obj) >= data; // revese order +#else + { + SalaObj tmp1 = evaluate(pointer,p_obj); + data = (tmp1 >= data); + } +#endif + break; + case SalaObj::S_LEQ: + data = evaluate(pointer,p_obj); + + // Quick mod - TV +#if defined(_MSC_VER) + data = evaluate(pointer,p_obj) <= data; // revese order +#else + { + SalaObj tmp1 = evaluate(pointer, p_obj); + data = (tmp1 <= data); + } +#endif + break; + default: + break; + } + } + catch (SalaError e) + { + // slow to go through one by one, but this is an exception... + for (size_t i = 0; i < g_sala_logical_ops.size(); i++) { + if (g_sala_logical_ops[i].func == func) { + e.message = "In '" + g_sala_logical_ops[i].name + "' operator: " + e.message; + break; + } + } + for (size_t j = 0; j < g_sala_comp_ops.size(); j++) { + if (g_sala_comp_ops[j].func == func) { + e.message = "In '" + g_sala_comp_ops[j].name + "' operator: " + e.message; + break; + } + } + e.lineno = m_line; throw e; + } + } + else if (group == SalaObj::S_GLOBAL_FUNCS) { + try { + switch (func) { + case SalaObj::S_LEN: + data = evaluate(pointer,p_obj); + data = SalaObj( data.length() ); + break; + case SalaObj::S_RANGE: + data = evaluate(pointer,p_obj); + { + int len = data.length(); + if (len != 2 && len != 3) { + throw SalaError("Range takes either 2 or 3 parameters",m_line); + } + int start = data.data.list.list->at(0).toInt(); + int end = data.data.list.list->at(1).toInt(); + int step = (len == 3) ? data.data.list.list->at(2).toInt() : 1; + if (step == 0) { + throw SalaError("Range cannot have a step of 0",m_line); + } + int listlen = (int) ceil(float(end - start) / float(step)); + if (listlen <= 0) { + data = SalaObj( SalaObj::S_LIST ); + } + else { + data = SalaObj( SalaObj::S_LIST, listlen ); + for (int i = start, j = 0; i < end; i += step, j++) { + data.data.list.list->at(j) = i; + } + } + } + break; + case SalaObj::S_SQRT: + data = sqrt(evaluate(pointer,p_obj).toDouble()); + break; + case SalaObj::S_LOG: + data = log10(evaluate(pointer,p_obj).toDouble()); + break; + case SalaObj::S_LN: + data = ln(evaluate(pointer,p_obj).toDouble()); + break; + case SalaObj::S_RAND: + data = evaluate(pointer,p_obj); + data.ensureNone(); + data = SalaObj(prandom()); + break; + case SalaObj::S_SIN: + data = sin(evaluate(pointer,p_obj).toDouble()); + break; + case SalaObj::S_COS: + data = cos(evaluate(pointer,p_obj).toDouble()); + break; + case SalaObj::S_TAN: + data = tan(evaluate(pointer,p_obj).toDouble()); + break; + case SalaObj::S_ASIN: + data = asin(evaluate(pointer,p_obj).toDouble()); + break; + case SalaObj::S_ACOS: + data = acos(evaluate(pointer,p_obj).toDouble()); + break; + case SalaObj::S_ATAN: + data = atan(evaluate(pointer,p_obj).toDouble()); + break; + default: + break; + } + } + catch (SalaError e) + { + // slow to go through one by one, but this is an exception... + for (size_t i = 0; i < g_sala_global_funcs.size(); i++) { + if (g_sala_global_funcs[i].func == func) { + e.message = "In '" + g_sala_global_funcs[i].name + "' function: " + e.message; + break; + } + } + e.lineno = m_line; throw e; + } + } + else if (group == SalaObj::S_MEMBER_FUNCS) { + try { + SalaObj param = evaluate(pointer,p_obj); + SalaObj obj = evaluate(pointer,p_obj); + switch (obj.type) { + case SalaObj::S_LIST: case SalaObj::S_TUPLE: + switch (func) { + case SalaObj::S_FAPPEND: + obj.data.list.list->push_back(param); + data = SalaObj(); // returns none + break; + case SalaObj::S_FEXTEND: + if (param.type & SalaObj::S_LIST) { + int count = param.data.list.list->size(); + for (int i = 0; i < count; i++) { + obj.data.list.list->push_back(param.data.list.list->at(i)); + } + } + else { + throw SalaError("Parameter must be a list not " + param.getTypeIndefArt() + param.getTypeStr(),m_line); + } + data = SalaObj(); // returns none + break; + case SalaObj::S_FPOP: + if (obj.data.list.list->size() == 0) { + throw SalaError("List is empty", m_line); + } + if (param.type == SalaObj::S_NONE) { + data = obj.data.list.list->tail(); + obj.data.list.list->pop_back(); + } + else { + pvector& list = *(obj.data.list.list); + int i = param.toInt(); + if (i < 0) + i += list.size(); + if (i < 0 || i >= (int)list.size()) + throw SalaError("Index out of range"); + data = list.at(i); + list.remove_at(i); + } + break; + case SalaObj::S_FCLEAR: + param.ensureNone(); + obj.data.list.list->clear(); + obj = SalaObj(); + break; + default: + throw SalaError("Not a member function of " + obj.getTypeStr(),m_line); + } + break; + case SalaObj::S_SHAPEMAPOBJ: case SalaObj::S_POINTMAPOBJ: + switch (func) { + case SalaObj::S_FVALUE: + { + const std::string& str = param.toStringRef(); + AttributeTable *table = obj.getTable(); + int col = -1; + if (str != "Ref Number") { + col = table->getColumnIndex(str); + if (col == -1) { + throw SalaError(str + " is an unknown column",m_line); + } + } + // *** NB! vga is keyed off pixelrefs *all* others use rowids directly *** + // (this may seem an odd way to do it, but it speeds up connection hunting to use whichever method the map uses -- note idepthmap uses the method to access attributes) + data = SalaObj(table->getValue((obj.type == SalaObj::S_POINTMAPOBJ) ? table->getRowid(obj.data.graph.node) : obj.data.graph.node,col)); + } + break; + case SalaObj::S_FSETVALUE: + { + if (param.length() != 2) { + throw SalaError("Function takes 2 parameters"); + } + const std::string& str = param.list_at(0).toStringRef(); + float val = (float) param.list_at(1).toDouble(); + AttributeTable *table = obj.getTable(); + int col = -1; + if (str != "Ref Number") { + col = table->getColumnIndex(str); + if (col == -1) { + throw SalaError(str + " is an unknown column",m_line); + } + } + // *** NB! vga is keyed off pixelrefs *all* others use rowids directly *** + // (this may seem an odd way to do it, but it speeds up connection hunting to use whichever method the map uses -- note idepthmap uses the method to access attributes) + table->setValue((obj.type == SalaObj::S_POINTMAPOBJ) ? table->getRowid(obj.data.graph.node) : obj.data.graph.node, col, val); + data = SalaObj(); // returns none + } + break; + case SalaObj::S_FCONNECTIONS: + { + data = connections(obj, param); + } + break; + case SalaObj::S_FMARK: + { + param.ensureNone(); + AttributeTable *table = obj.getTable(); + data = table->getMark((obj.type == SalaObj::S_POINTMAPOBJ) ? table->getRowid(obj.data.graph.node) : obj.data.graph.node); + } + break; + case SalaObj::S_FSETMARK: + { + AttributeTable *table = obj.getTable(); + table->setMark((obj.type == SalaObj::S_POINTMAPOBJ) ? table->getRowid(obj.data.graph.node) : obj.data.graph.node, param); + m_program->m_marked = true; // <- this tells the program to tidy up marks between executions + data = SalaObj(); // returns none + } + break; + default: + throw SalaError("Not a member function of " + obj.getTypeStr(),m_line); + } + break; + default: + throw SalaError("Not a member function of " + obj.getTypeStr(), m_line); + } + } + catch (SalaError e) + { + // slow to go through one by one, but this is an exception... + for (size_t i = 0; i < g_sala_member_funcs.size(); i++) { + if (g_sala_member_funcs[i].func == func) { + SalaObj type = SalaObj(g_sala_member_funcs[i].type); + e.message = "In " + type.getTypeStr() + " '" + g_sala_member_funcs[i].name + "' function: " + e.message; + break; + } + } + e.lineno = m_line; throw e; + } + } + } + else if (data.type == SalaObj::S_THIS) { + p_obj = &(m_program->m_thisobj); + return *p_obj; + } + else if (data.type & SalaObj::S_VAR) { + // retrieve value from variable stack (keeping in a variable stack means it can be reassigned dynamically) + p_obj = &(m_program->m_var_stack[data.data.var]); + return *p_obj; + } + else if (data.type & SalaObj::S_CONST_LIST) { + // build an list from either a const tuple or const list: + int x = data.data.count; + data = SalaObj((data.type == SalaObj::S_CONST_LIST) ? SalaObj::S_LIST : SalaObj::S_TUPLE, x); + for (--x; x >= 0; x--) { + data.data.list.list->at(x) = evaluate(pointer,p_obj); // n.b., direct access to the list + } + } + p_obj = NULL; + return data; +} + +///////////////////////////////////////////////////////////////////////////////// + +SalaObj SalaCommand::connections(SalaObj graphobj, SalaObj param) +{ + // now, depending on type of object, it may or may not be allowed parameters: + // for point maps it can be none (all connections) or a bin number (0-32) + // for segment maps it can be 'all' or 'forward' or 'back' (a string -- no parameters is excluded due to potential for errors) + // for axial maps it must be none + SalaObj list; + if ((graphobj.type & SalaObj::S_MAP) == SalaObj::S_POINTMAP) { + // point map version + Node& node = graphobj.data.graph.map.point->getPoint(graphobj.data.graph.node).getNode(); + if (param.type == SalaObj::S_NONE) { + int count = node.count(); + list = SalaObj( SalaObj::S_LIST, count); + node.first(); + for (int i = 0; i < count; i++) { + graphobj.data.graph.node = node.cursor(); + list.data.list.list->at(i) = graphobj; + node.next(); + } + } + else { + int b = param.toInt(); // note, will throw if it's not the right type + if (b < 0 || b > 31) { + throw SalaError("Bin must be in range 0 to 31"); + } + Bin& bin = node.bin(b); + int count = bin.count(); + list = SalaObj( SalaObj::S_LIST, count); + bin.first(); + for (int i = 0; i < count; i++) { + graphobj.data.graph.node = bin.cursor(); + list.data.list.list->at(i) = graphobj; + bin.next(); + } + } + } + else { + const Connector& connector = graphobj.data.graph.map.shape->getConnections().at(graphobj.data.graph.node); + int mode = Connector::CONN_ALL; + if (graphobj.data.graph.map.shape->isSegmentMap()) { + const std::string& str = param.toStringRef(); + if (str == "forward") { + mode = Connector::SEG_CONN_FW; + } + else if (str == "back") { + mode = Connector::SEG_CONN_BK; + } + else if (str == "all") { + mode = Connector::SEG_CONN_ALL; + } + } + else { + param.ensureNone(); + } + int count = connector.count(mode); + list = SalaObj( SalaObj::S_LIST, count); + connector.first(); + for (int i = 0; i < count; i++) { + graphobj.data.graph.node = connector.cursor(mode); + list.data.list.list->at(i) = graphobj; + connector.next(); + } + } + return list; +} + +///////////////////////////////////////////////////////////////////////////////// + +AttributeTable *SalaObj::getTable() +{ + if ((type & SalaObj::S_MAP) == SalaObj::S_POINTMAP) { + return &(data.graph.map.point->getAttributeTable()); + } + else { + return &(data.graph.map.shape->getAttributeTable()); + } +} + +int SalaObj::precedence() const +{ + int prec = 0; + if ((type & S_BRACKET) == 0) { // preserve bracket on func stack until after close bracket, remember to strip any at end + switch (func()) { + case S_ASSIGN: + prec = 1; // do absolutely last! + break; + case S_AND: + prec = 2; + break; + case S_OR: + prec = 3; + break; + case S_NOT: + prec = 4; + break; + case S_EQ: case S_IS: case S_LT: case S_GT: case S_LEQ: case S_GEQ: case S_NEQ: + prec = 5; + break; + case S_ADD: case S_SUBTRACT: + prec = 6; + break; + case S_MULTIPLY: case S_DIVIDE: case S_MODULO: + prec = 7; + break; + case S_POWER: + prec = 8; + break; + default: // function -- place straight on eval stack when you meet next operator + prec = 9; + break; + } + } + return prec; +} +} diff --git a/mgraph440/salaprogram.h b/mgraph440/salaprogram.h new file mode 100644 index 00000000..dbf1c174 --- /dev/null +++ b/mgraph440/salaprogram.h @@ -0,0 +1,805 @@ +// salaprogram.h - a component of the depthmapX - spatial network analysis platform +// SalaScripting language +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#ifndef __SALAPROGRAM_H__ +#define __SALAPROGRAM_H__ + +#include "mgraph440/stringutils.h" +#include "mgraph440/paftl.h" +#include +#include +#include + +namespace mgraph440 { + +class AttributeTable; +class PointMap; +class ShapeMap; + +inline bool isalphanum_(char c) +{ + if (isalnum(c) || c == '_') + return true; + else + return false; +} + +inline bool isalpha_(char c) +{ + if (isalpha(c) || c == '_') + return true; + else + return false; +} + +struct SalaError +{ + int lineno; + std::string message; + SalaError(const std::string& m = std::string(), int li = -1) + { message = m; lineno = li; } +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +// A series of 8-byte types to go in the SalaObj data union +// note, they cannot cannot instantiate a copy constructor as it is used as +// a member of the union in SalaObj + +class SalaObj; + +struct SalaStr +{ +public: + int *refcount; + std::string *string; +public: + friend bool operator == (const SalaStr& a, const SalaStr& b); + friend bool operator != (const SalaStr& a, const SalaStr& b); + friend bool operator < (const SalaStr& a, const SalaStr& b); + friend bool operator > (const SalaStr& a, const SalaStr& b); + // operator const std::string&() { return *string; } + char char_at(size_t i) const + { return string->operator[](i); } + size_t length() const + { return string->length(); } +}; +inline bool operator == (const SalaStr& a, const SalaStr& b) +{ return *(a.string) == *(b.string); } +inline bool operator != (const SalaStr& a, const SalaStr& b) +{ return *(a.string) != *(b.string); } +inline bool operator < (const SalaStr& a, const SalaStr& b) +{ return *(a.string) < *(b.string); } +inline bool operator > (const SalaStr& a, const SalaStr& b) +{ return *(a.string) > *(b.string); } + +struct SalaList { + int *refcount; + pvector *list; +public: + friend bool operator == (const SalaList& a, const SalaList& b); + friend bool operator != (const SalaList& a, const SalaList& b); + // inlines below +}; + +struct SalaGrf { + int node; + union Map { + PointMap *point; // vga + ShapeMap *shape; // everything else + }; + Map map; +}; + +// SalaObj is 16 bytes, which is larger than I intended, but it appears +// when you put both a double (8 bytes) and an int (4 bytes) into a class, it pads +// to 16 bytes rather than the 12 you would expect + +// union members aren't allow copy constructors, so the list functionality +// is built directly into the SalaObj, making it no more inefficient than if it +// were to reference directly to another object to find, e.g., length or refcount + +// note lists are stored by reference. I'm not sure if this is a good idea! + +class SalaObj +{ + friend class SalaProgram; + friend class SalaCommand; + friend class SalaArray; +public: + // Object types + enum Type { S_BRACKET = 0x0000003f, S_OPEN_SQR_BRACKET = 0x0000000c, + S_OPEN_BRACKET = 0x00000001, S_CLOSE_BRACKET = 0x00000002, + S_OPEN_SQR_BRACKET_LIST = 0x00000004, S_OPEN_SQR_BRACKET_ACCESS = 0x00000008, + S_CLOSE_SQR_BRACKET = 0x00000010, S_COMMA = 0x00000020, // bracket includes comma for checking purposes + S_NONE = 0x00000100, S_UNINIT = 0x00000200, S_FUNCTION = 0x00000400, + S_BOOL = 0x00001000, S_CHAR = 0x00002000, + S_INT = 0x00004000, S_DOUBLE = 0x00008000, S_NUMBER = 0x0000c000, + S_STRING = 0x00010000, S_VAR = 0x00020000, + S_CONST_LIST = 0x00100000, S_CONST_TUPLE = 0x00300000, // tuple is a type of list + S_LIST = 0x00400000, S_TUPLE = 0x00500000, // tuple is a type of list + // maps are bitwise 'or'ed to node to make appropriate node type for each map + S_GRAPHOBJ = 0x01000000, S_MAP = 0x06000000, S_POINTMAP = 0x02000000, S_SHAPEMAP = 0x04000000, + // however, as the variable is uses the typename of the enum, each must be filled in explicitly: + S_POINTMAPOBJ = 0x03000000, S_SHAPEMAPOBJ = 0x05000000, + S_THIS = 0x10000000 + }; + // Built-in Functions, note, some of the groupings contain other operations (eg., math ops includes assign, and logical ops includes both comparators and logical ops) + enum Func { + S_FNULL = 0x00000000, S_GROUP = 0xf0000000, + S_MATH_OPS = 0x10000000, S_LOGICAL_OPS = 0x20000000, S_GLOBAL_FUNCS = 0x30000000, S_MEMBER_FUNCS = 0x40000000, + S_ADD = 0x10000001, S_SUBTRACT = 0x10000002, S_MINUS = 0x10000003, S_PLUS = 0x10000004, + S_MULTIPLY = 0x10000005, S_DIVIDE = 0x10000006, S_MODULO = 0x10000007, S_POWER = 0x10000008, + S_ASSIGN = 0x10000009, S_LIST_ACCESS = 0x1000000a, + S_LT = 0x20000001, S_GT = 0x20000002, S_LEQ = 0x20000003, S_GEQ = 0x20000004, S_EQ = 0x20000005, + S_NEQ = 0x20000006, S_AND = 0x20000007, S_OR = 0x20000008, S_NOT = 0x20000009, S_IS = 0x2000000a, + S_LEN = 0x30000001, S_RANGE = 0x30000002, + S_SQRT = 0x30000003, S_LOG = 0x30000004, S_LN = 0x30000005, S_RAND = 0x30000006, + S_SIN = 0x30000007, S_COS = 0x30000008, S_TAN = 0x30000009, + S_ASIN = 0x3000000a, S_ACOS = 0x3000000b, S_ATAN = 0x3000000c, + S_FPOP = 0x40000001, S_FAPPEND = 0x40000002, S_FEXTEND = 0x40000003, S_FCLEAR = 0x40000004, + S_FVALUE = 0x40000011, S_FSETVALUE = 0x40000012, S_FCONNECTIONS = 0x40000013, + S_FMARK = 0x40000014, S_FSETMARK = 0x40000015 + }; +protected: + union Data { + bool b; + char ch; + int i; + double f; + SalaList list; + SalaStr str; + SalaGrf graph; + Func func; + int var; + int count; // used by brackets to count how many objects they have + }; + Data data; + Type type; +public: + SalaObj() { type = S_NONE; } + // Two usages: (a) used for brackets (=groups of things, hence the count) and commas + // (b) used for lists + SalaObj(Type t) + { + type = t; + if (t & S_LIST) { + data.list.refcount = new int(1); + data.list.list = new pvector; + } + else { + data.count = 1; + } + } + // Two usages: (a) used to address variable or user function tables + // (b) used for lists + SalaObj(Type t, int v) + { + type = t; + if (t & S_LIST) { + data.list.refcount = new int(1); + data.list.list = new pvector; + data.list.list->set(v); // set blanks + } + else { + data.var = v; + } + } + // other constructors + SalaObj(bool a) { type = S_BOOL; data.b = a; } + SalaObj(int a) { type = S_INT; data.i = a; } + SalaObj(double a) { type = S_DOUBLE; data.f = a; } + SalaObj(Func f) { type = S_FUNCTION; data.func = f; } + SalaObj(const std::string& a) { type = S_STRING; data.str.refcount = new int(1); data.str.string = new std::string(a); } + // note, type required here as sometimes this will be an axial map, sometimes segment map, sometimes point map, + // also not fully filled in until runtime, but still required by parse + SalaObj(Type t, SalaGrf graph) + { type = t; data.graph = graph; } + // + SalaObj(const SalaObj& obj); + SalaObj& operator = (const SalaObj& obj); + ~SalaObj(); + void reset(); + void uninit() { reset(); type = S_UNINIT; } // <- used to uninitialise variables before running program, thus they give nice error messages if used before initialisation + int func() const { return data.func; } + int precedence() const; + bool toBool() const; + int toInt() const; + double toDouble() const; + std::string toString() const; + const std::string& toStringRef() const; + friend SalaObj op_is(SalaObj& a, SalaObj& b); + friend SalaObj operator - (SalaObj& a); + friend SalaObj operator + (SalaObj& a, SalaObj& b); + friend SalaObj operator - (SalaObj& a, SalaObj& b); + friend SalaObj operator / (SalaObj& a, SalaObj& b); + friend SalaObj operator * (SalaObj& a, SalaObj& b); + friend SalaObj operator % (SalaObj& a, SalaObj& b); + friend bool operator || (SalaObj& a, SalaObj& b); + friend bool operator && (SalaObj& a, SalaObj& b); + friend bool operator ! (SalaObj& a); + friend bool operator == (SalaObj& a, SalaObj& b); + friend bool operator != (SalaObj& a, SalaObj& b); + friend bool operator > (SalaObj& a, SalaObj& b); + friend bool operator < (SalaObj& a, SalaObj& b); + friend bool operator >= (SalaObj& a, SalaObj& b); + friend bool operator <= (SalaObj& a, SalaObj& b); + // operations for lists: + SalaObj& list_at(int i); + SalaObj char_at(int i); // actually returns a string of the char -- note constant + int length(); + // check for no parameters + void ensureNone() + { if (type != SalaObj::S_NONE) throw SalaError("Does not take any parameters"); } + // + // operations for graphs / graph nodes: + AttributeTable *getTable(); + // + const std::string getTypeStr() const; + const std::string getTypeIndefArt() const; +}; + +// Quick mod - TV +class SalaProgram; + +class SalaCommand +{ + friend class SalaProgram; + // + enum Command { SC_NONE, SC_ROOT, SC_EXPR, SC_RETURN, SC_FOR, SC_WHILE, SC_IF, SC_ELIF, SC_ELSE }; + enum { SP_NONE, SP_DATA, SP_NUMBER, SP_FUNCTION, SP_COMMAND }; // used while calculating what is on eval stack +protected: + // + SalaProgram *m_program; // information about the running program (in particular, the global variable and error stack) + SalaCommand *m_parent; + prefvec m_children; + // + pqmap m_var_names; + // + Command m_command; + int m_indent; // vital for program flow due to Pythonesque syntax + pvector m_eval_stack; + pvector m_func_stack; + // + SalaObj m_for_iter; // object used in a for loop + // + int m_line; // useful for debugging to know which line this command starts on + std::string m_last_string; // occassionally useful in debugging if the user does something unsyntactical + // +public: + SalaCommand() { m_program = NULL; m_parent = NULL; m_indent = 0; m_command = SC_NONE; } + SalaCommand(SalaProgram *program, SalaCommand *parent, int indent, Command command = SC_NONE); +protected: + int parse(::std::istream& program, int line); + int decode(std::string string); + int decode_member(const std::string& string, bool apply_to_this); + void pushFunc(const SalaObj& func); + // + void evaluate(SalaObj& obj, bool& ret, bool& ifhandled); + SalaObj evaluate(int& pointer, SalaObj* &p_obj); + SalaObj connections(SalaObj graphnode, SalaObj param); +}; + +class SalaProgram +{ + friend class SalaCommand; + // + SalaCommand m_root_command; + pvector m_var_stack; + prefvec m_error_stack; + // + // column is stored away from the context, as it's not actually passed to the program itself, just used to update a column + int m_col; + // m_thisobj stores contextual information (which attribute table, node etc) + // NB ! -- this can be messed with by SalaCommand! + SalaObj m_thisobj; + // + bool m_marked; // this is used to tell the program that a node has been "marked" -- all marks are cleared at the end of the execution + // +public: + SalaProgram(SalaObj context); + ~SalaProgram(); + bool parse(::std::istream& program); + SalaObj evaluate(); + bool runupdate(int col, const std::set &selset = std::set()); + bool runselect(std::vector& selsetout, const std::set &selsetin = std::set()); + std::string getLastErrorMessage() const; +}; + +inline SalaObj::SalaObj(const SalaObj& obj) +{ + type = obj.type; + switch(obj.type) { + case S_FUNCTION: data.func = obj.data.func; break; + case S_BOOL: data.b = obj.data.b; break; + case S_INT: data.i = obj.data.i; break; + case S_DOUBLE: data.f = obj.data.f; break; + case S_VAR: data.var = obj.data.var; break; + case S_STRING: + data.str.string = obj.data.str.string; + data.str.refcount = obj.data.str.refcount; + *(data.str.refcount) += 1; + break; + case S_LIST: case S_TUPLE: + data.list.list = obj.data.list.list; + data.list.refcount = obj.data.list.refcount; + *(data.list.refcount) += 1; + break; + case S_NONE: case S_UNINIT: case S_THIS: + break; + case S_SHAPEMAPOBJ: case S_SHAPEMAP: + data.graph.map.shape = obj.data.graph.map.shape; + data.graph.node = obj.data.graph.node; + break; + case S_POINTMAPOBJ: case S_POINTMAP: + data.graph.map.point = obj.data.graph.map.point; + data.graph.node = obj.data.graph.node; + break; + case S_OPEN_BRACKET: case S_CLOSE_BRACKET: case S_OPEN_SQR_BRACKET_LIST: case S_OPEN_SQR_BRACKET_ACCESS: + case S_CLOSE_SQR_BRACKET: case S_COMMA: case S_CONST_LIST: case S_CONST_TUPLE: + data.count = obj.data.count; break; + default: throw SalaError("Cannot instantiate unknown type"); + } +} +inline SalaObj& SalaObj::operator = (const SalaObj& obj) +{ + if (this != &obj) { + reset(); + type = obj.type; + switch(obj.type) { + case S_FUNCTION: data.func = obj.data.func; break; + case S_BOOL: data.b = obj.data.b; break; + case S_INT: data.i = obj.data.i; break; + case S_DOUBLE: data.f = obj.data.f; break; + case S_VAR: data.var = obj.data.var; break; + case S_STRING: + data.str.string = obj.data.str.string; + data.str.refcount = obj.data.str.refcount; + *(data.str.refcount) += 1; + break; + case S_LIST: case S_TUPLE: + data.list.list = obj.data.list.list; + data.list.refcount = obj.data.list.refcount; + *(data.list.refcount) += 1; + break; + case S_NONE: case S_UNINIT: case S_THIS: + break; + case S_SHAPEMAPOBJ: case S_SHAPEMAP: + data.graph.map.shape = obj.data.graph.map.shape; + data.graph.node = obj.data.graph.node; + break; + case S_POINTMAPOBJ: case S_POINTMAP: + data.graph.map.point = obj.data.graph.map.point; + data.graph.node = obj.data.graph.node; + break; + case S_OPEN_BRACKET: case S_CLOSE_BRACKET: case S_OPEN_SQR_BRACKET_LIST: case S_OPEN_SQR_BRACKET_ACCESS: + case S_CLOSE_SQR_BRACKET: case S_COMMA: case S_CONST_LIST: case S_CONST_TUPLE: + data.count = obj.data.count; break; + default: throw SalaError("Cannot instantiate unknown type"); + } + } + return *this; +} +inline SalaObj::~SalaObj() +{ + reset(); +} +inline void SalaObj::reset() +{ + if (type & S_STRING) { + *(data.str.refcount) -= 1; + if (*(data.str.refcount) == 0) { + delete data.str.refcount; + delete data.str.string; + } + data.str.refcount = NULL; + data.str.string = NULL; + } + else if (type & S_LIST) + { + *(data.list.refcount) -= 1; + if (*(data.list.refcount) == 0) { + delete data.str.refcount; + delete data.list.list; + } + data.str.refcount = NULL; + data.list.list = NULL; + } + type = S_NONE; +} +inline bool SalaObj::toBool() const +{ + switch(type) { + case S_BOOL: return data.b; + case S_INT: return data.i != 0; + case S_DOUBLE: return data.f != 0.0; + default: + throw SalaError(std::string("Cannot convert ") + getTypeIndefArt() + getTypeStr() + std::string(" to a boolean value")); + } + return false; +} +inline int SalaObj::toInt() const +{ + switch(type) { + case S_BOOL: return data.b ? 1 : 0; + case S_INT: return data.i; + case S_DOUBLE: return int(floor(data.f)); // ensure properly implemented + default: throw SalaError(std::string("Cannot convert ") + getTypeIndefArt() + getTypeStr() + std::string(" to an integer value")); + } + return 0; +} +inline double SalaObj::toDouble() const +{ + switch(type) { + case S_BOOL: return data.b ? 1.0 : 0.0; + case S_INT: return double(data.i); + case S_DOUBLE: return data.f; + default: throw SalaError(std::string("Cannot convert ") + getTypeIndefArt() + getTypeStr() + std::string(" to a floating point number")); + } + return 0.0; +} +inline std::string SalaObj::toString() const +{ + switch(type) { + case S_INT: return dXstring440::formatString(data.i); + case S_DOUBLE: return dXstring440::formatString(data.f); + case S_STRING: return *(data.str.string); + default: throw SalaError(std::string("Cannot convert ") + getTypeIndefArt() + getTypeStr() + std::string(" to a string")); + } + return std::string(); +} +inline const std::string& SalaObj::toStringRef() const +{ + if (type != S_STRING) { + throw SalaError(std::string("Cannot convert ") + getTypeIndefArt() + getTypeStr() + std::string(" to a string reference")); + } + return *(data.str.string); +} + +inline SalaObj operator + (SalaObj& a, SalaObj& b) +{ + switch (a.type | b.type) { + case SalaObj::S_BOOL: throw SalaError("Cannot add booleans"); + case SalaObj::S_INT: return SalaObj(a.data.i + b.data.i); + case SalaObj::S_DOUBLE: return SalaObj(a.data.f + b.data.f); + case SalaObj::S_NUMBER: + return (a.type == SalaObj::S_INT) ? (double(a.data.i) + b.data.f) : (a.data.f + double(b.data.i)); + case SalaObj::S_STRING: return SalaObj(*(a.data.str.string) + *(b.data.str.string)); + default: throw SalaError(std::string("Cannot add ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" to ") + b.getTypeIndefArt() + b.getTypeStr()); + } + return SalaObj(); +} +inline SalaObj operator - (SalaObj& a, SalaObj& b) +{ + switch (a.type | b.type) { + case SalaObj::S_BOOL: throw SalaError("Cannot subtract booleans"); + case SalaObj::S_INT: return SalaObj(a.data.i - b.data.i); + case SalaObj::S_DOUBLE: return SalaObj(a.data.f - b.data.f); + case SalaObj::S_NUMBER: + return (a.type == SalaObj::S_INT) ? (double(a.data.i) - b.data.f) : (a.data.f - double(b.data.i)); + default: throw SalaError(std::string("Cannot subtract ") + b.getTypeIndefArt() + b.getTypeStr() + std::string(" from ") + a.getTypeIndefArt() + a.getTypeStr()); + } + return SalaObj(); +} +inline SalaObj operator - (SalaObj& a) +{ + switch (a.type) { + case SalaObj::S_BOOL: throw SalaError("Cannot minus booleans"); + case SalaObj::S_INT: return SalaObj(-a.data.i); + case SalaObj::S_DOUBLE: return SalaObj(-a.data.f); + default: throw SalaError(std::string("Cannot minus ") + a.getTypeIndefArt() + a.getTypeStr()); + } + return SalaObj(); +} +inline SalaObj operator * (SalaObj& a, SalaObj& b) +{ + switch (a.type | b.type) { + case SalaObj::S_INT: return SalaObj(a.data.i * b.data.i); + case SalaObj::S_DOUBLE: return SalaObj(a.data.f * b.data.f); + case SalaObj::S_NUMBER: + return (a.type == SalaObj::S_INT) ? (double(a.data.i) * b.data.f) : (a.data.f * double(b.data.i)); + default: throw SalaError(std::string("Cannot multiply ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" by ") + b.getTypeIndefArt() + b.getTypeStr()); + } + return SalaObj(); +} +inline SalaObj operator % (SalaObj& a, SalaObj& b) +{ + switch (a.type | b.type) { + case SalaObj::S_INT: return SalaObj(a.data.i % b.data.i); + case SalaObj::S_DOUBLE: return SalaObj(::std::fmod(a.data.f,b.data.f)); + case SalaObj::S_NUMBER: + return (a.type == SalaObj::S_INT) ? fmod(double(a.data.i),b.data.f) : fmod(a.data.f,double(b.data.i)); + default: throw SalaError(std::string("Cannot multiply ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" by ") + b.getTypeIndefArt() + b.getTypeStr()); + } + return SalaObj(); +} +inline SalaObj operator / (SalaObj& a, SalaObj& b) +{ + switch (a.type | b.type) { + case SalaObj::S_INT: if (b.data.i != 0) return SalaObj(a.data.i / b.data.i); else throw SalaError("Integer divide by zero error"); + case SalaObj::S_DOUBLE: return SalaObj(a.data.f / b.data.f); + case SalaObj::S_NUMBER: + return (a.type == SalaObj::S_INT) ? (double(a.data.i) / b.data.f) : (a.data.f / double(b.data.i)); + default: throw SalaError(std::string("Cannot divide ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" by ") + a.getTypeIndefArt() + b.getTypeStr()); + } + return SalaObj(); +} +// assume already bools (use convert to bool first) +inline bool operator && (SalaObj& a, SalaObj& b) +{ + return a.data.b && b.data.b; +} +// assume already bools (use convert to bool first) +inline bool operator || (SalaObj& a, SalaObj& b) +{ + return a.data.b || b.data.b; +} +// assume already bools (use convert to bool first) +inline bool operator ! (SalaObj& a) +{ + return !a.data.b; +} +inline bool operator == (SalaObj& a, SalaObj& b) +{ + switch (a.type | b.type) { + case SalaObj::S_NONE: return true; // none == none + case SalaObj::S_BOOL: return a.data.b == b.data.b; + case SalaObj::S_INT: return a.data.i == b.data.i; + case SalaObj::S_DOUBLE: return a.data.f == b.data.f; + case SalaObj::S_NUMBER: + return (a.type == SalaObj::S_INT) ? (double(a.data.i) == b.data.f) : (a.data.f == double(b.data.i)); + case SalaObj::S_STRING: return a.data.str == b.data.str; + case SalaObj::S_LIST: return a.data.list == b.data.list; + default: throw SalaError(std::string("Cannot compare ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" with ") + b.getTypeIndefArt() + b.getTypeStr() + std::string(" using '=='")); + } + return false; +} +inline SalaObj op_is(SalaObj& a, SalaObj& b) +{ + // note, op_is is forgiving: does not complain if cannot compare, just returns false + switch (a.type & b.type) { + case SalaObj::S_NONE: return true; // none is none + case SalaObj::S_BOOL: return a.data.b == b.data.b; + case SalaObj::S_INT: return a.data.i == b.data.i; + case SalaObj::S_DOUBLE: return a.data.f == b.data.f; + // n.b., no number! int is not double and v.v. + case SalaObj::S_STRING: return a.data.str.string == b.data.str.string; // n.b.: pointer compare! + case SalaObj::S_LIST: return a.data.list.list == b.data.list.list; // n.b.: pointer compare! + } + return false; +} + +inline bool operator != (SalaObj& a, SalaObj& b) +{ + switch (a.type | b.type) { + case SalaObj::S_BOOL: return a.data.b != b.data.b; + case SalaObj::S_INT: return a.data.i != b.data.i; + case SalaObj::S_DOUBLE: return a.data.f != b.data.f; + case SalaObj::S_NUMBER: + return (a.type == SalaObj::S_INT) ? (double(a.data.i) != b.data.f) : (a.data.f != double(b.data.i)); + case SalaObj::S_STRING: return a.data.str != b.data.str; + case SalaObj::S_LIST: return a.data.list != b.data.list; + default: throw SalaError(std::string("Cannot compare ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" with ") + b.getTypeIndefArt() + b.getTypeStr() + std::string(" using '!='")); + } + return false; +} +inline bool operator < (SalaObj& a, SalaObj& b) +{ + switch (a.type | b.type) { + case SalaObj::S_BOOL: return a.data.b < b.data.b; + case SalaObj::S_INT: return a.data.i < b.data.i; + case SalaObj::S_DOUBLE: return a.data.f < b.data.f; + case SalaObj::S_NUMBER: + return (a.type == SalaObj::S_INT) ? (double(a.data.i) < b.data.f) : (a.data.f < double(b.data.i)); + case SalaObj::S_STRING: return a.data.str < b.data.str; + default: throw SalaError(std::string("Cannot compare ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" with ") + b.getTypeIndefArt() + b.getTypeStr() + std::string(" using '<'")); + } + return false; +} +inline bool operator > (SalaObj& a, SalaObj& b) +{ + switch (a.type | b.type) { + case SalaObj::S_BOOL: return a.data.b > b.data.b; + case SalaObj::S_INT: return a.data.i > b.data.i; + case SalaObj::S_DOUBLE: return a.data.f > b.data.f; + case SalaObj::S_NUMBER: + return (a.type == SalaObj::S_INT) ? (double(a.data.i) > b.data.f) : (a.data.f > double(b.data.i)); + case SalaObj::S_STRING: return a.data.str > b.data.str; + default: throw SalaError(std::string("Cannot compare ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" with ") + b.getTypeIndefArt() + b.getTypeStr() + std::string(" using '>'")); + } + return false; +} +inline bool operator <= (SalaObj& a, SalaObj& b) +{ + switch (a.type | b.type) { + case SalaObj::S_BOOL: return a.data.b <= b.data.b; + case SalaObj::S_INT: return a.data.i <= b.data.i; + case SalaObj::S_DOUBLE: return a.data.f <= b.data.f; + case SalaObj::S_NUMBER: + return (a.type == SalaObj::S_INT) ? (double(a.data.i) <= b.data.f) : (a.data.f <= double(b.data.i)); + default: throw SalaError(std::string("Cannot compare ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" with ") + b.getTypeIndefArt() + b.getTypeStr() + std::string(" using '<='")); + } + return false; +} +inline bool operator >= (SalaObj& a, SalaObj& b) +{ + switch (a.type | b.type) { + case SalaObj::S_BOOL: return a.data.b >= b.data.b; + case SalaObj::S_INT: return a.data.i >= b.data.i; + case SalaObj::S_DOUBLE: return a.data.f >= b.data.f; + case SalaObj::S_NUMBER: + return (a.type == SalaObj::S_INT) ? (double(a.data.i) >= b.data.f) : (a.data.f >= double(b.data.i)); + default: throw SalaError(std::string("Cannot compare ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" with ") + b.getTypeIndefArt() + b.getTypeStr() + std::string(" using '>='")); + } + return false; +} +// list operations: note -> precheck in program and sort into list and string +inline SalaObj& SalaObj::list_at(int i) +{ + if (i < 0) + i += (int)data.list.list->size(); + if (i < 0 || size_t(i) >= data.list.list->size()) + throw SalaError("Index out of range"); + return data.list.list->at(i); +} +inline SalaObj SalaObj::char_at(int i) // actually returns a string of the char +{ + if (i < 0) + i += data.str.length(); + if (i < 0 || i >= static_cast(data.str.length())) + throw SalaError("String index out of range"); + return SalaObj(std::string(1,data.str.char_at(i))); +} +inline int SalaObj::length() +{ + if (type & S_LIST) + return (int)data.list.list->size(); + else if (type == S_STRING) + return (int)data.str.length(); + throw SalaError("Cannot get the length of " + getTypeIndefArt() + getTypeStr()); +} + +///////////////////////////////////////////////////////////////////////////////////// + +inline const std::string SalaObj::getTypeStr() const +{ + switch(type) { + case S_NONE: + return "none"; + case S_UNINIT: + return "uninitialised variable"; + case S_FUNCTION: + return "function"; + case S_BOOL: + return "boolean"; + case S_INT: + return "integer"; + case S_DOUBLE: + return "float"; + case S_STRING: + return "string"; + case S_LIST: + return "list"; + case S_TUPLE: + return "tuple"; + case S_THIS: + return "this"; + default: + break; + } + if (type & S_GRAPHOBJ) { + return "graph object"; + } + else if (type & S_MAP) { + return "graph"; + } + return "unknown type"; +} + +inline const std::string SalaObj::getTypeIndefArt() const +{ + switch(type & ~S_GRAPHOBJ) { + case S_FUNCTION: case S_BOOL: case S_DOUBLE: case S_STRING: case S_TUPLE: case S_LIST: + case S_SHAPEMAP: case S_POINTMAP: + return "a "; + case S_INT: case S_UNINIT: + return "an "; + case S_NONE: case S_THIS: + return ""; + default: + return "an "; // unknown type + } + return std::string(); +} + +///////////////////////////////////////////////////////////////////////////////////// + +// comparisons for lists (must be after the associated SalaObj comparisons have been declared) + +inline bool operator == (const SalaList& a, const SalaList& b) +{ + if (a.list->size() != a.list->size()) + return false; + for (size_t i = 0; i < a.list->size(); i++) { + if (a.list->at(i) != b.list->at(i)) + return false; + } + return true; +} +inline bool operator != (const SalaList& a, const SalaList& b) +{ + if (a.list->size() != a.list->size()) + return true; + for (size_t i = 0; i < a.list->size(); i++) { + if (a.list->at(i) != b.list->at(i)) + return true; + } + return false; +} + +///////////////////////////////////////////// + +// helpers for parser: + +struct SalaBuffer +{ + int bufpos; + char buffer[128]; + SalaBuffer() + { bufpos = -1; buffer[0] = '\0'; } + void add(char c) + { bufpos++; if (bufpos > 127) throw SalaError("Overlong string of characters"); + buffer[bufpos] = c; } + void clear() + { bufpos = -1; buffer[0] = '\0'; } + operator std::string() + { buffer[bufpos + 1] = '\0'; return std::string(buffer); } + bool empty() + { return bufpos == -1; } +}; + +/////////////////////////////////////////////////// + +///////////////////////////////////////////// + +// Operator and function names + +struct SalaFuncLabel +{ + SalaObj::Func func; + std::string name; + std::string desc; + SalaFuncLabel(SalaObj::Func f = SalaObj::S_FNULL, const std::string& str = std::string(), const std::string& des = std::string()) { + func = f; name = str; desc = des; + } +}; + +struct SalaMemberFuncLabel : public SalaFuncLabel +{ + SalaObj::Type type; + SalaMemberFuncLabel(SalaObj::Type t = SalaObj::S_NONE, SalaObj::Func f = SalaObj::S_FNULL, const std::string& str = std::string(), const std::string& des = std::string()) { + type = t; func = f; name = str; desc = des; + } +}; + + +///////////////////////////////////////////////////////////////////////////////////// + +} + +#endif diff --git a/mgraph440/shapemap.cpp b/mgraph440/shapemap.cpp new file mode 100644 index 00000000..6d88e0eb --- /dev/null +++ b/mgraph440/shapemap.cpp @@ -0,0 +1,1363 @@ +#include "mgraph440/shapemap.h" +#include "mgraph440/pointmap.h" +#include "mgraph440/spacepix.h" +#include "mgraph440/exceptions.h" + +namespace mgraph440 { + +static const double TOLERANCE_A = 1e-9; + +// import TOLERANCE_B from axial map... +static const double TOLERANCE_B = 1e-12; + +// copied from SpacePixel + +PixelRef ShapeMap::pixelate( const Point2f& p, bool constrain, int ) const +{ + PixelRef r; + + Point2f p1 = p; + p1.normalScale(m_region); + + if (constrain) { + if (p1.x <= 0.0) { + r.x = 0; + } + else if (p1.x >= 1.0) { + r.x = m_cols - 1; + } + else { + r.x = short(floor(p1.x * m_cols)); + } + } + else { + r.x = short(floor(p1.x * m_cols)); + } + + if (constrain) { + if (p1.y <= 0.0) { + r.y = 0; + } + else if (p1.y >= 1.0) { + r.y = m_rows - 1; + } + else { + r.y = short(floor(p1.y * m_rows)); + } + } + else { + r.y = short(floor(p1.y * m_rows)); + } + + return r; +} + +bool ShapeMap::read( std::ifstream& stream, int version, bool drawinglayer ) +{ + // turn off selection / editable etc + m_selection = false; + m_editable = false; + m_show = true; // <- by default show + m_map_type = ShapeMap::EMPTYMAP; + + // clear old BSP tree (if exists) + m_bsp_tree = false; + m_bsp_root = NULL; + + // clear old: + if (m_pixel_shapes) { + for (int i = 0; i < m_cols; i++) { + delete [] m_pixel_shapes[i]; + } + delete [] m_pixel_shapes; + m_pixel_shapes = NULL; + } + if (m_display_shapes) { + delete [] m_display_shapes; + m_display_shapes = NULL; + } + m_objects.clear(); + m_shapes.clear(); + m_attributes.clear(); + m_connectors.clear(); + m_links.clear(); + m_unlinks.clear(); + m_undobuffer.clear(); + + // read in an old file: + if (drawinglayer && version < VERSION_DRAWING_SHAPES) { + // the data in the file is for a SpacePixel + // the easiest solution, although not the most memory effective, is to read in the space pixel, + // and convert to a shape map: + SpacePixel layer; + layer.read(stream,version); + m_name = layer.m_name; + m_show = layer.m_show; + m_editable = false; // <- don't take from spacepixel in case conflicts in some way + m_region = layer.m_region; + m_rows = layer.m_rows; + m_cols = layer.m_cols; + m_tolerance = std::max(m_region.width(), m_region.height()) * TOLERANCE_A; + m_shape_ref = -1; + for (size_t i = 0; i < layer.m_lines.size(); i++) { + m_shape_ref++; + int index = m_shapes.add(m_shape_ref, SalaShape(layer.m_lines[i].line)); + // insert a dummy attribute row: + m_attributes.insertRow(m_shape_ref); + // note: as this is always a drawing layer, no need to set shape attributes + } + // prepare pixel map (using same number of cols and rows as the original spacepixel for convenience) + m_pixel_shapes = new pqvector *[m_cols]; + for (int j = 0; j < m_cols; j++) { + m_pixel_shapes[j] = new pqvector[m_rows]; + } + // Now add the pixel shapes pixel map: + // pixelate all polys in the pixel structure: + for (size_t k = 0; k < m_shapes.size(); k++) { + makePolyPixels(m_shapes.key(k)); + } + // set to read in display attribute: + // note that even though it's only a drawing layer, this still needs to be done + invalidateDisplayedAttribute(); + setDisplayedAttribute(-1); + + // all done + return true; + } + + // name + m_name = dXstring440::readString(stream); + + if (version >= VERSION_MAP_TYPES) { + stream.read( (char *) &m_map_type, sizeof(m_map_type)); + } + else { + // old versions data maps or drawing maps, + // the axial reader will override this with its own map type designation if necessary + if (drawinglayer) { + m_map_type = DRAWINGMAP; + } + else { + m_map_type = DATAMAP; + } + } + + if (version >= VERSION_DRAWING_SHAPES_B) { + stream.read( (char *) &m_show, sizeof(m_show) ); + stream.read( (char *) &m_editable, sizeof(m_editable) ); + } + + // PixelBase read + // read extents: + stream.read( (char *) &m_region, sizeof(m_region) ); + // read rows / cols + stream.read( (char *) &m_rows, sizeof(m_rows) ); + stream.read( (char *) &m_cols, sizeof(m_cols) ); + // calculate geom data: + m_tolerance = std::max(m_region.width(), m_region.height()) * TOLERANCE_A; + + // read next object ref to be used: + stream.read((char *) &m_obj_ref, sizeof(m_obj_ref)); + stream.read((char *) &m_shape_ref, sizeof(m_shape_ref)); + + // read shape data + int count = 0; + stream.read((char *) &count, sizeof(count)); + for (int j = 0; j < count; j++) { + int key; + stream.read((char *) &key, sizeof(key)); + int index = m_shapes.add(key, SalaShape()); + m_shapes.value(index).read(stream,version); + } + if (version < VERSION_SHAPE_CENTROIDS) { + // manually set centroid according to type: + for (size_t i = 0; i < m_shapes.size(); i++) { + switch (m_shapes[i].m_type & SalaShape::SHAPE_TYPE) { + case SalaShape::SHAPE_POINT: + m_shapes[i].m_centroid = m_shapes[i].m_region.bottom_left; + break; + case SalaShape::SHAPE_LINE: + m_shapes[i].m_centroid = m_shapes[i].m_region.getCentre(); + break; + case SalaShape::SHAPE_POLY: + m_shapes[i].setCentroidAreaPerim(); + break; + default: + break; + } + } + } + + // read object data (currently unused) + stream.read((char *) &count, sizeof(count)); + for (int k = 0; k < count; k++) { + int key; + stream.read((char *) &key, sizeof(key)); + int index = m_objects.add(key, SalaObject()); + m_objects.value(index).read(stream,version); + } + // read attribute data + m_attributes.read(stream,version); + stream.read((char *)&m_displayed_attribute,sizeof(m_displayed_attribute)); + + // prepare pixel map: + m_pixel_shapes = new pqvector *[m_cols]; + int i; + for (i = 0; i < m_cols; i++) { + m_pixel_shapes[i] = new pqvector[m_rows]; + } + // Now add the pixel shapes pixel map: + // pixelate all polys in the pixel structure: + for (size_t j = 0; j < m_shapes.size(); j++) { + makePolyPixels(m_shapes.key(j)); + } + + // later versions can have shape connections: + if (version >= VERSION_AXIAL_SHAPES) { + int count; + stream.read((char *)&count,sizeof(count)); + for (int i = 0; i < count; i++) { + m_connectors.push_back(Connector()); + m_connectors[i].read(stream,version); + if (version < VERSION_NO_SELF_CONNECTION) { + size_t self = m_connectors[i].m_connections.searchindex(i); + if (self != paftl::npos) { + m_connectors[i].m_connections.remove_at(self); + } + } + } + m_links.read(stream); + m_unlinks.read(stream); + } + + // some miscellaneous extra data for mapinfo files + if (m_mapinfodata) { + delete m_mapinfodata; + m_mapinfodata = NULL; + } + if (version >= VERSION_MAPINFO_SHAPES) { + char x = stream.get(); + if (x == 'm') { + m_mapinfodata = new MapInfoData; + m_mapinfodata->read(stream,version); + } + } + + invalidateDisplayedAttribute(); + setDisplayedAttribute(m_displayed_attribute); + + return true; +} +void ShapeMap::makePolyPixels(int polyref) +{ + // first add into pixels, and ensure you have a bl, tr for the set (useful for testing later) + SalaShape& poly = m_shapes.search(polyref); + if (poly.isClosed()) { + pmap relations; + for (size_t k = 0; k < poly.size(); k++) { + int nextk = (k + 1) % poly.size(); + Line li(poly[k],poly[nextk]); + if (k == 0) { + poly.m_region = li; + } + else { + poly.m_region = runion(poly.m_region,li); + } + PixelRefVector pixels = pixelateLine(li); + // debug + // int duplicate_shaperefs = 0; + // end debug + for (size_t i = 0; i < pixels.size(); i++) { + PixelRef pix = pixels[i]; + size_t x = m_pixel_shapes[pix.x][pix.y].searchindex(ShapeRef(polyref)); + if (x == paftl::npos) { + x = m_pixel_shapes[pix.x][pix.y].add(ShapeRef(polyref),paftl::ADD_HERE); + } + m_pixel_shapes[pix.x][pix.y][x].m_polyrefs.push_back(k); + relations.add(pixels[i],ShapeRef::SHAPE_EDGE); + } + } + // erase joined sides, and look for min: + PixelRef minpix = NoPixel; + for (size_t j = 0; j < relations.size(); j++) { + PixelRef pix = relations.key(j); + PixelRef nextpix; + nextpix = pix.right(); + if (includes(nextpix) && m_pixel_shapes[nextpix.x][nextpix.y].searchindex(ShapeRef(polyref)) != paftl::npos) { + relations.value(j) &= ~ShapeRef::SHAPE_R; + } + nextpix = pix.up(); + if (includes(nextpix) && m_pixel_shapes[nextpix.x][nextpix.y].searchindex(ShapeRef(polyref)) != paftl::npos) { + relations.value(j) &= ~ShapeRef::SHAPE_T; + } + nextpix = pix.down(); + if (includes(nextpix) && m_pixel_shapes[nextpix.x][nextpix.y].searchindex(ShapeRef(polyref)) != paftl::npos) { + relations.value(j) &= ~ShapeRef::SHAPE_B; + } + nextpix = pix.left(); + if (includes(nextpix) && m_pixel_shapes[nextpix.x][nextpix.y].searchindex(ShapeRef(polyref)) != paftl::npos) { + relations.value(j) &= ~ShapeRef::SHAPE_L; + } + if ((relations.value(j) & (ShapeRef::SHAPE_B | ShapeRef::SHAPE_L)) == (ShapeRef::SHAPE_B | ShapeRef::SHAPE_L)) { + if ((minpix == NoPixel) || (relations.key(j) < (int)minpix)) { + minpix = relations.key(j); + } + } + } + shapePixelBorder(relations,polyref,ShapeRef::SHAPE_L,minpix,minpix,true); + // go through any that aren't on the outer border: this will be internal edges, and will cause problems + // for point in polygon algorithms! + size_t i; + for (i = 0; i < relations.size(); i++) { + PixelRef pix = relations.key(i); + unsigned char& tags = m_pixel_shapes[pix.x][pix.y].search(polyref).m_tags; + if (tags == 0x00) { + tags |= ShapeRef::SHAPE_INTERNAL_EDGE; + } + } + // now, any remaining tags are internal sides, and need to be cleared through fill + // we could go either direction, but we just go left to right: + for (i = 0; i < relations.size(); i++) { + PixelRef pix = relations.key(i); + if (relations.value(i) & ShapeRef::SHAPE_R) { + int pos = 0; + do { + PixelRef nextpix = pix.right(); + if (!includes(nextpix)) { + // this shouldn't happen + break; + } + // returns -1 if cannot add due to already existing: + pos = m_pixel_shapes[nextpix.x][nextpix.y].add(ShapeRef(polyref,ShapeRef::SHAPE_CENTRE)); + pix = nextpix; + } while (pos != -1); + } + } + // Done...! This polygon is registered in the pixel polygon structure + } + else { + // Open shapes much easier! + switch (poly.m_type & SalaShape::SHAPE_TYPE) + { + case SalaShape::SHAPE_POINT: + { + PixelRef pix = pixelate(poly.m_centroid); + size_t x = m_pixel_shapes[pix.x][pix.y].searchindex(ShapeRef(polyref)); + if (x == paftl::npos) { + x = m_pixel_shapes[pix.x][pix.y].add(ShapeRef(polyref,ShapeRef::SHAPE_OPEN),paftl::ADD_HERE); + } + } + break; + case SalaShape::SHAPE_LINE: + { + PixelRefVector pixels = pixelateLine(poly.m_region); + for (size_t i = 0; i < pixels.size(); i++) { + PixelRef pix = pixels[i]; + size_t x = m_pixel_shapes[pix.x][pix.y].searchindex(ShapeRef(polyref)); + if (x == paftl::npos) { + x = m_pixel_shapes[pix.x][pix.y].add(ShapeRef(polyref,ShapeRef::SHAPE_OPEN),paftl::ADD_HERE); + } + } + } + break; + case SalaShape::SHAPE_POLY: + for (size_t k = 0; k < poly.size() - 1; k++) { + int nextk = (k + 1); + Line li(poly[k],poly[nextk]); + if (k == 0) { + poly.m_region = li; + } + else { + poly.m_region = runion(poly.m_region,li); + } + PixelRefVector pixels = pixelateLine(li); + for (size_t i = 0; i < pixels.size(); i++) { + PixelRef pix = pixels[i]; + size_t x = m_pixel_shapes[pix.x][pix.y].searchindex(ShapeRef(polyref)); + if (x == paftl::npos) { + x = m_pixel_shapes[pix.x][pix.y].add(ShapeRef(polyref,ShapeRef::SHAPE_OPEN),paftl::ADD_HERE); + } + m_pixel_shapes[pix.x][pix.y][x].m_polyrefs.push_back(k); + } + } + break; + } + } +} + +void SalaShape::setCentroidAreaPerim() +{ + m_area = 0.0; + m_perimeter = 0.0; + m_centroid = Point2f(0,0); + for (size_t i = 0; i < size(); i++) { + Point2f& p1 = at(i); + Point2f& p2 = at((i+1)%size()); + double a_i = (p1.x * p2.y - p2.x * p1.y) / 2.0; + m_area += a_i; + a_i /= 6.0; + m_centroid.x += (p1.x+p2.x) * a_i; + m_centroid.y += (p1.y+p2.y) * a_i; + Point2f side = p2 - p1; + m_perimeter += side.length(); + } + m_type &= ~SHAPE_CCW; + if (sgn(m_area) == 1) { + m_type |= SHAPE_CCW; + } + m_centroid.scale(2.0/m_area); // note, *not* fabs(m_area) as it is then confused by clockwise ordered shapes + m_area = fabs(m_area); + if (isOpen()) { + // take off the automatically collected final side + Point2f side = tail() - head(); + m_perimeter -= side.length(); + } +} + +void ShapeMap::setDisplayedAttribute(int col) const +{ + if (!m_invalidate && m_displayed_attribute == col) { + return; + } + m_displayed_attribute = col; + m_invalidate = true; + + // always override at this stage: + m_attributes.setDisplayColumn(m_displayed_attribute,true); + + m_invalidate = false; +} + +void ShapeMap::shapePixelBorder(pmap& relations, int polyref, int side, PixelRef currpix, PixelRef minpix, bool first) +{ + if (!first && currpix == minpix && side == ShapeRef::SHAPE_L) { + // looped: + return; + } + size_t rel = relations.searchindex(currpix); + if (relations[rel] & side) { + m_pixel_shapes[currpix.x][currpix.y].search(polyref).m_tags |= side; + relations[rel] &= ~side; // <- clear to check all have been done later + side <<= 1; + if (side > ShapeRef::SHAPE_T) { + side = ShapeRef::SHAPE_L; + } + shapePixelBorder(relations,polyref,side,currpix,minpix,false); + } + else { + currpix.move( moveDir(side) ); + side >>= 1; + if (side < ShapeRef::SHAPE_L) { + side = ShapeRef::SHAPE_T; + } + shapePixelBorder(relations,polyref,side,currpix,minpix,false); + } +} + +bool SalaShape::read(std::ifstream& stream, int version) +{ + // defaults + m_draworder = -1; + m_selected = false; + + stream.read((char *)&m_type,sizeof(m_type)); + + int sss = sizeof(m_region); + stream.read((char *)&m_region,sizeof(m_region)); + + if (version >= VERSION_SHAPE_CENTROIDS) { + stream.read((char *)&m_centroid,sizeof(m_centroid)); + if (version >= VERSION_SHAPE_AREA_PERIMETER) { + stream.read((char *)&m_area,sizeof(m_area)); + stream.read((char *)&m_perimeter,sizeof(m_perimeter)); + } + } + else { + // old types were simply 1,2,3... these are now labelled using bits: + if (m_type == 3) { + m_type = SHAPE_POLY; + } + else if (m_type == 4) { + m_type = SHAPE_POLY | SHAPE_CLOSED; + } + } + pqvector::read(stream); + + if (version < VERSION_SHAPE_AREA_PERIMETER) { + if (m_type & SHAPE_POLY) { + setCentroidAreaPerim(); + } + else if (m_type & SHAPE_LINE) { + m_perimeter = m_region.length(); + } + } + + return true; +} + +int ShapeMap::moveDir(int side) +{ + int dir; + switch (side) + { + case ShapeRef::SHAPE_L: + dir = PixelRef::NEGHORIZONTAL; + break; + case ShapeRef::SHAPE_B: + dir = PixelRef::NEGVERTICAL; + break; + case ShapeRef::SHAPE_R: + dir = PixelRef::HORIZONTAL; + break; + case ShapeRef::SHAPE_T: + dir = PixelRef::VERTICAL; + break; + } + return dir; +} +// n.b., only works from current selection (and uses point selected attribute) + +int ShapeMap::makeShapeFromPointSet(const PointMap& pointmap) +{ + bool bounds_good = true; + PixelRefVector selset; + Point2f offset = Point2f(pointmap.getSpacing()/2,pointmap.getSpacing()/2); + for (auto &sel: pointmap.getSelSet()) { + selset.push_back(sel); + if (!m_region.contains_touch(pointmap.depixelate(sel)-offset) || !m_region.contains_touch(pointmap.depixelate(sel)+offset)) { + bounds_good = false; + } + } + if (!bounds_good) { + QtRegion r(pointmap.getRegion().bottom_left - offset,pointmap.getRegion().top_right + offset); + init(m_shapes.size(),r); + } + pmap relations; + for (size_t j = 0; j < selset.size(); j++) { + PixelRef pix = selset[j]; + int x = relations.add(pix,ShapeRef::SHAPE_EDGE); + if (pointmap.includes(pix.right()) && pointmap.getPoint(pix.right()).selected()) { + relations.value(x) &= ~ShapeRef::SHAPE_R; + } + if (pointmap.includes(pix.up()) && pointmap.getPoint(pix.up()).selected()) { + relations.value(x) &= ~ShapeRef::SHAPE_T; + } + if (pointmap.includes(pix.down()) && pointmap.getPoint(pix.down()).selected()) { + relations.value(x) &= ~ShapeRef::SHAPE_B; + } + if (pointmap.includes(pix.left()) && pointmap.getPoint(pix.left()).selected()) { + relations.value(x) &= ~ShapeRef::SHAPE_L; + } + } + // now find pixel with SHAPE_B | SHAPE_L + PixelRef minpix = NoPixel; + size_t k; + for (k = 0; k < relations.size(); k++) { + if ((relations.value(k) & (ShapeRef::SHAPE_B | ShapeRef::SHAPE_L)) == (ShapeRef::SHAPE_B | ShapeRef::SHAPE_L)) { + if ((minpix == NoPixel) || (relations.key(k) < (int)minpix)) { + minpix = relations.key(k); + } + } + } + // now follow round anticlockwise... + SalaShape poly(SalaShape::SHAPE_POLY | SalaShape::SHAPE_CLOSED); + pointPixelBorder(pointmap,relations,poly,ShapeRef::SHAPE_L,minpix,minpix,true); + + bool retvar = true; + + for (k = 0; k < relations.size(); k++) { + if (relations[k] != 0) { + // more than one shape! + return -1; + } + } + poly.setCentroidAreaPerim(); + + m_shape_ref++; + int rowid = m_shapes.add(m_shape_ref,poly); + + if (bounds_good) { + // note: also sets polygon bounding box: + makePolyPixels(m_shape_ref); + } + else { + // pixelate all polys in the pixel new structure: + for (size_t i = 0; i < m_shapes.size(); i++) { + makePolyPixels(m_shapes.key(i)); + } + } + + m_attributes.insertRow(m_shape_ref); + m_newshape = true; + + return m_shape_ref; +} + +// the replacement for datalayers + +ShapeMap::ShapeMap(const std::string& name, int type) : m_attributes(name) +{ + m_name = name; + m_map_type = type; + m_hasgraph = false; + + // shape and object counters + m_obj_ref = -1; + m_shape_ref = -1; + // pixel map + m_pixel_shapes = NULL; + // + // -1 is the shape ref column (which will be shown by default) + m_displayed_attribute = -1; + m_display_shapes = NULL; + m_invalidate = false; + // for polygons: + m_show_lines = true; + m_show_fill = true; + m_show_centroids = false; + + // data (MUST be set before use) + m_tolerance = 0.0; + + m_selection = false; + + // note show is + m_show = true; + m_editable = false; + + m_bsp_tree = false; + m_bsp_root = NULL; + // + m_mapinfodata = NULL; +} + +ShapeMap::~ShapeMap() +{ + if (m_bsp_root) { + delete m_bsp_root; + m_bsp_root = NULL; + } + if (m_pixel_shapes) { + for (int i = 0; i < m_cols; i++) { + delete [] m_pixel_shapes[i]; + } + delete [] m_pixel_shapes; + m_pixel_shapes = NULL; + } + if (m_display_shapes) { + delete [] m_display_shapes; + m_display_shapes = NULL; + } + if (m_mapinfodata) { + delete m_mapinfodata; + m_mapinfodata = NULL; + } +} + +Point2f ShapeMap::pointOffset(const PointMap& pointmap, int currpix, int side) +{ + Point2f p; + switch (side) + { + case ShapeRef::SHAPE_L: + p = Point2f(-pointmap.getSpacing()/2,0.0); + break; + case ShapeRef::SHAPE_B: + p = Point2f(0.0,-pointmap.getSpacing()/2); + break; + case ShapeRef::SHAPE_R: + p = Point2f(pointmap.getSpacing()/2,0.0); + break; + case ShapeRef::SHAPE_T: + p = Point2f(0.0,pointmap.getSpacing()/2); + break; + } + return p; +} + +// note that this is almost exactly the same as shapePixelBorder +void ShapeMap::pointPixelBorder(const PointMap& pointmap, pmap& relations, SalaShape& poly, int side, PixelRef currpix, PixelRef minpix, bool first) +{ + if (!first && currpix == minpix && side == ShapeRef::SHAPE_L) { + // looped: + return; + } + size_t rel = relations.searchindex(currpix); + if (relations[rel] & side) { + poly.push_back(pointmap.depixelate(currpix)+pointOffset(pointmap,currpix,side)); + relations[rel] &= ~side; // <- clear to check all have been done later + side <<= 1; + if (side > ShapeRef::SHAPE_T) { + side = ShapeRef::SHAPE_L; + } + pointPixelBorder(pointmap,relations,poly,side,currpix,minpix,false); + } + else { + currpix.move( moveDir(side) ); + side >>= 1; + if (side < ShapeRef::SHAPE_L) { + side = ShapeRef::SHAPE_T; + } + pointPixelBorder(pointmap,relations,poly,side,currpix,minpix,false); + } +} + +bool ShapeMap::clearSel() +{ + // note, only clear if need be, as m_attributes.deselectAll is slow + if (m_selection_set.size()) { + m_attributes.deselectAll(); + m_selection = false; + for (auto& sel: m_selection_set) { + m_shapes.value(sel).m_selected = false; + } + m_selection_set.clear(); + } + return true; +} + +// this can be reinit as well + +void ShapeMap::init(int size, const QtRegion &r) +{ + if (m_pixel_shapes) { + for (int i = 0; i < m_cols; i++) { + delete [] m_pixel_shapes[i]; + } + delete [] m_pixel_shapes; + m_pixel_shapes = NULL; + } + if (m_display_shapes) { + delete [] m_display_shapes; + m_display_shapes = NULL; + } + m_rows = std::min(std::max(20,(int)sqrt((double)size)),32768); + m_cols = std::min(std::max(20,(int)sqrt((double)size)),32768); + if (m_region.atZero()) { + m_region = r; + } + else { + m_region = runion(m_region,r); + } + // calculate geom data: + m_tolerance = std::max(m_region.width(), m_region.height()) * TOLERANCE_A; + // + m_pixel_shapes = new pqvector *[m_cols]; + for (int i = 0; i < m_cols; i++) { + m_pixel_shapes[i] = new pqvector[m_rows]; + } +} + +int ShapeMap::makeLineShape(const Line& line, bool through_ui, bool tempshape) +{ + // note, map must have editable flag on if we are to make a shape through the user interface: + if (through_ui && !m_editable) { + return -1; + } + + bool bounds_good = true; + + if (!(m_region.contains_touch(line.start()) && m_region.contains_touch(line.end()))) { + bounds_good = false; + init(m_shapes.size(),line); + } + + m_shape_ref++; + // note, shape constructor sets centroid, length etc + int rowid = m_shapes.add(m_shape_ref,SalaShape(line)); + + if (bounds_good) { + // note: also sets polygon bounding box: + makePolyPixels(m_shape_ref); + } + else { + // pixelate all polys in the pixel new structure: + for (size_t i = 0; i < m_shapes.size(); i++) { + makePolyPixels(m_shapes.key(i)); + } + } + + if (!tempshape) { + m_attributes.insertRow(m_shape_ref); + m_newshape = true; + } + + if (through_ui) { + // + // manually add connections: + if (m_hasgraph) { + if (isAxialMap()) { + connectIntersected(rowid,true); // "true" means line-line intersections only will be applied + } + else { + connectIntersected(rowid,false); + } + } + // if through ui, set undo counter: + m_undobuffer.push_back(SalaEvent(SalaEvent::SALA_CREATED,m_shape_ref)); + // update displayed attribute if through ui: + invalidateDisplayedAttribute(); + setDisplayedAttribute(m_displayed_attribute); + } + + return m_shape_ref; +} +// code to add intersections when shapes are added to the graph one by one: +int ShapeMap::connectIntersected(int rowid, bool linegraph) +{ + int shaperef = m_shapes.key(rowid); + int conn_col = m_attributes.getOrInsertColumnIndex("Connectivity"); + m_attributes.setColumnLock(conn_col); + int leng_col = -1; + if (linegraph) { + // historically line length has always been added at this point + leng_col = m_attributes.getOrInsertLockedColumnIndex("Line Length"); + } + // all indices should match... this grows connectors if necessary to same length as shapes + while (m_connectors.size() < m_shapes.size()) { + m_connectors.push_back( Connector() ); + } + int connectivity = linegraph ? + getLineConnections( shaperef, m_connectors[rowid].m_connections, TOLERANCE_B*std::max(m_region.height(),m_region.width())) : + getShapeConnections( shaperef, m_connectors[rowid].m_connections, TOLERANCE_B*std::max(m_region.height(),m_region.width())); + m_attributes.setValue(rowid, conn_col, (float) connectivity ); + if (linegraph) { + m_attributes.setValue(rowid, leng_col, (float) m_shapes[rowid].getLength() ); + } + // now go through our connections, and add ourself: + for (size_t k = 0; k < m_connectors[rowid].m_connections.size(); k++) { + int myplace = m_connectors[rowid].m_connections[k]; + if (myplace != rowid) { // <- exclude self! + m_connectors[myplace].m_connections.add(rowid); + m_attributes.incrValue(myplace,conn_col); + } + } + return connectivity; +} +// this assumes this is a line map (to speed up axial map creation) +// use the other version, getShapeConnections for arbitrary shape-shape connections +// note, connections are listed by rowid in list, *not* reference number +// (so they may vary: must be checked carefully when shapes are removed / added) +int ShapeMap::getLineConnections(int lineref, pvecint& connections, double tolerance) +{ + SalaShape& poly = m_shapes.search(lineref); + if (!poly.isLine()) { + return 0; + } + const Line& l = poly.getLine(); + + pvecint testedshapes; + + // As of version 10, self-connections are *not* added + // In the past: + // it's useful to have yourself in your connections list + // (apparently! -- this needs checking, as most of the time it is then checked to exclude self again!) + // connections.add(m_shapes.searchindex(lineref)); + + testedshapes.add(lineref); + + int num_intersections = 0; + + PixelRefVector list = pixelateLine( l ); + + for (size_t i = 0; i < list.size(); i++) { + pqvector& shapes = m_pixel_shapes[ list[i].x ][ list[i].y ]; + for (size_t j = 0; j < shapes.size(); j++) { + ShapeRef& shape = shapes[j]; + if (testedshapes.searchindex(shape.m_shape_ref) != paftl::npos) { + continue; + } + testedshapes.add(shape.m_shape_ref,paftl::ADD_HERE); + if ((shape.m_tags & ShapeRef::SHAPE_OPEN) == ShapeRef::SHAPE_OPEN) { + try { + const Line& line = m_shapes.search(shape.m_shape_ref).getLine(); + if ( intersect_region(line, l, line.length() * tolerance) ) { + // n.b. originally this followed the logic that we must normalise intersect_line properly: tolerance * line length one * line length two + // in fact, works better if it's just line.length() * tolerance... + if ( intersect_line(line, l, line.length() * tolerance) ) { + connections.add(m_shapes.searchindex(shape.m_shape_ref)); + num_intersections++; + } + } + } + catch (pexception) { + // the lineref may have been deleted -- this is supposed to be tidied up + // just ignore... + } + } + } + } + + return num_intersections; +} + +// this is only problematic as there is lots of legacy code with shape-in-shape testing, +int ShapeMap::getShapeConnections(int shaperef, pvecint& connections, double tolerance) +{ + // In versions prior to 10, note that unlike getLineConnections, self-connection is excluded by all of the following functions + // As of version 10, both getShapeConnections and getLineConnections exclude self-connection + + size_t index = m_shapes.searchindex(shaperef); + if (index != paftl::npos) { + SalaShape& shape = m_shapes[index]; + if (shape.isPoint()) { + // a point is simple, it never intersects itself: + pointInPolyList(shape.getPoint(),connections); + } + else if (shape.isPolygon()) { + // a closed poly is actually quite simple too as we already have code using a polyref: + polyInPolyList(shaperef,connections,tolerance); + } + else if (shape.isLine()) { + // line is a bit slow because there's no tested shape as in getLineConnections, but similar: + lineInPolyList(shape.getLine(),connections,shaperef,tolerance); + } + else if (shape.isPolyLine()) { + // this is the worst for efficiency: potential for many possible retries of the same shape: + for (size_t i = 1; i < shape.size() - 1; i++) { + Line li(shape[i-1], shape[i]); + lineInPolyList(li,connections,shaperef,tolerance); + } + } + } + + return connections.size(); +} + +// similar to above, but builds a list + +void ShapeMap::pointInPolyList(const Point2f& p, pvecint& shapeindexlist) const +{ + if (!m_region.contains(p)) { + return ; + } + pvecint testedshapes; + PixelRef pix = pixelate(p); + pqvector &shapes = m_pixel_shapes[pix.x][pix.y]; + for (size_t i = 0; i < shapes.size(); i++) { + const ShapeRef& shape = shapes[i]; + if (testedshapes.searchindex(shape.m_shape_ref) != paftl::npos) { + continue; + } + testedshapes.add(shape.m_shape_ref,paftl::ADD_HERE); + + int shapeindex = testPointInPoly(p,shape); + + // if there's a shapeindex, then add (note it is an add -- you may be passed a list again to expand) + if (shapeindex != -1) { + shapeindexlist.add(shapeindex); + } + } +} + +// note, lineref is only used as an "exclude self" test when called from getShapeConnections +void ShapeMap::lineInPolyList(const Line& li_orig, pvecint& shapeindexlist, int lineref, double tolerance) const +{ + if (!intersect_region(m_region,li_orig)) { + return; + } + Line li = li_orig; + if (!m_region.contains(li.start()) || !m_region.contains(li.end())) { + li.crop(m_region); + } + + pointInPolyList(li.start(),shapeindexlist); + pointInPolyList(li.end(),shapeindexlist); + + // only now pixelate and test for any other shapes: + PixelRefVector list = pixelateLine(li); + for (size_t i = 0; i < list.size(); i++) { + PixelRef pix = list[i]; + if (includes(pix)) { + pqvector& shapes = m_pixel_shapes[pix.x][pix.y]; + for (size_t j = 0; j < shapes.size(); j++) { + const ShapeRef& shape = shapes[j]; + // slow to do this as it can repeat -- really need to use a linetest like structure to avoid retest of + // polygon lines + if (shape.m_shape_ref != lineref && shape.m_tags & (ShapeRef::SHAPE_EDGE | ShapeRef::SHAPE_INTERNAL_EDGE | ShapeRef::SHAPE_OPEN)) { + const SalaShape& poly = m_shapes.search(shape.m_shape_ref); + switch (poly.m_type & (SalaShape::SHAPE_LINE | SalaShape::SHAPE_POLY)) { + case SalaShape::SHAPE_LINE: + if (intersect_region(li,poly.m_region)) { + // note: in this case m_region is stored as a line: + if (intersect_line(li,poly.m_region,tolerance)) { + shapeindexlist.add(m_shapes.searchindex(shape.m_shape_ref)); + } + } + break; + case SalaShape::SHAPE_POLY: + { + for (int k = 0; k < shape.m_polyrefs.size(); k++) { + Line lineb = Line(poly[shape.m_polyrefs[k]],poly[((shape.m_polyrefs[k]+1)%poly.size())]); + if (intersect_region(li,lineb)) { + if (intersect_line(li,lineb,tolerance)) { + shapeindexlist.add(m_shapes.searchindex(shape.m_shape_ref)); + } + } + } + } + break; + default: + break; + } + } + } + } + } +} + +void ShapeMap::polyInPolyList(int polyref, pvecint& shapeindexlist, double tolerance) const +{ + size_t index = m_shapes.searchindex(polyref); + if (index == paftl::npos) { + return; + } + const SalaShape& poly = m_shapes[index]; + if (poly.isClosed()) { // <- it ought to be, you shouldn't be using this function if not! + pvecint testedlist; + // easiest just to use scan lines to find internal pixels rather than trace a complex border: + PixelRef minpix = pixelate(poly.m_region.bottom_left); + PixelRef maxpix = pixelate(poly.m_region.top_right); + // pass one: shape centre of either object coincident automatically adds + int x; + for (x = minpix.x; x <= maxpix.x; x++) { + for (int y = minpix.y; y <= maxpix.y; y++) { + size_t pos = m_pixel_shapes[x][y].searchindex(polyref); + if (pos != paftl::npos) { + pqvector& shaperefs = m_pixel_shapes[x][y]; + // this has us in it, now looked through everything else: + for (size_t i = 0; i < shaperefs.size(); i++) { + ShapeRef& shaperef = shaperefs[i]; + if (i != pos && ((shaperefs[pos].m_tags & ShapeRef::SHAPE_CENTRE) || (shaperef.m_tags & ShapeRef::SHAPE_CENTRE))) { + if (testedlist.add(shaperef.m_shape_ref) != -1) { + shapeindexlist.add(m_shapes.searchindex(shaperef.m_shape_ref)); + } + } + } + } + } + } + // that was the easy bit... now, pass 2, for non centre things: + for (x = minpix.x; x <= maxpix.x; x++) { + for (int y = minpix.y; y <= maxpix.y; y++) { + size_t pos = m_pixel_shapes[x][y].searchindex(polyref); + if (pos != paftl::npos) { + pqvector& shaperefs = m_pixel_shapes[x][y]; + ShapeRef& shaperef = shaperefs[pos]; + if ((shaperef.m_tags & ShapeRef::SHAPE_CENTRE) == 0) { + // this has us in it, now looked through everything else: + for (size_t i = 0; i < shaperefs.size(); i++) { + ShapeRef& shaperefb = shaperefs[i]; + if (i != pos && testedlist.searchindex(shaperefb.m_shape_ref) == paftl::npos) { + size_t indexb = m_shapes.searchindex(shaperefb.m_shape_ref); + const SalaShape& polyb = m_shapes[indexb]; + if (polyb.isPoint()) { + if (testPointInPoly(polyb.getPoint(),shaperef) != -1) { + shapeindexlist.add((int)indexb); + } + } + else if (polyb.isLine()) { + if (testPointInPoly(polyb.getLine().start(),shaperef) != -1 || testPointInPoly(polyb.getLine().end(),shaperef) != -1) { + testedlist.add(shaperefb.m_shape_ref,paftl::ADD_HERE); + shapeindexlist.add((int)indexb); + } + else { + for (int k = 0; k < shaperef.m_polyrefs.size(); k++) { + Line line = Line(poly[shaperef.m_polyrefs[k]],poly[((shaperef.m_polyrefs[k]+1)%poly.size())]); + if (intersect_region(line,polyb.getLine())) { + if (intersect_line(line,polyb.getLine(),tolerance)) { + testedlist.add(shaperefb.m_shape_ref,paftl::ADD_HERE); + shapeindexlist.add((int)indexb); + break; + } + } + } + } + } + else if (polyb.isPolyLine()) { + if (testPointInPoly(polyb[shaperefb.m_polyrefs[0]],shaperef) != -1) { + testedlist.add(shaperefb.m_shape_ref,paftl::ADD_HERE); + shapeindexlist.add(indexb); + } + else { + for (int k = 0; k < shaperef.m_polyrefs.size(); k++) { + for (int kk = 0; kk < shaperefb.m_polyrefs.size(); kk++) { + Line line = Line(poly[shaperef.m_polyrefs[k]],poly[((shaperef.m_polyrefs[k]+1)%poly.size())]); + Line lineb = Line(polyb[shaperefb.m_polyrefs[kk]],polyb[((shaperefb.m_polyrefs[kk]+1)%polyb.size())]); + if (intersect_region(line,lineb)) { + if (intersect_line(line,lineb,tolerance)) { + if (testedlist.add(shaperefb.m_shape_ref) != -1) { + shapeindexlist.add(indexb); + break; + } + } + } + } + } + } + } + else { + // poly to poly, ick! + // first test one entirely inside the other + // any point at all will suffice to check this: however, we need to check that the polyref point *itself* is within the + // pixel, not just part of the line associated with it... + if ((pixelate(polyb[shaperefb.m_polyrefs[0]]) == PixelRef(x,y) && testPointInPoly(polyb[shaperefb.m_polyrefs[0]],shaperef) != -1) || + (pixelate(poly[shaperef.m_polyrefs[0]]) == PixelRef(x,y) && testPointInPoly(poly[shaperef.m_polyrefs[0]],shaperefb) != -1)) { + testedlist.add(shaperefb.m_shape_ref,paftl::ADD_HERE); + shapeindexlist.add(indexb); + } + else { + // now check crossing + bool breakit = false; + for (int k = 0; k < shaperef.m_polyrefs.size() && !breakit; k++) { + for (int kk = 0; kk < shaperefb.m_polyrefs.size(); kk++) { + Line line = Line(poly[shaperef.m_polyrefs[k]],poly[((shaperef.m_polyrefs[k]+1)%poly.size())]); + Line lineb = Line(polyb[shaperefb.m_polyrefs[kk]],polyb[((shaperefb.m_polyrefs[kk]+1)%polyb.size())]); + if (intersect_region(line,lineb)) { + if (intersect_line(line,lineb,tolerance)) { + testedlist.add(shaperefb.m_shape_ref,paftl::ADD_HERE); + shapeindexlist.add(indexb); + breakit = true; + break; + } + } + } + } + } + } + } + } + } + } + } + } + + } + else { + throw depthmapX440::RuntimeException("this function is to be used for polygons only"); + } +} + +// helper for point in poly -- +// currently needs slight rewrite to avoid problem if point is in line with a vertex +// (counter incremented twice on touching implies not in poly when is) + +int ShapeMap::testPointInPoly(const Point2f& p, const ShapeRef& shape) const +{ + size_t shapeindex = paftl::npos; + // simplist: in shape centre + if (shape.m_tags & ShapeRef::SHAPE_CENTRE) { + shapeindex = m_shapes.searchindex(shape.m_shape_ref); + } + // check not an open shape (cannot be inside) + else if ((shape.m_tags & ShapeRef::SHAPE_OPEN) == 0) { + const SalaShape& poly = m_shapes.search(shape.m_shape_ref); + if (poly.m_region.contains_touch(p)) { + // next simplest, on the outside border: + int alpha = 0; + int counter = 0; + int parity = 0; + if (shape.m_tags & ShapeRef::SHAPE_EDGE) { + // run a test line to the edge: + if (shape.m_tags & (ShapeRef::SHAPE_L | ShapeRef::SHAPE_R)) { + if (shape.m_tags & ShapeRef::SHAPE_L) { + parity = -1; + } + else if (shape.m_tags & ShapeRef::SHAPE_R) { + parity = +1; + } + for (int j = 0; j < shape.m_polyrefs.size(); j++) { + Line lineb = Line(poly[shape.m_polyrefs[j]],poly[((shape.m_polyrefs[j]+1)%poly.size())]); + if (lineb.bottom_left.y <= p.y && lineb.top_right.y >= p.y) { + // crosses or touches... but we need to check + // touching exception: + if (lineb.t_start().y == p.y) { + if (parity * lineb.t_start().x >= parity * p.x) { + alpha -= 1; + counter++; + } + } + // the other touching exception + else if (lineb.t_end().y == p.y) { + if (parity * lineb.t_end().x >= parity * p.x) { + alpha += 1; + // n.b., no counter here + } + } + // at this stage we know the line isn't horizontal, so we can find the intersection point: + else if (parity * (lineb.grad(XAXIS)*(p.y-lineb.ay()) + lineb.ax()) >= parity * p.x) { + counter++; + } + } + } + } + else { + if (shape.m_tags & ShapeRef::SHAPE_B) { + parity = -1; + } + else if (shape.m_tags & ShapeRef::SHAPE_T) { + parity = +1; + } + for (int j = 0; j < shape.m_polyrefs.size(); j++) { + Line lineb = Line(poly[shape.m_polyrefs[j]],poly[((shape.m_polyrefs[j]+1)%poly.size())]); + if (lineb.bottom_left.x <= p.x && lineb.top_right.x >= p.x) { + // crosses or touches... but we need to check + // touching exception: + if (lineb.top_right.x == p.x) { + if (parity * lineb.by() >= parity * p.y) { + alpha -= 1; + counter++; + } + } + // the other touching exception + else if (lineb.bottom_left.x == p.x) { + if (parity * lineb.ay() >= parity * p.y) { + alpha += 1; + // n.b., no counter here + } + } + // at this stage we know the line isn't vertical, so we can find the intersection point: + else if (parity * (lineb.grad(YAXIS)*(p.x-lineb.ax()) + lineb.ay()) >= parity * p.y) { + counter++; + } + } + } + } + if (counter % 2 != 0 && alpha == 0) { + shapeindex = m_shapes.searchindex(shape.m_shape_ref); + } + } + // and now the pig -- it's somewhere in the middle of the poly: + else if (shape.m_tags & ShapeRef::SHAPE_INTERNAL_EDGE) { + pvecint testnodes; + size_t j; + for (j = 0; j < size_t(shape.m_polyrefs.size()); j++) { // <- note, polyrefs is a subvec and has maximum number according to sizeof(T) + testnodes.add(shape.m_polyrefs[j]); + } + PixelRef pix2 = pixelate(p); + // bit of code duplication like this, but easier on params to this function: + pix2.move(PixelRef::NEGVERTICAL); // move pix2 down, search for this shape... + size_t nextindex = m_pixel_shapes[pix2.x][pix2.y].searchindex(shape.m_shape_ref); + while (nextindex != paftl::npos) { + const ShapeRef& shape2 = m_pixel_shapes[pix2.x][pix2.y][nextindex]; + for (int k = 0; k < shape2.m_polyrefs.size(); k++) { + testnodes.add(shape2.m_polyrefs[k]); + } + pix2.move(PixelRef::NEGVERTICAL); // move pix2 down, search for this shape... + if (includes(pix2)) { + nextindex = m_pixel_shapes[pix2.x][pix2.y].searchindex(shape.m_shape_ref); + } + else { + nextindex = paftl::npos; + } + } + int alpha = 0; + int counter = 0; + int parity = -1; + for (j = 0; j < testnodes.size(); j++) { + Line lineb = Line(poly[testnodes[j]],poly[((testnodes[j]+1)%poly.size())]); + if (lineb.bottom_left.x <= p.x && lineb.top_right.x >= p.x) { + // crosses or touches... but we need to check + // touching exception: + if (lineb.top_right.x == p.x) { + if (parity * lineb.by() >= parity * p.y) { + alpha -= 1; + counter++; + } + } + // the other touching exception + else if (lineb.bottom_left.x == p.x) { + if (parity * lineb.ay() >= parity * p.y) { + alpha += 1; + // n.b., no counter here + } + } + // at this stage we know the line isn't vertical, so we can find the intersection point: + else if (parity * (lineb.grad(YAXIS)*(p.x-lineb.ax()) + lineb.ay()) >= parity * p.y) { + counter++; + } + } + } + if (counter % 2 != 0 && alpha == 0) { + shapeindex = m_shapes.searchindex(shape.m_shape_ref); + } + } + } + } + return (shapeindex == paftl::npos) ? -1 : int(shapeindex); // note convert to -1 +} + +bool ShapeMap::write(std::ostream &stream, int version ) +{ + // name + dXstring440::writeString(stream, m_name); + + stream.write( (char *) &m_map_type, sizeof(m_map_type)); + stream.write( (char *) &m_show, sizeof(m_show) ); + stream.write( (char *) &m_editable, sizeof(m_editable) ); + + // PixelBase write + // write extents: + stream.write( (char *) &m_region, sizeof(m_region) ); + // write rows / cols + stream.write( (char *) &m_rows, sizeof(m_rows) ); + stream.write( (char *) &m_cols, sizeof(m_cols) ); + + // write next object ref to be used: + stream.write((char *) &m_obj_ref, sizeof(m_obj_ref)); + stream.write((char *) &m_shape_ref, sizeof(m_shape_ref)); + + // write shape data + int count = m_shapes.size(); + stream.write((char *) &count, sizeof(count)); + for (int j = 0; j < count; j++) { + int key = m_shapes.key(j); + stream.write((char *) &key, sizeof(key)); + m_shapes.value(j).write(stream); + } + // write object data (currently unused) + count = m_objects.size(); + stream.write((char *) &count, sizeof(count)); + for (int k = 0; k < count; k++) { + int key = m_objects.key(k); + stream.write((char *) &key, sizeof(key)); + m_objects.value(k).write(stream); + } + // write attribute data + m_attributes.write(stream,version); + stream.write((char *)&m_displayed_attribute,sizeof(m_displayed_attribute)); + + // write connections data + count = m_connectors.size(); + stream.write((char *)&count,sizeof(count)); + + for (int i = 0; i < count; i++) { + m_connectors[i].write(stream); + } + m_links.write(stream); + m_unlinks.write(stream); + + // some miscellaneous extra data for mapinfo files + if (m_mapinfodata) { + stream.put('m'); + m_mapinfodata->write(stream); + } + else { + stream.put('x'); + } + + return true; +} + +bool SalaShape::write(std::ostream &stream) +{ + stream.write((char *)&m_type,sizeof(m_type)); + stream.write((char *)&m_region,sizeof(m_region)); + stream.write((char *)&m_centroid,sizeof(m_centroid)); + stream.write((char *)&m_area,sizeof(m_area)); + stream.write((char *)&m_perimeter,sizeof(m_perimeter)); + pqvector::write(stream); + return true; +} + +} diff --git a/mgraph440/shapemap.h b/mgraph440/shapemap.h new file mode 100644 index 00000000..b2f658ec --- /dev/null +++ b/mgraph440/shapemap.h @@ -0,0 +1,321 @@ +#pragma once + +#include "mgraph440/pixelbase.h" +#include "mgraph440/mapinfodata.h" +#include "mgraph440/attributes.h" +#include "mgraph440/connector.h" +#include "mgraph440/paftl.h" +#include "mgraph440/mgraph_consts.h" +#include "mgraph440/stringutils.h" +#include "mgraph440/bspnode.h" + +namespace mgraph440 { + +class SalaShape : public pqvector +{ +public: + enum {SHAPE_POINT = 0x01, SHAPE_LINE = 0x02, SHAPE_POLY = 0x04, SHAPE_CIRCLE = 0x08, SHAPE_TYPE = 0x0f, SHAPE_CLOSED = 0x40, SHAPE_CCW = 0x80 }; + friend class ShapeMap; + + unsigned char m_type; + Point2f m_centroid; // centre of mass, but also used as for point if object is a point + Line m_region; // bounding box, but also used as a line if object is a line, hence type + double m_area; + double m_perimeter; + // these are all temporary data which are recalculated on reload + mutable bool m_selected; + mutable float m_color; + mutable int m_draworder; + + SalaShape(unsigned char type = 0) + { m_type = type; m_draworder = -1; m_selected = false; m_area = 0.0; m_perimeter = 0.0; } + SalaShape(const Point2f& point) + { m_type = SHAPE_POINT; m_draworder = -1; m_selected = false; m_region = Line(point,point); m_centroid = point; m_area = 0.0; m_perimeter = 0.0; } + SalaShape(const Line& line) + { m_type = SHAPE_LINE; m_draworder = -1; m_selected = false; m_region = line; m_centroid = m_region.getCentre(); m_area = 0.0; m_perimeter = m_region.length(); } + // + bool isOpen() const + { return (m_type & SHAPE_CLOSED) == 0; } + bool isClosed() const + { return (m_type & SHAPE_CLOSED) == SHAPE_CLOSED; } + bool isPoint() const + { return (m_type == SHAPE_POINT); } + bool isLine() const + { return (m_type == SHAPE_LINE); } + bool isPolyLine() const + { return (m_type & (SHAPE_POLY | SHAPE_CLOSED)) == SHAPE_POLY; } + bool isPolygon() const + { return (m_type & (SHAPE_POLY | SHAPE_CLOSED)) == (SHAPE_POLY | SHAPE_CLOSED); } +// bool isCCW() const +// { return (m_type & SHAPE_CCW) == SHAPE_CCW; } +// // + const Point2f& getPoint() const + { return m_centroid; } + const Line& getLine() const + { return m_region; } +// const QtRegion& getBoundingBox() const +// { return m_region; } +// // +// double getArea() const +// { return m_area; } +// double getPerimeter() const +// { return m_perimeter; } +// // duplicate function, but easier to understand naming convention + double getLength() const + { return m_perimeter; } +// // + void setCentroidAreaPerim(); +// void setCentroid(const Point2f& p); +// // duplicate function, but easier to understand naming convention +// const Point2f& getCentroid() const +// { return m_centroid; } +// // +// double getAngDev() const; +// // +// pqvector getClippingSet(QtRegion& clipframe) const; +// // + bool read(std::ifstream& stream, int version); + bool write(std::ostream& stream); +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +class SalaObject : public pvecint +{ + friend class ShapeMap; +protected: + Point2f m_centroid; +public: + SalaObject() {;} + // + bool read(std::ifstream& stream, int version); + bool write(std::ostream& stream); +}; +inline bool SalaObject::read(std::ifstream& stream, int) +{ + stream.read((char *)&m_centroid,sizeof(m_centroid)); + pvecint::read(stream); + return true; +} +inline bool SalaObject::write(std::ostream& stream) +{ + stream.write((char *)&m_centroid,sizeof(m_centroid)); + pvecint::write(stream); + return true; +} +struct SalaEvent +{ + enum { SALA_NULL_EVENT, SALA_CREATED, SALA_DELETED, SALA_MOVED }; + int m_action; + int m_shape_ref; + SalaShape m_geometry; + SalaEvent(int action = SALA_NULL_EVENT, int shape_ref = -1) { m_action = action; m_shape_ref = shape_ref; } +}; + +struct ShapeRef +{ + enum {SHAPE_REF_NULL = 0xFFFFFFFF}; + enum {SHAPE_L = 0x01, SHAPE_B = 0x02, SHAPE_R = 0x04, SHAPE_T = 0x08 }; + enum {SHAPE_EDGE = 0x0f, SHAPE_INTERNAL_EDGE = 0x10, SHAPE_CENTRE = 0x20, SHAPE_OPEN = 0x40 }; + unsigned char m_tags; + unsigned int m_shape_ref; + psubvec m_polyrefs; + ShapeRef( unsigned int sref = SHAPE_REF_NULL, unsigned char tags = 0x00 ) + { m_shape_ref = sref; m_tags = tags; } + friend bool operator == (const ShapeRef& a, const ShapeRef& b); + friend bool operator != (const ShapeRef& a, const ShapeRef& b); + friend bool operator < (const ShapeRef& a, const ShapeRef& b); + friend bool operator > (const ShapeRef& a, const ShapeRef& b); +}; +inline bool operator == (const ShapeRef& a, const ShapeRef& b) +{ return a.m_shape_ref == b.m_shape_ref; } +inline bool operator != (const ShapeRef& a, const ShapeRef& b) +{ return a.m_shape_ref != b.m_shape_ref; } +inline bool operator < (const ShapeRef& a, const ShapeRef& b) +{ return a.m_shape_ref < b.m_shape_ref; } +inline bool operator > (const ShapeRef& a, const ShapeRef& b) +{ return a.m_shape_ref > b.m_shape_ref; } + +class ShapeMap : public PixelBase +{ +public: + ShapeMap(const std::string& name = std::string(),int type = EMPTYMAP); + virtual ~ShapeMap(); + + enum {EMPTYMAP = 0x0000, SEGMENTMAP = 0x0040, AXIALMAP = 0x0020, ALLLINEMAP = 0x0010, DRAWINGMAP = 0x0001, DATAMAP = 0x0002}; + int m_map_type; + std::string m_name; + bool m_show; // used when shape map is a drawing layer + bool m_editable; + bool m_selection; + mutable BSPNode *m_bsp_root; + mutable bool m_bsp_tree; + // quick grab for shapes + pqvector **m_pixel_shapes; // i rows of j columns + // for screen drawing + mutable int *m_display_shapes; + pqmap m_shapes; + pqmap m_objects; // THIS IS UNUSED! Meant for each object to have many shapes + prefvec m_undobuffer; + AttributeTable m_attributes; + // for graph functionality + // Note: this list is stored PACKED for optimal performance on graph analysis + // ALWAYS check it is in the same order as the shape list and attribute table + prefvec m_connectors; + int m_shape_ref; + pqvector m_links; + pqvector m_unlinks; + double m_tolerance; + int m_obj_ref; + mutable bool m_invalidate; + mutable int m_displayed_attribute; + MapInfoData *m_mapinfodata; + std::set m_selection_set; // note: uses rowids not keys + mutable bool m_show_lines; + mutable bool m_show_fill; + mutable bool m_show_centroids; + bool m_hasgraph; + mutable bool m_newshape; // if a new shape has been added + + void makePolyPixels(int shaperef); + // required for PixelBase, have to implement your own version of pixelate + PixelRef pixelate( const Point2f& p, bool constrain = true, int = 1) const; + const std::string& getName() const + { return m_name; } + bool read( std::ifstream& stream, int version, bool drawinglayer = false ); + bool write( std::ostream& stream, int version ); + void invalidateDisplayedAttribute() + { m_invalidate = true; } + void setDisplayedAttribute( int col ) const; + void shapePixelBorder(pmap& relations, int shaperef, int side, PixelRef currpix, PixelRef minpix, bool first); + int moveDir(int side); + // convert a selected pixels to a layer object (note, uses selection attribute on pixel, you must select to make this work): + int makeShapeFromPointSet(const PointMap& pointmap); + AttributeTable& getAttributeTable() + { return m_attributes; } + // use set displayed attribute instead unless you are deliberately changing the column order: + void overrideDisplayedAttribute(int attribute) + { m_displayed_attribute = attribute; } + const prefvec& getConnections() const + { return m_connectors; } + bool isSegmentMap() const + { return m_map_type == SEGMENTMAP; } + void pointPixelBorder(const PointMap& pointmap, pmap& relations, SalaShape& shape, int side, PixelRef currpix, PixelRef minpix, bool first); + bool clearSel(); + void init(int size, const QtRegion& r); + Point2f pointOffset(const PointMap& pointmap, int currpix, int side); + int makeLineShape(const Line& line, bool through_ui = false, bool tempshape = false); + bool isAxialMap() const + { return m_map_type == ALLLINEMAP || m_map_type == AXIALMAP; } + // Connect a particular shape into the graph + int connectIntersected(int rowid, bool linegraph); + // Get the connections for a particular line + int getLineConnections(int lineref, pvecint& connections, double tolerance); + // Get arbitrary shape connections for a particular shape + int getShapeConnections(int polyref, pvecint& connections, double tolerance); + // retrieve lists of polys point intersects: + void pointInPolyList(const Point2f& p, pvecint& shapeindexlist) const; + void lineInPolyList(const Line& li, pvecint& shapeindexlist, int lineref = -1, double tolerance = 0.0) const; + void polyInPolyList(int polyref, pvecint& shapeindexlist, double tolerance = 0.0) const; + // helper to make actual test of point in shape: + int testPointInPoly(const Point2f& p, const ShapeRef& shape) const; +}; + +// Quick mod - TV +template +class ShapeMaps : public /*protected*/ prefvec +{ +public: + size_t m_displayed_map; + ShapeMaps() { m_displayed_map = paftl::npos;} + virtual ~ShapeMaps() {;} + // + size_t addMap(const std::string& name, int type); + void setDisplayedMapRef(size_t map); + // Quick mod - TV + T& getMap(size_t index) + { return prefvec::at(index); } + size_t getMapRef(const std::string& name) const; + bool read( std::ifstream& stream, int version ); + bool write(::std::ostream &stream, int version, bool displayedmaponly = false ); +}; +template +void ShapeMaps::setDisplayedMapRef(size_t map) +{ + if (m_displayed_map != paftl::npos && m_displayed_map != map) + prefvec::at(m_displayed_map).clearSel(); + m_displayed_map = map; +} +template +size_t ShapeMaps::addMap(const std::string& name, int type) +{ + ShapeMaps::push_back(T(name,type)); + setDisplayedMapRef(pmemvec::size()-1); + return (pmemvec::size()-1); +} +template +bool ShapeMaps::read( std::ifstream& stream, int version ) +{ + prefvec::clear(); // empty existing data + // n.b. -- do not change to size_t as will cause 32-bit to 64-bit conversion problems + unsigned int displayed_map; + stream.read((char *)&displayed_map,sizeof(displayed_map)); + m_displayed_map = size_t(displayed_map); + // read maps + // n.b. -- do not change to size_t as will cause 32-bit to 64-bit conversion problems + unsigned int count = 0; + stream.read((char *) &count, sizeof(count)); + if (version < VERSION_NO_SHAPEMAP_NAME_LOOKUP) { + for (size_t i = 0; i < size_t(count); i++) { + // dummy name lookup (now simply creates on fly, as the name lookup may be corrupted in earlier versions) + std::string name = dXstring440::readString(stream); + int number; + stream.read((char *)&number,sizeof(number)); + } + } + for (size_t j = 0; j < size_t(count); j++) { + ShapeMaps::push_back(T()); + prefvec::tail().read(stream,version); + } + return true; +} +template +bool ShapeMaps::write( ::std::ostream& stream, int version, bool displayedmaponly ) +{ + if (!displayedmaponly) { + // n.b. -- do not change to size_t as will cause 32-bit to 64-bit conversion problems + unsigned int displayed_map = (unsigned int)(m_displayed_map); + stream.write((char *)&displayed_map,sizeof(displayed_map)); + // write maps + // n.b. -- do not change to size_t as will cause 32-bit to 64-bit conversion problems + unsigned int count = (unsigned int) pmemvec::size(); + stream.write((char *) &count, sizeof(count)); + for (size_t j = 0; j < count; j++) { + prefvec::at(j).write(stream,version); + } + } + else { + unsigned int dummy; + // displayed map is 0 + dummy = 0; + stream.write((char *)&dummy,sizeof(dummy)); + // count is 1 + dummy = 1; + stream.write((char *)&dummy,sizeof(dummy)); + // write map: + prefvec::at(m_displayed_map).write(stream,version); + } + return true; +} +template +size_t ShapeMaps::getMapRef(const std::string& name) const +{ + // note, only finds first map with this name + for (size_t i = 0; i < pmemvec::size(); i++) { + if (prefvec::at(i).getName() == name) + return i; + } + return -1; +} + +} diff --git a/mgraph440/spacepix.cpp b/mgraph440/spacepix.cpp new file mode 100644 index 00000000..c52475e3 --- /dev/null +++ b/mgraph440/spacepix.cpp @@ -0,0 +1,118 @@ +#include "mgraph440/spacepix.h" + +namespace mgraph440 { + +PixelRef SpacePixel::pixelate( const Point2f& p, bool constrain, int ) const +{ + PixelRef r; + + Point2f p1 = p; + p1.normalScale(m_region); + + r.x = short(p1.x * double(m_cols-1e-9)); + if (constrain) { + if (r.x >= m_cols) + r.x = m_cols - 1; + else if (r.x < 0) + r.x = 0; + } + r.y = short(p1.y * double(m_rows-1e-9)); + if (constrain) { + if (r.y >= m_rows) + r.y = m_rows - 1; + else if (r.y < 0) + r.y = 0; + } + + return r; +} + +bool SpacePixel::read( std::ifstream& stream, int version ) +{ + // clear anything that was there: + if (m_pixel_lines) + { + for (int i = 0; i < m_cols; i++) { + delete [] m_pixel_lines[i]; + } + delete [] m_pixel_lines; + m_pixel_lines = NULL; + } + if (m_display_lines) { + delete [] m_display_lines; + m_display_lines = NULL; + } + m_lines.clear(); + + // read name: + if (version >= VERSION_SPACEPIXELGROUPS) { + m_name = dXstring440::readString(stream ); + stream.read( (char *) &m_show, sizeof(m_show) ); + } + else { + m_name = ""; + } + if (m_name.empty()) { + m_name = ""; + } + + m_edit = false; // <- just default to not editable on read + + if (version >= VERSION_LAYERCOLORS) { + stream.read( (char *) &m_color, sizeof(m_color) ); + } + + // read extents: + stream.read( (char *) &m_region, sizeof(m_region) ); + + // read rows / cols + stream.read( (char *) &m_rows, sizeof(m_rows) ); + stream.read( (char *) &m_cols, sizeof(m_cols) ); + + // could work these two out on the fly, but it's easier to have them stored: + //m_pixel_height = m_region.height() / double(m_rows); + //m_pixel_width = m_region.width() / double(m_cols); + + // prepare loader: + m_pixel_lines = new pvecint *[m_cols]; + for (int i = 0; i < m_cols; i++) { + m_pixel_lines[i] = new pvecint[m_rows]; + } + + if (version < VERSION_DYNAMICLINES) { + // read lines as refvec... + prefvec lines; + lines.read( stream ); + // ... and transfer to new system: + m_ref = -1; + for (size_t i = 0; i < lines.size(); i++) { + m_lines.add(++m_ref, LineTest(lines[i],0)); + } + } + else { + stream.read((char *) &m_ref, sizeof(m_ref)); + m_lines.read( stream ); + } + + if (version < VERSION_SPACEPIXELGROUPS) { + // Scale up lines (should just work) + for (size_t i = 0; i < m_lines.size(); i++) { + m_lines[i].line.denormalScale(m_region); + } + } + + // now load into structure: + for (size_t n = 0; n < m_lines.size(); n++) { + + PixelRefVector list = pixelateLine( m_lines[n].line ); + + for (size_t m = 0; m < list.size(); m++) { + // note: m_pixel_lines is an *ordered* list! --- used by other ops. + m_pixel_lines[list[m].x][list[m].y].push_back( n ); + } + } + + return true; +} + +} diff --git a/mgraph440/spacepix.h b/mgraph440/spacepix.h new file mode 100644 index 00000000..c95315ff --- /dev/null +++ b/mgraph440/spacepix.h @@ -0,0 +1,134 @@ +#pragma once + +#include "mgraph440/shapemap.h" +#include "mgraph440/pafcolor.h" +#include "mgraph440/paftl.h" +#include "mgraph440/p2dpoly.h" + +namespace mgraph440 { + +struct LineTest { + Line line; + unsigned int test; + LineTest(const Line& l = Line(), int t = -1) + { line = l; test = t; } +}; + +class SpacePixel : public PixelBase +{ + friend class PointMap; + friend class AxialMaps; + friend class AxialPolygons; + friend class ShapeMap; // for transfer to everything being ShapeMaps +public: +//protected: + PafColor m_color; + std::string m_name; + bool m_show; + bool m_edit; + pvecint **m_pixel_lines; + int m_ref; + pmap m_lines; + // + // for screen drawing + mutable int *m_display_lines; + PixelRef pixelate( const Point2f& p, bool constrain = true, int = 1 ) const; + const pmap& getAllLines() const // Danger! Use solely to look at the raw line data + { return m_lines; } + std::string getName() + { return m_name; } + virtual bool read( std::ifstream& stream, int version ); +}; + +// simply check they are the same name... useful for findindex from the group +inline bool operator == (const SpacePixel& a, const SpacePixel& b) +{ + return a.m_name == b.m_name; +} + +template +class SpacePixelGroup : public pqvector +{ +protected: + std::string m_name; // <- file name + mutable int m_current_layer; +public: + QtRegion m_region; // easier public for now + // + SpacePixelGroup(const std::string& name = std::string()) + { m_name = name; m_current_layer = -1; } + void setName(const std::string& name) + { m_name = name; } + const std::string& getName() const + { return m_name; } + // + QtRegion& getRegion() const + { return (QtRegion&) m_region; } + // + // Screen functionality: + void makeViewportShapes( const QtRegion& viewport = QtRegion() ) const; + bool findNextShape(bool& nextlayer) const; + + // Quick mod - TV +#if 0 +#if !defined(_MSC_VER) + size_t size() const + { return pmemvec::size(); } + + T& at(size_t pos) + { return prefvec::at(pos); } + + T& tail() + { return prefvec::tail(); } + +#endif +#endif + +public: + bool read(std::ifstream& stream, int version, bool = true); + bool write(std::ostream &stream, int version ); +}; + +template +bool SpacePixelGroup::read( std::ifstream& stream, int version, bool ) +{ + if (version >= VERSION_SPACEPIXELGROUPS) { + m_name = dXstring440::readString(stream); + stream.read( (char *) &m_region, sizeof(m_region) ); + int count; + stream.read( (char *) &count, sizeof(count) ); + for (int i = 0; i < count; i++) { + SpacePixelGroup::push_back(T()); + prefvec::tail().read(stream,version,true); + } + } + else { + m_name = ""; + SpacePixelGroup::push_back(T()); + prefvec::tail().read(stream,version,true); + m_region = prefvec::tail().getRegion(); + } + if (m_name.empty()) { + m_name = ""; + } + return true; +} + +template +bool SpacePixelGroup::write( std::ostream& stream, int version ) +{ + dXstring440::writeString(stream, m_name); + stream.write( (char *) &m_region, sizeof(m_region) ); + + // Quick mod - TV + int count = prefvec::size(); + stream.write( (char *) &count, sizeof(count) ); + for (int i = 0; i < count; i++) { + prefvec::at(i).write(stream,version); + } + return true; +} +typedef SpacePixelGroup < ShapeMap> SpacePixelFile; +typedef SpacePixelGroup SuperSpacePixel; + +} diff --git a/mgraph440/stringutils.cpp b/mgraph440/stringutils.cpp new file mode 100644 index 00000000..6d169757 --- /dev/null +++ b/mgraph440/stringutils.cpp @@ -0,0 +1,141 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "mgraph440/stringutils.h" +#include +#include +#include +#include +#include + +namespace dXstring440 { + std::vector split(const std::string &s, char delim, bool skipEmptyTokens) + { + std::vector elems; + std::stringstream ss; + ss.str(s); + std::string item; + while (std::getline(ss, item, delim)) + { + if (skipEmptyTokens && item.empty()) + { + continue; + } + elems.push_back(item); + } + + return elems; + } + + std::string readString(std::istream & stream) + { + unsigned int length; + stream.read(reinterpret_cast(&length), sizeof(length)); + if ( length == 0) + { + return std::string(); + } + std::string result( length, '\0'); + char *ptr = &result[0]; + stream.read(ptr, length); + return result; + } + + void writeString(std::ostream &stream, const std::string &s) + { + unsigned int length = s.length(); + stream.write(reinterpret_cast(&length), sizeof(unsigned int)); + if (length > 0) + { + stream.write(s.data(), length); + } + } + + std::string formatString(double value, const std::string &format) + { + std::vector buffer(24 + format.length(), '\0'); + sprintf( &buffer[0], format.c_str(), value ); + return std::string(&buffer[0]); + } + + std::string formatString(int value, const std::string &format) + { + std::vector buffer(24 + format.length(), '\0'); + sprintf( &buffer[0], format.c_str(), value ); + return std::string(&buffer[0]); + } + + + std::string& toLower(std::string &str) + { + std::transform(str.begin(), str.end(), str.begin(), tolower); + return str; + } + + // trim from start (in place) + void ltrim(std::string &s, char c) { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [&c](int ch) { + return ch != c; + })); + } + + // trim from end (in place) + void rtrim(std::string &s, char c) { + s.erase(std::find_if(s.rbegin(), s.rend(), [&c](int ch) { + return ch != c; + }).base(), s.end()); + } + + void makeInitCaps(std::string &s) + { + bool literal = false; + bool reset = true; + for( auto& c : s) + { + if (!isalpha(c)) + { + if ( c == '"') + { + literal = !literal; + } + reset = true; + } + else + { + if (!literal) + { + if (reset) + { + c = toupper(c); + } + else + { + c = tolower(c); + } + } + reset = false; + } + } + } + + bool isDouble(const std::string &s) + { + // nasty const cast to satisfy the function signature - we will not change the value of endPtr + char *endPtr = const_cast(&s[0]); + strtod(s.c_str(), &endPtr); + return endPtr != &s[0]; + } + +} diff --git a/mgraph440/stringutils.h b/mgraph440/stringutils.h new file mode 100644 index 00000000..d49833ee --- /dev/null +++ b/mgraph440/stringutils.h @@ -0,0 +1,43 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// Collection of utility functions that are required to add pstring functionality +// to std::strings (i.e. splitting and compatible serialisation/deserialisation) +#include +#include +#include +#include + +#pragma once +namespace dXstring440 { + std::vector split(const std::string &s, char delim, bool skipEmptyTokens = false); + std::string readString(std::istream & stream); + void writeString(std::ostream &stream, const std::string &s); + std::string formatString(double value, const std::string &format = "%+.16le"); + std::string formatString(int value, const std::string &format = "% 16d"); + /// Inplace conversion to lower case + std::string &toLower(std::string &str); + void ltrim(std::string &s, char c = ' '); + void rtrim(std::string &s, char c = ' '); + void makeInitCaps(std::string &s); + bool isDouble(const std::string &s); + template bool beginsWith(const T &input, const T match) + { + return input.size() >= match.size() && + equal(match.begin(), match.end(), input.begin()); + } + + +} diff --git a/mgraph440Test/CMakeLists.txt b/mgraph440Test/CMakeLists.txt new file mode 100644 index 00000000..e8cab4ef --- /dev/null +++ b/mgraph440Test/CMakeLists.txt @@ -0,0 +1,15 @@ +set(mgraph440Test mgraph440Test) +set(mgraph440Test_SRCS + main.cpp + testcontainers.cpp + testconverters.cpp) + +set(LINK_LIBS + salalib + mgraph440 + genlib) + +include_directories("../ThirdParty/Catch") + +add_executable(${mgraph440Test} ${mgraph440Test_SRCS}) +target_link_libraries(${mgraph440Test} ${LINK_LIBS}) diff --git a/mgraph440Test/main.cpp b/mgraph440Test/main.cpp new file mode 100644 index 00000000..757cef3d --- /dev/null +++ b/mgraph440Test/main.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#define CATCH_CONFIG_MAIN +#include "catch.hpp" diff --git a/mgraph440Test/testcontainers.cpp b/mgraph440Test/testcontainers.cpp new file mode 100644 index 00000000..ec9d50fc --- /dev/null +++ b/mgraph440Test/testcontainers.cpp @@ -0,0 +1,116 @@ +// Copyright (C) 2018 Christian Sailer +// Copyright (C) 2019 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" + +#include <../cliTest/selfcleaningfile.h> +#include <../genlib/containerutils.h> +#include <../genlib/readwritehelpers.h> +#include <../mgraph440/paftl.h> + +using namespace mgraph440; + +template void comparePvecAndStdVec(const pvector &pvec, const std::vector &stdVec) { + REQUIRE(pvec.size() == stdVec.size()); + for (size_t i = 0; i < stdVec.size(); ++i) { + REQUIRE(pvec[i] == stdVec[i]); + } +} + +TEST_CASE("Comaptibility between vector pvector streaming") { + std::vector intVec{1, 5, 34, -2, 5}; + SelfCleaningFile intFile("integers.bin"); + { + std::ofstream outfile(intFile.Filename()); + dXreadwrite::writeVector(outfile, intVec); + } + + pvector pveci; + { + std::ifstream infile(intFile.Filename()); + pveci.read(infile); + } + comparePvecAndStdVec(pveci, intVec); + + pvector intPvec; + intPvec.push_back(324); + intPvec.push_back(-23); + intPvec.push_back(87764); + intPvec.push_back(-9); + + { + std::ofstream outfile(intFile.Filename()); + intPvec.write(outfile); + } + + std::vector copyVec; + { + std::ifstream infile(intFile.Filename()); + dXreadwrite::readIntoVector(infile, copyVec); + } + + comparePvecAndStdVec(intPvec, copyVec); +} + +template void comparePmapAndStdMap(const pmap &pMap, const std::map &stdMap) { + const double EPSILON = 0.001; + + REQUIRE(pMap.size() == stdMap.size()); + for (size_t i = 0; i < stdMap.size(); ++i) { + REQUIRE(pMap.key(i) == depthmapX::getMapAtIndex(stdMap, i)->first); + REQUIRE(pMap.value(i) == Approx(double(depthmapX::getMapAtIndex(stdMap, i)->second)).epsilon(EPSILON)); + } +} + +TEST_CASE("Comaptibility between map pmap streaming") { + std::map intFloatMap; + intFloatMap.insert(std::make_pair(1, 0.1f)); + intFloatMap.insert(std::make_pair(5, 5000.0f)); + intFloatMap.insert(std::make_pair(34, -3.4f)); + intFloatMap.insert(std::make_pair(-2, 0.2f)); + intFloatMap.insert(std::make_pair(6, 0.6f)); + SelfCleaningFile intFloatFile("intFloatMap.bin"); + { + std::ofstream outfile(intFloatFile.Filename()); + dXreadwrite::writeMap(outfile, intFloatMap); + } + + pmap pmapi; + { + std::ifstream infile(intFloatFile.Filename()); + pmapi.read(infile); + } + comparePmapAndStdMap(pmapi, intFloatMap); + + pmap intFloatPmap; + intFloatPmap.add(324, 0.2f); + intFloatPmap.add(-23, 14000); + intFloatPmap.add(87764, -0.102f); + intFloatPmap.add(-9, 0.00001f); + + { + std::ofstream outfile(intFloatFile.Filename()); + intFloatPmap.write(outfile); + } + + std::map copyMap; + { + std::ifstream infile(intFloatFile.Filename()); + dXreadwrite::readIntoMap(infile, copyMap); + } + + comparePmapAndStdMap(intFloatPmap, copyMap); +} diff --git a/mgraph440Test/testconverters.cpp b/mgraph440Test/testconverters.cpp new file mode 100644 index 00000000..f13b1f9f --- /dev/null +++ b/mgraph440Test/testconverters.cpp @@ -0,0 +1,26 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "../mgraph440/legacyconverters.h" +#include "catch.hpp" + +TEST_CASE("vector conversion") { + std::vector vec{1, 4, 5}; + mgraph440::pvector result = genshim440::toPVector(vec); + REQUIRE(result.size() == 3); + REQUIRE(result[0] == 1); + REQUIRE(result[1] == 4); + REQUIRE(result[2] == 5); +} diff --git a/releases/README.txt b/releases/README.txt index 3a5745d3..4beb8a56 100644 --- a/releases/README.txt +++ b/releases/README.txt @@ -1,2 +1,22 @@ -Latest version: -https://github.com/varoudis/depthmapX/wiki/Download-and-Install \ No newline at end of file +depthmapX + +To install, just unpack the content of this zip file to your local hard drive and start depthmapX - this should contain everything you need. + +depthmapX documentation can be found at https://github.com/blackseamonster/depthmapX/tree/master/docs + +The wiki for this project is at: +https://github.com/blackseamonster/depthmapX/wiki + +Changelog +- Fixed some internal memory/runtime issues +- Import links from file +- Fixed crash on zoom-out issue +- command line app (depthmapXcli) +- restructured the code base to have more libraries that can be tested and reused +- added catch as unit test framework +- made simple mode option persistent +- fixed persistence of user options on Windows +- fixed mouse wheel zoom (center on mouse pointer, not center of the map) + + +If you have any issues or questions, you can raise a ticket at https://github.com/blackseamonster/depthmapX/issues or send an email to depthmapX@blackseamonster.com diff --git a/releases/gplv3.txt b/releases/gplv3.txt new file mode 100644 index 00000000..94a9ed02 --- /dev/null +++ b/releases/gplv3.txt @@ -0,0 +1,674 @@ + 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 + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/releases/lgplv3.txt b/releases/lgplv3.txt new file mode 100644 index 00000000..65c5ca88 --- /dev/null +++ b/releases/lgplv3.txt @@ -0,0 +1,165 @@ + GNU LESSER 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. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser 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 +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/releases/licenses.txt b/releases/licenses.txt new file mode 100644 index 00000000..b9bbe994 --- /dev/null +++ b/releases/licenses.txt @@ -0,0 +1,10 @@ +depthmapX +C 2000-2010 University College London, Alasdair Turner, Eva Friedrich +C 2011-2014 Tasos Varoudis, UCL +C 2017 Christian Sailer, Petros Koutsolampros + +Released under Gnu Public License (GPL v3) +Please see gplv3.txt for license details + +This program uses QT5 under the LGPL v3 +Please see lgplv3.txt for license details diff --git a/salaTest/CMakeLists.txt b/salaTest/CMakeLists.txt new file mode 100644 index 00000000..811d84bd --- /dev/null +++ b/salaTest/CMakeLists.txt @@ -0,0 +1,30 @@ +set(salaTest salaTest) + +set(salaTest_SRCS + main.cpp + testentityparsing.cpp + testpointmap.cpp + testlinkutils.cpp + testgridproperties.cpp + testisovistdef.cpp + testmgraph.cpp + testshapegraphs.cpp + teststructsizes.cpp + testsparksieve.cpp + testattributetable.cpp + testattributetableindex.cpp + testlayermanager.cpp + testattributetablehelpers.cpp + testattributetableview.cpp + testshapemaps.cpp + testgeometrygenerators.cpp + testmapinfodata.cpp + testsalaprogram.cpp + testdxfp.cpp) + +include_directories("../ThirdParty/Catch" "../ThirdParty/FakeIt") + +set(LINK_LIBS salalib genlib mgraph440) + +add_executable(${salaTest} ${salaTest_SRCS}) +target_link_libraries(${salaTest} ${LINK_LIBS}) diff --git a/salaTest/main.cpp b/salaTest/main.cpp new file mode 100644 index 00000000..b2cdafa5 --- /dev/null +++ b/salaTest/main.cpp @@ -0,0 +1,18 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#define CATCH_CONFIG_MAIN +#include "catch.hpp" diff --git a/salaTest/testattributetable.cpp b/salaTest/testattributetable.cpp new file mode 100644 index 00000000..ccf5dab4 --- /dev/null +++ b/salaTest/testattributetable.cpp @@ -0,0 +1,469 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "Catch/fakeit.hpp" +#include +#include +#include +#include +#include + +TEST_CASE("test attribute column") +{ + AttributeColumnImpl col("colName"); + REQUIRE(col.getName() == "colName"); + REQUIRE(col.getFormula() == ""); + + REQUIRE_FALSE(col.isHidden()); + REQUIRE_FALSE(col.isLocked()); + + col.setLock(true); + REQUIRE_FALSE(col.isHidden()); + REQUIRE(col.isLocked()); + + col.setHidden(true); + REQUIRE(col.isHidden()); + REQUIRE(col.isLocked()); + + REQUIRE(col.m_stats.max == -1.0); + REQUIRE(col.m_stats.min == -1.0); + REQUIRE(col.m_stats.total == -1.0); + REQUIRE(col.m_stats.visibleMax == -1.0); + REQUIRE(col.m_stats.visibleMin == -1.0); + REQUIRE(col.m_stats.visibleTotal == -1.0); + + col.updateStats(1.2f); + REQUIRE(col.m_stats.max == Approx(1.2)); + REQUIRE(col.m_stats.min == Approx(1.2)); + REQUIRE(col.m_stats.total == Approx(1.2)); + REQUIRE(col.m_stats.visibleMax == -1.0); + REQUIRE(col.m_stats.visibleMin == -1.0); + REQUIRE(col.m_stats.visibleTotal == -1.0); + + col.updateStats(2.0f); + REQUIRE(col.m_stats.max == Approx(2.0)); + REQUIRE(col.m_stats.min == Approx(1.2)); + REQUIRE(col.m_stats.total == Approx(3.2)); + REQUIRE(col.m_stats.visibleMax == -1.0); + REQUIRE(col.m_stats.visibleMin == -1.0); + REQUIRE(col.m_stats.visibleTotal == -1.0); + + col.updateStats(3.0f,1.2f); + REQUIRE(col.m_stats.max == Approx(3.0)); + REQUIRE(col.m_stats.min == Approx(1.2)); + REQUIRE(col.m_stats.total == Approx(5)); + REQUIRE(col.m_stats.visibleMax == -1.0); + REQUIRE(col.m_stats.visibleMin == -1.0); + REQUIRE(col.m_stats.visibleTotal == -1.0); + + // test read/write + SelfCleaningFile scf("column.bin"); + { + std::ofstream outfile(scf.Filename()); + col.write(outfile, 0); + } + AttributeColumnImpl copy(""); + { + std::ifstream infile(scf.Filename()); + copy.read(infile); + } + REQUIRE(copy.getName() == "colName"); + REQUIRE(copy.getFormula() == ""); + REQUIRE(copy.isHidden()); + REQUIRE(copy.isLocked()); + REQUIRE(copy.m_stats.max == Approx(3.0)); + REQUIRE(copy.m_stats.min == Approx(1.2)); + REQUIRE(copy.m_stats.total == Approx(5)); + REQUIRE(copy.m_stats.visibleMax == -1.0); + REQUIRE(copy.m_stats.visibleMin == -1.0); + REQUIRE(copy.m_stats.visibleTotal == -1.0); + + +} + +TEST_CASE("test attribute row") +{ + using namespace fakeit; + Mock colMan; + When(Method(colMan,getColumnIndex).Using(std::string("col1"))).AlwaysReturn(0); + When(Method(colMan,getColumnIndex).Using(std::string("col2"))).AlwaysReturn(1); + When(Method(colMan,getColumnIndex).Using(std::string("colx"))).AlwaysThrow(std::out_of_range("mock out of range")); + + When(Method(colMan,getNumColumns)).Return(2); + + Mock col1; + Mock col2; + When(Method(colMan, getColumn).Using(0)).AlwaysReturn(col1.get()); + When(Method(colMan, getColumn).Using(1)).AlwaysReturn(col2.get()); + When(Method(col1,updateStats)).AlwaysReturn(); + When(Method(col2,updateStats)).AlwaysReturn(); + + AttributeRowImpl row(colMan.get()); + row.setValue("col1", 1.2f); + REQUIRE(row.getValue("col1") == Approx(1.2f)); + REQUIRE(row.getValue(0) == Approx(1.2f)); + + row.setValue(1, 2.2f); + REQUIRE(row.getValue("col2") == Approx(2.2f)); + REQUIRE(row.getValue(1) == Approx(2.2f)); + + row.setValue(1, 3.2f); + REQUIRE(row.getValue("col2") == Approx(3.2f)); + REQUIRE(row.getValue(1) == Approx(3.2f)); + + + Verify(Method(col1,updateStats).Using(1.2f,0.0f)).Once(); + Verify(Method(col2,updateStats).Using(2.2f,0.0f)).Once(); + Verify(Method(col2,updateStats).Using(3.2f,2.2f)).Once(); + + REQUIRE_THROWS_AS(row.setValue("colx", 1.1f), std::out_of_range); + REQUIRE_THROWS_AS(row.setValue(2, 1.2f), std::out_of_range); + REQUIRE_THROWS_AS(row.getValue("colx"), std::out_of_range); + REQUIRE_THROWS_AS(row.getValue(2), std::out_of_range); + + // test attribute row impl only methods + // note that these do not affect the column manager - that will have to + // be handled by the caller - that's why these are impl only! + row.addColumn(); + REQUIRE(row.getValue(2) == -1.0f); + + row.removeColumn(1); + REQUIRE(row.getValue(1) == -1.0f); + REQUIRE(row.getValue(0) == Approx(1.2f)); + REQUIRE_THROWS_AS(row.getValue(2), std::out_of_range); + + //test reading/writing + SelfCleaningFile scf("rowfile.bin"); + { + std::ofstream outfile(scf.Filename()); + row.write(outfile); + } + Mock copiedColMan; + When(Method(copiedColMan,getNumColumns)).Return(2); + AttributeRowImpl copiedRow(copiedColMan.get()); + { + std::ifstream infile(scf.Filename()); + copiedRow.read(infile); + } + + REQUIRE(copiedRow.getValue(0) == Approx(1.2f)); + + row.incrValue(0, 1.0f); + REQUIRE(row.getValue(0) == Approx(2.2f)); + Verify(Method(col1,updateStats).Using(2.2f,1.2f)).Once(); + + AttributeRow& ifRef = row; + ifRef.incrValue(0); + REQUIRE(row.getValue(0) == Approx(3.2f)); + Verify(Method(col1,updateStats).Using(3.2f,2.2f)).Once(); + + +} + +TEST_CASE("test attribute table") +{ + AttributeTable table; + + table.insertOrResetColumn("col1"); + table.getOrInsertColumn("col2"); + table.insertOrResetLockedColumn("lcol1"); + table.getOrInsertLockedColumn("lcol2", "formula"); + + REQUIRE(table.getNumColumns() == 4); + REQUIRE(table.getColumnIndex("col2") == 1); + REQUIRE(table.getColumnName(1) == "col2"); + REQUIRE(table.getColumn(1).getName() == "col2"); + REQUIRE(table.getColumn(1).isLocked() == false); + REQUIRE(table.getColumn(3).getName() == "lcol2"); + REQUIRE(table.getColumn(3).isLocked()); + + table.addRow(AttributeKey(0)); + REQUIRE(table.getRow(AttributeKey(0)).getValue("col1") == -1 ); + table.getRow(AttributeKey(0)).setValue("col1", 1.2f ); + REQUIRE(table.getRow(AttributeKey(0)).getValue("col1") == Approx(1.2f) ); + REQUIRE(table.getRow(AttributeKey(0)).getValue(0) == Approx(1.2f) ); + + REQUIRE(table.getRow(AttributeKey(0)).getValue("lcol2") == -1 ); + table.getRow(AttributeKey(0)).setValue(3, 1.4f ); + REQUIRE(table.getRow(AttributeKey(0)).getValue("lcol2") == Approx(1.4f) ); + REQUIRE(table.getRow(AttributeKey(0)).getValue(3) == Approx(1.4f) ); + + REQUIRE_THROWS_AS(table.getRow(AttributeKey(0)).getValue(4), std::out_of_range); + + table.removeColumn(0); + table.removeColumn(1); + + REQUIRE(table.getNumColumns() == 2); + REQUIRE(table.getColumn(0).getName() == "col2"); + REQUIRE(table.getColumn(1).getName() == "lcol2"); + REQUIRE(table.getColumnIndex("lcol2") == 1); + + REQUIRE(table.getRow(AttributeKey(0)).getValue("col2") == -1.0 ); + REQUIRE(table.getRow(AttributeKey(0)).getValue(0) == -1.0 ); + REQUIRE(table.getRow(AttributeKey(0)).getValue("lcol2") == Approx(1.4f) ); + REQUIRE(table.getRow(AttributeKey(0)).getValue(1) == Approx(1.4f) ); + + + REQUIRE_THROWS_AS(table.getRow(AttributeKey(0)).getValue(2), std::out_of_range); + + table.addRow(AttributeKey(1)); + REQUIRE_THROWS_AS(table.getRow(AttributeKey(1)).getValue(2), std::out_of_range); + REQUIRE(table.getRow(AttributeKey(1)).getValue("col2") == -1.0 ); + REQUIRE(table.getRow(AttributeKey(1)).getValue(0) == -1.0 ); + REQUIRE(table.getRow(AttributeKey(1)).getValue("lcol2") == -1.0 ); + REQUIRE(table.getRow(AttributeKey(1)).getValue(1) == -1.0 ); + + table.getRow(AttributeKey(1)).setValue(0, 2.4f); + table.getRow(AttributeKey(1)).setValue("lcol2", 2.6f); + REQUIRE(table.getRow(AttributeKey(1)).getValue("col2") == Approx(2.4) ); + REQUIRE(table.getRow(AttributeKey(1)).getValue(1) == Approx(2.6) ); + + size_t idx = table.getOrInsertColumn("col2"); + REQUIRE(idx == 0); + REQUIRE(table.getRow(AttributeKey(1)).getValue("col2") == Approx(2.4) ); + REQUIRE(table.getColumn(0).getStats().max == Approx(2.4)); + + idx = table.insertOrResetColumn("col2"); + REQUIRE(idx == 0); + REQUIRE(table.getRow(AttributeKey(1)).getValue("col2") == -1.0 ); + REQUIRE(table.getColumn(0).getStats().max == -1.0); + + size_t newColIndex = table.getOrInsertColumn("newCol"); + REQUIRE(newColIndex == 2); + REQUIRE(table.getColumnName(2) == "newCol"); + REQUIRE(table.getColumnIndex("newCol") == 2); + REQUIRE(table.getColumn(2).getName() == "newCol"); + + REQUIRE(table.getRow(AttributeKey(0)).getValue(2) == -1.0); + + table.renameColumn("col2", "col_foo"); + REQUIRE(table.getColumnName(0) == "col_foo"); + REQUIRE(table.getColumnIndex("col_foo") == 0); + REQUIRE(table.getColumn(0).getName() == "col_foo"); + + REQUIRE_THROWS_AS(table.getColumnIndex("col2"), std::out_of_range); + + table.getRow(AttributeKey(0)).setSelection(true); + + REQUIRE(table.getRow(AttributeKey(0)).isSelected()); + auto iter = table.begin(); + REQUIRE(iter->getRow().isSelected()); + ++iter; + REQUIRE_FALSE(iter->getRow().isSelected()); + + table.deselectAllRows(); + for (auto& item : table) + { + REQUIRE_FALSE(item.getRow().isSelected()); + } + + // check read/write + LayerManagerImpl layerManager; + SelfCleaningFile scf("tablefile.bin"); + { + std::ofstream outfile(scf.Filename()); + table.write(outfile, layerManager); + } +} + +TEST_CASE("Existing and non-existing rows") +{ + AttributeTable table; + table.getOrInsertColumn("col1"); + table.getOrInsertColumn("col2"); + table.addRow(AttributeKey(0)).setValue(0, 1.0f); + table.addRow(AttributeKey(1)).setValue(0, 0.5f); + table.addRow(AttributeKey(2)).setValue(0, 2.0f); + + const AttributeTable& constRef = table; + + table.getRow(AttributeKey(0)); + constRef.getRow(AttributeKey(0)); + REQUIRE_THROWS_AS(table.getRow(AttributeKey(5)), std::out_of_range); + REQUIRE_THROWS_AS(constRef.getRow(AttributeKey(5)), std::out_of_range); + + REQUIRE( table.getRowPtr(AttributeKey(1)) != 0); + REQUIRE( constRef.getRowPtr(AttributeKey(1)) != 0); + + REQUIRE( table.getRowPtr(AttributeKey(5)) == 0); + REQUIRE( constRef.getRowPtr(AttributeKey(5)) == 0); +} + +TEST_CASE("normalised values"){ + AttributeTable table; + table.getOrInsertColumn("col1"); + table.getOrInsertColumn("col2"); + table.addRow(AttributeKey(0)).setValue(0, 1.0f); + table.addRow(AttributeKey(1)).setValue(0, 0.5f); + table.addRow(AttributeKey(2)).setValue(0, 2.0f); + + REQUIRE(table.getRow(AttributeKey(0)).getNormalisedValue(1) == Approx(0.5f)); + REQUIRE(table.getRow(AttributeKey(0)).getNormalisedValue(0) == Approx(0.33333f)); + REQUIRE(table.getRow(AttributeKey(1)).getNormalisedValue(0) == Approx(0.0f)); + REQUIRE(table.getRow(AttributeKey(2)).getNormalisedValue(0) == Approx(1.0f)); + + table.addRow(AttributeKey(3)).setValue(1,1.0f); + + REQUIRE(table.getRow(AttributeKey(1)).getNormalisedValue(1) == Approx(0.5f)); + REQUIRE(table.getRow(AttributeKey(3)).getNormalisedValue(1) == Approx(0.5f)); + + table.getRow(AttributeKey(0)).setValue(1,1.1f); + REQUIRE(table.getRow(AttributeKey(3)).getNormalisedValue(1) == Approx(0.0f)); + REQUIRE(table.getRow(AttributeKey(1)).getNormalisedValue(1) == Approx(-1.0f)); + + +} + +TEST_CASE("attibute table iterations") +{ + AttributeTable table; + + table.insertOrResetColumn("col1"); + table.getOrInsertColumn("col2"); + + auto& row = table.addRow(AttributeKey(0)); + row.setValue(0, 0.5f); + auto& row2 = table.addRow(AttributeKey(1)); + row2.setValue(0, 1.0f); + + AttributeTable::iterator iter = table.begin(); + REQUIRE((*iter).getKey().value == 0); + REQUIRE(iter->getRow().getValue(0) == Approx(0.5)); + iter++; + REQUIRE((*iter).getKey().value == 1); + REQUIRE(iter->getRow().getValue(0) == Approx(1.0)); + iter++; + + REQUIRE(iter == table.end()); + + for( auto& item : table) + { + item.getRow().setValue(1, 2.0f); + } + + REQUIRE(table.getRow(AttributeKey(0)).getValue(1) == Approx(2.0)); + REQUIRE(table.getRow(AttributeKey(1)).getValue(1) == Approx(2.0)); + + const AttributeTable& const_table = table; + + auto citer = const_table.begin(); + REQUIRE((*citer).getKey().value == 0); + REQUIRE(citer->getRow().getValue(0) == Approx(0.5)); + citer++; + REQUIRE((*citer).getKey().value == 1); + REQUIRE(citer->getRow().getValue(0) == Approx(1.0)); + citer++; + + auto cend = const_table.end(); + REQUIRE(citer == cend); + REQUIRE(citer == table.end()); + + AttributeTable::iterator foo(iter); + AttributeTable::const_iterator cfoo(iter); + AttributeTable::const_iterator ccfoo(citer); + + REQUIRE(iter == foo); + REQUIRE(cfoo == iter); + REQUIRE(ccfoo == iter); + + cfoo = table.end(); + foo = table.begin(); + + cfoo = foo; + + foo->getRow().setValue(1,2.2f); + ++foo; + foo->getRow().setValue(1, 3.2f); + + REQUIRE(table.getRow(AttributeKey(0)).getValue(1) == Approx(2.2)); + REQUIRE(table.getRow(AttributeKey(1)).getValue(1) == Approx(3.2)); +} + +#include + +TEST_CASE("Attribute Table - serialisation") +{ + LayerManagerImpl layerManager; + layerManager.addLayer("extra layer"); + REQUIRE(layerManager.getLayerIndex("extra layer") == 1); + + AttributeTable newTable; + size_t colIndex1 = newTable.getOrInsertColumn("foo", "foo formula"); + size_t colIndex2 = newTable.getOrInsertColumn("bar"); + + DisplayParams overAllDp; + overAllDp.blue = 1.2f; + overAllDp.red = 1.3f; + + DisplayParams fooDp; + fooDp.blue = 2.2f; + fooDp.red = 2.3f; + + DisplayParams barDp; + + newTable.getColumn(colIndex1).setDisplayParams(fooDp); + newTable.getColumn(colIndex2).setDisplayParams(barDp); + newTable.setDisplayParams(overAllDp); + + auto& row = newTable.addRow(AttributeKey(0)); + auto& row2 = newTable.addRow(AttributeKey(10)); + + row.setValue(0,1.0f); + row.setValue(1,2.0f); + + row2.setValue(0, 11.0f); + row2.setValue(1, 12.0f); + row2.setSelection(true); + + dXreimpl::pushSelectionToLayer(newTable, layerManager, "sel layer"); + REQUIRE(isObjectVisible(layerManager, row2)); + REQUIRE_FALSE(isObjectVisible(layerManager, row)); + + + + SelfCleaningFile newTableFile("newtable.bin"); + + { + std::ofstream outfile(newTableFile.Filename()); + newTable.write(outfile, layerManager); + } + + AttributeTable copyTable; + LayerManagerImpl copyLayerManager; + { + std::ifstream infile(newTableFile.Filename()); + copyTable.read(infile, copyLayerManager); + } + + auto& copyRow = copyTable.getRow(AttributeKey(0)); + REQUIRE(copyRow.getValue(0) == Approx(1.0f)); + REQUIRE(copyRow.getValue(1) == Approx(2.0f)); + + auto& copyRow2 = copyTable.getRow(AttributeKey(10)); + REQUIRE(copyRow2.getValue(0) == Approx(11.0f)); + REQUIRE(copyRow2.getValue(1) == Approx(12.0f)); + + REQUIRE(isObjectVisible(copyLayerManager, copyRow2)); + REQUIRE_FALSE(isObjectVisible(copyLayerManager, copyRow)); + + REQUIRE(copyTable.getColumnIndex("foo") == colIndex1); + REQUIRE(copyTable.getColumnIndex("bar") == colIndex2); + + REQUIRE(copyTable.getColumn(colIndex1).getDisplayParams().blue == Approx(fooDp.blue)); + REQUIRE(copyTable.getDisplayParams().blue == Approx(overAllDp.blue)); + +} + diff --git a/salaTest/testattributetablehelpers.cpp b/salaTest/testattributetablehelpers.cpp new file mode 100644 index 00000000..636ac75b --- /dev/null +++ b/salaTest/testattributetablehelpers.cpp @@ -0,0 +1,49 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include +#include + + +TEST_CASE("push to layer") +{ + using namespace dXreimpl; + using namespace fakeit; + Mock layMan; + AttributeTable table; + When(Method(layMan,addLayer)).Do([](const std::string &name)->size_t{REQUIRE(name == "testlayer"); return 1;}); + When(Method(layMan,getKey).Using(1)).AlwaysReturn(2); + When(Method(layMan,isVisible).Using(1)).AlwaysReturn(true); + When(Method(layMan,setLayerVisible)).AlwaysReturn(); + + table.insertOrResetColumn("col1"); + table.getOrInsertColumn("col2"); + + auto& row = table.addRow(AttributeKey(0)); + row.setValue(0, 0.5f); + row.setSelection(true); + auto& row2 = table.addRow(AttributeKey(1)); + row2.setValue(0, 1.0f); + + pushSelectionToLayer(table, layMan.get(), "testlayer"); + Verify(Method(layMan,addLayer)).Once(); + Verify(Method(layMan,getKey).Using(1)).Once(); + Verify(Method(layMan,setLayerVisible).Using(1, true)).Once(); + + REQUIRE(row.getLayerKey()== 3); + REQUIRE(row2.getLayerKey() == 1); +} + diff --git a/salaTest/testattributetableindex.cpp b/salaTest/testattributetableindex.cpp new file mode 100644 index 00000000..b3e89410 --- /dev/null +++ b/salaTest/testattributetableindex.cpp @@ -0,0 +1,45 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include + +TEST_CASE("Check index creation") +{ + AttributeTable table; + table.getOrInsertColumn("col1"); + table.getOrInsertColumn("col2"); + + auto& row0 = table.addRow(AttributeKey(0)); + auto& row1 = table.addRow(AttributeKey(1)); + auto& row2 = table.addRow(AttributeKey(2)); + auto& row3 = table.addRow(AttributeKey(3)); + + row0.setValue(0, 10.0); + row1.setValue(0, 8.5); + row2.setValue(0, 11.0); + row3.setValue(0, 4.5); + + auto index = makeAttributeIndex(table, 0); + REQUIRE(index.size() == 4); + REQUIRE(index[0].key.value == 3); + REQUIRE(index[1].key.value == 1); + REQUIRE(index[2].key.value == 0); + REQUIRE(index[3].key.value == 2); + + index[3].mutable_row->setValue(1, 1.5); + REQUIRE(table.getRow(AttributeKey(2)).getValue(1) == Approx(1.5)); +} + diff --git a/salaTest/testattributetableview.cpp b/salaTest/testattributetableview.cpp new file mode 100644 index 00000000..5a67a7db --- /dev/null +++ b/salaTest/testattributetableview.cpp @@ -0,0 +1,85 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include + +TEST_CASE("Test Attribute view"){ + AttributeTable table; + + table.insertOrResetColumn("foo"); + table.insertOrResetColumn("bar"); + table.addRow(AttributeKey(0)).setValue(0,1.0f).setValue(1, 1.1f); + table.addRow(AttributeKey(7)).setValue(0,0.7f).setValue(1,1.7f); + + AttributeTableView view(table); + view.setDisplayColIndex(0); + + REQUIRE(view.getConstTableIndex().front().key.value == 7); + + REQUIRE(view.getNormalisedValue(view.getConstTableIndex().front().key, *view.getConstTableIndex().front().row) == Approx(0.0f)); + + REQUIRE(&view.getDisplayParams() != &table.getDisplayParams()); + REQUIRE(&view.getDisplayParams() == &table.getColumn(0).getDisplayParams()); + + + table.addRow(AttributeKey(3)); + view.setDisplayColIndex(-1); + REQUIRE(view.getNormalisedValue(AttributeKey(3), table.getRow(AttributeKey(3))) == Approx(3.0/7)); + REQUIRE(view.getConstTableIndex().size() == 3); + + REQUIRE(&table.getDisplayParams() == &view.getDisplayParams()); + + view.setDisplayColIndex(-2); + REQUIRE(view.getNormalisedValue(AttributeKey(3), table.getRow(AttributeKey(3))) == Approx(3.0/7)); + REQUIRE(view.getConstTableIndex().empty()); + + REQUIRE(&table.getDisplayParams() == &view.getDisplayParams()); + +} + + +TEST_CASE("Test attribute table handle") +{ + AttributeTable table; + + table.insertOrResetColumn("foo"); + table.insertOrResetColumn("bar"); + table.addRow(AttributeKey(0)).setValue(0,1.0f).setValue(1, 1.1f); + table.addRow(AttributeKey(7)).setValue(0,0.7f).setValue(1,1.7f); + + AttributeTableHandle handle(table); + handle.setDisplayColIndex(0); + + REQUIRE(handle.getTableIndex().front().key.value == 7); + REQUIRE(handle.getConstTableIndex().front().key.value == 7); + + + handle.getTableIndex().front().mutable_row->setValue(0, 0.8f); + + REQUIRE(table.getRow(AttributeKey(7)).getValue(0) == Approx(0.8)); + + handle.setDisplayColIndex(-1); + REQUIRE(handle.getTableIndex().size() == 2); + + REQUIRE(&table.getDisplayParams() == &handle.getDisplayParams()); + + handle.setDisplayColIndex(-2); + REQUIRE(handle.getTableIndex().empty()); + + REQUIRE(&table.getDisplayParams() == &handle.getDisplayParams()); + + +} diff --git a/salaTest/testdxfp.cpp b/salaTest/testdxfp.cpp new file mode 100644 index 00000000..b904528c --- /dev/null +++ b/salaTest/testdxfp.cpp @@ -0,0 +1,544 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "salalib/parsers/dxfp.h" + +#include "genlib/comm.h" +#include "genlib/p2dpoly.h" + +TEST_CASE("DXF Parsing (lines)") +{ + const float EPSILON = 0.001f; + Point2f lineStart(-1,-2); + Point2f lineEnd(3,4); + std::string layer("0"); + + std::stringstream stream; + + stream << "0\nSECTION\n" + << "2\nENTITIES\n" + << "0\nLINE\n" + << "8\n"<< layer << "\n" + << "10\n" << lineStart.x << "\n" + << "20\n" << lineStart.y << "\n" + << "30\n0\n" + << "11\n" << lineEnd.x << "\n" + << "21\n" << lineEnd.y << "\n" + << "31\n0\n" + << "0\nENDSEC\n" + << "0\nEOF\n"; + + DxfParser dxfParser; + dxfParser.open(stream); + REQUIRE(dxfParser.numLayers() == 1); + REQUIRE(dxfParser.getLayer(layer.c_str())->numLines() == 1); + REQUIRE(dxfParser.getLayer(layer.c_str())->getLine(0).getStart().x == Approx(lineStart.x).epsilon(EPSILON)); + REQUIRE(dxfParser.getLayer(layer.c_str())->getLine(0).getStart().y == Approx(lineStart.y).epsilon(EPSILON)); + REQUIRE(dxfParser.getLayer(layer.c_str())->getLine(0).getEnd().x == Approx(lineEnd.x).epsilon(EPSILON)); + REQUIRE(dxfParser.getLayer(layer.c_str())->getLine(0).getEnd().y == Approx(lineEnd.y).epsilon(EPSILON)); +} + +TEST_CASE("DXF Parsing (arcs)") +{ + const float EPSILON = 0.001f; + Point2f centre(1,-2); + float radius = 3; + float startAngle = 45; + float endAngle = 67; + std::string layer("0"); + + std::stringstream stream; + + stream << "0\nSECTION\n" + << "2\nENTITIES\n" + << "0\nARC\n" + << "8\n"<< layer << "\n" + << "10\n" << centre.x << "\n" + << "20\n" << centre.y << "\n" + << "30\n0\n" + << "40\n" << radius << "\n" + << "50\n" << startAngle << "\n" + << "51\n" << endAngle << "\n" + << "0\nENDSEC\n" + << "0\nEOF\n"; + + DxfParser dxfParser; + dxfParser.open(stream); + REQUIRE(dxfParser.numLayers() == 1); + REQUIRE(dxfParser.getLayer(layer.c_str())->numArcs() == 1); + REQUIRE(dxfParser.getLayer(layer.c_str())->getArc(0).getCentre().x == Approx(centre.x).epsilon(EPSILON)); + REQUIRE(dxfParser.getLayer(layer.c_str())->getArc(0).getCentre().y == Approx(centre.y).epsilon(EPSILON)); + REQUIRE(dxfParser.getLayer(layer.c_str())->getArc(0).getRadius() == Approx(radius).epsilon(EPSILON)); + // arc start angle not publicly accessible + // arc end angle not publicly accessible +} + +TEST_CASE("DXF Parsing (circles)") +{ + const float EPSILON = 0.001f; + Point2f centre(1,-2); + float radius = 3; + std::string layer("0"); + + std::stringstream stream; + + stream << "0\nSECTION\n" + << "2\nENTITIES\n" + << "0\nCIRCLE\n" + << "8\n"<< layer << "\n" + << "10\n" << centre.x << "\n" + << "20\n" << centre.y << "\n" + << "30\n0\n" + << "40\n" << radius << "\n" + << "0\nENDSEC\n" + << "0\nEOF\n"; + + DxfParser dxfParser; + dxfParser.open(stream); + REQUIRE(dxfParser.numLayers() == 1); + REQUIRE(dxfParser.getLayer(layer.c_str())->numCircles() == 1); + REQUIRE(dxfParser.getLayer(layer.c_str())->getCircle(0).getCentre().x == Approx(centre.x).epsilon(EPSILON)); + REQUIRE(dxfParser.getLayer(layer.c_str())->getCircle(0).getCentre().y == Approx(centre.y).epsilon(EPSILON)); + REQUIRE(dxfParser.getLayer(layer.c_str())->getCircle(0).getRadius() == Approx(radius).epsilon(EPSILON)); +} + +TEST_CASE("DXF Parsing (points)") +{ + const float EPSILON = 0.001f; + Point2f point(1,-2); + std::string layer("0"); + + std::stringstream stream; + + stream << "0\nSECTION\n" + << "2\nENTITIES\n" + << "0\nPOINT\n" + << "8\n"<< layer << "\n" + << "10\n" << point.x << "\n" + << "20\n" << point.y << "\n" + << "30\n0\n" + << "0\nENDSEC\n" + << "0\nEOF\n"; + + DxfParser dxfParser; + dxfParser.open(stream); + REQUIRE(dxfParser.numLayers() == 1); + REQUIRE(dxfParser.getLayer(layer.c_str())->numPoints() == 1); + REQUIRE(dxfParser.getLayer(layer.c_str())->getPoint(0).x == Approx(point.x).epsilon(EPSILON)); + REQUIRE(dxfParser.getLayer(layer.c_str())->getPoint(0).y == Approx(point.y).epsilon(EPSILON)); +} + +TEST_CASE("DXF Parsing (lwpolyline)") +{ + const float EPSILON = 0.001f; + Point2f point1(-1,-2); + Point2f point2(3,4); + Point2f point3(-5,6); + Point2f point4(7,-8); + std::string layer("0"); + + int closed = 0; + + SECTION ("open polyline") { + closed = 0; + } + SECTION ("closed polyline") { + closed = 1; + } + + std::stringstream stream; + + stream << "0\nSECTION\n" + << "2\nENTITIES\n" + << "0\nLWPOLYLINE\n" + << "8\n"<< layer << "\n" + << "10\n" << point1.x << "\n" + << "20\n" << point1.y << "\n" + << "30\n0\n" + << "10\n" << point2.x << "\n" + << "20\n" << point2.y << "\n" + << "30\n0\n" + << "10\n" << point3.x << "\n" + << "20\n" << point3.y << "\n" + << "30\n0\n" + << "10\n" << point4.x << "\n" + << "20\n" << point4.y << "\n" + << "30\n0\n" + << "70\n" << closed << "\n" + << "0\nENDSEC\n" + << "0\nEOF\n"; + + DxfParser dxfParser; + dxfParser.open(stream); + REQUIRE(dxfParser.numLayers() == 1); + REQUIRE(dxfParser.getLayer(layer.c_str())->numPolyLines() == 1); + DxfPolyLine polyline = dxfParser.getLayer(layer.c_str())->getPolyLine(0); + REQUIRE(polyline.numVertices() == 4); + REQUIRE(polyline.getVertex(0).x == Approx(point1.x).epsilon(EPSILON)); + REQUIRE(polyline.getVertex(0).y == Approx(point1.y).epsilon(EPSILON)); + REQUIRE(polyline.getVertex(1).x == Approx(point2.x).epsilon(EPSILON)); + REQUIRE(polyline.getVertex(1).y == Approx(point2.y).epsilon(EPSILON)); + REQUIRE(polyline.getVertex(2).x == Approx(point3.x).epsilon(EPSILON)); + REQUIRE(polyline.getVertex(2).y == Approx(point3.y).epsilon(EPSILON)); + REQUIRE(polyline.getVertex(3).x == Approx(point4.x).epsilon(EPSILON)); + REQUIRE(polyline.getVertex(3).y == Approx(point4.y).epsilon(EPSILON)); + REQUIRE((polyline.getAttributes() & polyline.CLOSED) == closed); +} + +TEST_CASE("DXF Parsing (polyline)") +{ + const float EPSILON = 0.001f; + Point2f point1(-1,-2); + Point2f point2(3,4); + Point2f point3(-5,6); + Point2f point4(7,-8); + std::string layer("0"); + + int closed = 0; + + SECTION ("open polyline") { + closed = 0; + } + SECTION ("closed polyline") { + closed = 1; + } + + std::stringstream stream; + + stream << "0\nSECTION\n" + << "2\nENTITIES\n" + << "0\nPOLYLINE\n" + << "8\n"<< layer << "\n" + << "70\n" << closed << "\n" + << "0\nVERTEX\n" + << "10\n" << point1.x << "\n" + << "20\n" << point1.y << "\n" + << "30\n0\n" + << "0\nVERTEX\n" + << "10\n" << point2.x << "\n" + << "20\n" << point2.y << "\n" + << "30\n0\n" + << "0\nVERTEX\n" + << "10\n" << point3.x << "\n" + << "20\n" << point3.y << "\n" + << "30\n0\n" + << "0\nVERTEX\n" + << "10\n" << point4.x << "\n" + << "20\n" << point4.y << "\n" + << "30\n0\n" + << "0\nSEQEND\n" + << "0\nENDSEC\n" + << "0\nEOF\n"; + + DxfParser dxfParser; + dxfParser.open(stream); + REQUIRE(dxfParser.numLayers() == 1); + REQUIRE(dxfParser.getLayer(layer.c_str())->numPolyLines() == 1); + DxfPolyLine polyline = dxfParser.getLayer(layer.c_str())->getPolyLine(0); + REQUIRE(polyline.numVertices() == 4); + REQUIRE(polyline.getVertex(0).x == Approx(point1.x).epsilon(EPSILON)); + REQUIRE(polyline.getVertex(0).y == Approx(point1.y).epsilon(EPSILON)); + REQUIRE(polyline.getVertex(1).x == Approx(point2.x).epsilon(EPSILON)); + REQUIRE(polyline.getVertex(1).y == Approx(point2.y).epsilon(EPSILON)); + REQUIRE(polyline.getVertex(2).x == Approx(point3.x).epsilon(EPSILON)); + REQUIRE(polyline.getVertex(2).y == Approx(point3.y).epsilon(EPSILON)); + REQUIRE(polyline.getVertex(3).x == Approx(point4.x).epsilon(EPSILON)); + REQUIRE(polyline.getVertex(3).y == Approx(point4.y).epsilon(EPSILON)); + REQUIRE((polyline.getAttributes() & polyline.CLOSED) == closed); +} + +TEST_CASE("DXF Parsing (spline)") +{ + const float EPSILON = 0.001f; + + std::vector weights = { + 0.0, 0.0, 0.0, 0.0, + 2.72, 5.15, 6.93, + 6.93, 6.93, 6.93}; + + std::vector controlPoints = { + Point2f(32.80, 27.09), + Point2f(31.58, 26.71), + Point2f(29.28, 25.98), + Point2f(30.69, 30.55), + Point2f(31.35, 28.67), + Point2f(31.64, 27.87) + }; + + std::vector fitPoints = { + Point2f(32.80, 27.09), + Point2f(30.08, 27.09), + Point2f(30.75, 29.42), + Point2f(31.64, 27.87), + }; + std::string layer("0"); + + int closed = 0; + + SECTION ("open spline") { + closed = 0; + } + SECTION ("closed spline") { + closed = 1; + } + + std::stringstream stream; + + stream << "0\nSECTION\n" + << "2\nENTITIES\n" + << "0\nSPLINE\n" + << "8\n"<< layer << "\n" + << "70\n"<< closed << "\n" + << "72\n"<< (controlPoints.size() + fitPoints.size()) << "\n" + << "73\n"<< controlPoints.size() << "\n"; + + std::vector::iterator weightsIter = weights.begin(), weightsEnd = + weights.end(); + for ( ; weightsIter != weightsEnd; ++weightsIter ) + { + stream << "40\n" << *weightsIter << "\n"; + } + + std::vector::iterator cPointsIter = controlPoints.begin(), cPointsEnd = + controlPoints.end(); + for ( ; cPointsIter != cPointsEnd; ++cPointsIter ) + { + Point2f point = *cPointsIter; + stream << "10\n" << point.x << "\n" + << "20\n" << point.y << "\n" + << "30\n0\n"; + } + + std::vector::iterator fPointsIter = fitPoints.begin(), fPointsEnd = + fitPoints.end(); + for ( ; fPointsIter != fPointsEnd; ++fPointsIter ) + { + Point2f point = *fPointsIter; + stream << "11\n" << point.x << "\n" + << "21\n" << point.y << "\n" + << "31\n0\n"; + } + + stream << "0\nENDSEC\n" + << "0\nEOF\n"; + + DxfParser dxfParser; + dxfParser.open(stream); + REQUIRE(dxfParser.numLayers() == 1); + REQUIRE(dxfParser.getLayer(layer.c_str())->numSplines() == 1); + DxfSpline spline = dxfParser.getLayer(layer.c_str())->getSpline(0); + REQUIRE(spline.numVertices() == controlPoints.size()); + for (size_t i = 0; i < controlPoints.size(); i++) + { + REQUIRE(spline.getVertex(i).x == Approx(controlPoints[i].x).epsilon(EPSILON)); + REQUIRE(spline.getVertex(i).y == Approx(controlPoints[i].y).epsilon(EPSILON)); + } + REQUIRE((spline.getAttributes() & spline.CLOSED) == closed); +} +TEST_CASE("DXF Parsing (zero-length line)") +{ + // parser skips zero-length lines + + const float EPSILON = 0.001f; + Point2f lineStart(1,2); + Point2f lineEnd(1,2); + std::string layer("0"); + + std::stringstream stream; + + stream << "0\nSECTION\n" + << "2\nENTITIES\n" + << "0\nLINE\n" + << "8\n"<< layer << "\n" + << "10\n" << lineStart.x << "\n" + << "20\n" << lineStart.y << "\n" + << "30\n0\n" + << "11\n" << lineEnd.x << "\n" + << "21\n" << lineEnd.y << "\n" + << "31\n0\n" + << "0\nENDSEC\n" + << "0\nEOF\n"; + + DxfParser dxfParser; + dxfParser.open(stream); + REQUIRE(dxfParser.numLayers() == 1); + REQUIRE(dxfParser.getLayer(layer.c_str())->numLines() == 0); +} + +TEST_CASE("DXF Parsing (zero-length lwpolyline)") +{ + // parser does not skip zero-length polylines + + const float EPSILON = 0.001f; + Point2f point1(1,2); + Point2f point2(1,2); + std::string layer("0"); + + int closed = 0; + + std::stringstream stream; + + stream << "0\nSECTION\n" + << "2\nENTITIES\n" + << "0\nLWPOLYLINE\n" + << "8\n"<< layer << "\n" + << "10\n" << point1.x << "\n" + << "20\n" << point1.y << "\n" + << "30\n0\n" + << "10\n" << point2.x << "\n" + << "20\n" << point2.y << "\n" + << "30\n0\n" + << "70\n" << closed << "\n" + << "0\nENDSEC\n" + << "0\nEOF\n"; + + DxfParser dxfParser; + dxfParser.open(stream); + REQUIRE(dxfParser.numLayers() == 1); + REQUIRE(dxfParser.getLayer(layer.c_str())->numPolyLines() == 1); + DxfPolyLine polyline = dxfParser.getLayer(layer.c_str())->getPolyLine(0); + REQUIRE(polyline.numVertices() == 2); + REQUIRE(polyline.getVertex(0).x == Approx(point1.x).epsilon(EPSILON)); + REQUIRE(polyline.getVertex(0).y == Approx(point1.y).epsilon(EPSILON)); + REQUIRE(polyline.getVertex(1).x == Approx(point2.x).epsilon(EPSILON)); + REQUIRE(polyline.getVertex(1).y == Approx(point2.y).epsilon(EPSILON)); + REQUIRE((polyline.getAttributes() & polyline.CLOSED) == closed); +} + + +TEST_CASE("DXF Parsing (block)") +{ + const float EPSILON = 0.001f; + Point2f lineStart(-1,-2); + Point2f lineEnd(3,4); + std::string block("bl"); + Point2f blockTranslation(5, -6); + Point2f blockScale(1, 1); + double blockRotation = 0; + std::string layer("0"); + + std::stringstream stream; + + stream << "0\nSECTION\n" + << "2\nBLOCKS\n" + << "0\nBLOCK\n" + << "2\n" << block << "\n" + << "8\n" << layer << "\n" + << "0\nLINE\n" + << "8\n" << layer << "\n" + << "10\n" << lineStart.x << "\n" + << "20\n" << lineStart.y << "\n" + << "30\n0\n" + << "11\n" << lineEnd.x << "\n" + << "21\n" << lineEnd.y << "\n" + << "31\n0\n" + << "0\nENDBLK\n" + << "0\nENDSEC\n" + << "0\nSECTION\n" + << "2\nENTITIES\n" + << "0\nINSERT\n" + << "8\n" << layer << "\n" + << "2\n" << block << "\n" + << "10\n" << blockTranslation.x << "\n" + << "20\n" << blockTranslation.y << "\n" + << "30\n" << 0 << "\n" + << "41\n" << blockScale.x << "\n" + << "42\n" << blockScale.y << "\n" + << "43\n" << 0 << "\n" + << "50\n" << blockRotation << "\n" + << "0\nENDSEC\n" + << "0\nEOF\n"; + + DxfParser dxfParser; + dxfParser.open(stream); + REQUIRE(dxfParser.numLayers() == 1); + REQUIRE(dxfParser.getLayer(layer.c_str())->numLines() == 1); + REQUIRE(dxfParser.getLayer(layer.c_str())->getLine(0).getStart().x == Approx(lineStart.x + blockTranslation.x).epsilon(EPSILON)); + REQUIRE(dxfParser.getLayer(layer.c_str())->getLine(0).getStart().y == Approx(lineStart.y + blockTranslation.y).epsilon(EPSILON)); + REQUIRE(dxfParser.getLayer(layer.c_str())->getLine(0).getEnd().x == Approx(lineEnd.x + blockTranslation.x).epsilon(EPSILON)); + REQUIRE(dxfParser.getLayer(layer.c_str())->getLine(0).getEnd().y == Approx(lineEnd.y + blockTranslation.y).epsilon(EPSILON)); +} + + +TEST_CASE("DXF Parsing (deeper blocks)") +{ + const float EPSILON = 0.001f; + Point2f lineStart(-1,-2); + Point2f lineEnd(3,4); + std::string block("bl"); + std::string blockInternal("bli"); + Point2f blockTranslation(5, -6); + Point2f blockScale(1, 1); + double blockRotation = 0; + std::string layer("0"); + + std::stringstream stream; + + stream << "0\nSECTION\n" + << "2\nBLOCKS\n" + << "0\nBLOCK\n" + << "2\n" << block << "\n" + << "8\n" << layer << "\n" + + << "0\nINSERT\n" + << "8\n" << layer << "\n" + << "2\n" << blockInternal << "\n" + << "10\n" << blockTranslation.x << "\n" + << "20\n" << blockTranslation.y << "\n" + << "30\n" << 0 << "\n" + << "41\n" << blockScale.x << "\n" + << "42\n" << blockScale.y << "\n" + << "43\n" << 0 << "\n" + << "50\n" << blockRotation << "\n" + + << "0\nENDBLK\n" + << "0\nBLOCK\n" + << "2\n" << blockInternal << "\n" + << "8\n" << layer << "\n" + << "0\nLINE\n" + << "8\n" << layer << "\n" + << "10\n" << lineStart.x << "\n" + << "20\n" << lineStart.y << "\n" + << "30\n0\n" + << "11\n" << lineEnd.x << "\n" + << "21\n" << lineEnd.y << "\n" + << "31\n0\n" + << "0\nENDBLK\n" + << "0\nENDSEC\n" + << "0\nSECTION\n" + << "2\nENTITIES\n" + << "0\nINSERT\n" + << "8\n" << layer << "\n" + << "2\n" << block << "\n" + << "10\n" << blockTranslation.x << "\n" + << "20\n" << blockTranslation.y << "\n" + << "30\n" << 0 << "\n" + << "41\n" << blockScale.x << "\n" + << "42\n" << blockScale.y << "\n" + << "43\n" << 0 << "\n" + << "50\n" << blockRotation << "\n" + << "0\nENDSEC\n" + << "0\nEOF\n"; + + DxfParser dxfParser; + dxfParser.open(stream); + REQUIRE(dxfParser.numLayers() == 1); + REQUIRE(dxfParser.getLayer(layer.c_str())->numLines() == 1); + REQUIRE(dxfParser.getLayer(layer.c_str())->getLine(0).getStart().x == Approx(lineStart.x + 2*blockTranslation.x).epsilon(EPSILON)); + REQUIRE(dxfParser.getLayer(layer.c_str())->getLine(0).getStart().y == Approx(lineStart.y + 2*blockTranslation.y).epsilon(EPSILON)); + REQUIRE(dxfParser.getLayer(layer.c_str())->getLine(0).getEnd().x == Approx(lineEnd.x + 2*blockTranslation.x).epsilon(EPSILON)); + REQUIRE(dxfParser.getLayer(layer.c_str())->getLine(0).getEnd().y == Approx(lineEnd.y + 2*blockTranslation.y).epsilon(EPSILON)); +} diff --git a/salaTest/testentityparsing.cpp b/salaTest/testentityparsing.cpp new file mode 100644 index 00000000..a5b45729 --- /dev/null +++ b/salaTest/testentityparsing.cpp @@ -0,0 +1,239 @@ +// Copyright (C) 2017 Petros Koutsolampros, Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "salalib/entityparsing.h" +#include "genlib/p2dpoly.h" +#include +#include + +TEST_CASE("Failing line parser", "") +{ + const float EPSILON = 0.001; + { + // header only has 3 elements + std::stringstream stream; + stream << "x1,y1,x2" << std::endl; + REQUIRE_THROWS_WITH(EntityParsing::parseLines(stream,','), Catch::Contains("Badly formatted header (should contain x1, y1, x2 and y2)")); + } + + { + // header has y1 twice instead of y2 + std::stringstream stream; + stream << "x1,y1,x2,y1" << std::endl; + REQUIRE_THROWS_WITH(EntityParsing::parseLines(stream,','), Catch::Contains("Badly formatted header (should contain x1, y1, x2 and y2)")); + } + + { + // error parsing line + std::stringstream stream; + stream << "x1,y1,x2,y2" << std::endl; + stream << "1.2,3.4,5.6" << std::endl; + REQUIRE_THROWS_WITH(EntityParsing::parseLines(stream,','), Catch::Contains("Error parsing line")); + } +} +TEST_CASE("Successful line parser", "") +{ + const float EPSILON = 0.001; + { + std::stringstream stream; + stream << "x1,y1,x2,y2" << std::endl; + stream << "1.2,3.4,5.6,7.8" << std::endl; + std::vector lines = EntityParsing::parseLines(stream,','); + REQUIRE(lines.size() == 1); + REQUIRE(lines[0].start().x == Approx(1.2).epsilon(EPSILON)); + REQUIRE(lines[0].start().y == Approx(3.4).epsilon(EPSILON)); + REQUIRE(lines[0].end().x == Approx(5.6).epsilon(EPSILON)); + REQUIRE(lines[0].end().y == Approx(7.8).epsilon(EPSILON)); + } + + { + std::stringstream stream; + stream << "x1\ty1\tx2\ty2" << std::endl; + stream << "1.2\t3.4\t5.6\t7.8" << std::endl; + std::vector lines = EntityParsing::parseLines(stream,'\t'); + REQUIRE(lines.size() == 1); + REQUIRE(lines[0].start().x == Approx(1.2).epsilon(EPSILON)); + REQUIRE(lines[0].start().y == Approx(3.4).epsilon(EPSILON)); + REQUIRE(lines[0].end().x == Approx(5.6).epsilon(EPSILON)); + REQUIRE(lines[0].end().y == Approx(7.8).epsilon(EPSILON)); + } + + { + std::stringstream stream; + stream << "x1\ty1\tx2\ty2" << std::endl; + stream << "1.2\t3.4\t5.6\t7.8" << std::endl; + stream << "0.1\t0.2\t0.3\t0.4" << std::endl; + std::vector lines = EntityParsing::parseLines(stream,'\t'); + REQUIRE(lines.size() == 2); + REQUIRE(lines[0].start().x == Approx(1.2).epsilon(EPSILON)); + REQUIRE(lines[0].start().y == Approx(3.4).epsilon(EPSILON)); + REQUIRE(lines[0].end().x == Approx(5.6).epsilon(EPSILON)); + REQUIRE(lines[0].end().y == Approx(7.8).epsilon(EPSILON)); + REQUIRE(lines[1].start().x == Approx(0.1).epsilon(EPSILON)); + REQUIRE(lines[1].start().y == Approx(0.2).epsilon(EPSILON)); + REQUIRE(lines[1].end().x == Approx(0.3).epsilon(EPSILON)); + REQUIRE(lines[1].end().y == Approx(0.4).epsilon(EPSILON)); + } +} + +TEST_CASE("Failing point parser", "") +{ + const float EPSILON = 0.001; + { + // header only has 3 elements + std::stringstream stream; + stream << "x" << std::endl; + REQUIRE_THROWS_WITH(EntityParsing::parsePoints(stream,','), Catch::Contains("Badly formatted header (should contain x and y)")); + } + + { + // header has y1 twice instead of y2 + std::stringstream stream; + stream << "x,x" << std::endl; + REQUIRE_THROWS_WITH(EntityParsing::parsePoints(stream,','), Catch::Contains("Badly formatted header (should contain x and y)")); + } + + { + // error parsing line + std::stringstream stream; + stream << "x,y" << std::endl; + stream << "1.2" << std::endl; + REQUIRE_THROWS_WITH(EntityParsing::parsePoints(stream,','), Catch::Contains("Error parsing line")); + } +} +TEST_CASE("Successful point parser", "") +{ + const float EPSILON = 0.001; + { + std::stringstream stream; + stream << "x,y" << std::endl; + stream << "1.2,3.4" << std::endl; + std::vector points = EntityParsing::parsePoints(stream,','); + REQUIRE(points.size() == 1); + REQUIRE(points[0].x == Approx(1.2).epsilon(EPSILON)); + REQUIRE(points[0].y == Approx(3.4).epsilon(EPSILON)); + } + + { + std::stringstream stream; + stream << "x\ty" << std::endl; + stream << "1.2\t3.4" << std::endl; + std::vector points = EntityParsing::parsePoints(stream,'\t'); + REQUIRE(points.size() == 1); + REQUIRE(points[0].x == Approx(1.2).epsilon(EPSILON)); + REQUIRE(points[0].y == Approx(3.4).epsilon(EPSILON)); + } + + { + std::stringstream stream; + stream << "x\ty" << std::endl; + stream << "1.2\t3.4" << std::endl; + stream << "0.1\t0.2" << std::endl; + std::vector points = EntityParsing::parsePoints(stream,'\t'); + REQUIRE(points.size() == 2); + REQUIRE(points[0].x == Approx(1.2).epsilon(EPSILON)); + REQUIRE(points[0].y == Approx(3.4).epsilon(EPSILON)); + REQUIRE(points[1].x == Approx(0.1).epsilon(EPSILON)); + REQUIRE(points[1].y == Approx(0.2).epsilon(EPSILON)); + } +} + + +TEST_CASE("Test point parsing") +{ + REQUIRE_THROWS_WITH(EntityParsing::parsePoint("foo", '|'), Catch::Contains("Badly formatted point data, should be |, was foo" )); + auto point = EntityParsing::parsePoint("1.235|27.25", '|'); + REQUIRE(point.x == Approx(1.235)); + REQUIRE(point.y == Approx(27.25)); + + point = EntityParsing::parsePoint("1.235|bar", '|'); + REQUIRE(point.x == Approx(1.235)); + REQUIRE(point.y == 0.0); +} + +TEST_CASE("Successful Isovist parser") +{ + const float EPSILON = 0.0001; + { + std::stringstream stream; + stream << "x,y\n1.0,2.34\n0.5,9.2\n" << std::flush; + auto result = EntityParsing::parseIsovists(stream, ','); + REQUIRE(result.size() == 2); + REQUIRE(result[0].getLocation().x == Approx(1.0).epsilon(EPSILON)); + REQUIRE(result[0].getLocation().y == Approx(2.34).epsilon(EPSILON)); + REQUIRE(result[0].getAngle() == Approx(0.0).epsilon(EPSILON)); + REQUIRE(result[0].getViewAngle() == 0.0); + REQUIRE(result[1].getLocation().x == Approx(0.5).epsilon(EPSILON)); + REQUIRE(result[1].getLocation().y == Approx(9.2).epsilon(EPSILON)); + REQUIRE(result[1].getAngle() == Approx(0.0).epsilon(EPSILON)); + REQUIRE(result[1].getViewAngle() == 0.0); + } + { + std::stringstream stream; + stream << "x,y,angle,viewAngle\n1.0,2.34,90,90\n0.5,9.2,180,270\n" << std::flush; + auto result = EntityParsing::parseIsovists(stream, ','); + REQUIRE(result.size() == 2); + REQUIRE(result[0].getLocation().x == Approx(1.0).epsilon(EPSILON)); + REQUIRE(result[0].getLocation().y == Approx(2.34).epsilon(EPSILON)); + REQUIRE(result[0].getAngle() == Approx(M_PI/2.0).epsilon(EPSILON)); + REQUIRE(result[0].getViewAngle() == Approx(M_PI/2.0).epsilon(EPSILON)); + REQUIRE(result[1].getLocation().x == Approx(0.5).epsilon(EPSILON)); + REQUIRE(result[1].getLocation().y == Approx(9.2).epsilon(EPSILON)); + REQUIRE(result[1].getAngle() == Approx(M_PI).epsilon(EPSILON)); + REQUIRE(result[1].getViewAngle() == Approx(M_PI*1.5).epsilon(EPSILON)); + } +} + +TEST_CASE("Failing Isovist parser") +{ + { + std::stringstream stream; + stream << "x,angle,viewAngle\n" << std::flush; + REQUIRE_THROWS_WITH(EntityParsing::parseIsovists(stream, ','), Catch::Contains("Badly formatted header (should contain x and y, might also have angle and viewangle for partial isovists)")); + } + + { + std::stringstream stream; + stream << "x,y,angle,viewAngle\n1.0,1.0,270" << std::flush; + REQUIRE_THROWS_WITH(EntityParsing::parseIsovists(stream, ','), Catch::Contains("Error parsing line: 1.0,1.0,270")); + } +} + +TEST_CASE("Parsing single isovist") +{ + SECTION("Success full") + { + auto result = EntityParsing::parseIsovist("1,1"); + REQUIRE(result.getLocation().x == Approx(1.0)); + REQUIRE(result.getLocation().y == Approx(1.0)); + REQUIRE(result.getAngle() == 0.0); + REQUIRE(result.getViewAngle() == 0.0); + } + + SECTION("Success partial isovist") + { + auto result = EntityParsing::parseIsovist("1,1,27,90"); + REQUIRE(result.getLocation().x == Approx(1.0)); + REQUIRE(result.getLocation().y == Approx(1.0)); + REQUIRE(result.getAngle() == Approx(0.4712388)); + REQUIRE(result.getViewAngle() == Approx(M_PI/2.0)); + } + + SECTION("Failed bad string") + { + REQUIRE_THROWS_WITH(EntityParsing::parseIsovist("1,1,27"), Catch::Contains("Failed to parse '1,1,27' to an isovist definition")); + } +} diff --git a/salaTest/testgeometrygenerators.cpp b/salaTest/testgeometrygenerators.cpp new file mode 100644 index 00000000..3ba33375 --- /dev/null +++ b/salaTest/testgeometrygenerators.cpp @@ -0,0 +1,100 @@ +// Copyright (C) 2017 Petros Koutsolampros, Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "salalib/geometrygenerators.h" +#include "genlib/p2dpoly.h" + +TEST_CASE("Test disk triangles generation", "") +{ + const float EPSILON = 0.001; + int sides = 8; + float radius = 2; + + std::vector expected { + Point2f(0,0), Point2f(1.41421,1.41421), Point2f(0,2), + Point2f(0,0), Point2f(2,0), Point2f(1.41421,1.41421), + Point2f(0,0), Point2f(1.41421,-1.41421), Point2f(2,0), + Point2f(0,0), Point2f(0,-2), Point2f(1.41421,-1.41421), + Point2f(0,0), Point2f(-1.41421,-1.41421), Point2f(0,-2), + Point2f(0,0), Point2f(-2,0), Point2f(-1.41421,-1.41421), + Point2f(0,0), Point2f(-1.41421,1.41421), Point2f(-2,0), + Point2f(0,0), Point2f(0,2), Point2f(-1.41421,1.41421) + }; + + std::vector diskTriangles = GeometryGenerators::generateDiskTriangles(sides, radius); + + REQUIRE(diskTriangles.size() == expected.size()); + for(size_t i = 0; i < diskTriangles.size(); i++) { + REQUIRE(diskTriangles[i].x == Approx(expected[i].x).epsilon(EPSILON)); + REQUIRE(diskTriangles[i].y == Approx(expected[i].y).epsilon(EPSILON)); + } + + std::vector offsets { + Point2f(1,2), Point2f(3, -4), Point2f(-5, -6), Point2f(-7, 8) + }; + + std::vector multiDiskTriangles = GeometryGenerators::generateMultipleDiskTriangles(sides, radius, offsets); + + REQUIRE(multiDiskTriangles.size() == expected.size()*offsets.size()); + + for(size_t i = 0; i < multiDiskTriangles.size(); i++) { + REQUIRE(multiDiskTriangles[i].x == Approx(expected[i%(sides*3)].x + offsets[i/(sides*3)].x).epsilon(EPSILON)); + REQUIRE(multiDiskTriangles[i].y == Approx(expected[i%(sides*3)].y + offsets[i/(sides*3)].y).epsilon(EPSILON)); + } +} + +TEST_CASE("Test circle perimeter line generation", "") +{ + const float EPSILON = 0.001; + int sides = 8; + float radius = 2; + + std::vector expected { + SimpleLine(Point2f(1.41421,1.41421), Point2f(0,2)), + SimpleLine(Point2f(2,0), Point2f(1.41421,1.41421)), + SimpleLine(Point2f(1.41421,-1.41421), Point2f(2,0)), + SimpleLine(Point2f(0,-2), Point2f(1.41421,-1.41421)), + SimpleLine(Point2f(-1.41421,-1.41421), Point2f(0,-2)), + SimpleLine(Point2f(-2,0), Point2f(-1.41421,-1.41421)), + SimpleLine(Point2f(-1.41421,1.41421), Point2f(-2,0)), + SimpleLine(Point2f(0,2), Point2f(-1.41421,1.41421)) + }; + + std::vector circleLines = GeometryGenerators::generateCircleLines(sides, radius); + + REQUIRE(circleLines.size() == expected.size()); + for(size_t i = 0; i < circleLines.size(); i++) { + REQUIRE(circleLines[i].start().x == Approx(expected[i].start().x).epsilon(EPSILON)); + REQUIRE(circleLines[i].start().y == Approx(expected[i].start().y).epsilon(EPSILON)); + REQUIRE(circleLines[i].end().x == Approx(expected[i].end().x).epsilon(EPSILON)); + REQUIRE(circleLines[i].end().y == Approx(expected[i].end().y).epsilon(EPSILON)); + } + + std::vector offsets { + Point2f(1,2), Point2f(3, -4), Point2f(-5, -6), Point2f(-7, 8) + }; + + std::vector multiCircleLines = GeometryGenerators::generateMultipleCircleLines(sides, radius, offsets); + + REQUIRE(multiCircleLines.size() == expected.size()*offsets.size()); + + for(size_t i = 0; i < multiCircleLines.size(); i++) { + REQUIRE(multiCircleLines[i].start().x == Approx(expected[i%sides].start().x + offsets[i/sides].x).epsilon(EPSILON)); + REQUIRE(multiCircleLines[i].start().y == Approx(expected[i%sides].start().y + offsets[i/sides].y).epsilon(EPSILON)); + REQUIRE(multiCircleLines[i].end().x == Approx(expected[i%sides].end().x + offsets[i/sides].x).epsilon(EPSILON)); + REQUIRE(multiCircleLines[i].end().y == Approx(expected[i%sides].end().y + offsets[i/sides].y).epsilon(EPSILON)); + } +} diff --git a/salaTest/testgridproperties.cpp b/salaTest/testgridproperties.cpp new file mode 100644 index 00000000..f82ca1b6 --- /dev/null +++ b/salaTest/testgridproperties.cpp @@ -0,0 +1,26 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "salalib/gridproperties.h" + +TEST_CASE("TestGridProperties", "Test the calculations of grid properties") +{ + double maxDimension = 4.583; + GridProperties gp(maxDimension); + REQUIRE(gp.getDefault() == Approx(0.04)); + REQUIRE(gp.getMax() == Approx(0.8)); + REQUIRE(gp.getMin() == Approx(0.004)); +} diff --git a/salaTest/testisovistdef.cpp b/salaTest/testisovistdef.cpp new file mode 100644 index 00000000..c53ba29a --- /dev/null +++ b/salaTest/testisovistdef.cpp @@ -0,0 +1,76 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "../salalib/isovistdef.h" + +TEST_CASE("Full Isovist") +{ + IsovistDefinition isovist(1.0, 1.0); + REQUIRE(isovist.getLocation().x == Approx(1.0)); + REQUIRE(isovist.getLocation().y == Approx(1.0)); + REQUIRE(isovist.getAngle() == 0.0); + REQUIRE(isovist.getViewAngle() == 0.0); +} + +TEST_CASE("Partial Isovist") +{ + SECTION("No overrun") + { + IsovistDefinition isovist(1.0, 1.0, 2.0, 1.0); + REQUIRE(isovist.getLocation().x == Approx(1.0)); + REQUIRE(isovist.getLocation().y == Approx(1.0)); + REQUIRE(isovist.getAngle() == Approx(2.0)); + REQUIRE(isovist.getViewAngle() == Approx(1.0)); + REQUIRE(isovist.getLeftAngle() == Approx(1.5) ); + REQUIRE(isovist.getRightAngle() == Approx(2.5) ); + } + + SECTION("Overrun left") + { + IsovistDefinition isovist(1.0, 1.0, 0.1, 1.0); + REQUIRE(isovist.getLocation().x == Approx(1.0)); + REQUIRE(isovist.getLocation().y == Approx(1.0)); + REQUIRE(isovist.getAngle() == Approx(0.1)); + REQUIRE(isovist.getViewAngle() == Approx(1.0)); + REQUIRE(isovist.getLeftAngle() == Approx(5.8831853072) ); + REQUIRE(isovist.getRightAngle() == Approx(0.6) ); + + } + + SECTION("Overrun right") + { + IsovistDefinition isovist(1.0, 1.0, 6.1, 1.0); + REQUIRE(isovist.getLocation().x == Approx(1.0)); + REQUIRE(isovist.getLocation().y == Approx(1.0)); + REQUIRE(isovist.getAngle() == Approx(6.1)); + REQUIRE(isovist.getViewAngle() == Approx(1.0)); + REQUIRE(isovist.getLeftAngle() == Approx(5.6) ); + REQUIRE(isovist.getRightAngle() == Approx(0.31681469) ); + } + + SECTION("Actually a full isovist in a partial list") + { + IsovistDefinition isovist(1.0, 1.0, 6.1, 2 * M_PI); + REQUIRE(isovist.getLocation().x == Approx(1.0)); + REQUIRE(isovist.getLocation().y == Approx(1.0)); + REQUIRE(isovist.getAngle() == 0.0); + REQUIRE(isovist.getViewAngle() == 0.0); + REQUIRE(isovist.getLeftAngle() == 0.0); + REQUIRE(isovist.getRightAngle() == 0.0 ); + + } + +} diff --git a/salaTest/testlayermanager.cpp b/salaTest/testlayermanager.cpp new file mode 100644 index 00000000..0b7e8fc0 --- /dev/null +++ b/salaTest/testlayermanager.cpp @@ -0,0 +1,96 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include +#include +#include + +TEST_CASE("Test layer manager") +{ + LayerManagerImpl manager; + REQUIRE(manager.isVisible(1)); + REQUIRE(manager.getLayerName(0) == "Everything"); + REQUIRE(manager.isLayerVisible(0)); + REQUIRE(manager.getLayerIndex("Everything") == 0); + REQUIRE(manager.getKey(0) == 1); + + + size_t index1 = manager.addLayer("some layer"); + REQUIRE(index1 == 1); + REQUIRE_FALSE(manager.isVisible(2)); + REQUIRE_FALSE(manager.isLayerVisible(1)); + REQUIRE(manager.getLayerName(1) == "some layer"); + REQUIRE(manager.getLayerIndex("some layer") == 1); + REQUIRE(manager.getKey(1) == 2); + REQUIRE(manager.getKey(5) == 32); + + manager.setLayerVisible(1, true); + REQUIRE_FALSE(manager.isVisible(1)); + REQUIRE(manager.isVisible(2)); + + size_t index2 = manager.addLayer("another layer"); + REQUIRE(index2 == 2); + REQUIRE(manager.getLayerName(2) == "another layer"); + REQUIRE(manager.getLayerIndex("another layer") == 2); + REQUIRE_FALSE(manager.isLayerVisible(2)); + + manager.setLayerVisible(2, true); + REQUIRE_FALSE(manager.isVisible(1)); + REQUIRE(manager.isVisible(2)); + REQUIRE(manager.isVisible(4)); + + manager.setLayerVisible(2, false); + REQUIRE_FALSE(manager.isVisible(1)); + REQUIRE(manager.isVisible(2)); + REQUIRE_FALSE(manager.isVisible(4)); + + manager.setLayerVisible(0, false); + REQUIRE_FALSE(manager.isVisible(1)); + REQUIRE_FALSE(manager.isVisible(2)); + REQUIRE_FALSE(manager.isVisible(4)); + + manager.setLayerVisible(2, true); + REQUIRE_FALSE(manager.isVisible(1)); + REQUIRE_FALSE(manager.isVisible(2)); + REQUIRE(manager.isVisible(4)); + + manager.setLayerVisible(0, true); + REQUIRE(manager.isVisible(1)); + REQUIRE_FALSE(manager.isVisible(2)); + REQUIRE_FALSE(manager.isVisible(4)); + + REQUIRE_THROWS_AS(manager.addLayer("another layer"), LayerManager::DuplicateKeyException); + + // test read and write + SelfCleaningFile serialisedManager("manager.bin"); + { + std::ofstream file(serialisedManager.Filename()); + manager.write(file); + } + + LayerManagerImpl copy; + { + std::ifstream file(serialisedManager.Filename()); + copy.read(file); + } + REQUIRE(copy.getLayerName(1) == "some layer"); + REQUIRE(copy.getLayerIndex("some layer") == 1); + REQUIRE(copy.isVisible(1)); + REQUIRE_FALSE(copy.isVisible(2)); + REQUIRE_FALSE(copy.isVisible(4)); + + +} diff --git a/salaTest/testlinkutils.cpp b/salaTest/testlinkutils.cpp new file mode 100644 index 00000000..8b265661 --- /dev/null +++ b/salaTest/testlinkutils.cpp @@ -0,0 +1,274 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "salalib/mgraph.h" +#include "salalib/linkutils.h" + + +TEST_CASE("Test linking - fully filled grid (no geometry)", "") +{ + double spacing = 0.5; + Point2f offset(0,0); // seems that this is always set to 0,0 + Point2f bottomLeft(0,0); + Point2f topRight(2,4); + int fill_type = 0; // = QDepthmapView::FULLFILL + + std::unique_ptr metaGraph(new MetaGraph("Test MetaGraph")); + metaGraph->setRegion(bottomLeft, topRight); + PointMap pointMap(metaGraph->getRegion(), metaGraph->m_drawingFiles, "Test PointMap"); + pointMap.setGrid(spacing, offset); + Point2f gridBottomLeft = pointMap.getRegion().bottom_left; + Point2f midPoint(gridBottomLeft.x + spacing * (floor(pointMap.getCols() * 0.5) + 0.5), + gridBottomLeft.y + spacing * (floor(pointMap.getRows() * 0.5) + 0.5)); + pointMap.makePoints(midPoint, fill_type); + + std::vector mergeLines; + + SECTION ("Successful: bottom-left to top-right") + { + mergeLines.push_back(Line(bottomLeft,topRight)); + std::vector links = depthmapX::pixelateMergeLines(mergeLines,pointMap); + REQUIRE(links.size() == 1); + REQUIRE(links[0].a.x == 0); + REQUIRE(links[0].a.y == 0); + REQUIRE(links[0].b.x == 4); + REQUIRE(links[0].b.y == 8); + + // make sure pixels are not already merged + REQUIRE(!pointMap.isPixelMerged(links[0].a)); + REQUIRE(!pointMap.isPixelMerged(links[0].b)); + + // merge + depthmapX::mergePixelPairs(links, pointMap); + + // make sure pixels are merged + REQUIRE(pointMap.isPixelMerged(links[0].a)); + REQUIRE(pointMap.isPixelMerged(links[0].b)); + + const std::vector> &mergedPixelPairs = pointMap.getMergedPixelPairs(); + + REQUIRE(mergedPixelPairs.size() == 1); + REQUIRE(mergedPixelPairs[0].first.x == 0); + REQUIRE(mergedPixelPairs[0].first.y == 0); + REQUIRE(mergedPixelPairs[0].second.x == 4); + REQUIRE(mergedPixelPairs[0].second.y == 8); + + const std::vector &mergeLines = depthmapX::getMergedPixelsAsLines(pointMap); + + Point2f p1position = pointMap.depixelate(links[0].a); + Point2f p2position = pointMap.depixelate(links[0].b); + + REQUIRE(mergeLines.size() == 1); + REQUIRE(mergeLines[0].start().x == p1position.x); + REQUIRE(mergeLines[0].start().y == p1position.y); + REQUIRE(mergeLines[0].end().x == p2position.x); + REQUIRE(mergeLines[0].end().y == p2position.y); + } + + SECTION ("Successfull: bottom-left to top-right and bottom-right to top-left") + { + mergeLines.push_back(Line(bottomLeft,topRight)); + Point2f start(topRight.x, bottomLeft.y); + Point2f end(bottomLeft.x, topRight.y); + mergeLines.push_back(Line(start,end)); + std::vector links = depthmapX::pixelateMergeLines(mergeLines,pointMap); + REQUIRE(links.size() == 2); + REQUIRE(links[0].a.x == 0); + REQUIRE(links[0].a.y == 0); + REQUIRE(links[0].b.x == 4); + REQUIRE(links[0].b.y == 8); + REQUIRE(links[1].a.x == 0); + REQUIRE(links[1].a.y == 8); + REQUIRE(links[1].b.x == 4); + REQUIRE(links[1].b.y == 0); + + // make sure pixels are not already merged + REQUIRE(!pointMap.isPixelMerged(links[0].a)); + REQUIRE(!pointMap.isPixelMerged(links[0].b)); + REQUIRE(!pointMap.isPixelMerged(links[1].a)); + REQUIRE(!pointMap.isPixelMerged(links[1].b)); + + // merge + depthmapX::mergePixelPairs(links, pointMap); + + // make sure pixels are merged + REQUIRE(pointMap.isPixelMerged(links[0].a)); + REQUIRE(pointMap.isPixelMerged(links[0].b)); + REQUIRE(pointMap.isPixelMerged(links[1].a)); + REQUIRE(pointMap.isPixelMerged(links[1].b)); + } + + SECTION ("Failing: merge line start out of grid") + { + Point2f start(bottomLeft.x - spacing, bottomLeft.y - spacing); + mergeLines.push_back(Line(start,topRight)); + std::vector links = depthmapX::pixelateMergeLines(mergeLines,pointMap); + REQUIRE_THROWS_WITH(depthmapX::mergePixelPairs(links, pointMap), + Catch::Contains("Line ends not both on painted analysis space")); + } + + SECTION ("Failing: merge line end out of grid") + { + Point2f end(topRight.x + spacing, topRight.y + spacing); + mergeLines.push_back(Line(bottomLeft,end)); + std::vector links = depthmapX::pixelateMergeLines(mergeLines,pointMap); + REQUIRE_THROWS_WITH(depthmapX::mergePixelPairs(links, pointMap), + Catch::Contains("Line ends not both on painted analysis space")); + } + + SECTION ("Failing: second link start overlapping") + { + mergeLines.push_back(Line(bottomLeft,topRight)); + Point2f start(bottomLeft.x, bottomLeft.y); + Point2f end(topRight.x - 1, topRight.y); + mergeLines.push_back(Line(start,end)); + std::vector links = depthmapX::pixelateMergeLines(mergeLines,pointMap); + REQUIRE_THROWS_WITH(depthmapX::mergePixelPairs(links, pointMap), + Catch::Contains("Overlapping link found")); + } + + SECTION("Failing: second link end overlapping") + { + mergeLines.push_back(Line(bottomLeft,topRight)); + Point2f start(bottomLeft.x + 1, bottomLeft.y); + Point2f end(topRight.x, topRight.y); + mergeLines.push_back(Line(start,end)); + std::vector links = depthmapX::pixelateMergeLines(mergeLines,pointMap); + REQUIRE_THROWS_WITH(depthmapX::mergePixelPairs(links, pointMap), + Catch::Contains("Overlapping link found")); + } + + SECTION("Failing: fully overlapping link (bottom-left to top-right)") + { + mergeLines.push_back(Line(bottomLeft,topRight)); + mergeLines.push_back(Line(bottomLeft,topRight)); + std::vector links = depthmapX::pixelateMergeLines(mergeLines,pointMap); + REQUIRE_THROWS_WITH(depthmapX::mergePixelPairs(links, pointMap), + Catch::Contains("Overlapping link found")); + } + + SECTION("Failing: link overlapping to previously merged") + { + mergeLines.push_back(Line(bottomLeft,topRight)); + std::vector links = depthmapX::pixelateMergeLines(mergeLines,pointMap); + REQUIRE(links.size() == 1); + REQUIRE(links[0].a.x == 0); + REQUIRE(links[0].a.y == 0); + REQUIRE(links[0].b.x == 4); + REQUIRE(links[0].b.y == 8); + + // make sure pixels are not already merged + REQUIRE(!pointMap.isPixelMerged(links[0].a)); + REQUIRE(!pointMap.isPixelMerged(links[0].b)); + + // merge + depthmapX::mergePixelPairs(links, pointMap); + + // make sure pixels are merged + REQUIRE(pointMap.isPixelMerged(links[0].a)); + REQUIRE(pointMap.isPixelMerged(links[0].b)); + + // now try to merge the same link again + REQUIRE_THROWS_WITH(depthmapX::mergePixelPairs(links, pointMap), + Catch::Contains("Link pixel found that is already linked on the map")); + } +} + +TEST_CASE("Test linking - half filled grid", "") +{ + + double spacing = 0.5; + Point2f offset(0,0); // seems that this is always set to 0,0 + int fill_type = 0; // = QDepthmapView::FULLFILL + + Point2f lineStart(0,0); + Point2f lineEnd(2,4); + + Point2f bottomLeft(std::min(lineStart.x,lineEnd.x),std::min(lineStart.y,lineEnd.y)); + Point2f topRight(std::max(lineStart.x,lineEnd.x),std::max(lineStart.y,lineEnd.y)); + + std::unique_ptr metaGraph(new MetaGraph("Test MetaGraph")); + metaGraph->m_drawingFiles.emplace_back("Test SpacePixelGroup"); + metaGraph->m_drawingFiles.back().m_spacePixels.emplace_back("Test ShapeMap"); + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(lineStart, lineEnd)); + metaGraph->m_drawingFiles.back().m_region = metaGraph->m_drawingFiles.back().m_spacePixels.back().getRegion(); + metaGraph->setRegion(metaGraph->m_drawingFiles.back().m_region.bottom_left, + metaGraph->m_drawingFiles.back().m_region.top_right); + + PointMap pointMap(metaGraph->getRegion(), metaGraph->m_drawingFiles, "Test PointMap"); + pointMap.setGrid(spacing, offset); + + Point2f gridBottomLeft = pointMap.getRegion().bottom_left; + Point2f gridTopRight = pointMap.getRegion().top_right; + Point2f topLeftFillPoint(gridBottomLeft.x+spacing, gridTopRight.y-spacing); + pointMap.makePoints(topLeftFillPoint, fill_type); + + std::vector mergeLines; + + SECTION("Successful: top-left pixel to one to its right") + { + Point2f start(bottomLeft.x, topRight.y); + Point2f end(bottomLeft.x + spacing, topRight.y); + mergeLines.push_back(Line(start,end)); + std::vector links = depthmapX::pixelateMergeLines(mergeLines,pointMap); + REQUIRE(links.size() == 1); + REQUIRE(links[0].a.x == 0); + REQUIRE(links[0].a.y == 8); + REQUIRE(links[0].b.x == 1); + REQUIRE(links[0].b.y == 8); + + // make sure pixels are not already merged + REQUIRE(!pointMap.isPixelMerged(links[0].a)); + REQUIRE(!pointMap.isPixelMerged(links[0].b)); + + // merge + depthmapX::mergePixelPairs(links, pointMap); + + // make sure pixels are merged + REQUIRE(pointMap.isPixelMerged(links[0].a)); + REQUIRE(pointMap.isPixelMerged(links[0].b)); + } + + SECTION("Failing: merge line (bottom-right to the one its left) completely out of grid") + { + Point2f start(topRight.x, bottomLeft.y); + Point2f end(topRight.x - 1, bottomLeft.y); + mergeLines.push_back(Line(start,end)); + std::vector links = depthmapX::pixelateMergeLines(mergeLines,pointMap); + REQUIRE_THROWS_WITH(depthmapX::mergePixelPairs(links, pointMap), + Catch::Contains("Line ends not both on painted analysis space")); + } + + SECTION("Failing: merge line (bottom-right to top-left) start out of grid") + { + Point2f start(topRight.x, bottomLeft.y); + Point2f end(bottomLeft.x, topRight.y); + mergeLines.push_back(Line(start,end)); + std::vector links = depthmapX::pixelateMergeLines(mergeLines,pointMap); + REQUIRE_THROWS_WITH(depthmapX::mergePixelPairs(links, pointMap), + Catch::Contains("Line ends not both on painted analysis space")); + } + + SECTION("Failing: merge line (top-left to bottom-right) end out of grid") + { + Point2f start(bottomLeft.x, topRight.y); + Point2f end(topRight.x, bottomLeft.y); + mergeLines.push_back(Line(start,end)); + std::vector links = depthmapX::pixelateMergeLines(mergeLines,pointMap); + REQUIRE_THROWS_WITH(depthmapX::mergePixelPairs(links, pointMap), + Catch::Contains("Line ends not both on painted analysis space")); + } +} diff --git a/salaTest/testmapinfodata.cpp b/salaTest/testmapinfodata.cpp new file mode 100644 index 00000000..8fe2cfbd --- /dev/null +++ b/salaTest/testmapinfodata.cpp @@ -0,0 +1,172 @@ +// Copyright (C) 2017-2018 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "salalib/mgraph.h" +#include "salalib/parsers/mapinfodata.h" + +TEST_CASE("MapInfo failing header", "") +{ + std::string mifdata = "Version 300\n"; + + SECTION("Missing quotes around delimiter") { + mifdata += "Charset \"WindowsLatin1\"\n" \ + "Delimiter ,\n" \ + "Index 1,2\n" \ + "CoordSys Earth Projection 8, 79, \"m\", -2, 49, 0.9996012717, 400000, -100000"; + } + + SECTION("Missing CoordSys") { + mifdata += "Charset \"WindowsLatin1\"\n" \ + "Delimiter \",\"\n" \ + "Index 1,2\n" \ + "Bounds (-7845061.1011, -15524202.1641) (8645061.1011, 4470074.53373)\n"; + } + + std::stringstream mifstream(mifdata); + + MapInfoData mapinfodata; + REQUIRE_FALSE(mapinfodata.readheader(mifstream)); +} + +TEST_CASE("MapInfo failing column attribute columns", "") +{ + + std::string mifdata = ""; + + + SECTION("Missing Columns at beginning") { + mifdata += "Tolumns 2\n" \ + " ID Integer\n" \ + " Length_m Float\n" \ + "Data\n"; + } + + SECTION("Missing Column number") { + mifdata += "Columns\n" \ + " ID Integer\n" \ + " Length_m Float\n" \ + "Data\n"; + } + + SECTION("Missing Data at end") { + mifdata += "Columns 2\n" \ + " ID Integer\n" \ + " Length_m Float\n" \ + "Bata\n"; + } + + std::string middata = + "1,1017.81\n" \ + "2,568.795\n" \ + "3,216.026"; + + std::stringstream mifstream(mifdata); + std::stringstream midstream(middata); + + std::vector columnheads; + + MapInfoData mapinfodata; + REQUIRE_FALSE(mapinfodata.readcolumnheaders(mifstream, columnheads)); +} + +TEST_CASE("Complete proper MapInfo file", "") +{ + const float EPSILON = 0.001; + + // A typical MIF + + std::string mifdata = + "Version 300\n" \ + "Charset \"WindowsLatin1\"\n" \ + "Delimiter \",\"\n" \ + "Index 1,2\n" \ + "CoordSys Earth Projection 8, 79, \"m\", -2, 49, 0.9996012717, 400000, -100000"; + + SECTION("With Bounds") { + mifdata += "Bounds (-7845061.1011, -15524202.1641) (8645061.1011, 4470074.53373)\n"; + } + + SECTION("Without Bounds") { + mifdata += "\n"; + } + + mifdata += + "Columns 2\n" \ + " ID Integer\n" \ + " Length_m Float\n" \ + "Data\n" \ + "\n" \ + "Line 534014.29 182533.33 535008.52 182764.11\n" \ + " Pen (1,2,0)\n" \ + "Line 533798.68 183094.69 534365.48 183159.01\n" \ + " Pen (1,2,0)\n" \ + "Point 534014.29 182533.33\n" \ + " Symbol (34,0,12)"; + + + // A Typical MID + + std::string middata = + "1,1017.81\n" \ + "2,568.795\n" \ + "3,216.026"; + + ShapeMap shapeMap("MapInfoTest"); + MapInfoData mapinfodata; + + std::stringstream mifstream(mifdata); + std::stringstream midstream(middata); + REQUIRE(mapinfodata.import(mifstream, midstream, shapeMap) == MINFO_OK); + + std::map shapes = shapeMap.getAllShapes(); + auto shapeRef0 = depthmapX::getMapAtIndex(shapes, 0); + auto shapeRef1 = depthmapX::getMapAtIndex(shapes, 1); + auto shapeRef2 = depthmapX::getMapAtIndex(shapes, 2); + + auto &shape0 = shapeRef0->second; + auto &shape1 = shapeRef1->second; + auto &shape2 = shapeRef2->second; + REQUIRE(shapes.size() == 3); + REQUIRE(shape0.isLine()); + REQUIRE(shape0.getLine().ax() == Approx(534014.29).epsilon(EPSILON)); + REQUIRE(shape0.getLine().ay() == Approx(182533.33).epsilon(EPSILON)); + REQUIRE(shape0.getLine().bx() == Approx(535008.52).epsilon(EPSILON)); + REQUIRE(shape0.getLine().by() == Approx(182764.11).epsilon(EPSILON)); + REQUIRE(shape1.isLine()); + REQUIRE(shape1.getLine().ax() == Approx(533798.68).epsilon(EPSILON)); + REQUIRE(shape1.getLine().ay() == Approx(183094.69).epsilon(EPSILON)); + REQUIRE(shape1.getLine().bx() == Approx(534365.48).epsilon(EPSILON)); + REQUIRE(shape1.getLine().by() == Approx(183159.01).epsilon(EPSILON)); + REQUIRE(shape2.isPoint()); + REQUIRE(shape2.getPoint().x == Approx(534014.29).epsilon(EPSILON)); + REQUIRE(shape2.getPoint().y == Approx(182533.33).epsilon(EPSILON)); + + AttributeTable& att = shapeMap.getAttributeTable(); + REQUIRE(att.getNumColumns() == 2); + REQUIRE(att.getColumnName(0) == "Id"); + REQUIRE(att.getColumnName(1) == "Length_M"); + + REQUIRE(att.getNumRows() == 3); + auto &row0 = att.getRow(AttributeKey(shapeRef0->first)); + auto &row1 = att.getRow(AttributeKey(shapeRef1->first)); + auto &row2 = att.getRow(AttributeKey(shapeRef2->first)); + REQUIRE(row0.getValue("Id") == 1); + REQUIRE(row1.getValue("Id") == 2); + REQUIRE(row2.getValue("Id") == 3); + REQUIRE(row0.getValue("Length_M") == Approx(1017.81).epsilon(EPSILON)); + REQUIRE(row1.getValue("Length_M") == Approx(568.795).epsilon(EPSILON)); + REQUIRE(row2.getValue("Length_M") == Approx(216.026).epsilon(EPSILON)); +} diff --git a/salaTest/testmgraph.cpp b/salaTest/testmgraph.cpp new file mode 100644 index 00000000..a26c99c8 --- /dev/null +++ b/salaTest/testmgraph.cpp @@ -0,0 +1,109 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "salalib/mgraph.h" + + +TEST_CASE("Test getVisibleLines", "") +{ + const float EPSILON = 0.001; + + // create a new MetaGraph + std::unique_ptr mgraph(new MetaGraph()); + + Point2f visibleLineStart(0,0); + Point2f visibleLineEnd(2,4); + Point2f hiddenLineStart(1,1); + Point2f hiddenLineEnd(3,5); + + // push a SpacePixelFile in the MetaGraph + mgraph->m_drawingFiles.emplace_back("Test SpacePixelFile"); + + // push a ShapeMap in the SpacePixelFile + mgraph->m_drawingFiles.back().m_spacePixels.emplace_back("Visible ShapeMap"); + + // add a line to the first ShapeMap + mgraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(visibleLineStart, visibleLineEnd)); + + // push a ShapeMap in the SpacePixelFile + mgraph->m_drawingFiles.back().m_spacePixels.emplace_back("Hidden ShapeMap"); + + // add a line to the second ShapeMap + mgraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(hiddenLineStart, hiddenLineEnd)); + + SECTION( "Get visible lines when none is hidden" ) + { + // first check without hiding anything + + const std::vector& visibleLines = mgraph->getVisibleDrawingLines(); + + REQUIRE(visibleLines.size() == 2); + REQUIRE(visibleLines[0].start().x == Approx(visibleLineStart.x).epsilon(EPSILON)); + REQUIRE(visibleLines[0].start().y == Approx(visibleLineStart.y).epsilon(EPSILON)); + REQUIRE(visibleLines[0].end().x == Approx(visibleLineEnd.x).epsilon(EPSILON)); + REQUIRE(visibleLines[0].end().y == Approx(visibleLineEnd.y).epsilon(EPSILON)); + REQUIRE(visibleLines[1].start().x == Approx(hiddenLineStart.x).epsilon(EPSILON)); + REQUIRE(visibleLines[1].start().y == Approx(hiddenLineStart.y).epsilon(EPSILON)); + REQUIRE(visibleLines[1].end().x == Approx(hiddenLineEnd.x).epsilon(EPSILON)); + REQUIRE(visibleLines[1].end().y == Approx(hiddenLineEnd.y).epsilon(EPSILON)); + } + + SECTION( "Get visible lines when some are hidden" ) + { + // now hide the second SpacePixelFile + mgraph->m_drawingFiles.back().m_spacePixels.back().setShow(false); + + const std::vector& visibleLines = mgraph->getVisibleDrawingLines(); + + REQUIRE(visibleLines.size() == 1); + REQUIRE(visibleLines[0].start().x == Approx(visibleLineStart.x).epsilon(EPSILON)); + REQUIRE(visibleLines[0].start().y == Approx(visibleLineStart.y).epsilon(EPSILON)); + REQUIRE(visibleLines[0].end().x == Approx(visibleLineEnd.x).epsilon(EPSILON)); + REQUIRE(visibleLines[0].end().y == Approx(visibleLineEnd.y).epsilon(EPSILON)); + } +} + +TEST_CASE("Test pointMaps", "") +{ + std::unique_ptr mgraph(new MetaGraph()); + int pointMapIdx = mgraph->addNewPointMap("Kenny"); + REQUIRE(mgraph->getPointMaps().size() == 1); + REQUIRE(pointMapIdx == 0); + REQUIRE(mgraph->getPointMaps()[0].getName() == "Kenny"); + REQUIRE(mgraph->getDisplayedPointMapRef() == pointMapIdx); + REQUIRE(mgraph->getDisplayedPointMap().getName() == "Kenny"); + + SECTION( "Add another and remove the first through the MetaGraph" ) + { + int pointMapIdx = mgraph->addNewPointMap("Stan"); + REQUIRE(mgraph->getPointMaps().size() == 2); + REQUIRE(pointMapIdx == 1); + REQUIRE(mgraph->getPointMaps()[1].getName() == "Stan"); + REQUIRE(mgraph->getDisplayedPointMapRef() == 1); + REQUIRE(mgraph->getDisplayedPointMap().getName() == "Stan"); + + mgraph->setState(MetaGraph::POINTMAPS); + mgraph->setViewClass(MetaGraph::SHOWVGATOP); + mgraph->setDisplayedPointMapRef(0); + REQUIRE(mgraph->getDisplayedPointMapRef() == 0); + REQUIRE(mgraph->getDisplayedPointMap().getName() == "Kenny"); + + mgraph->removeDisplayedMap(); + REQUIRE(mgraph->getPointMaps().size() == 1); + REQUIRE(mgraph->getPointMaps()[0].getName() == "Stan"); + REQUIRE(mgraph->getDisplayedPointMapRef() == 0); + } +} diff --git a/salaTest/testpointmap.cpp b/salaTest/testpointmap.cpp new file mode 100644 index 00000000..a9834d20 --- /dev/null +++ b/salaTest/testpointmap.cpp @@ -0,0 +1,549 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "salalib/mgraph.h" + + +TEST_CASE("Test MetaGraph construction", "") +{ + const float EPSILON = 0.001; + double spacing = 0.5; + Point2f offset(0,0); // seems that this is always set to 0,0 + + // create a new MetaGraph + // The PointMap needs the m_region variable from this + // object as a definition of the area the grid needs to cover + std::unique_ptr metaGraph(new MetaGraph("Test MetaGraph")); + + SECTION( "Construct a plain MetaGraph without underlying geometry" ) + { + Point2f bottomLeft(0,0); + Point2f topRight(2,4); + + // set m_region to the bounds + metaGraph->setRegion(bottomLeft, topRight); + + // check if the bounds are set correctly + REQUIRE(metaGraph->getRegion().bottom_left.x == Approx(bottomLeft.x).epsilon(EPSILON)); + REQUIRE(metaGraph->getRegion().bottom_left.y == Approx(bottomLeft.y).epsilon(EPSILON)); + REQUIRE(metaGraph->getRegion().top_right.x == Approx(topRight.x).epsilon(EPSILON)); + REQUIRE(metaGraph->getRegion().top_right.y == Approx(topRight.y).epsilon(EPSILON)); + } + + SECTION( "Construct a MetaGraph using underlying geometry" ) + { + Point2f lineStart(0,0); + Point2f lineEnd(2,4); + + Point2f bottomLeft(std::min(lineStart.x,lineEnd.x),std::min(lineStart.y,lineEnd.y)); + Point2f topRight(std::max(lineStart.x,lineEnd.x),std::max(lineStart.y,lineEnd.y)); + + // push a SpacePixelFile in the MetaGraph + metaGraph->m_drawingFiles.emplace_back("Test MetaGraph"); + + // push a ShapeMap in the SpacePixelFile + metaGraph->m_drawingFiles.back().m_spacePixels.emplace_back("Test ShapeMap"); + + // add a line to the ShapeMap + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(lineStart, lineEnd)); + + // check if the ShapeMap bounds are set correctly + REQUIRE(metaGraph->m_drawingFiles.back().m_spacePixels.back().getRegion().bottom_left.x == Approx(bottomLeft.x).epsilon(EPSILON)); + REQUIRE(metaGraph->m_drawingFiles.back().m_spacePixels.back().getRegion().bottom_left.y == Approx(bottomLeft.y).epsilon(EPSILON)); + REQUIRE(metaGraph->m_drawingFiles.back().m_spacePixels.back().getRegion().top_right.x == Approx(topRight.x).epsilon(EPSILON)); + REQUIRE(metaGraph->m_drawingFiles.back().m_spacePixels.back().getRegion().top_right.y == Approx(topRight.y).epsilon(EPSILON)); + + // MetaGraph and SpacePixelFile do not automatically grow + // their region when new shapemaps/files are added to them + // therefore we have to do this externally + metaGraph->m_drawingFiles.back().m_region = metaGraph->m_drawingFiles.back().m_spacePixels.back().getRegion(); + + // check if the SpacePixelFile bounds are set correctly + REQUIRE(metaGraph->m_drawingFiles.back().m_region.bottom_left.x == Approx(bottomLeft.x).epsilon(EPSILON)); + REQUIRE(metaGraph->m_drawingFiles.back().m_region.bottom_left.y == Approx(bottomLeft.y).epsilon(EPSILON)); + REQUIRE(metaGraph->m_drawingFiles.back().m_region.top_right.x == Approx(topRight.x).epsilon(EPSILON)); + REQUIRE(metaGraph->m_drawingFiles.back().m_region.top_right.y == Approx(topRight.y).epsilon(EPSILON)); + + metaGraph->setRegion(metaGraph->m_drawingFiles.back().m_region.bottom_left, + metaGraph->m_drawingFiles.back().m_region.top_right); + + // check if the MetaGraph bounds are set correctly + REQUIRE(metaGraph->getRegion().bottom_left.x == Approx(bottomLeft.x).epsilon(EPSILON)); + REQUIRE(metaGraph->getRegion().bottom_left.y == Approx(bottomLeft.y).epsilon(EPSILON)); + REQUIRE(metaGraph->getRegion().top_right.x == Approx(topRight.x).epsilon(EPSILON)); + REQUIRE(metaGraph->getRegion().top_right.y == Approx(topRight.y).epsilon(EPSILON)); + } + + // construct a sample pointMap + PointMap pointMap(metaGraph->getRegion(), metaGraph->m_drawingFiles, "Test PointMap"); +} + +TEST_CASE("Test grid filling", "") +{ + const float EPSILON = 0.001; + double spacing = 0.5; + Point2f offset(0,0); // seems that this is always set to 0,0 + + // create a new MetaGraph + // The PointMap needs the m_region variable from this + // object as a definition of the area the grid needs to cover + std::unique_ptr metaGraph(new MetaGraph("Test MetaGraph")); + + // Construct a plain MetaGraph without underlying geometry + { + Point2f bottomLeft(0,0); + Point2f topRight(2,4); + + // set m_region to the bounds + metaGraph->setRegion(bottomLeft, topRight); + + // check if the bounds are set correctly + REQUIRE(metaGraph->getRegion().bottom_left.x == Approx(bottomLeft.x).epsilon(EPSILON)); + REQUIRE(metaGraph->getRegion().bottom_left.y == Approx(bottomLeft.y).epsilon(EPSILON)); + REQUIRE(metaGraph->getRegion().top_right.x == Approx(topRight.x).epsilon(EPSILON)); + REQUIRE(metaGraph->getRegion().top_right.y == Approx(topRight.y).epsilon(EPSILON)); + } + + // construct a sample pointMap + PointMap pointMap(metaGraph->getRegion(), metaGraph->m_drawingFiles, "Test PointMap"); + + // set the grid + + // create the grid with bounds as set above + bool gridIsSet = pointMap.setGrid(spacing, offset); + + // check if the grid was set + REQUIRE(gridIsSet); + + // check if the spacing is correct + REQUIRE(spacing == pointMap.getSpacing()); + + // fill the grid + + // seems like fill_type is actually connected to the + // QDepthmapView class which is a GUI class (depthmapview.h) + // TODO Disentangle GUI enum from pointMap.makePoints + int fill_type = 0; // = QDepthmapView::FULLFILL + + Point2f gridBottomLeft = pointMap.getRegion().bottom_left; + + SECTION( "Check if the points are made when fill selection in a cell" ) + { + // Check if the points are made (grid filled) when + // the selected position is certainly in a cell + // This calculation should make the point directly + // at the centre of a central cell + Point2f midPoint(gridBottomLeft.x + spacing * (floor(pointMap.getCols() * 0.5) + 0.5), + gridBottomLeft.y + spacing * (floor(pointMap.getRows() * 0.5) + 0.5)); + bool pointsMade = pointMap.makePoints(midPoint, fill_type); + REQUIRE(pointsMade); + + } + + SECTION("Check if the points are made when fill selection between cells") + { + // Check if the points are made (grid filled) when + // the selected position is certainly between cells + // This calculation should make the point directly + // at the edge of a central cell + Point2f midPoint(gridBottomLeft.x + spacing * (floor(pointMap.getCols() * 0.5)), + gridBottomLeft.y + spacing * (floor(pointMap.getRows() * 0.5))); + bool pointsMade = pointMap.makePoints(midPoint, fill_type); + REQUIRE(pointsMade); + } +} + +// PointMap::setGrid is quite convoluted with various parameters +// affecting the result, such as the limits of the region to be +// covered (bottomLeft, topRight), the spacing and the location +// of the plan in space. For example every grid created will be +// in relation to the origin (0,0), no matter where the region +// is and the current pixel can always be calculated as if the +// origin always falls in the centre of a cell. + +TEST_CASE("Quirks in grid creation - Origin always at 0", "") +{ + + double spacing = 0.5; + const float EPSILON = 0.001; + Point2f offset(0,0); // seems that this is always set to 0,0 + + Point2f bottomLeft(0,0); + Point2f topRight(0,0); + + SECTION ("Region from origin to positive x, positive y quadrant") + { + spacing = 0.5; + bottomLeft.x = 0; + bottomLeft.y = 0; + topRight.x = 1; + topRight.y = 1; + } + + SECTION ("Region away from origin to positive x, positive y quadrant") + { + spacing = 0.5; + bottomLeft.x = 1; + bottomLeft.y = 1; + topRight.x = 2; + topRight.y = 2; + } + + SECTION ("Region from origin to negative x, negative y quadrant") + { + spacing = 0.5; + bottomLeft.x = -1; + bottomLeft.y = -1; + topRight.x = 0; + topRight.y = 0; + } + + SECTION ("Region in all quadrants") + { + spacing = 0.5; + bottomLeft.x = -1; + bottomLeft.y = -1; + topRight.x = 1; + topRight.y = 1; + } + + SECTION ("Region in positive x, positive y quadrant, non-rectangular") + { + spacing = 0.5; + bottomLeft.x = 1; + bottomLeft.y = 2; + topRight.x = 3; + topRight.y = 4; + } + + SECTION ("Region in positive x, positive y quadrant, floating-point limits") + { + spacing = 0.5; + bottomLeft.x = 1.1; + bottomLeft.y = 2.2; + topRight.x = 3.3; + topRight.y = 4.4; + } + + SECTION ("Region in positive x, positive y quadrant, floating-point limits") + { + spacing = 0.5; + bottomLeft.x = 0.1; + bottomLeft.y = 0.2; + topRight.x = 0.3; + topRight.y = 0.4; + } + + SECTION ("Region in negative x, negative y quadrant, floating-point limits") + { + spacing = 0.5; + bottomLeft.x = -0.4; + bottomLeft.y = -0.3; + topRight.x = -0.2; + topRight.y = -0.1; + } + + SECTION ("Region in all quadrants, floating-point limits") + { + spacing = 0.5; + bottomLeft.x = -1.1; + bottomLeft.y = -2.2; + topRight.x = 3.3; + topRight.y = 4.4; + } + + SECTION ("Region in all quadrants, floating-point limits, smaller spacing") + { + spacing = 0.25; + bottomLeft.x = 1.1; + bottomLeft.y = 2.2; + topRight.x = 3.3; + topRight.y = 4.4; + } + + std::unique_ptr metaGraph(new MetaGraph("Test MetaGraph")); + metaGraph->setRegion(bottomLeft, topRight); + PointMap pointMap(metaGraph->getRegion(), metaGraph->m_drawingFiles, "Test PointMap"); + bool gridIsSet = pointMap.setGrid(spacing, offset); + + int bottomLeftPixelIndexX = int(floor(bottomLeft.x / spacing - 0.5)) + 1; + int bottomLeftPixelIndexY = int(floor(bottomLeft.y / spacing - 0.5)) + 1; + + int topRightPixelIndexX = int(floor(topRight.x / spacing - 0.5)) + 1; + int topRightPixelIndexY = int(floor(topRight.y / spacing - 0.5)) + 1; + + int numCellsX = topRightPixelIndexX - bottomLeftPixelIndexX + 1; + int numCellsY = topRightPixelIndexY - bottomLeftPixelIndexY + 1; + + // check if the size of the grid is as expected + REQUIRE(pointMap.getCols() == numCellsX); + REQUIRE(pointMap.getRows() == numCellsY); + + Point2f gridBottomLeft(bottomLeftPixelIndexX * spacing - 0.5 * spacing, + bottomLeftPixelIndexY * spacing - 0.5 * spacing); + + // check if the bottom-left corner of the bottom-left pixel is as expected + REQUIRE(pointMap.getRegion().bottom_left.x == Approx(gridBottomLeft.x).epsilon(EPSILON)); + REQUIRE(pointMap.getRegion().bottom_left.y == Approx(gridBottomLeft.y).epsilon(EPSILON)); + + Point2f midPoint(gridBottomLeft.x + spacing * (floor(numCellsX * 0.5) + 0.5), + gridBottomLeft.y + spacing * (floor(numCellsY * 0.5) + 0.5)); + + int fill_type = 0; // = QDepthmapView::FULLFILL + + bool pointsMade = pointMap.makePoints(midPoint, fill_type); + + // check if the grid is filled + REQUIRE(pointsMade); +} + +TEST_CASE("Test PointMap connections output", "") +{ + const float EPSILON = 0.001; + double spacing = 0.5; + Point2f offset(0,0); // seems that this is always set to 0,0 + + std::unique_ptr metaGraph(new MetaGraph("Test MetaGraph")); + + double rectSize = 1.5; + + Point2f line0Start(0,0); + Point2f line0End(0,rectSize); + Point2f line1Start(0,rectSize); + Point2f line1End(rectSize,rectSize); + Point2f line2Start(rectSize,rectSize); + Point2f line2End(rectSize,0); + Point2f line3Start(rectSize,0); + Point2f line3End(0,0); + + metaGraph->m_drawingFiles.emplace_back("Test SpacePixelGroup"); + metaGraph->m_drawingFiles.back().m_spacePixels.emplace_back("Test ShapeMap"); + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line0Start, line0End)); + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line1Start, line1End)); + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line2Start, line2End)); + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line3Start, line3End)); + metaGraph->m_drawingFiles.back().m_region = metaGraph->m_drawingFiles.back().m_spacePixels.back().getRegion(); + metaGraph->setRegion(metaGraph->m_drawingFiles.back().m_region.bottom_left, + metaGraph->m_drawingFiles.back().m_region.top_right); + PointMap pointMap(metaGraph->getRegion(), metaGraph->m_drawingFiles, "Test PointMap"); + + Point2f gridBottomLeft = pointMap.getRegion().bottom_left; + + Point2f midPoint(gridBottomLeft.x + spacing * (floor(pointMap.getCols() * 0.5) + 0.5), + gridBottomLeft.y + spacing * (floor(pointMap.getRows() * 0.5) + 0.5)); + + int fill_type = 0; // = QDepthmapView::FULLFILL + bool gridIsSet = pointMap.setGrid(spacing, offset); + + bool pointsMade = pointMap.makePoints(midPoint, fill_type); + + bool boundaryGraph = false; + double maxDist = -1; + // a communicator is required in order to create the connections between the pixels + std::unique_ptr comm(new ICommunicator()); + + bool graphMade = pointMap.sparkGraph2(comm.get(), boundaryGraph, maxDist); + + REQUIRE(graphMade); + + SECTION("PointMap::outputLinksAsCSV") { + std::stringstream stream; + pointMap.mergePixels(65537, 131074); + pointMap.mergePixels(131073, 65538); + pointMap.outputLinksAsCSV(stream); + + REQUIRE(stream.good()); + char line[1000]; + std::vector lines; + while( !stream.eof()) + { + stream.getline(line, 1000); + lines.push_back(line); + } + std::vector expected{ "RefFrom,RefTo", + "65537,131074", + "65538,131073"}; + REQUIRE(lines == expected); + } + + SECTION("PointMap::outputConnectionsAsCSV") { + std::stringstream stream; + pointMap.outputConnectionsAsCSV(stream); + + REQUIRE(stream.good()); + char line[1000]; + std::vector lines; + while( !stream.eof()) + { + stream.getline(line, 1000); + lines.push_back(line); + } + std::vector expected{ "RefFrom,RefTo", + "65537,131073", "65537,131074", "65537,65538", + "65538,131074", "65538,131073", "131073,131074"}; + REQUIRE(lines == expected); + } + + SECTION("PointMap::outputConnections") { + std::stringstream stream; + pointMap.outputConnections(stream); + + REQUIRE(stream.good()); + char line[1000]; + std::vector lines; + while( !stream.eof()) + { + stream.getline(line, 1000); + lines.push_back(line); + } + std::vector expected{ "#graph v1.0", + "node {", + " ref 65537", + " origin 0.5 0.5 0", + " connections [", + " 131073,", + " 131074,", + " 65538,", + " ]", + "}", + "node {", + " ref 65538", + " origin 0.5 1 0", + " connections [", + " 131074,", + " 65537,", + " 131073,", + " ]", + "}", + "node {", + " ref 131073", + " origin 1 0.5 0", + " connections [", + " 131074,", + " 65538,", + " 65537,", + " ]", + "}", + "node {", + " ref 131074", + " origin 1 1 0", + " connections [", + " 65538,", + " 65537,", + " 131073,", + " ]", + "}", + "" }; + REQUIRE(lines == expected); + } + +} +TEST_CASE("Direct pointmap linking - fully filled grid (no geometry)", "") +{ + double spacing = 0.5; + Point2f offset(0,0); // seems that this is always set to 0,0 + Point2f bottomLeft(0,0); + Point2f topRight(2,4); + int fill_type = 0; // = QDepthmapView::FULLFILL + + std::unique_ptr metaGraph(new MetaGraph("Test MetaGraph")); + metaGraph->setRegion(bottomLeft, topRight); + PointMap pointMap(metaGraph->getRegion(), metaGraph->m_drawingFiles, "Test PointMap"); + pointMap.setGrid(spacing, offset); + Point2f gridBottomLeft = pointMap.getRegion().bottom_left; + Point2f midPoint(gridBottomLeft.x + spacing * (floor(pointMap.getCols() * 0.5) + 0.5), + gridBottomLeft.y + spacing * (floor(pointMap.getRows() * 0.5) + 0.5)); + pointMap.makePoints(midPoint, fill_type); + + std::vector mergeLines; + + PixelRef bottomLeftPixel = pointMap.pixelate(bottomLeft); + PixelRef topRightPixel = pointMap.pixelate(topRight); + + // make sure pixels are not already merged + REQUIRE(!pointMap.isPixelMerged(bottomLeftPixel)); + REQUIRE(!pointMap.isPixelMerged(topRightPixel)); + + // merge + pointMap.mergePixels(bottomLeftPixel, topRightPixel); + + // make sure pixels are merged + REQUIRE(pointMap.isPixelMerged(bottomLeftPixel)); + REQUIRE(pointMap.isPixelMerged(topRightPixel)); + + SECTION ("Make sure we get the correct number of merged pixel pairs") + { + const std::vector> &pixelPairs = pointMap.getMergedPixelPairs(); + REQUIRE(pixelPairs.size() == 1); + REQUIRE(pixelPairs[0].first == bottomLeftPixel); + REQUIRE(pixelPairs[0].second == topRightPixel); + } + + SECTION ("Overwrite the pixelpair by re-merging the first pixel of the pair") + { + PixelRef aboveBottomLeftPixel = pointMap.pixelate(Point2f(bottomLeft.x, bottomLeft.y + 1)); + + // merge + pointMap.mergePixels(aboveBottomLeftPixel, topRightPixel); + + // make sure pixels are merged + REQUIRE(pointMap.isPixelMerged(aboveBottomLeftPixel)); + REQUIRE(pointMap.isPixelMerged(topRightPixel)); + + // and previous pixel is not merged any more + REQUIRE(!pointMap.isPixelMerged(bottomLeftPixel)); + + // make sure we get the correct number of merged pixel pairs + const std::vector> &pixelPairs = pointMap.getMergedPixelPairs(); + REQUIRE(pixelPairs.size() == 1); + REQUIRE(pixelPairs[0].first == aboveBottomLeftPixel); + REQUIRE(pixelPairs[0].second == topRightPixel); + } + + SECTION ("Overwrite the pixelpair by re-merging the second pixel of the pair") + { + PixelRef belowTopRightPixel = pointMap.pixelate(Point2f(topRight.x, topRight.y - 1)); + + // merge + pointMap.mergePixels(bottomLeftPixel, belowTopRightPixel); + + // make sure pixels are merged + REQUIRE(pointMap.isPixelMerged(bottomLeftPixel)); + REQUIRE(pointMap.isPixelMerged(belowTopRightPixel)); + + // and previous pixel is not merged any more + REQUIRE(!pointMap.isPixelMerged(topRightPixel)); + + // make sure we get the correct number of merged pixel pairs + const std::vector> &pixelPairs2 = pointMap.getMergedPixelPairs(); + REQUIRE(pixelPairs2.size() == 1); + REQUIRE(pixelPairs2[0].first == bottomLeftPixel); + REQUIRE(pixelPairs2[0].second == belowTopRightPixel); + } + + SECTION ("Merge the same pixel twice to erase the pair") + { + pointMap.mergePixels(bottomLeftPixel, bottomLeftPixel); + + // make sure no pixel is merged + REQUIRE(!pointMap.isPixelMerged(bottomLeftPixel)); + REQUIRE(!pointMap.isPixelMerged(topRightPixel)); + + // make sure we get the correct number of merged pixel pairs + const std::vector> &pixelPairs3 = pointMap.getMergedPixelPairs(); + REQUIRE(pixelPairs3.size() == 0); + } +} diff --git a/salaTest/testsalaprogram.cpp b/salaTest/testsalaprogram.cpp new file mode 100644 index 00000000..f7dc0839 --- /dev/null +++ b/salaTest/testsalaprogram.cpp @@ -0,0 +1,381 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "../salalib/mapconverter.h" +#include "catch.hpp" +#include "salalib/salaprogram.h" +#include "genlib/p2dpoly.h" +#include "salalib/mgraph.h" +#include "salalib/axialmap.h" +#include + +// Most of these test cases are adapted from salalib/salascript-tests.txt +// with some added for completeness + +TEST_CASE("Trivial scripts") { + + std::stringstream script; + SalaObj expected; + + SECTION("comment") { + script << "# comment\n"; + } + + SECTION("single dimension lists") { + script << "x = [1,2]\n" + << "x[1] = 10\n" + << "x[1]\n"; + expected = SalaObj(10); + } + + SECTION("multiple dimension lists") { + script << "x = [[1,2],[3,4]]\n" + << "x[0][1] = 10\n" + << "x[0][1]\n"; + expected = SalaObj(10); + } + + SECTION("range direct access") { + script << "range(5,10)[2]\n"; + expected = SalaObj(7); + } + + SECTION("list return length") { + script << "x = [1,2,3]\n" + << "len(x)\n"; + expected = SalaObj(3); + } + + SECTION("list return list") { + script << "x = [1,2,3]\n" + << "x\n"; + expected = SalaObj(SalaObj::Type::S_LIST, 3); + expected.list_at(0) = SalaObj(1); + expected.list_at(1) = SalaObj(2); + expected.list_at(2) = SalaObj(3); + } + + SECTION("2D list return length") { + script << "x = [[1,2],[3,4]]\n" + << "len(x)\n"; + expected = SalaObj(2); + } + + SECTION("2D list return list") { + script << "x = [[1,2],[3,4]]\n" + << "x\n"; + expected = SalaObj(SalaObj::Type::S_LIST, 2); + expected.list_at(0) = SalaObj(SalaObj::Type::S_LIST, 2); + expected.list_at(0).list_at(0) = SalaObj(1); + expected.list_at(0).list_at(1) = SalaObj(2); + expected.list_at(1) = SalaObj(SalaObj::Type::S_LIST, 2); + expected.list_at(1).list_at(0) = SalaObj(3); + expected.list_at(1).list_at(1) = SalaObj(4); + } + + SECTION("Pythonesque curios: lists by reference") { + script << "x = [1,2,3,4]\n" + << "y = x\n" + << "y[3] = 40\n" + << "x[3]\n"; + expected = SalaObj(40); + } + + SalaGrf graph; + SalaObj context = SalaObj(SalaObj::S_POINTMAPOBJ, graph); + SalaProgram program(context); + program.parse(script); + SalaObj result = program.evaluate(); + REQUIRE(result == expected); +} + +TEST_CASE("Trivial errors") { + + std::stringstream script; + + SECTION("simple for with error: i should be uninitialised") { + script << "x = 0\n" + << "for i in range(5,10):\n" + << " x = 1\n" + << "x = x + i\n"; + } + + SalaGrf graph; + SalaObj context = SalaObj(SalaObj::S_POINTMAPOBJ, graph); + SalaProgram program(context); + program.parse(script); + REQUIRE_THROWS_WITH(program.evaluate(), ""); + + +} + +TEST_CASE("Variables from outer scope are accessible in inner scope") { + std::stringstream script; + SalaObj expected; + SECTION("Access to global scope from within a for loop") { + script << "x = 5\n" + << "for i in range(0,1):\n" + << " x = 100\n" + << "x"; + expected = SalaObj(100); + } + + SalaGrf graph; + SalaObj context = SalaObj(SalaObj::S_POINTMAPOBJ, graph); + SalaProgram program(context); + program.parse(script); + SalaObj result = program.evaluate(); + REQUIRE(result.toInt() == expected.toInt()); +} + +TEST_CASE("Shapemap scripts") { + + const double EPSILON = 0.001; + + Point2f line1Start(0,0); + Point2f line1End (3,0); + Point2f line2Start(1,1); + Point2f line2End (1,-1); + Point2f line3Start(2,1); + Point2f line3End (2,-2); + Point2f line4Start(2,1); + Point2f line4End (4,1); + Point2f line5Start(5,3); + Point2f line5End (3,1); + + std::unique_ptr metaGraph(new MetaGraph("Test SuperSpacePixel")); + + metaGraph->m_drawingFiles.push_back(SpacePixelFile("Test SpacePixelGroup")); + metaGraph->m_drawingFiles.back().m_spacePixels.push_back(ShapeMap("Test ShapeMap")); + + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line1Start, line1End)); + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line2Start, line2End)); + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line3Start, line3End)); + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line4Start, line4End)); + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line5Start, line5End)); + + auto shapeGraph = MapConverter::convertDrawingToAxial(0, "Test axial", metaGraph->m_drawingFiles); + + + std::stringstream script; + std::vector expectedColVals; + + SECTION("pass ref to new column") { + script << "value(\"Ref Number\")\n"; + expectedColVals.push_back(0.0); + expectedColVals.push_back(1.0); + expectedColVals.push_back(2.0); + expectedColVals.push_back(3.0); + expectedColVals.push_back(4.0); + } + + SECTION("if, function of a function on a range") { + script << "x = len(range(1,value(\"Ref Number\")))\n" + << "if x == 2:\n" + << " return 5\n" + << "elif x < 1:\n" + << " return 10\n" + << "x\n" + << "# first two objects should be set to 10, next to 5, and then ref number after that;\n"; + expectedColVals.push_back(10.0); + expectedColVals.push_back(10.0); + expectedColVals.push_back(1.0); + expectedColVals.push_back(5.0); + expectedColVals.push_back(3.0); + } + + SECTION("simple if") { + script << "if value(\"Ref Number\") < 2:\n" + << " 0\n" + << "elif value(\"Ref Number\") == 3:\n" + << " 5\n" + << "else\n" + << " 10\n"; + expectedColVals.push_back(0.0); + expectedColVals.push_back(0.0); + expectedColVals.push_back(10.0); + expectedColVals.push_back(5.0); + expectedColVals.push_back(10.0); + } + + SECTION("various member functions tests") { + script << "this.value(\"Ref Number\")\n" + << " len(range(1,this.value(\"Ref Number\")))\n" + << "elif value(\"Ref Number\") == 3:\n" + << " range(1,this.value(\"Ref Number\")).length()\n"; + expectedColVals.push_back(0.0); + expectedColVals.push_back(0.0); + expectedColVals.push_back(1.0); + expectedColVals.push_back(2.0); + expectedColVals.push_back(3.0); + } + + int newCol = shapeGraph->addAttribute("NewCol"); + SalaGrf graph; + graph.map.shape = shapeGraph.get(); + SalaObj context = SalaObj(SalaObj::S_SHAPEMAPOBJ, graph); + SalaProgram program(context); + program.parse(script); + program.runupdate(newCol); + + REQUIRE(shapeGraph->getAttributeTable().getNumRows() == expectedColVals.size()); + + auto iter = expectedColVals.begin(); + auto &attributes = shapeGraph->getAttributeTable(); + for (auto rowIter = attributes.begin(); rowIter != attributes.end(); rowIter++) { + REQUIRE(rowIter->getRow().getValue(newCol) == Approx(*iter).epsilon(EPSILON)); + iter++; + } +} + +TEST_CASE("Shapemap scripts with unexpected results") { + + const double EPSILON = 0.001; + + Point2f line1Start(0,0); + Point2f line1End (3,0); + Point2f line2Start(1,1); + Point2f line2End (1,-1); + Point2f line3Start(2,1); + Point2f line3End (2,-2); + Point2f line4Start(2,1); + Point2f line4End (4,1); + Point2f line5Start(5,3); + Point2f line5End (3,1); + + std::unique_ptr metaGraph(new MetaGraph("Test SuperSpacePixel")); + + metaGraph->m_drawingFiles.push_back(SpacePixelFile("Test SpacePixelGroup")); + metaGraph->m_drawingFiles.back().m_spacePixels.push_back(ShapeMap("Test ShapeMap")); + + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line1Start, line1End)); + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line2Start, line2End)); + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line3Start, line3End)); + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line4Start, line4End)); + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line5Start, line5End)); + + auto shapeGraph = MapConverter::convertDrawingToAxial(0, "Test axial", metaGraph->m_drawingFiles); + + + std::stringstream script; + std::vector expectedColVals; + + SECTION("for with else and 0 length ranges") { + script << "int x = 0\n" + << "for i in range(2,value(\"Ref Number\")):\n" + << " x = x + i\n" + << " x\n" + << "else:\n" + << " 0\n"; + expectedColVals.push_back(0.0); + expectedColVals.push_back(0.0); + expectedColVals.push_back(0.0); + expectedColVals.push_back(2.0); + expectedColVals.push_back(5.0); + } + + SECTION("Total Depth Calculation") { + script << "total_depth = 0\n" + << "depth = 0\n" + << "pop_list = [this]\n" + << "push_list = []\n" + << "setmark(true)\n" + << "while len(pop_list):\n" + << " total_depth = total_depth + depth\n" + << " curs = pop_list.pop()\n" + << " for i in curs.connections():\n" + << " if i.mark() is none:\n" + << " i.setmark(true)\n" + << " push_list.append(i)\n" + << " if len(pop_list) == 0:\n" + << " depth = depth + 1\n" + << " pop_list = push_list\n" + << " push_list = []\n" + << "total_depth\n"; + expectedColVals.push_back(7.0); + expectedColVals.push_back(10.0); + expectedColVals.push_back(6.0); + expectedColVals.push_back(7.0); + expectedColVals.push_back(10.0); + } + + SECTION("Shortest Cycle") { + script << "push_list = []\n" + << "pop_list = []\n" + << "live_paths = []\n" + << "setmark([-1,0])\n" + << "depth = 1\n" + << "path_index = 0\n" + << "for i in connections():\n" + << " pop_list.append([path_index,i])\n" + << " live_paths.append(1)\n" + << " i.setmark([path_index,depth])\n" + << " path_index = path_index + 1\n" + << "if path_index < 2:\n" + << " return -1 # no cycle possible\n" + << "live_path_count = path_index\n" + << "while len(pop_list) and live_path_count > 1:\n" + << " curs = pop_list.pop()\n" + << " path_index = curs[0]\n" + << " this_node = curs[1]\n" + << " live_paths[path_index] = live_paths[path_index] - 1\n" + << " for i in this_node.connections():\n" + << " if i.mark() is none:\n" + << " i.setmark([path_index,depth+1])\n" + << " push_list.append([path_index,i])\n" + << " live_paths[path_index] = live_paths[path_index] + 1\n" + << " elif i.mark()[0] != path_index and i.mark()[0] != -1:\n" + << " # found a cycle!\n" + << " return i.mark()[1] + this_node.mark()[1] + 1\n" + << " if live_paths[path_index] == 0:\n" + << " live_path_count = live_path_count - 1\n" + << " if len(pop_list) == 0:\n" + << " depth = depth + 1\n" + << " pop_list = push_list\n" + << " push_list = []\n" + << "-1 # no cycle found\n"; + expectedColVals.push_back(-1.0); + expectedColVals.push_back(-1.0); + expectedColVals.push_back(-1.0); + expectedColVals.push_back(-1.0); + expectedColVals.push_back(-1.0); + } + + + + int newCol = shapeGraph->addAttribute("NewCol"); + SalaGrf graph; + graph.map.shape = shapeGraph.get(); + SalaObj context = SalaObj(SalaObj::S_SHAPEMAPOBJ, graph); + SalaProgram program(context); + program.parse(script); + program.runupdate(newCol); + + REQUIRE(shapeGraph->getAttributeTable().getNumRows() == expectedColVals.size()); + + auto iter = expectedColVals.begin(); + auto &attributes = shapeGraph->getAttributeTable(); + for (auto rowIter = attributes.begin(); rowIter != attributes.end(); rowIter++) { + REQUIRE(rowIter->getRow().getValue(newCol) == Approx(*iter).epsilon(EPSILON)); + iter++; + } +} + +TEST_CASE("Performance tests") { + //# For a graph with 100000 segments for cpu timing: + //x=value("Angular Connectivity")*value("Angular Step Depth")+value("Axial Line Ref")+value("Connectivity")/value("Segment Length")^value("T1024 Choice R1000 metric") + //y=value("T1024 Choice R3000 metric")*value("T1024 Choice R4000 metric")/value("T1024 Choice R5000 metric")^value("T1024 Total Depth [Segment Length Wgt] R4000 metric") + //y/x +} diff --git a/salaTest/testshapegraphs.cpp b/salaTest/testshapegraphs.cpp new file mode 100644 index 00000000..ca064e40 --- /dev/null +++ b/salaTest/testshapegraphs.cpp @@ -0,0 +1,163 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "../salalib/mapconverter.h" +#include "../genlib/p2dpoly.h" +#include "../salalib/mgraph.h" +#include "../salalib/shapemap.h" +#include "../salalib/axialmap.h" +#include "catch.hpp" +#include +#include + +TEST_CASE("Testing ShapeGraph::writeAxialConnections"){ + + Point2f line1Start(0,0); + Point2f line1End (3,0); + Point2f line2Start(1,1); + Point2f line2End (1,-1); + Point2f line3Start(2,1); + Point2f line3End (2,-2); + + std::unique_ptr metaGraph(new MetaGraph("Test MetaGraph")); + + metaGraph->m_drawingFiles.emplace_back("Test SpacePixelGroup"); + metaGraph->m_drawingFiles.back().m_spacePixels.emplace_back("Test ShapeMap"); + + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line1Start, line1End)); + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line2Start, line2End)); + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line3Start, line3End)); + + auto shapegraph = MapConverter::convertDrawingToAxial(0, "Test axial", metaGraph->m_drawingFiles); + + SECTION("writeAxialConnectionsAsDotGraph") { + std::stringstream stream; + shapegraph->writeAxialConnectionsAsDotGraph(stream); + + REQUIRE(stream.good()); + char line[1000]; + std::vector lines; + while( !stream.eof()) + { + stream.getline(line, 1000); + lines.push_back(line); + } + std::vector expected{ "strict graph {", " 0 -- 1", " 0 -- 2", + " 1 -- 0", " 2 -- 0", "}", "" }; + REQUIRE(lines == expected); + } + SECTION("writeAxialConnectionsAsPairsCSV") { + std::stringstream stream; + shapegraph->writeAxialConnectionsAsPairsCSV(stream); + + REQUIRE(stream.good()); + char line[1000]; + std::vector lines; + while( !stream.eof()) + { + stream.getline(line, 1000); + lines.push_back(line); + } + std::vector expected{ "refA,refB", "0,1", "0,2", "1,0", "2,0" }; + REQUIRE(lines == expected); + } +} +TEST_CASE("Testing ShapeGraph::writeSegmentConnections") +{ + // As we are converting the drawing directly to segments + // the lines need to touch, not cross + + Point2f line1Start(1,1); + Point2f line1End (1,0); + Point2f line2Start(1,0); + Point2f line2End (2,0); + Point2f line3Start(2,0); + Point2f line3End (2,2); + + std::unique_ptr metaGraph(new MetaGraph("Test MetaGraph")); + + metaGraph->m_drawingFiles.emplace_back("Test SpacePixelGroup"); + metaGraph->m_drawingFiles.back().m_spacePixels.emplace_back("Test ShapeMap"); + + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line1Start, line1End)); + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line2Start, line2End)); + metaGraph->m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(line3Start, line3End)); + + auto shapegraph = MapConverter::convertDrawingToSegment(0, "Test segment", metaGraph->m_drawingFiles); + + SECTION("writeSegmentConnectionsAsPairsCSV") { + std::stringstream stream; + shapegraph->writeSegmentConnectionsAsPairsCSV(stream); + + REQUIRE(stream.good()); + char line[1000]; + std::vector lines; + while( !stream.eof()) + { + stream.getline(line, 1000); + lines.push_back(line); + } + std::vector expected{ "refA,refB,ss_weight,for_back,dir", "0,1,1,0,1", "1,2,1,0,1", "1,0,1,1,-1", + "2,1,1,1,-1" }; + REQUIRE(lines == expected); + } +} + +// While the linking functionality is placed in the ShapeMap, +// (for example the variables m_links and m_unlinks) it can +// only be used through ShapeGraph because it starts with +// m_hasgraph = true. Ideally the linking functionality should +// move to the ShapeGraph + +TEST_CASE("Testing ShapeMap::getAllLinkLines and ShapeMap::getAllUnlinkPoints()") +{ + const float EPSILON = 0.001; + const double TOLERANCE_A = 1e-9; + Point2f line0Start (0.522, 0.424); + Point2f line0End (0.709, 1.098); + Point2f line1Start (0.897, 1.123); + Point2f line1End (1.122, 0.421); + Point2f line2Start (1.073, 0.386); + Point2f line2End (1.269, 1.196); + + std::unique_ptr shapeGraph(new ShapeGraph("Test ShapeMap")); + + shapeGraph->makeLineShape(Line(line0Start, line0End)); + shapeGraph->makeLineShape(Line(line1Start, line1End)); + shapeGraph->makeLineShape(Line(line2Start, line2End)); + + shapeGraph->makeShapeConnections(); + + shapeGraph->linkShapes(0,1); + shapeGraph->unlinkShapes(1,2); + + std::vector linkLines = shapeGraph->getAllLinkLines(); + + REQUIRE(linkLines.size() == 1); + + REQUIRE(linkLines[0].start().x == Approx((line0Start.x + line0End.x)*0.5).epsilon(EPSILON)); + REQUIRE(linkLines[0].start().y == Approx((line0Start.y + line0End.y)*0.5).epsilon(EPSILON)); + REQUIRE(linkLines[0].end().x == Approx((line1Start.x + line1End.x)*0.5).epsilon(EPSILON)); + REQUIRE(linkLines[0].end().y == Approx((line1Start.y + line1End.y)*0.5).epsilon(EPSILON)); + + std::vector unlinkPoints = shapeGraph->getAllUnlinkPoints(); + + REQUIRE(unlinkPoints.size() == 1); + + Point2f intersection = intersection_point(Line(line1Start, line1End), Line(line2Start, line2End), TOLERANCE_A); + + REQUIRE(unlinkPoints[0].x == Approx(intersection.x).epsilon(EPSILON)); + REQUIRE(unlinkPoints[0].y == Approx(intersection.y).epsilon(EPSILON)); +} diff --git a/salaTest/testshapemaps.cpp b/salaTest/testshapemaps.cpp new file mode 100644 index 00000000..43d1eba5 --- /dev/null +++ b/salaTest/testshapemaps.cpp @@ -0,0 +1,123 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "../genlib/p2dpoly.h" +#include "../salalib/mgraph.h" +#include "../salalib/shapemap.h" +#include "../salalib/axialmap.h" +#include "catch.hpp" +#include +#include + +TEST_CASE("Testing ShapeMap::getAllShapes variants") +{ + const float EPSILON = 0.001; + Point2f line0Start(0,1); + Point2f line0End (3,2); + Point2f line1Start(1,1); + Point2f line1End (1,-1); + + std::unique_ptr shapeMap(new ShapeMap("Test ShapeMap")); + + shapeMap->makeLineShape(Line(line0Start, line0End)); + shapeMap->makeLineShape(Line(line1Start, line1End)); + + std::vector polyVertices; + polyVertices.push_back(Point2f(-1,-1)); + polyVertices.push_back(Point2f( 2,-1)); + polyVertices.push_back(Point2f( 0, 0)); + + shapeMap->makePolyShape(polyVertices, false, false); + + SECTION("ShapeMap::getAllShapesAsLines") + { + std::vector lines = shapeMap->getAllShapesAsLines(); + + REQUIRE(lines.size() == 5); + + REQUIRE(lines[0].start().x == Approx(line0Start.x).epsilon(EPSILON)); + REQUIRE(lines[0].start().y == Approx(line0Start.y).epsilon(EPSILON)); + REQUIRE(lines[0].end().x == Approx(line0End.x).epsilon(EPSILON)); + REQUIRE(lines[0].end().y == Approx(line0End.y).epsilon(EPSILON)); + + REQUIRE(lines[1].start().x == Approx(line1Start.x).epsilon(EPSILON)); + REQUIRE(lines[1].start().y == Approx(line1Start.y).epsilon(EPSILON)); + REQUIRE(lines[1].end().x == Approx(line1End.x).epsilon(EPSILON)); + REQUIRE(lines[1].end().y == Approx(line1End.y).epsilon(EPSILON)); + + REQUIRE(lines[2].start().x == Approx(polyVertices[0].x).epsilon(EPSILON)); + REQUIRE(lines[2].start().y == Approx(polyVertices[0].y).epsilon(EPSILON)); + REQUIRE(lines[2].end().x == Approx(polyVertices[1].x).epsilon(EPSILON)); + REQUIRE(lines[2].end().y == Approx(polyVertices[1].y).epsilon(EPSILON)); + + REQUIRE(lines[3].start().x == Approx(polyVertices[1].x).epsilon(EPSILON)); + REQUIRE(lines[3].start().y == Approx(polyVertices[1].y).epsilon(EPSILON)); + REQUIRE(lines[3].end().x == Approx(polyVertices[2].x).epsilon(EPSILON)); + REQUIRE(lines[3].end().y == Approx(polyVertices[2].y).epsilon(EPSILON)); + + REQUIRE(lines[4].start().x == Approx(polyVertices[2].x).epsilon(EPSILON)); + REQUIRE(lines[4].start().y == Approx(polyVertices[2].y).epsilon(EPSILON)); + REQUIRE(lines[4].end().x == Approx(polyVertices[0].x).epsilon(EPSILON)); + REQUIRE(lines[4].end().y == Approx(polyVertices[0].y).epsilon(EPSILON)); + } + SECTION("ShapeMap::getAllLinesWithColour") + { + shapeMap->overrideDisplayedAttribute(-2); + shapeMap->setDisplayedAttribute(-1); // displayed attribute is shape_ref + + std::vector> colouredLines = shapeMap->getAllLinesWithColour(); + + REQUIRE(colouredLines.size() == 2); + + REQUIRE(colouredLines[0].first.start().x == Approx(std::min(line0Start.x, line0End.x)).epsilon(EPSILON)); + REQUIRE(colouredLines[0].first.start().y == Approx(std::min(line0Start.y, line0End.y)).epsilon(EPSILON)); + REQUIRE(colouredLines[0].first.end().x == Approx(std::max(line0Start.x, line0End.x)).epsilon(EPSILON)); + REQUIRE(colouredLines[0].first.end().y == Approx(std::max(line0Start.y, line0End.y)).epsilon(EPSILON)); + REQUIRE(colouredLines[0].second.redf() == Approx(0.2f).epsilon(EPSILON)); + REQUIRE(colouredLines[0].second.greenf() == Approx(0.2f).epsilon(EPSILON)); + REQUIRE(colouredLines[0].second.bluef() == Approx(0.86667f).epsilon(EPSILON)); + + REQUIRE(colouredLines[1].first.start().x == Approx(line1Start.x).epsilon(EPSILON)); + REQUIRE(colouredLines[1].first.start().y == Approx(line1Start.y).epsilon(EPSILON)); + REQUIRE(colouredLines[1].first.end().x == Approx(line1End.x).epsilon(EPSILON)); + REQUIRE(colouredLines[1].first.end().y == Approx(line1End.y).epsilon(EPSILON)); + REQUIRE(colouredLines[1].second.redf() == Approx(0.13333f).epsilon(EPSILON)); + REQUIRE(colouredLines[1].second.greenf() == Approx(0.86667f).epsilon(EPSILON)); + REQUIRE(colouredLines[1].second.bluef() == Approx(0.53333f).epsilon(EPSILON)); + } + SECTION("ShapeMap::getAllPolygonsWithColour") + { + shapeMap->overrideDisplayedAttribute(-2); + shapeMap->setDisplayedAttribute(-1); // displayed attribute is shape_ref + + std::map, PafColor> colouredPolygons = shapeMap->getAllPolygonsWithColour(); + + REQUIRE(colouredPolygons.size() == 1); + + std::map, PafColor>::const_iterator iter = colouredPolygons.begin(); + const std::vector vertices = iter->first; + const PafColor colour = iter->second; + + REQUIRE(vertices[0].x == Approx(polyVertices[0].x).epsilon(EPSILON)); + REQUIRE(vertices[0].y == Approx(polyVertices[0].y).epsilon(EPSILON)); + REQUIRE(vertices[1].x == Approx(polyVertices[1].x).epsilon(EPSILON)); + REQUIRE(vertices[1].y == Approx(polyVertices[1].y).epsilon(EPSILON)); + REQUIRE(vertices[2].x == Approx(polyVertices[2].x).epsilon(EPSILON)); + REQUIRE(vertices[2].y == Approx(polyVertices[2].y).epsilon(EPSILON)); + REQUIRE(colour.redf() == Approx(0.86667f).epsilon(EPSILON)); + REQUIRE(colour.greenf() == Approx(0.2f).epsilon(EPSILON)); + REQUIRE(colour.bluef() == Approx(0.2f).epsilon(EPSILON)); + } +} diff --git a/salaTest/testsparksieve.cpp b/salaTest/testsparksieve.cpp new file mode 100644 index 00000000..13b1dbf6 --- /dev/null +++ b/salaTest/testsparksieve.cpp @@ -0,0 +1,83 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "salalib/sparksieve2.h" +#include + + +TEST_CASE("One block garbage") +{ + Point2f centre(1,1); + sparkSieve2 sieve(centre); + std::vector lines; + // these lines get turned into "blocks" based by a tanify function based on q and the centre given + // above. Given q=4 and centre 1,1 this line will be from 0.625 to something bigger than 1 + lines.push_back(Line(Point2f(0.5, 0.2), Point2f(0.5, 0.7))); + sieve.block(lines,4); + sieve.collectgarbage(); + REQUIRE(sieve.m_gaps.size() == 1); + REQUIRE(sieve.m_gaps.begin()->start == 0); + REQUIRE(sieve.m_gaps.begin()->end == Approx(0.625)); +} + + +TEST_CASE("Shift start and end") +{ + Point2f centre(1,1); + sparkSieve2 sieve(centre); + std::vector lines; + // .625 -> > 1 + lines.push_back(Line(Point2f(0.5, 0.2), Point2f(0.5, 0.7))); + // < 0 -> 0.55555557 + lines.push_back(Line(Point2f(0.5,0.1),Point2f(1.1,0.9))); + sieve.block(lines,4); + sieve.collectgarbage(); + REQUIRE(sieve.m_gaps.size() == 1); + REQUIRE(sieve.m_gaps.begin()->start == Approx(0.55555555555)); + REQUIRE(sieve.m_gaps.begin()->end == Approx(0.625)); +} + +TEST_CASE("delete gap") +{ + Point2f centre(1,1); + sparkSieve2 sieve(centre); + std::vector lines; + // < 0 -> > 1 the block covers the whole gap + lines.push_back(Line(Point2f(1.1, 0.2), Point2f(0.5, 0.7))); + sieve.block(lines,4); + sieve.collectgarbage(); + REQUIRE(sieve.m_gaps.empty()); +} + +TEST_CASE("add gap") +{ + Point2f centre(1,1); + sparkSieve2 sieve(centre); + std::vector lines; + // 0.55555 -> .625 the block splits the gap + lines.push_back(Line(Point2f(0.5, 0.2), Point2f(0.5, 0.1))); + // 0.71428571 -> > 1 + lines.push_back(Line(Point2f(0.5,0.3), Point2f(0.5,0.7))); + sieve.block(lines,4); + sieve.collectgarbage(); + REQUIRE(sieve.m_gaps.size() == 2); + auto iter = sieve.m_gaps.begin(); + REQUIRE(iter->start == 0); + REQUIRE(iter->end == Approx(0.55555555555)); + iter++; + REQUIRE(iter->start == Approx(0.625)); + REQUIRE(iter->end == Approx( 0.71428571)); +} diff --git a/salaTest/teststructsizes.cpp b/salaTest/teststructsizes.cpp new file mode 100644 index 00000000..5cf2add8 --- /dev/null +++ b/salaTest/teststructsizes.cpp @@ -0,0 +1,32 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "catch.hpp" +#include "salalib/axialmap.h" +#include "salalib/axialpolygons.h" + +/** + * This seems a bit silly, but this is a list of structs that are serialised by just dumping the memory content + * into a stream, so the size/layout of these must be the same across all platforms to ensure + * reading writing of graph files. + */ +TEST_CASE("Enforce struct sizes") +{ + REQUIRE(sizeof(RadialKey) == 16); + REQUIRE(sizeof(RadialLine) == 64); + REQUIRE(sizeof(PolyConnector) == 56); + REQUIRE(sizeof(QtRegion) == 32); + REQUIRE(sizeof(Line) == 40); +} diff --git a/salalib/CMakeLists.txt b/salalib/CMakeLists.txt new file mode 100644 index 00000000..0ca8d68d --- /dev/null +++ b/salalib/CMakeLists.txt @@ -0,0 +1,43 @@ +set(salalib salalib) + +set(salalib_SRCS + axialmap.cpp + connector.cpp + isovist.cpp + mgraph.cpp + ngraph.cpp + pointdata.cpp + salaprogram.cpp + shapemap.cpp + spacepix.cpp + sparksieve2.cpp + entityparsing.cpp + linkutils.cpp + gridproperties.cpp + attributetable.cpp + layermanagerimpl.cpp + attributetableview.cpp + geometrygenerators.cpp + point.cpp + pafcolor.cpp + spacepixfile.cpp + alllinemap.cpp + axialminimiser.cpp + axialpolygons.cpp + tidylines.cpp + mapconverter.cpp + importutils.cpp + attributetableindex.cpp) + +add_compile_definitions(_DEPTHMAP SALALIB_LIBRARY) + +add_library(${salalib} STATIC ${salalib_SRCS} ${vgamodules_SRCS} ${axialmodules_SRCS} ${segmmodules_SRCS} ${parsers_SRCS}) + +add_subdirectory(vgamodules) +add_subdirectory(axialmodules) +add_subdirectory(segmmodules) +add_subdirectory(parsers) +add_subdirectory(agents) + + + diff --git a/salalib/MapInfoData.cpp b/salalib/MapInfoData.cpp deleted file mode 100644 index abce0913..00000000 --- a/salalib/MapInfoData.cpp +++ /dev/null @@ -1,609 +0,0 @@ -// sala - a component of the depthmapX - spatial network analysis platform -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - - - -#include -#include -#include -#include -#include "MapInfoData.h" - -/////////////////////////////////////////////////////////////////////// - -// A typical MIF - -/* -Version 300 -Charset "WindowsLatin1" -Delimiter "," -Index 1,2 -CoordSys Earth Projection 8, 79, "m", -2, 49, 0.9996012717, 400000, -100000 Bounds (-7845061.1011, -15524202.1641) (8645061.1011, 4470074.53373) -Columns 2 - ID Integer - Length_m Float -Data - -Line 534014.29 182533.33 535008.52 182764.11 - Pen (1,2,0) -Line 533798.68 183094.69 534365.48 183159.01 - Pen (1,2,0) -...etc... -Point 534014.29 182533.33 - Symbol (34,0,12) -Point 533798.68 183094.69 - Symbol (34,0,12) -Point 534365.48 183159.01 - Symbol (34,0,12) -...etc... -*/ - -// A Typical MID - -/* -1,1017.81 -2,568.795 -3,216.026 -*/ - - -/////////////////////////////////////////////////////////////////////////////////// - -int MapInfoData::import(istream& miffile, istream& midfile, ShapeMap& map) -{ - int retvar = MINFO_OK; - - // read the header... - if (!readheader(miffile)) { - return MINFO_HEADER; - } - - pvecstring columnheads; - - AttributeTable& table = map.getAttributeTable(); - - // read mif table - if (!readcolumnheaders(miffile,midfile,columnheads)) { - return MINFO_TABLE; - } - - // set up a list of readable columns from the headers: - // - pvecstring colnames; - pvecint readable, colindexes; - size_t i; - for (i = 0; i < columnheads.size(); i++) { - columnheads[i].ltrim(); - pvecstring tokens = columnheads[i].tokenize(' ',true); - if (compare(tokens[1],"Integer",7) || compare(tokens[1],"Smallint",8) || compare(tokens[1],"Decimal",7) || compare(tokens[1],"Float",5)) { - colnames.push_back(tokens[0]); - table.insertColumn(colnames.tail()); - readable.push_back(i); - } - } - - for (i = 0; i < colnames.size(); i++) { - colindexes.push_back(table.getColumnIndex(colnames[i])); - } - - pstring textline; - prefvec pointsets; - pvecint duplicates; - pvecint types; - - try { - // now read line data into the axial map - while (!miffile.eof()) { - miffile >> textline; - textline.ltrim(); - textline.makelower(); - if (textline.empty()) { - continue; - } - if (compare(textline,"point",5)) { - pvecstring tokens = textline.tokenize(' ',true); - pointsets.push_back(pvecpoint()); - types.push_back(SalaShape::SHAPE_POINT); - pointsets.tail().push_back(Point2f(tokens[1].c_double(),tokens[2].c_double())); - } - if (compare(textline,"line",4)) { - pvecstring tokens = textline.tokenize(' ',true); - pointsets.push_back(pvecpoint()); - types.push_back(SalaShape::SHAPE_LINE); - pointsets.tail().push_back(Point2f(tokens[1].c_double(),tokens[2].c_double())); - pointsets.tail().push_back(Point2f(tokens[3].c_double(),tokens[4].c_double())); - } - else if (compare(textline,"pline",5) || compare(textline,"region",6)) { - int type = compare(textline,"pline",5) ? SalaShape::SHAPE_POLY : (SalaShape::SHAPE_POLY | SalaShape::SHAPE_CLOSED); - // note: polylines, even multiple lines, are condensed into a single line - pvecstring tokens = textline.tokenize(' ',true); - int multiple = 1; - if (tokens.size() > 1) { - if (tokens[1] == "multiple") { - multiple = tokens[2].c_int(); - } - else if (type & SalaShape::SHAPE_CLOSED) { - multiple = tokens[1].c_int(); - } - // if for some reason c_int fails: - if (multiple == 0) { - multiple = 1; - } - } - for (int i = 0; i < multiple; i++) { - int count = -1; - if ((type & SalaShape::SHAPE_CLOSED) != SalaShape::SHAPE_CLOSED && tokens.size() == 2) { - // token 2 can apparently be used for count in pline rather than a newline being used... - count = tokens[1].c_int(); - } - else { - miffile >> textline; - textline.ltrim(); - count = textline.c_int(); - } - pointsets.push_back(pvecpoint()); - types.push_back(type); - for (int j = 0; j < count; j++) { - miffile >> textline; - textline.ltrim(); - pvecstring tokens = textline.tokenize(' ',true); - pointsets.tail().push_back(Point2f(tokens[0].c_double(),tokens[1].c_double())); - } - if (i != 0) { - // warn about extraneous pline data - retvar = MINFO_MULTIPLE; - duplicates.push_back(pointsets.size() - 1); - } - } - } - } - } - catch (pexception) { - // unhandled parsing exceptions return read error: - return MINFO_MIFPARSE; - } - - size_t nextduplicate = 0; - int lastrow = -1; - - QtRegion region(pointsets[0][0],pointsets[0][0]); - for (i = 0; i < pointsets.size(); i++) { - for (size_t j = 0; j < pointsets[i].size(); j++) { - region.encompass(pointsets[i][j]); - } - } - - try { - // switch lines into our format - map.init(pointsets.size(),region); - for (size_t i = 0; i < pointsets.size(); i++) { - bool open = false; - if ((types[i] & SalaShape::SHAPE_CLOSED) == 0) { - open = true; - } - map.makePolyShape(pointsets[i],open); - int row = table.getRowCount() - 1; - // - // table data entries: - if (nextduplicate < duplicates.size() && duplicates[nextduplicate] == i) { - // duplicate last row: - for (size_t i = 0; i < colindexes.size(); i++) { - table.setValue(row,colindexes[i],table.getValue(lastrow,colindexes[i])); - } - nextduplicate++; - } - else { - // read next row: - pstring line; - while (!midfile.eof() && line.empty()) { - midfile >> line; - } - if (line.empty()) { - return MINFO_OBJROWS; - } - bool instring = false; - size_t here = 0, first = 0, reading = 0, nextreadable = 0; - while (nextreadable < readable.size()) { - char next = line[here]; - if (next == '\"') { - instring = !instring; - } - here++; - if ((!instring && next == m_delimiter) || here >= line.length()) { - int length = (here < line.length()) ? here-first-1 : here-first; - pstring field = line.substr(first,length); - first = here; - if (reading == readable[nextreadable]) { - float val = (float) field.c_double(); - table.setValue(row,colindexes[nextreadable],val); - nextreadable++; - } - reading++; - } - } - } - lastrow = row; - } - } - catch (pexception) { - // unhandled parsing exceptions return read error: - return MINFO_TABLE; - } - - return retvar; -} -/* -bool MapInfoData::exportFile(ostream& miffile, ostream& midfile, const ShapeGraph& map) -{ - // if bounds has not been filled in, fill it in - if (m_bounds.empty()) { - char bounds[256]; - sprintf(bounds,"Bounds (%10f, %10f) (%10f, %10f)", map.m_region.bottom_left.x, - map.m_region.bottom_left.y, - map.m_region.top_right.x, - map.m_region.top_right.y); - m_bounds = bounds; - } - - // write the header... - writeheader(miffile); - - // write the mif table - writetable(miffile,midfile,map.m_attributes); - - miffile.precision(16); - - for (int i = 0; i < map.m_lines.size(); i++) { - miffile << "Line " << map.m_lines[i].line.start().x << " " - << map.m_lines[i].line.start().y << " " - << map.m_lines[i].line.end().x << " " - << map.m_lines[i].line.end().y << endl; - miffile << " Pen (1,2,0)" << endl; - } - - return true; -} -*/ -bool MapInfoData::exportFile(ostream& miffile, ostream& midfile, const PointMap& points) -{ - // if bounds has not been filled in, fill it in - if (m_bounds.empty()) { - char bounds[256]; - sprintf(bounds,"Bounds (%10f, %10f) (%10f, %10f)", points.m_region.bottom_left.x, - points.m_region.bottom_left.y, - points.m_region.top_right.x, - points.m_region.top_right.y); - m_bounds = bounds; - } - - // write the header... - writeheader(miffile); - - // write the mif table - writetable(miffile,midfile,points.m_attributes); - - miffile.precision(16); - - for (int i = 0; i < points.m_attributes.getRowCount(); i++) { - PixelRef pix = points.m_attributes.getRowKey(i); - Point2f p = points.depixelate(pix); - miffile << "Point " << p.x << " " << p.y << endl; - miffile << " Symbol (32,0,10)" << endl; - } - - return true; -} - -bool MapInfoData::exportFile(ostream& miffile, ostream& midfile, const ShapeMap& map) -{ - // if bounds has not been filled in, fill it in - if (m_bounds.empty()) { - char bounds[256]; - sprintf(bounds,"Bounds (%10f, %10f) (%10f, %10f)", map.getRegion().bottom_left.x, - map.getRegion().bottom_left.y, - map.getRegion().top_right.x, - map.getRegion().top_right.y); - m_bounds = bounds; - } - - // write the header... - writeheader(miffile); - - // write the mid table - writetable(miffile,midfile,map.m_attributes); - - miffile.precision(16); - - for (size_t i = 0; i < map.m_shapes.size(); i++) { - // note, attributes must align for this: - if (map.getAttributeTable().isVisible(i)) { - const SalaShape& poly = map.m_shapes[i]; - if (poly.isPoint()) { - miffile << "POINT " << poly.getPoint().x << " " << poly.getPoint().y << endl; - miffile << " SYMBOL (32,0,10)" << endl; - } - else if (poly.isLine()) { - miffile << "LINE " << poly.getLine().start().x << " " - << poly.getLine().start().y << " " - << poly.getLine().end().x << " " - << poly.getLine().end().y << endl; - miffile << " PEN (1,2,0)" << endl; - } - else if (poly.isPolyLine()) { - miffile << "PLINE" << endl; - miffile << " " << poly.size() << endl; - for (size_t k = 0; k < poly.size(); k++) { - miffile << poly[k].x << " " << poly[k].y << endl; - } - miffile << " PEN (1,2,0)" << endl; - } - else if (poly.isPolygon()) { - miffile << "REGION 1" << endl; - miffile << " " << poly.size() + 1 << endl; - for (size_t k = 0; k < poly.size(); k++) { - miffile << poly[k].x << " " << poly[k].y << endl; - } - miffile << poly[0].x << " " << poly[0].y << endl; - miffile << " PEN (1,2,0)" << endl; - miffile << " BRUSH (2,16777215,16777215)" << endl; - miffile << " CENTER " << poly.getCentroid().x << " " << poly.getCentroid().y << endl; - } - } - } - - return true; -} - -bool MapInfoData::exportPolygons(ostream& miffile, ostream& midfile, const prefvec& polygons, const QtRegion& region) -{ - // if bounds has not been filled in, fill it in - if (m_bounds.empty()) { - char bounds[256]; - sprintf(bounds,"Bounds (%10f, %10f) (%10f, %10f)", region.bottom_left.x, - region.bottom_left.y, - region.top_right.x, - region.top_right.y); - m_bounds = bounds; - } - - // write the header... - writeheader(miffile); - - // dummy attributes table: - AttributeTable attributes; - for (size_t i = 0; i < polygons.size(); i++) { - attributes.insertRow(i); - } - - // write the mid table - writetable(miffile,midfile,attributes); - - miffile.precision(16); - for (size_t j = 0; j < polygons.size(); j++) { - Point2f centre; - miffile << "QtRegion 1" << endl; - miffile << " " << polygons[j].size() + 1 << endl; - for (size_t k = 0; k < polygons[j].size(); k++) { - centre += polygons[j][k]; - miffile << polygons[j][k].x << " " << polygons[j][k].y << endl; - } - miffile << polygons[j][0].x << " " << polygons[j][0].y << endl; - miffile << " Pen (1,2,0)" << endl; - miffile << " Brush (2,16777215,16777215)" << endl; - centre /= polygons[j].size(); - miffile << " Center " << centre.x << " " << centre.y << endl; - } - - return true; -} - - -/////////////////////////////////////////////////////////////////////// - -MapInfoData::MapInfoData() -{ - m_version = "Version 300"; - m_charset = "Charset \"WindowsLatin1\""; - m_delimiter = ','; - m_index = "Index 1"; - m_coordsys = "CoordSys NonEarth Units \"m\" "; - // note: m_bounds is filled in later -} - -bool MapInfoData::readheader(istream& miffile) -{ - pstring line; - - miffile >> m_version; - miffile >> m_charset; - m_charset.makeinitcaps(); - // this should read "Charset..." but some files have delimiter straight away... - if (compare(m_charset,"Delimiter",9)) { - line = m_charset; - m_charset = "Charset \"WindowsLatin1\""; - } - else { - miffile >> line; - } - size_t index = line.findindex("\""); - if (index == paftl::npos) { - return false; - } - m_delimiter = line[index+1]; - miffile >> line; - line.makeinitcaps(); - while (compare(line,"Index",5) || compare(line,"Unique",6)) { - m_index = line; - miffile >> line; - } - - line.ltrim(); - line.makeinitcaps(); - if (compare(line,"Coordsys",8)) { - line[5] = 'S'; // set back to CoordSys - // coordsys and bounds together in one line - m_coordsys = line.splice("Bounds"); - m_bounds = pstring("Bounds") + line; - } - else { - return false; - } - - return true; -} - -bool MapInfoData::readcolumnheaders(istream& miffile, istream& midfile, pvecstring& columnheads) -{ - pstring line; - - miffile >> line; - line.makeinitcaps(); - size_t colplace = line.findindex("Columns"); - if (colplace == paftl::npos) { - return false; - } - pstring temp = line.splice(' '); - int cols = line.c_int(); - - for (int i = 0; i < cols; i++) { - miffile >> line; - line.makeinitcaps(); - columnheads.push_back(line); - } - - miffile >> line; - line.makeinitcaps(); - if (line != "Data") { - return false; - } - - return true; -} - -void MapInfoData::writeheader(ostream& miffile) -{ - miffile << m_version << endl; - miffile << m_charset << endl; - miffile << "Delimiter \"" << m_delimiter << "\"" << endl; - miffile << m_index << endl; - miffile << m_coordsys; - miffile << m_bounds << endl; -} - -// note: stopped using m_table and m_columnheads as of VERSION_MAPINFO_SHAPES -// simply hack up the table now for own purposes - -void MapInfoData::writetable(ostream& miffile, ostream& midfile, const AttributeTable& attributes) -{ - miffile << "Columns " << attributes.getColumnCount() + 1 << endl; - /* - miffile << "Columns " << m_columnheads.size() + 1 + attributes.getColumnCount() << endl; - - for (int i = 0; i < m_columnheads.size(); i++) { - miffile << m_columnheads[i] << endl; - } - */ - miffile << " Depthmap_Ref Integer" << endl; - - for (int j = 0; j < attributes.getColumnCount(); j++) { - pstring colname = attributes.getColumnName(j); - miffile << " "; - bool lastalpha = false; - for (size_t i = 0; i < colname.length(); i++) { - // get rid of any character that's not alphanumeric: - if (isalnum(colname[i])) { - miffile << colname[i]; - lastalpha = true; - } - else if (lastalpha) { - miffile << "_"; - lastalpha = false; - } - } - miffile << " Float" << endl; - } - - miffile << "Data" << endl << endl; - - for (int k = 0; k < attributes.getRowCount(); k++) { - /* - if (k < m_table.size()) { - midfile << m_table[k] << m_delimiter; - } - */ - if (attributes.isVisible(k)) { - midfile << attributes.getRowKey(k); - // note: outputRow prefixes delimiter, so no delimiter necessary first - attributes.outputRow( k, midfile, m_delimiter ); - } - } -} - -//////////////////////////////////////////////////////////////////////////////// - -istream& MapInfoData::read(istream& stream, int version) -{ - m_version.read(stream); - m_charset.read(stream); - m_delimiter = stream.get(); - m_index.read(stream); - m_coordsys.read(stream); - m_bounds.read(stream); - // - // this is no longer used: just a dummy read: - if (version < VERSION_MAPINFO_SHAPES) { - int columns, rows; - pstring temp; - pvecstring columnheads; - pvecstring table; - stream.read((char *) &columns, sizeof(int)); - for (int i = 0; i < columns; i++) { - temp.read(stream); - columnheads.push_back(temp); - } - stream.read((char *) &rows, sizeof(int)); - for (int j = 0; j < rows; j++) { - temp.read(stream); - table.push_back(temp); - } - } - - return stream; -} - -ostream& MapInfoData::write(ostream& stream) -{ - m_version.write(stream); - m_charset.write(stream); - stream.put(m_delimiter); - m_index.write(stream); - m_coordsys.write(stream); - m_bounds.write(stream); - /* - // No longer used as of VERSION_MAPINFO_SHAPES - int columns = m_columnheads.size(); - int rows = m_table.size(); - stream.write((char *)&columns, sizeof(columns)); - for (int i = 0; i < m_columnheads.size(); i++) { - m_columnheads[i].write(stream); - } - stream.write((char *)&rows, sizeof(rows)); - for (int j = 0; j < m_table.size(); j++) { - m_table[j].write(stream); - } - */ - return stream; -} diff --git a/salalib/agents/CMakeLists.txt b/salalib/agents/CMakeLists.txt new file mode 100644 index 00000000..ad85daaf --- /dev/null +++ b/salalib/agents/CMakeLists.txt @@ -0,0 +1,15 @@ +target_sources(salalib + PUBLIC + agent.h + agentprogram.h + agentset.h + agentengine.h + agentga.h + agenthelpers.h + PRIVATE + agent.cpp + agentprogram.cpp + agentset.cpp + agentengine.cpp + agentga.cpp) + diff --git a/salalib/agents/agent.cpp b/salalib/agents/agent.cpp new file mode 100644 index 00000000..f464019b --- /dev/null +++ b/salalib/agents/agent.cpp @@ -0,0 +1,745 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2019, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "agent.h" +#include "agenthelpers.h" + +Agent::Agent(AgentProgram *program, PointMap *pointmap, int output_mode) { + m_program = program; + m_pointmap = pointmap; + m_output_mode = output_mode; + m_trail_num = -1; +} + +void Agent::onInit(PixelRef node, int trail_num) { + m_node = node; + m_loc = m_pointmap->depixelate(m_node); + if (m_output_mode & OUTPUT_GATE_COUNTS) { + // see note about gates in Through vision analysis + m_gate = (m_pointmap->getPoint(node).filled()) + ? (int)m_pointmap->getAttributeTable().getRow(AttributeKey(m_node)).getValue(g_col_gate) + : -1; + } else { + m_gate = -1; + } + m_gate_encountered = false; + m_step = 0; + m_stuck = false; + m_stopped = false; + m_frame = 0; + m_target_lock = false; + m_vector = Point2f(1, 0); + + m_at_target = false; + m_at_destination = false; + + m_trail_num = trail_num; + + m_vector = onLook(true); + + m_vector.normalise(); + + m_target_pix = NoPixel; +} + +void Agent::onMove() { + m_at_target = false; + m_frame++; + if (m_program->m_destination_directed && dist(m_loc, m_destination) < 10.0) { + // reached final destination + onDestination(); + } else if ((m_program->m_sel_type & AgentProgram::SEL_TARGETTED) && + dist(m_loc, m_target) < m_pointmap->getSpacing()) { + // reached target (intermediate destination) + m_step = 0; + onTarget(); + m_vector = onLook(false); + } else if (prandomr() < (1.0 / m_program->m_steps) && !m_target_lock) { // note, on average, will change 1 in steps + m_step = 0; + m_vector = onLook(false); + /* + if (m_program->m_destination_directed) { + Point2f vec2 = m_destination - m_loc; + vec2.normalise(); + if (dot(vec2,m_vector) < 0.0) { + m_vector = onLook(false); + } + } + */ + } + if (m_stuck) { + // oops... + return; + } + // now step... + PixelRef lastnode = m_node; + onStep(); + if (m_node != lastnode && m_output_mode != OUTPUT_NOTHING) { + if (m_pointmap->getPoint(m_node).filled()) { + AttributeRow &row = m_pointmap->getAttributeTable().getRow(AttributeKey(m_node)); + if (m_output_mode & OUTPUT_COUNTS) { + row.incrValue(g_col_total_counts); + } + if (m_output_mode & OUTPUT_GATE_COUNTS) { + int obj = (int)row.getValue(g_col_gate); + if (m_gate != obj) { + m_gate = obj; + if (m_gate != -1) { + row.incrValue(g_col_gate_counts); + // actually crossed into a new gate: + m_gate_encountered = true; + } + } + } + } + } + // done. happy hamster. +} +void Agent::onDestination() { m_at_destination = true; } +void Agent::onTarget() { + m_occ_memory.a().clear(); + m_at_target = true; +} + +//////////////////////////////////////////////////////////////////// + +void Agent::onStep() { + m_stopped = false; + m_step++; + // + Point2f nextloc = m_loc + (m_pointmap->getSpacing() * m_vector); + // note: false returns unconstrained pixel: goodStep must check it is in bounds using m_pointmap->includes + PixelRef nextnode = m_pointmap->pixelate(nextloc, false); + if (nextnode != m_node) { + // quick check location is okay... + if (goodStep(nextnode)) { + m_node = nextnode; + m_loc = nextloc; + } else { + // try other nearby nodes... + if (!diagonalStep()) { + m_stopped = true; + } + } + } else { + m_loc = nextloc; + } + if (!m_stopped && m_trail_num != -1) { + m_program->m_trails[m_trail_num].push_back(Event2f(m_loc, m_program->m_steps)); + } +} +bool Agent::diagonalStep() { + Point2f vector1 = m_vector; + vector1.rotate(M_PI / 4.0); + Point2f nextloc1 = m_loc + (m_pointmap->getSpacing() * vector1); + // note: "false" does not constrain to bounds: must be checked using m_pointmap->includes before getPoint is used + PixelRef nextnode1 = m_pointmap->pixelate(nextloc1, false); + + Point2f vector2 = m_vector; + vector2.rotate(-M_PI / 4.0); + Point2f nextloc2 = m_loc + (m_pointmap->getSpacing() * vector2); + // note: "false" does not constrain to bounds: must be checked using m_pointmap->includes before getPoint is used + int nextnode2 = m_pointmap->pixelate(nextloc2, false); + + bool good = false; + if (pafrand() % 2 == 0) { + if (goodStep(nextnode1)) { + m_node = nextnode1; + m_loc = nextloc1; + good = true; + } else if (goodStep(nextnode2)) { + m_node = nextnode2; + m_loc = nextloc2; + good = true; + } + } else { + if (goodStep(nextnode2)) { + m_node = nextnode2; + m_loc = nextloc2; + good = true; + } else if (goodStep(nextnode1)) { + m_node = nextnode1; + m_loc = nextloc1; + good = true; + } + } + return good; +} +bool Agent::goodStep(PixelRef node) { + if (!m_pointmap->includes(node)) { + return false; + } + // n.b., you have to know how the nodes are labelled for this connectValue trick + PixelRef dir; + dir.x = node.x - m_node.x; + dir.y = node.y - m_node.y; + // now translate dir to correct CONNECT value + if (m_pointmap->getPoint(m_node).getGridConnections() & connectValue(dir)) { + return true; + } + + return false; +} + +////////////////////////////////////////////////////////////////////// + +// The various look algorithms + +Point2f Agent::onLook(bool wholeisovist) { + Point2f dir; + if (m_program->m_sel_type & AgentProgram::SEL_GIBSONIAN) { + dir = onGibsonianLook(wholeisovist); + } else if ((m_program->m_sel_type & AgentProgram::SEL_OCCLUSION) == AgentProgram::SEL_OCCLUSION) { + dir = onOcclusionLook(wholeisovist, m_program->m_sel_type); + } else { + switch (m_program->m_sel_type) { + case AgentProgram::SEL_STANDARD: + dir = onStandardLook(wholeisovist); + break; + case AgentProgram::SEL_LOS: + case AgentProgram::SEL_LOS_OCC: + if (m_program->m_destination_directed) { + dir = onDirectedLoSLook(wholeisovist, m_program->m_sel_type); + } else { + dir = onLoSLook(wholeisovist, m_program->m_sel_type); + } + break; + case AgentProgram::SEL_OPTIC_FLOW2: + dir = onGibsonianLook2(wholeisovist); + break; + } + } + if ((m_program->m_sel_type & AgentProgram::SEL_GIBSONIAN) && !m_stuck) { + // remember what the view looked like here, facing our new direction: + calcLoS(binfromvec(dir), false); + } + if ((m_program->m_sel_type & AgentProgram::SEL_GIBSONIAN2) && !m_stuck) { + calcLoS2(binfromvec(dir), false); + } + + return dir; +} + +Point2f Agent::onStandardLook(bool wholeisovist) { + int tarpixelate = -1; + int vbin = m_program->m_vbin; + if (wholeisovist || vbin == -1) { + vbin = 16; + } + int directionbin = 32 + binfromvec(m_vector) - vbin; + int choices = 0; + // reset for getting list, check in range: + vbin = vbin * 2 + 1; + if (vbin > 32) { + vbin = 32; + } + for (int i = 0; i < vbin; i++) { + choices += m_pointmap->getPoint(m_node).getNode().bincount((directionbin + i) % 32); + } + if (choices == 0) { + if (!wholeisovist) { + return onStandardLook(true); + } else { + m_stuck = true; + m_target = m_loc; + m_target_pix = m_node; + return Point2f(0, 0); + } + } else { + int chosen = pafrand() % choices; + Node &node = m_pointmap->getPoint(m_node).getNode(); + for (; chosen >= node.bincount(directionbin % 32); directionbin++) { + chosen -= node.bincount(directionbin % 32); + } + Bin &bin = node.bin(directionbin % 32); + bin.first(); + tarpixelate = bin.cursor(); + for (; chosen > 0; chosen--) { + bin.next(); + tarpixelate = bin.cursor(); + } + } + + m_target_pix = tarpixelate; + m_target = m_pointmap->depixelate(tarpixelate); + + return (m_target - m_loc).normalise(); +} + +// TODO: Expose this functionality to the UIs +Point2f Agent::onWeightedLook(bool wholeisovist) { + if (wholeisovist) { + // use standard targetted look instead: + return onStandardLook(true); + } + int tarpixelate = -1; + int vbin = m_program->m_vbin; + if (vbin == -1) { + vbin = 16; + } + int aheadbin = binfromvec(m_vector); + int directionbin = 32 + binfromvec(m_vector) - vbin; + std::vector weightmap; + double weight = 0.0; + // reset for getting list, check in range: + vbin = vbin * 2 + 1; + if (vbin > 32) { + vbin = 32; + } + for (int i = 0; i < vbin; i++) { + Bin &bin = m_pointmap->getPoint(m_node).getNode().bin((directionbin + i) % 32); + bin.first(); + + // Quick mod - TV +#if defined(_MSC_VER) + int node = bin.is_tail() ? -1 : bin.cursor(); +#else + int node = bin.is_tail() ? -1 : bin.cursor().x; +#endif + while (node != -1) { + weight += ((directionbin + i) % 32 == aheadbin) ? 5.0 : 1.0; + weightmap.push_back(wpair(weight, node)); + bin.next(); + // Quick mod - TV +#if defined(_MSC_VER) + node = bin.is_tail() ? -1 : bin.cursor(); +#else + node = bin.is_tail() ? -1 : bin.cursor().x; +#endif + } + } + if (weightmap.size() == 0) { + return onWeightedLook(true); + } else { + double chosen = prandomr() * weight; + for (size_t i = 0; i < weightmap.size(); i++) { + if (chosen < weightmap[i].weight) { + tarpixelate = weightmap[i].node; + break; + } + } + } + + m_target_pix = tarpixelate; + m_target = m_pointmap->depixelate(tarpixelate); + + return (m_target - m_loc).normalise(); +} + +Point2f Agent::onOcclusionLook(bool wholeisovist, int looktype) { + if (AgentProgram::SEL_OCC_MEMORY) { + m_occ_memory.flip(); + m_occ_memory.a().clear(); + } + + if (wholeisovist) { + // use standard targetted look instead: + return onStandardLook(true); + } + PixelRef tarpixelate = NoPixel; + int vbin = m_program->m_vbin; + if (vbin == -1) { + vbin = 16; + } + int directionbin = 32 + binfromvec(m_vector) - vbin; + // reset for getting list, check in range: + vbin = vbin * 2 + 1; + if (vbin > 32) { + vbin = 32; + } + if (looktype == AgentProgram::SEL_OCC_ALL) { + int choices = 0; + Node &node = m_pointmap->getPoint(m_node).getNode(); + for (int i = 0; i < vbin; i++) { + if (node.m_occlusion_bins[(directionbin + i) % 32].size()) { + choices += node.m_occlusion_bins[(directionbin + i) % 32].size(); + } + } + if (choices == 0) { + if (!wholeisovist) { + return onStandardLook(false); + } else { + m_stuck = true; + m_target_pix = m_node; + m_target = m_loc; + return Point2f(0, 0); + } + } else { + size_t chosen = pafrand() % choices; + for (; chosen >= node.m_occlusion_bins[directionbin % 32].size(); directionbin++) { + chosen -= node.m_occlusion_bins[directionbin % 32].size(); + } + tarpixelate = node.m_occlusion_bins[directionbin % 32].at(chosen); + } + } else { + int subset = 1; + if (looktype == AgentProgram::SEL_OCC_BIN45) { + subset = 3; + } else if (looktype == AgentProgram::SEL_OCC_BIN60) { + subset = 5; + } + std::vector weightmap; + double weight = 0.0; + Node &node = m_pointmap->getPoint(m_node).getNode(); + for (int i = 0; i < vbin; i += subset) { + PixelRef nigpix; + double fardist = -1.0; + for (int k = 0; k < subset; k++) { + for (size_t j = 0; j < node.m_occlusion_bins[(directionbin + i + k) % 32].size(); j++) { + PixelRef pix = node.m_occlusion_bins[(directionbin + i + k) % 32].at(j); + if (dist(pix, m_node) > fardist) { + fardist = dist(pix, m_node); + nigpix = pix; + } + } + } + if (fardist != -1.0) { + bool cont = true; + if (looktype == AgentProgram::SEL_OCC_MEMORY) { + depthmapX::addIfNotExists(m_occ_memory.a(), nigpix); + // the turn chance (pafrand() % 2) may have to be modified later... + if (!m_at_target && std::find(m_occ_memory.b().begin(), m_occ_memory.b().end(), nigpix) != + m_occ_memory.b().end()) { + cont = false; + } + } + if (cont) { + switch (looktype) { + case AgentProgram::SEL_OCC_WEIGHT_DIST: + weight += fardist; + break; + case AgentProgram::SEL_OCC_WEIGHT_ANG: + weight += (double(vbin - abs(i - vbin))); + break; + case AgentProgram::SEL_OCC_WEIGHT_DIST_ANG: + weight += fardist * (double(vbin - abs(i - vbin))); + break; + default: + weight += 1.0; + break; + } + weightmap.push_back(wpair(weight, nigpix)); + } + } + } + if (weightmap.size() == 0) { + if (!wholeisovist) { + return onStandardLook(false); + } else { + m_stuck = true; + m_target = m_loc; + return Point2f(0, 0); + } + } else { + double chosen = prandomr() * weight; + for (size_t i = 0; i < weightmap.size(); i++) { + if (chosen < weightmap[i].weight) { + tarpixelate = weightmap[i].node; + break; + } + } + } + } + + m_target_pix = tarpixelate; + m_target = m_pointmap->depixelate(tarpixelate); + + return (m_target - m_loc).normalise(); +} + +// note: LOS look uses similar weighted choice mechanism + +Point2f Agent::onLoSLook(bool wholeisovist, int look_type) { + int bbin = -1; + if (m_program->m_destination_directed) { + Point2f vec2 = m_destination - m_loc; + vec2.normalise(); + bbin = binfromvec(vec2); + } + int targetbin = -1; + int vbin = m_program->m_vbin; + if (wholeisovist || vbin == -1) { + vbin = 16; + } + int directionbin = 32 + binfromvec(m_vector) - vbin; + std::vector weightmap; + double weight = 0.0; + // reset for getting list, check in range: + vbin = vbin * 2 + 1; + if (vbin > 32) { + vbin = 32; + } + for (int i = 0; i < vbin; i++) { + double los = (look_type == AgentProgram::SEL_LOS) + ? m_pointmap->getPoint(m_node).getNode().bindistance((directionbin + i) % 32) + : m_pointmap->getPoint(m_node).getNode().occdistance((directionbin + i) % 32); + if (m_program->m_los_sqrd) { + los *= los; + } + if (m_program->m_destination_directed) { + los *= 1.0 - double(binsbetween(((directionbin + i) % 32), bbin)) / 16.0; + } + weight += los; + weightmap.push_back(wpair(weight, (directionbin + i) % 32)); + } + if (weight == 0.0) { + if (!wholeisovist) { + return onLoSLook(true, look_type); + } else { + // oops! + m_stuck = true; + return Point2f(0, 0); + } + } else { + double chosen = prandomr() * weight; + for (size_t i = 0; i < weightmap.size(); i++) { + if (chosen < weightmap[i].weight) { + targetbin = weightmap[i].node; + break; + } + } + } + + float angle = (float)anglefrombin2(targetbin); + + return Point2f(cosf(angle), sinf(angle)); +} + +Point2f Agent::onDirectedLoSLook(bool wholeisovist, int look_type) { + Point2f vec2 = m_destination - m_loc; + vec2.normalise(); + int targetbin = -1; + int vbin = m_program->m_vbin; + if (wholeisovist || vbin == -1) { + vbin = 16; + } + int directionbin = 32 + binfromvec(vec2) - vbin; + std::vector weightmap; + double weight = 0.0; + // reset for getting list, check in range: + vbin = vbin * 2 + 1; + if (vbin > 32) { + vbin = 32; + } + for (int i = 0; i < vbin; i++) { + double los = (look_type == AgentProgram::SEL_LOS) + ? m_pointmap->getPoint(m_node).getNode().bindistance((directionbin + i) % 32) + : m_pointmap->getPoint(m_node).getNode().occdistance((directionbin + i) % 32); + if (m_program->m_los_sqrd) { + los *= los; + } + weight += los; + weightmap.push_back(wpair(weight, (directionbin + i) % 32)); + } + if (weight == 0.0) { + if (!wholeisovist) { + return onLoSLook(true, look_type); + } else { + // oops! + m_stuck = true; + return Point2f(0, 0); + } + } else { + double chosen = prandomr() * weight; + for (size_t i = 0; i < weightmap.size(); i++) { + if (chosen < weightmap[i].weight) { + targetbin = weightmap[i].node; + break; + } + } + } + + float angle = (float)anglefrombin2(targetbin); + + return Point2f(cosf(angle), sinf(angle)); +} + +// Gibsonian agents record their last known information, +// and act according to their rules: + +Point2f Agent::onGibsonianLook(bool wholeisovist) { + // at start, go in any direction: + if (wholeisovist) { + return onLoSLook(true, AgentProgram::SEL_LOS); + } + // + calcLoS(binfromvec(m_vector), true); + // now, choose action according to type of agent: + int rule_choice = -1; + int dir = 0; + for (int k = 0; k < 4; k++) { + dir = onGibsonianRule(m_program->m_rule_order[k]); + if (dir != 0) { + rule_choice = m_program->m_rule_order[k]; + break; + } + } + + float angle = 0.0; + + if (rule_choice != -1) { + angle = (float)anglefrombin2((binfromvec(m_vector) + (2 * rule_choice + 1) * dir + 32) % 32); + } + + // if no rule selection made, carry on in current direction + return (rule_choice == -1) ? m_vector : Point2f(cosf(angle), sinf(angle)); +} + +int Agent::onGibsonianRule(int rule) { + int option = 0; + switch (m_program->m_sel_type) { + case AgentProgram::SEL_LENGTH: + // rule_threshold from 0 to 100m + if (m_curr_los[rule + 1] > m_program->m_rule_threshold[rule]) { + option = 0x01; + } + if (m_curr_los[rule + 5] > m_program->m_rule_threshold[rule]) { + option |= 0x10; + } + break; + case AgentProgram::SEL_OPTIC_FLOW: + // rule_threshold reflects from 0x (0) to 5x (100.0) + if ((m_curr_los[rule + 1] + 1) / (m_last_los[rule + 1] + 1) > m_program->m_rule_threshold[rule] / 20.0) { + option = 0x01; + } + if ((m_curr_los[rule + 5] + 1) / (m_last_los[rule + 5] + 1) > m_program->m_rule_threshold[rule] / 20.0) { + option |= 0x10; + } + break; + case AgentProgram::SEL_COMPARATIVE_LENGTH: + // rule_threshold reflects from 0x (0) to 10x (100.0) + if ((m_curr_los[rule + 1] + 1) / (m_curr_los[0] + 1) > m_program->m_rule_threshold[rule] / 10.0) { + option = 0x01; + } + if ((m_curr_los[rule + 5] + 1) / (m_curr_los[0] + 1) > m_program->m_rule_threshold[rule] / 10.0) { + option |= 0x10; + } + break; + case AgentProgram::SEL_COMPARATIVE_OPTIC_FLOW: + // rule_threshold reflects from 0x (0) to 10x (100.0) + if ((m_curr_los[rule + 1] * m_last_los[0] + 1) / (m_last_los[rule + 1] * m_curr_los[0] + 1) > + m_program->m_rule_threshold[rule] / 10.0) { + option = 0x01; + } + if ((m_curr_los[rule + 5] * m_last_los[0] + 1) / (m_last_los[rule + 5] * m_curr_los[0] + 1) > + m_program->m_rule_threshold[rule] / 10.0) { + option |= 0x10; + } + break; + } + int dir = 0; + if (option == 0x01 && m_program->m_rule_probability[0] > prandomr()) { + dir = -1; + } else if (option == 0x10 && m_program->m_rule_probability[0] > prandomr()) { + dir = +1; + } else if (option == 0x11 && m_program->m_rule_probability[0] > prandomr() * prandomr()) { + // note, use random * random event as there are two ways to do this + dir = (rand() % 2) ? -1 : +1; + } + return dir; +} + +Point2f Agent::onGibsonianLook2(bool wholeisovist) { + // at start, go in any direction: + if (wholeisovist) { + return onLoSLook(true, AgentProgram::SEL_LOS); + } + // + calcLoS2(binfromvec(m_vector), true); + int maxbin = 0; + /* + // first action: adjust to longest line of sight + if (m_curr_los[3] > m_curr_los[0]) { + maxbin = -m_program->m_vahead; + if (m_curr_los[4] > m_curr_los[0] && (pafrand() % 2)) { + maxbin = m_program->m_vahead; + } + } + else if (m_curr_los[4] > m_curr_los[0]) { + maxbin = m_program->m_vahead; + } + */ + // second action, apply feeler rule: + char dir = 0x00; + if ((m_curr_los[1] - m_last_los[1]) / m_curr_los[1] > m_program->m_feeler_threshold) { + dir |= 0x01; + } + if ((m_curr_los[2] - m_last_los[2]) / m_curr_los[2] > m_program->m_feeler_threshold) { + dir |= 0x10; + } + if (dir == 0x01 && m_program->m_feeler_probability > prandomr()) { + maxbin = -m_program->m_vbin; + } else if (dir == 0x10 && m_program->m_feeler_probability > prandomr()) { + maxbin = m_program->m_vbin; + } else if (dir == 0x11 && m_program->m_feeler_probability > prandomr() * prandomr()) { + maxbin = (pafrand() % 2) ? m_program->m_vbin : -m_program->m_vbin; + } + // third action: detect heading for dead-end + if (maxbin == 0 && (m_curr_los[0] / m_pointmap->getSpacing() < m_program->m_ahead_threshold)) { + if (m_curr_los[1] >= m_curr_los[2]) { + maxbin = -m_program->m_vbin; + } else { + maxbin = m_program->m_vbin; + } + } + + int bin = binfromvec(m_vector) + maxbin; + float angle = (float)anglefrombin2(bin); + + return (maxbin == 0) ? m_vector : Point2f(cosf(angle), sinf(angle)); +} + +void Agent::calcLoS(int directionbin, bool curr) { + float *los; + if (curr) { + los = m_curr_los; + } else { + los = m_last_los; + } + Node &node = m_pointmap->getPoint(m_node).getNode(); + // ahead + los[0] = node.bindistance(directionbin % 32); + // directions: + int count = 1; + for (int i = 1; i <= 7; i += 2) { + los[count] = node.bindistance((directionbin - i + 32) % 32); + count++; + } + for (int j = 1; j <= 7; j += 2) { + los[count] = node.bindistance((directionbin + j) % 32); + count++; + } +} + +void Agent::calcLoS2(int directionbin, bool curr) { + float *los; + if (curr) { + los = m_curr_los; + } else { + los = m_last_los; + } + Node &node = m_pointmap->getPoint(m_node).getNode(); + // ahead + los[0] = node.bindistance(directionbin % 32); + // directions: + los[1] = node.bindistance((directionbin - m_program->m_vbin + 32) % 32); + los[2] = node.bindistance((directionbin + m_program->m_vbin) % 32); + // + los[3] = node.bindistance((directionbin - m_program->m_vahead + 32) % 32); + los[4] = node.bindistance((directionbin + m_program->m_vahead) % 32); +} diff --git a/salalib/agents/agent.h b/salalib/agents/agent.h new file mode 100644 index 00000000..eb3d0126 --- /dev/null +++ b/salalib/agents/agent.h @@ -0,0 +1,139 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2019, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "agentprogram.h" + +#include "salalib/pixelref.h" +#include "salalib/pointdata.h" + +#include "genlib/p2dpoly.h" +#include "genlib/pflipper.h" + +class Agent { + public: + enum { OUTPUT_NOTHING = 0x00, OUTPUT_COUNTS = 0x01, OUTPUT_GATE_COUNTS = 0x02, OUTPUT_TRAILS = 0x04 }; + + protected: + AgentProgram *m_program; + PointMap *m_pointmap; + // + PixelRef m_node; + int m_step; + int m_frame; + int m_gate; + bool m_stuck; + bool m_stopped; + bool m_target_lock; + bool m_gate_encountered; + bool m_at_target; + bool m_at_destination; + int m_output_mode; + Point2f m_loc; + Point2f m_target; + Point2f m_vector; + PixelRef m_target_pix; + // a long term goal: + Point2f m_destination; + // + // for recording trails: + int m_trail_num; + // + // for occlusion memory + pflipper m_occ_memory; + // + // extra memory of last observed values for Gibsonian agents: + float m_last_los[9]; + float m_curr_los[9]; + + public: + Agent() { + m_program = NULL; + m_pointmap = NULL; + m_output_mode = OUTPUT_NOTHING; + } + Agent(AgentProgram *program, PointMap *pointmap, int output_mode = OUTPUT_NOTHING); + void onInit(PixelRef node, int trail_num = -1); + void onClose(); + Point2f onLook(bool wholeisovist); + Point2f onStandardLook(bool wholeisovist); + Point2f onWeightedLook(bool wholeisovist); + Point2f onOcclusionLook(bool wholeisovist, int looktype); + Point2f onLoSLook(bool wholeisovist, int look_type); + Point2f onDirectedLoSLook(bool wholeisovist, int look_type); + Point2f onGibsonianLook(bool wholeisovist); + Point2f onGibsonianLook2(bool wholeisovist); + int onGibsonianRule(int rule); + void calcLoS(int directionbin, bool curr); + void calcLoS2(int directionbin, bool curr); + void onMove(); + void onTarget(); + void onDestination(); + void onStep(); + bool diagonalStep(); + bool goodStep(PixelRef node); + bool gateEncountered() { return m_gate_encountered; } + const Point2f &getLoc() const { return m_loc; } + // + bool atTarget() const { return m_at_target; } + bool atDestination() const { return m_at_destination; } + // + const Point2f &getLocation() const { return m_loc; } + const Point2f &getVector() const { return m_vector; } + const PixelRef getNode() const { return m_node; } + int getFrame() const { return m_frame; } + const PointMap &getPointMap() const { return *m_pointmap; } +}; + +// note the add 0.5 means angles from e.g., -1/32 to 1/32 are in bin 0 +inline int binfromvec(const Point2f &p) { return int(32.0 * (0.5 * p.angle() / M_PI) + 0.5); } + +// a random angle based on a bin direction +inline double anglefrombin2(int here) { return (2.0 * M_PI) * ((double(here) - 0.5) / 32.0 + prandom() / 32.0); } + +inline int binsbetween(int bin1, int bin2) { + int b = abs(bin1 - bin2); + if (b > 16) { + b = 32 - b; + } + return b; +} + +// weighting +struct wpair { + double weight; + int node; + wpair(double w = 0.0, int n = -1) { + weight = w; + node = n; + } +}; + +// convert an x / y difference to it's corresponding connection direction +inline char connectValue(PixelRef dir) { + if (dir.y > 0) { + return (Point::CONNECT_NE << (1 - dir.x)); + } else if (dir.y < 0) { + return (Point::CONNECT_SW << (dir.x + 1)); + } else if (dir.x == 1) { + return (char)Point::CONNECT_E; + } else { + return (char)Point::CONNECT_W; + } +} diff --git a/salalib/agents/agentengine.cpp b/salalib/agents/agentengine.cpp new file mode 100644 index 00000000..f80b39e0 --- /dev/null +++ b/salalib/agents/agentengine.cpp @@ -0,0 +1,113 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2019, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "agentengine.h" +#include "agenthelpers.h" + +// run one agent engine only + +AgentEngine::AgentEngine() { + m_timesteps = 5000; + m_gatelayer = -1; + m_record_trails = false; +} + +void AgentEngine::run(Communicator *comm, PointMap *pointmap) { + for (auto &agentSet : agentSets) { + if (agentSet.m_sel_type == AgentProgram::SEL_LOS_OCC) { + pointmap->requireIsovistAnalysis(); + } + } + time_t atime = 0; + if (comm) { + qtimer(atime, 0); + comm->CommPostMessage(Communicator::NUM_RECORDS, m_timesteps); + } + + AttributeTable &table = pointmap->getAttributeTable(); + int displaycol = table.getOrInsertColumn(g_col_total_counts); + + int output_mode = Agent::OUTPUT_COUNTS; + if (m_gatelayer != -1) { + output_mode |= Agent::OUTPUT_GATE_COUNTS; + } + + int trail_num = -1; + if (m_record_trails) { + if (m_trail_count < 1) { + m_trail_count = 1; + } + for (auto& agentSet: agentSets) { + agentSet.m_trails = std::vector>(m_trail_count); + } + trail_num = 0; + } + + // remove any agents that are left from a previous run + for (auto &agentSet : agentSets) { + agentSet.agents.clear(); + } + + for (int i = 0; i < m_timesteps; i++) { + for (auto &agentSet : agentSets) { + int q = invcumpoisson(prandomr(), agentSet.m_release_rate); + int length = agentSet.agents.size(); + int k; + for (k = 0; k < q; k++) { + agentSet.agents.push_back(Agent(&(agentSet), pointmap, output_mode)); + } + for (k = 0; k < q; k++) { + agentSet.init(length + k, trail_num); + if (trail_num != -1) { + trail_num++; + // after trail count, stop recording: + if (trail_num == m_trail_count) { + trail_num = -1; + } + } + } + } + + for (auto &agentSet : agentSets) { + agentSet.move(); + } + + if (comm) { + if (qtimer(atime, 500)) { + if (comm->IsCancelled()) { + throw Communicator::CancelledException(); + } + comm->CommPostMessage(Communicator::CURRENT_RECORD, i); + } + } + } + + pointmap->overrideDisplayedAttribute(-2); + pointmap->setDisplayedAttribute(displaycol); +} + +void AgentEngine::insertTrailsInMap(ShapeMap& trailsMap) { + for (auto &agentSet : agentSets) { + // there is currently only one AgentSet. If at any point there are more then + // this could be amended to put the AgentSet id as a property of the trail + for (auto &trail : agentSet.m_trails) { + std::vector trailGeometry(trail.begin(), trail.end()); + trailsMap.makePolyShape(trailGeometry, true, false); + } + } +} diff --git a/salalib/agents/agentengine.h b/salalib/agents/agentengine.h new file mode 100644 index 00000000..8234454f --- /dev/null +++ b/salalib/agents/agentengine.h @@ -0,0 +1,37 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2019, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "agentset.h" + +class AgentEngine { + public: // public for now for speed + std::vector agentSets; + int m_gatelayer; + int m_timesteps; + + public: + bool m_record_trails; + int m_trail_count = 50; + + public: + AgentEngine(); + void run(Communicator *comm, PointMap *pointmap); + void insertTrailsInMap(ShapeMap& trailsMap); +}; diff --git a/salalib/agents/agentga.cpp b/salalib/agents/agentga.cpp new file mode 100644 index 00000000..31fb7eae --- /dev/null +++ b/salalib/agents/agentga.cpp @@ -0,0 +1,61 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2019, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "agentga.h" + +#include "genlib/pafmath.h" + +int thisrun = 0; + +/////////////////////////////////////////////////////////////////////////////////////////////// + +static int rankselect(int popsize) { + int num = int(prandom() * popsize * (popsize + 1) * 0.5); + for (int i = 0; i < popsize; i++) { + if (num < (popsize - i)) { + return i; + } + num -= (popsize - i); + } + return 0; // <- this shouldn't happen +} + +// note: this is tested and right: higher fitness, lower rank (so population[0] is best) +int progcompare(const void *a, const void *b) { + double test = (((AgentProgram *)a)->m_fitness - ((AgentProgram *)b)->m_fitness); + if (test < 0.0) { + return 1; + } else if (test > 0.0) { + return -1; + } + return 0; +} + +AgentProgram *ProgramPopulation::makeChild() { + int a = rankselect(POPSIZE); + int b = rankselect(POPSIZE); + while (a == b) + b = rankselect(POPSIZE); + m_population[POPSIZE - 1] = crossover(m_population[a], m_population[b]); + m_population[POPSIZE - 1].mutate(); + + return &(m_population[POPSIZE - 1]); +} + +// note: this is correct -- do not use &m_population! +void ProgramPopulation::sort() { qsort(m_population, POPSIZE, sizeof(AgentProgram), progcompare); } diff --git a/salalib/agents/agentga.h b/salalib/agents/agentga.h new file mode 100644 index 00000000..931a87e0 --- /dev/null +++ b/salalib/agents/agentga.h @@ -0,0 +1,40 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2019, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "agentprogram.h" + +const int POPSIZE = 500; +// redo ASSAYs -- assaysize * assays (3 * 200 = 600 evaluations total) +// then take mean fitness: due to large variation in fitnesses with +// short assays such as this +const int ASSAYS = 3; +const int ASSAYSIZE = 25000; +const int GENERATIONS = 10000; +const int TIMESTEPS = 1600; + +struct ProgramPopulation { + public: + AgentProgram m_population[POPSIZE]; + + public: + ProgramPopulation() {} + AgentProgram *makeChild(); + void sort(); +}; diff --git a/salalib/agents/agenthelpers.h b/salalib/agents/agenthelpers.h new file mode 100644 index 00000000..cccb68a4 --- /dev/null +++ b/salalib/agents/agenthelpers.h @@ -0,0 +1,23 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2019, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +const static std::string g_col_total_counts = "Gate Counts"; +const static std::string g_col_gate_counts = "__Internal_Gate_Counts"; +const static std::string g_col_gate = "__Internal_Gate"; diff --git a/salalib/agents/agentprogram.cpp b/salalib/agents/agentprogram.cpp new file mode 100644 index 00000000..229b93c2 --- /dev/null +++ b/salalib/agents/agentprogram.cpp @@ -0,0 +1,255 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2019, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "agentprogram.h" + +#include "genlib/pafmath.h" +#include "genlib/stringutils.h" + +#include + +AgentProgram::AgentProgram() { + m_sel_type = SEL_LOS; + m_steps = 3; + m_vbin = 7; + m_destination_directed = false; + m_los_sqrd = false; +} + +void AgentProgram::mutate() { + // do mutate rule order occassionally: + if (pafrand() % 20 == 0) { + // rule order relies on putting rules into slots: + for (int i = 0; i < 4; i++) { + m_rule_order[i] = -1; + } + for (int j = 0; j < 4; j++) { + int choice = pafrand() % (4 - j); + for (int k = 0; k < choice + 1; k++) { + if (m_rule_order[k] != -1) { + choice++; + } + } + m_rule_order[choice] = j; + } + } + // mutate the rule threshold / probabilities + for (int i = 0; i < 4; i++) { + if (pafrand() % 20 == 0) { // 5% mutation rate + m_rule_threshold[i] = float(prandom() * 100.0); + } + if (pafrand() % 20 == 0) { // 5% mutation rate + m_rule_probability[i] = float(prandom()); + } + } +} + +AgentProgram crossover(const AgentProgram &prog_a, const AgentProgram &prog_b) { + AgentProgram child; + + // either one rule priority order or the other (don't try to mix!) + if (pafrand() % 2) { + for (int i = 0; i < 4; i++) { + child.m_rule_order[i] = prog_a.m_rule_order[i]; + } + } else { + for (int i = 0; i < 4; i++) { + child.m_rule_order[i] = prog_b.m_rule_order[i]; + } + } + // for each rule, either one rule threshold / probability or the other: + for (int i = 0; i < 4; i++) { + if (pafrand() % 2) { + child.m_rule_threshold[i] = prog_a.m_rule_threshold[i]; + } else { + child.m_rule_threshold[i] = prog_b.m_rule_threshold[i]; + } + if (pafrand() % 2) { + child.m_rule_probability[i] = prog_a.m_rule_probability[i]; + } else { + child.m_rule_probability[i] = prog_b.m_rule_probability[i]; + } + } + + return child; +} + +// TODO: Expose this functionality to the UIs +void AgentProgram::save(const std::string &filename) { + // standard ascii: + std::ofstream file(filename.c_str()); + + file << "Destination selection: "; + switch (m_sel_type) { + case SEL_STANDARD: + file << "Standard" << std::endl; + break; + case SEL_LENGTH: + file << "Gibsonian Length" << std::endl; + break; + case SEL_OPTIC_FLOW: + file << "Gibsonian Optic Flow" << std::endl; + break; + case SEL_COMPARATIVE_LENGTH: + file << "Gibsonian Comparative Length" << std::endl; + break; + case SEL_COMPARATIVE_OPTIC_FLOW: + file << "Gibsonian Comparative Optic Flow" << std::endl; + break; + default: + file << "Unknown" << std::endl; + } + + file << "Steps: " << m_steps << std::endl; + file << "Bins: " << ((m_vbin == -1) ? 32 : m_vbin * 2 + 1) << std::endl; + file << "Rule order: " << m_rule_order[0] << " " << m_rule_order[1] << " " << m_rule_order[2] << " " + << m_rule_order[3] << std::endl; + + for (int i = 0; i < 4; i++) { + file << "Rule " << i << " (Bin -" << 1 + (i * 2) << "/+" << 1 + (i * 2) << ")" << std::endl; + file << "Threshold: " << m_rule_threshold[i] << std::endl; + file << "Turn Probability: " << m_rule_probability[i] << std::endl; + } + + file << "Fitness: " << m_fitness << std::endl; +} + +bool AgentProgram::open(const std::string &filename) { + // standard ascii: + std::ifstream file(filename.c_str()); + + std::string line; + file >> line; + if (!line.empty()) { + dXstring::toLower(line); + if (line.substr(0, 22) != "destination selection:") { + return false; + } else { + std::string method = line.substr(22); + dXstring::ltrim(method); + if (!method.empty()) { + if (method == "standard") { + m_sel_type = SEL_STANDARD; + } else if (method == "gibsonian length") { + m_sel_type = SEL_LENGTH; + } else if (method == "gibsonian optic flow") { + m_sel_type = SEL_OPTIC_FLOW; + } else if (method == "gibsonian comparative length") { + m_sel_type = SEL_COMPARATIVE_LENGTH; + } else if (method == "gibsonian comparative optic flow") { + m_sel_type = SEL_COMPARATIVE_OPTIC_FLOW; + } + file >> line; + } else { + return false; + } + } + } else { + return false; + } + + bool foundsteps = false; + bool foundbins = false; + + if (!line.empty()) { + dXstring::toLower(line); + if (line.substr(0, 6) == "steps:") { + std::string steps = line.substr(6); + dXstring::ltrim(steps); + m_steps = stoi(steps); + file >> line; + foundsteps = true; + } + } else { + return false; + } + + if (!line.empty()) { + dXstring::toLower(line); + if (line.substr(0, 5) == "bins:") { + std::string bins = line.substr(6); + dXstring::ltrim(bins); + int binx = stoi(bins); + if (binx == 32) { + m_vbin = -1; + } else { + m_vbin = (atoi(bins.c_str()) - 1) / 2; + } + file >> line; + foundbins = true; + } + } + + if (m_sel_type == SEL_STANDARD) { + if (foundbins && foundsteps) { + return true; + } else { + return false; + } + } + + if (!line.empty()) { + dXstring::toLower(line); + if (line.substr(0, 11) == "rule order:") { + std::string ruleorder = line.substr(11); + dXstring::ltrim(ruleorder); + auto orders = dXstring::split(ruleorder, ' '); + if (orders.size() != 4) { + return false; + } + for (int i = 0; i < 4; i++) { + m_rule_order[i] = stoi(orders[i]); + } + file >> line; + } else { + return false; + } + } else { + return false; + } + for (int i = 0; i < 4; i++) { + if (!line.empty()) { + dXstring::toLower(line); + if (line.substr(0, 4) == "rule") { + file >> line; + } + dXstring::toLower(line); + if (line.substr(0, 10) == "threshold:") { + auto threshold = line.substr(10); + dXstring::ltrim(threshold); + m_rule_threshold[i] = stof(threshold); + file >> line; + } else { + return false; + } + dXstring::toLower(line); + if (line.substr(0, 17) == "turn probability:") { + auto prob = line.substr(17); + dXstring::ltrim(prob); + m_rule_probability[i] = stof(prob); + file >> line; + } else { + return false; + } + } else { + return false; + } + } + + return true; +} diff --git a/salalib/agents/agentprogram.h b/salalib/agents/agentprogram.h new file mode 100644 index 00000000..ea16bd45 --- /dev/null +++ b/salalib/agents/agentprogram.h @@ -0,0 +1,79 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2019, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "genlib/p2dpoly.h" + +#include + +struct AgentProgram { + // comparative is comparative with current heading + enum { + SEL_LOS = 0x0001, + SEL_LOS_OCC = 0x0002, + SEL_TARGETTED = 0x1000, + SEL_STANDARD = 0x1001, + SEL_WEIGHTED = 0x1002, + SEL_GIBSONIAN = 0x2000, + SEL_LENGTH = 0x2001, + SEL_OPTIC_FLOW = 0x2002, + SEL_COMPARATIVE_LENGTH = 0x2003, + SEL_COMPARATIVE_OPTIC_FLOW = 0x2004, + SEL_GIBSONIAN2 = 0x4000, + SEL_OPTIC_FLOW2 = 0x4001, + SEL_OCCLUSION = 0x9000, + SEL_OCC_ALL = 0x9001, + SEL_OCC_BIN45 = 0x9002, + SEL_OCC_BIN60 = 0x9003, + SEL_OCC_STANDARD = 0x9004, + SEL_OCC_WEIGHT_DIST = 0x9005, + SEL_OCC_WEIGHT_ANG = 0x9006, + SEL_OCC_WEIGHT_DIST_ANG = 0x9007, + SEL_OCC_MEMORY = 0x9008 + }; + int m_sel_type; + int m_steps; + int m_vbin; + // these three variables for evolved Gibsonian agents: + int m_rule_order[4]; + float m_rule_threshold[4]; + float m_rule_probability[4]; + // these are for optic flow 2 agents + int m_vahead; // how wide your ahead vision is + float m_ahead_threshold; // will turn if neg flow greater than this threshold (set in range 1/100 to 1) + float m_feeler_threshold; // will turn if flow greater than this threshold (set in range 1 to 5) + float m_feeler_probability; // turn with this much probability if a feeler triggers + // + // simple long range destinations: + bool m_destination_directed; + bool m_los_sqrd; + // + // if it is going to evolved, then have it remember its fitness: + double m_fitness; + // + AgentProgram(); + // + // for evolution + void mutate(); + friend AgentProgram crossover(const AgentProgram &prog_a, const AgentProgram &prog_b); + // to reload later: + void save(const std::string &filename); + bool open(const std::string &filename); + std::vector> m_trails; +}; diff --git a/salalib/agents/agentset.cpp b/salalib/agents/agentset.cpp new file mode 100644 index 00000000..4a178c3f --- /dev/null +++ b/salalib/agents/agentset.cpp @@ -0,0 +1,50 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2019, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "agentset.h" + +#include "salalib/pixelref.h" + +AgentSet::AgentSet() { + m_release_rate = 0.1; + m_lifetime = 1000; +} + +void AgentSet::init(int agent, int trail_num) { + if (m_release_locations.size()) { + int which = pafrand() % m_release_locations.size(); + agents[agent].onInit(m_release_locations[which], trail_num); + } else { + const PointMap &map = agents[agent].getPointMap(); + PixelRef pix; + do { + pix = map.pickPixel(prandom(m_release_locations_seed)); + } while (!map.getPoint(pix).filled()); + agents[agent].onInit(pix, trail_num); + } +} + +void AgentSet::move() { + // go through backwards so remove does not affect later agents + for (auto rev_iter = agents.rbegin(); rev_iter != agents.rend(); ++rev_iter) { + rev_iter->onMove(); + if (rev_iter->getFrame() >= m_lifetime) { + agents.erase(std::next(rev_iter).base()); + } + } +} diff --git a/salalib/agents/agentset.h b/salalib/agents/agentset.h new file mode 100644 index 00000000..116799ff --- /dev/null +++ b/salalib/agents/agentset.h @@ -0,0 +1,33 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2019, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "agent.h" +#include "agentprogram.h" + +struct AgentSet : public AgentProgram { + std::vector agents; + std::vector m_release_locations; + int m_release_locations_seed = 0; + double m_release_rate; + int m_lifetime; + AgentSet(); + void move(); + void init(int agent, int trail_num = -1); +}; diff --git a/salalib/alllinemap.cpp b/salalib/alllinemap.cpp new file mode 100644 index 00000000..242dfef9 --- /dev/null +++ b/salalib/alllinemap.cpp @@ -0,0 +1,356 @@ +#include "alllinemap.h" +#include "salalib/axialminimiser.h" +#include "salalib/tolerances.h" +#include "genlib/exceptions.h" +#include +#include + +AllLineMap::AllLineMap(Communicator *comm, + std::vector &drawingLayers, + const Point2f& seed, + const std::string& name): + ShapeGraph(name, ShapeMap::ALLLINEMAP) +{ + if (comm) { + comm->CommPostMessage( Communicator::NUM_STEPS, 3 ); + comm->CommPostMessage( Communicator::CURRENT_STEP, 1 ); + } + // this has a nasty habit of crashing if reused... + // reset everything at the top level, including any existing all-line map: + m_polygons.clear(); + m_poly_connections.clear(); + m_radial_lines.clear(); + + // starting off... finding a polygon... + // for ease, I'm just going to make a construction line set from all the visible lines... + + QtRegion region; + + std::vector lines; + + // add all visible layers to the set of polygon lines... + for (const auto& pixelGroup: drawingLayers) { + for (const auto& pixel: pixelGroup.m_spacePixels) { + if (pixel.isShown()) { + if (region.atZero()) { + region = pixel.getRegion(); + } + else { + region = runion(region, pixel.getRegion()); + } + std::vector newLines = pixel.getAllShapesAsLines(); + for (const auto& line: newLines) { + lines.push_back(Line(line.start(), line.end())); + } + } + } + } + + region.grow(1.30); + m_polygons.init(lines, region); + m_polygons.m_handled_list.clear(); + + // find a corner visible from the seed: + AxialVertexKey seedvertex = m_polygons.seedVertex( seed ); + + if (seedvertex == NoVertex) { + // oops... can't find a visible vertex + throw depthmapX::RuntimeException("No visible vertices found"); + } + + // okay, we've got as far as finding a seed corner, now the real fun begins... + // test outwards from corner, add other corners to + // test set... + std::vector axiallines; + KeyVertices preaxialdata; + // also poly_connections used in fewest line axial map construction: + m_poly_connections.clear(); + m_radial_lines.clear(); + + AxialVertex vertex = m_polygons.makeVertex(seedvertex, seed); + if (!vertex.m_initialised) { + // oops... can't init for some reason + throw depthmapX::RuntimeException("Failed to initialise axial vertices"); + } + + + time_t atime = 0; + int count = 0; + if (comm) { + qtimer( atime, 0 ); + comm->CommPostMessage( Communicator::CURRENT_STEP, 2 ); + comm->CommPostMessage( Communicator::NUM_RECORDS, m_polygons.m_vertex_possibles.size() ); + } + + std::set openvertices; + openvertices.insert(vertex); + while (!openvertices.empty()) { + m_polygons.makeAxialLines(openvertices, axiallines, preaxialdata, m_poly_connections, m_radial_lines); + count++; + // + if (comm) { + if (qtimer( atime, 500 )) { + if (comm->IsCancelled()) { + throw Communicator::CancelledException(); + } + comm->CommPostMessage( Communicator::CURRENT_RECORD, count ); + } + } + + } + + if (comm) { + comm->CommPostMessage( Communicator::CURRENT_STEP, 3 ); + comm->CommPostMessage( Communicator::CURRENT_RECORD, 0 ); + } + + // cut out duplicates: + int removed = 0; // for testing purposes + for (size_t j = 0; j < axiallines.size(); j++) { + for (size_t k = axiallines.size() - 1; k > j; k--) { + double maxdim = __max(region.width(),region.height()); + if (approxeq(axiallines[j].start(), axiallines[k].start(), maxdim * TOLERANCE_B) && approxeq(axiallines[j].end(), axiallines[k].end(), maxdim * TOLERANCE_B)) { + for (int preaxiali: preaxialdata[k]) { + preaxialdata[j].insert(preaxiali); + } + preaxialdata.erase(preaxialdata.begin() + int(k)); + axiallines.erase(axiallines.begin() + int(k)); + removed++; + } + } + } + + region.grow(0.99); // <- this paired with crop code below to prevent error + init(axiallines.size(), m_polygons.getRegion()); // used to be double density here + initialiseAttributesAxial(); + for (size_t k = 0; k < axiallines.size(); k++) { + axiallines[k].crop(region); // <- should be cropped anyway, but causing an error + makeLineShape(axiallines[k]); + } + + // n.b. make connections also initialises attributes + // -> don't know what this was for: alllinemap.sortBins(m_poly_connections); + makeConnections(preaxialdata); + + setKeyVertexCount(m_polygons.m_vertex_possibles.size()); +} + +std::tuple, std::unique_ptr> AllLineMap::extractFewestLineMaps(Communicator *comm) +{ + + if (comm) { + comm->CommPostMessage( Communicator::NUM_STEPS, 2 ); + comm->CommPostMessage( Communicator::CURRENT_STEP, 1 ); + } + + pafsrand((unsigned int)time(NULL)); + + // make one rld for each radial line... + std::map > radialdivisions; + size_t i; + for (auto& radial_line: m_radial_lines) { + radialdivisions.insert(std::make_pair( (RadialKey) radial_line, std::set() )); + } + + // also, a list of radial lines cut by each axial line + std::map > ax_radial_cuts; + std::map > ax_seg_cuts; + for (auto shape: getAllShapes()) { + ax_radial_cuts.insert(std::make_pair(shape.first, std::set())); + ax_seg_cuts.insert(std::make_pair(shape.first, std::set())); + } + + // make divisions -- this is the slow part and the comm updates + makeDivisions(m_poly_connections, m_radial_lines, radialdivisions, ax_radial_cuts, comm); + + // the slow part is over, we're into the final straight... reset the current record flag: + if (comm) { + comm->CommPostMessage( Communicator::CURRENT_STEP, 2 ); + comm->CommPostMessage( Communicator::CURRENT_RECORD, 0 ); + } + + // a little further setting up is still required... + std::map radialsegs; + + // now make radial segments from the radial lines... (note, start at 1) + auto iter = m_radial_lines.begin(); + auto prevIter = m_radial_lines.begin(); + ++iter; + for (;iter != m_radial_lines.end();) { + if (iter->vertex == prevIter->vertex && iter->ang != prevIter->ang) { + radialsegs.insert(std::make_pair( (RadialKey)(*iter), (RadialSegment)(*prevIter))); + } + ++iter; + ++prevIter; + } + + // and segment divisors from the axial lines... + // TODO: (CS) Restructure this to get rid of all those brittle parallel data structure + auto axIter = ax_radial_cuts.begin(); + auto axSeg = ax_seg_cuts.begin(); + for (i = 0; i < getAllShapes().size(); i++) { + auto axRadCutIter = axIter->second.begin(); + auto axRadCutIterPrev = axIter->second.begin(); + ++axRadCutIter; + for (size_t j = 1; j < axIter->second.size(); ++j) { + // note similarity to loop above + RadialKey& rk_end = m_radial_lines[size_t(*axRadCutIter)]; + RadialKey& rk_start = m_radial_lines[size_t(*axRadCutIterPrev)]; + if (rk_start.vertex == rk_end.vertex) { + auto radialSegIter = radialsegs.find(rk_end); + if (radialSegIter != radialsegs.end() && rk_start == radialSegIter->second.radial_b) { + radialSegIter->second.indices.insert(axIter->first); + axSeg->second.insert(std::distance(radialsegs.begin(), radialSegIter)); + } + } + ++axRadCutIter; + ++axRadCutIterPrev; + } + axIter++; + axSeg++; + } + + // and a little more setting up: key vertex relationships + std::vector > keyvertexconns; + std::vector keyvertexcounts(static_cast(m_keyvertexcount), 0); + // this sets up a two step relationship: looks for the key vertices for all lines connected to you + for (size_t y = 0; y < m_connectors.size(); y++) { + keyvertexconns.push_back(std::vector()); + auto &conn = keyvertexconns.back(); + Connector& axa = m_connectors[y]; + for (size_t z = 0; z < axa.m_connections.size(); z++) { + std::set& axb = m_keyvertices[axa.m_connections[z]]; + for (int axbi: axb) { + auto res = std::lower_bound(conn.begin(), conn.end(), axbi); + if (res == conn.end() || axbi < *res ) + { + conn.insert(res, axbi); + keyvertexcounts[axbi] += 1; + } + } + } + } + + // ok, after this fairly tedious set up, we are ready to go... + // note axradialcuts aren't required anymore... + + AxialMinimiser minimiser(*this, ax_seg_cuts.size(), radialsegs.size()); + + std::vector lines_s, lines_m; + + minimiser.removeSubsets(ax_seg_cuts, radialsegs, radialdivisions, m_radial_lines, keyvertexconns, keyvertexcounts); + + // make new lines here (assumes line map has only lines) + int k = -1; + for (auto& shape: m_shapes) { + k++; + if (!minimiser.removed(k)) { + lines_s.push_back( shape.second.getLine() ); + } + } + + minimiser.fewestLongest(ax_seg_cuts, radialsegs, radialdivisions, m_radial_lines, keyvertexconns, keyvertexcounts); + + // make new lines here (assumes line map has only lines + for (int k = 0; k < int(getAllShapes().size()); k++) { + if (!minimiser.removed(k)) { + lines_m.push_back( depthmapX::getMapAtIndex(getAllShapes(), k)->second.getLine() ); + } + } + + std::unique_ptr fewestlinemap_subsets(new ShapeGraph("Fewest-Line Map (Subsets)", ShapeMap::AXIALMAP)); + fewestlinemap_subsets->clearAll(); + fewestlinemap_subsets->init(int(lines_s.size()),m_polygons.getRegion()); + + fewestlinemap_subsets->initialiseAttributesAxial(); + for (size_t k = 0; k < lines_s.size(); k++) { + fewestlinemap_subsets->makeLineShape(lines_s[k]); + } + fewestlinemap_subsets->makeConnections(); + + + std::unique_ptr fewestlinemap_minimal(new ShapeGraph("Fewest-Line Map (Minimal)", ShapeMap::AXIALMAP)); + fewestlinemap_minimal->clearAll(); + fewestlinemap_minimal->init(int(lines_m.size()),m_polygons.getRegion()); // used to have a '2' for double pixel density + + fewestlinemap_minimal->initialiseAttributesAxial(); + for (size_t k = 0; k < lines_m.size(); k++) { + fewestlinemap_minimal->makeLineShape(lines_m[k]); + } + fewestlinemap_minimal->makeConnections(); + + return std::make_tuple(std::move(fewestlinemap_subsets), std::move(fewestlinemap_minimal)); +} + +void AllLineMap::makeDivisions(const std::vector& polyconnections, const std::vector &radiallines, + std::map >& radialdivisions, std::map > &axialdividers, + Communicator *comm) +{ + time_t atime = 0; + if (comm) { + qtimer( atime, 0 ); + comm->CommPostMessage( Communicator::NUM_RECORDS, polyconnections.size() ); + } + + for (size_t i = 0; i < polyconnections.size(); i++) { + PixelRefVector pixels = pixelateLine(polyconnections[i].line); + std::vector testedshapes; + auto connIter = radialdivisions.find(polyconnections[i].key); + size_t connindex = std::distance(radialdivisions.begin(), connIter); + double tolerance = sqrt(TOLERANCE_A);// * polyconnections[i].line.length(); + for (size_t j = 0; j < pixels.size(); j++) { + PixelRef pix = pixels[j]; + auto& shapes = m_pixel_shapes(static_cast(pix.y), + static_cast(pix.x)); + for (const ShapeRef& shape: shapes) { + auto iter = depthmapX::findBinary( testedshapes, shape.m_shape_ref ); + if (iter != testedshapes.end()) { + continue; + } + testedshapes.insert(iter, int(shape.m_shape_ref)); + const Line& line = m_shapes.find(shape.m_shape_ref)->second.getLine(); + // + if (intersect_region(line, polyconnections[i].line, tolerance * line.length()) ) { + switch ( intersect_line_distinguish(line, polyconnections[i].line, tolerance * line.length()) ) { + case 0: + break; + case 2: + { + size_t index = depthmapX::findIndexFromKey(axialdividers, (int) shape.m_shape_ref); + if (index != shape.m_shape_ref) { + throw 1; // for the code to work later this can't be true! + } + axialdividers[index].insert(connindex); + connIter->second.insert(shape.m_shape_ref); + } + break; + case 1: + { + size_t index = depthmapX::findIndexFromKey(axialdividers, (int) shape.m_shape_ref); + if (index != shape.m_shape_ref) { + throw 1; // for the code to work later this can't be true! + } + // + // this makes sure actually crosses between the line and the openspace properly + if (radiallines[connindex].cuts(line)) { + axialdividers[index].insert(connindex); + connIter->second.insert(shape.m_shape_ref); + } + } + break; + default: + break; + } + } + } + } + if (comm) { + if (qtimer( atime, 500 )) { + if (comm->IsCancelled()) { + throw Communicator::CancelledException(); + } + comm->CommPostMessage( Communicator::CURRENT_RECORD, i ); + } + } + } +} diff --git a/salalib/alllinemap.h b/salalib/alllinemap.h new file mode 100644 index 00000000..ae836a59 --- /dev/null +++ b/salalib/alllinemap.h @@ -0,0 +1,26 @@ +#pragma once + +#include "salalib/axialmap.h" +#include "salalib/axialpolygons.h" + +class AllLineMap: public ShapeGraph +{ +public: + AllLineMap(Communicator *comm, + std::vector &drawingLayers, + const Point2f& seed, + const std::string& name = "All-Line Map"); + AllLineMap(const std::string& name = "All-Line Map"): + ShapeGraph(name, ShapeMap::ALLLINEMAP) {} + AxialPolygons m_polygons; + std::vector m_poly_connections; + std::vector m_radial_lines; + void setKeyVertexCount(int keyvertexcount) { + m_keyvertexcount = keyvertexcount; + } + std::tuple, std::unique_ptr> extractFewestLineMaps(Communicator *comm); + void makeDivisions(const std::vector& polyconnections, const std::vector &radiallines, + std::map > &radialdivisions, std::map > &axialdividers, + Communicator *comm); + +}; diff --git a/salalib/attributetable.cpp b/salalib/attributetable.cpp new file mode 100644 index 00000000..81afe885 --- /dev/null +++ b/salalib/attributetable.cpp @@ -0,0 +1,531 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#include "attributetable.h" +#include "displayparams.h" +#include +#include + +#include +#include + +const std::string &AttributeColumnImpl::getName() const +{ + return m_name; +} + +bool AttributeColumnImpl::isLocked() const +{ + return m_locked; +} + +void AttributeColumnImpl::setLock(bool lock) +{ + m_locked = lock; +} + +bool AttributeColumnImpl::isHidden() const +{ + return m_hidden; +} + +void AttributeColumnImpl::setHidden(bool hidden) +{ + m_hidden = hidden; +} + +void AttributeColumnImpl::setFormula(std::string newFormula) +{ + m_formula = newFormula; +} + +const std::string &AttributeColumnImpl::getFormula() const +{ + return m_formula; +} + +const AttributeColumnStats &AttributeColumnImpl::getStats() const +{ + return m_stats; +} + +void AttributeColumnImpl::updateStats(float val, float oldVal) const +{ + if (m_stats.total < 0) + { + m_stats.total = val; + } + else + { + m_stats.total += val; + m_stats.total -= oldVal; + } + if (val > m_stats.max) + { + m_stats.max = val; + } + if (m_stats.min < 0 || val < m_stats.min) + { + m_stats.min = val; + } +} + +void AttributeColumnImpl::setName(const std::string &name) +{ + m_name = name; +} + +size_t AttributeColumnImpl::read(std::istream &stream) +{ + m_name = dXstring::readString(stream); + float val; + stream.read((char *)&val, sizeof(float)); + m_stats.min = val; + stream.read((char *)&val, sizeof(float)); + m_stats.max = val; + stream.read((char *)&m_stats.total, sizeof(double)); + int physical_column; + stream.read((char *)&physical_column, sizeof(int)); // physical column is obsolete + stream.read((char *)&m_hidden, sizeof(bool)); + stream.read((char *)&m_locked, sizeof(bool)); + + stream.read((char*)&m_displayParams,sizeof(DisplayParams)); + m_formula = dXstring::readString(stream); + return physical_column; +} + +void AttributeColumnImpl::write(std::ostream &stream, int physicalCol) +{ + dXstring::writeString(stream, m_name); + float min = (float)m_stats.min; + float max = (float)m_stats.max; + stream.write((char *)&min, sizeof(float)); + stream.write((char *)&max, sizeof(float)); + stream.write((char *)&m_stats.total, sizeof(m_stats.total)); + stream.write((char *)&physicalCol, sizeof(int)); + stream.write((char *)&m_hidden, sizeof(bool)); + stream.write((char *)&m_locked, sizeof(bool)); + stream.write((char *)&m_displayParams, sizeof(DisplayParams)); + dXstring::writeString(stream, m_formula); + +} + + +// AttributeRow implementation +float AttributeRowImpl::getValue(const std::string &column) const +{ + return getValue(m_colManager.getColumnIndex(column)); +} + +float AttributeRowImpl::getValue(size_t index) const +{ + checkIndex(index); + return m_data[index]; +} + +float AttributeRowImpl::getNormalisedValue(size_t index) const +{ + checkIndex(index); + auto& colStats = m_colManager.getColumn(index).getStats(); + if (colStats.max == colStats.min) + { + return 0.5f; + } + return m_data[index] < 0 ? -1.0f : float((m_data[index] - colStats.min)/(colStats.max - colStats.min)); +} + +AttributeRow& AttributeRowImpl::setValue(const std::string &column, float value) +{ + return setValue(m_colManager.getColumnIndex(column), value); +} + +AttributeRow& AttributeRowImpl::setValue(size_t index, float value) +{ + checkIndex(index); + float oldVal = m_data[index]; + m_data[index] = value; + if (oldVal < 0.0f) + { + oldVal = 0.0f; + } + m_colManager.getColumn(index).updateStats(value, oldVal); + return *this; +} + +AttributeRow& AttributeRowImpl::setSelection(bool selected) +{ + m_selected = selected; + return *this; +} + +bool AttributeRowImpl::isSelected() const +{ + return m_selected; +} + +void AttributeRowImpl::addColumn() +{ + m_data.push_back(-1); +} + +void AttributeRowImpl::removeColumn(size_t index) +{ + checkIndex(index); + m_data.erase(m_data.begin() + index); +} + +void AttributeRowImpl::read(std::istream &stream) +{ + stream.read((char *)&m_layerKey, sizeof(m_layerKey)); + dXreadwrite::readIntoVector(stream, m_data); +} + +void AttributeRowImpl::write(std::ostream &stream) +{ + stream.write((char *)&m_layerKey, sizeof(m_layerKey)); + dXreadwrite::writeVector(stream, m_data); +} + +void AttributeRowImpl::checkIndex(size_t index) const +{ + if( index >= m_data.size()) + { + throw std::out_of_range("AttributeColumn index out of range"); + } +} + + + +AttributeRow &AttributeRowImpl::incrValue(size_t index, float value) +{ + checkIndex(index); + float val = m_data[index]; + if ( val < 0) + { + setValue(index, value); + } + else + { + setValue(index, val + value); + } + return *this; +} + + +AttributeRow &AttributeRowImpl::incrValue(const std::string &colName, float value) +{ + return incrValue(m_colManager.getColumnIndex(colName), value); +} + +AttributeRow &AttributeTable::getRow(const AttributeKey &key) +{ + auto* row = getRowPtr(key); + if (row == 0) + { + throw std::out_of_range("Invalid row key"); + } + return *row; +} + +const AttributeRow& AttributeTable::getRow(const AttributeKey &key) const +{ + auto* row = getRowPtr(key); + if (row == 0) + { + throw std::out_of_range("Invalid row key"); + } + return *row; +} + +AttributeRow *AttributeTable::getRowPtr(const AttributeKey &key) +{ + auto iter = m_rows.find(key); + if (iter == m_rows.end()) + { + return 0; + } + return iter->second.get(); +} + +const AttributeRow *AttributeTable::getRowPtr(const AttributeKey &key) const +{ + auto iter = m_rows.find(key); + if (iter == m_rows.end()) + { + return 0; + } + return iter->second.get(); +} + +AttributeRow &AttributeTable::addRow(const AttributeKey &key) +{ + auto iter = m_rows.find(key); + if (iter != m_rows.end()) + { + throw new std::invalid_argument("Duplicate key"); + } + auto res = m_rows.insert(std::make_pair(key, std::unique_ptr(new AttributeRowImpl(*this)))); + return *res.first->second; +} + +void AttributeTable::removeRow(const AttributeKey &key) +{ + auto iter = m_rows.find(key); + if (iter == m_rows.end()) + { + throw new std::invalid_argument("Row does not exist"); + } + m_rows.erase(iter); +} + +AttributeColumn &AttributeTable::getColumn(size_t index) +{ + if(index == size_t(-1)) { + return m_keyColumn; + } + checkColumnIndex(index); + return m_columns[index]; +} + +size_t AttributeTable::insertOrResetColumn(const std::string &columnName, const std::string &formula) +{ + auto iter = m_columnMapping.find(columnName); + if (iter == m_columnMapping.end()) + { + return addColumnInternal(columnName, formula); + } + + // it exists - we need to reset it + m_columns[iter->second].m_stats = AttributeColumnStats(); + m_columns[iter->second].setLock(false); + for (auto& row : m_rows) + { + row.second->setValue(iter->second, -1.0f); + } + return iter->second; +} + +size_t AttributeTable::insertOrResetLockedColumn(const std::string &columnName, const std::string &formula) +{ + size_t index = insertOrResetColumn(columnName, formula); + m_columns[index].setLock(true); + return index; +} + +size_t AttributeTable::getOrInsertColumn(const std::string &columnName, const std::string &formula) +{ + auto iter = m_columnMapping.find(columnName); + if ( iter != m_columnMapping.end()) + { + return iter->second; + } + return addColumnInternal(columnName, formula); +} + +size_t AttributeTable::getOrInsertLockedColumn(const std::string &columnName, const std::string &formula) +{ + size_t index = getOrInsertColumn(columnName, formula); + m_columns[index].setLock(true); + return index; +} + +void AttributeTable::removeColumn(size_t colIndex) +{ + checkColumnIndex(colIndex); + const std::string& name = m_columns[colIndex].getName(); + auto iter = m_columnMapping.find(name); + m_columnMapping.erase(iter); + for (auto& elem : m_columnMapping) + { + if (elem.second > colIndex) + { + elem.second--; + } + } + m_columns.erase(m_columns.begin()+colIndex); + for (auto& row : m_rows) + { + row.second->removeColumn(colIndex); + } +} + +void AttributeTable::renameColumn(const std::string &oldName, const std::string &newName) +{ + auto iter = m_columnMapping.find(oldName); + if (iter == m_columnMapping.end()) + { + throw std::out_of_range("Invalid column name"); + } + + size_t colIndex = iter->second; + m_columns[colIndex].setName(newName); + m_columnMapping.erase(iter); + m_columnMapping[newName] = colIndex; + +} + +void AttributeTable::deselectAllRows() +{ + for (auto& row : m_rows) + { + row.second->setSelection(false); + } +} + +void AttributeTable::setDisplayParamsForAllAttributes(const DisplayParams ¶ms) +{ + for (auto& col: m_columns) + { + col.setDisplayParams(params); + } + +} + +void AttributeTable::read(std::istream &stream, LayerManager &layerManager) +{ + layerManager.read(stream); + int colcount; + stream.read((char *)&colcount, sizeof(colcount)); + std::map tmp; + for (int j = 0; j < colcount; j++) { + AttributeColumnImpl col(""); + tmp[col.read(stream)] = col; + } + + for (auto & c : tmp) + { + m_columnMapping[c.second.getName()] = m_columns.size(); + m_columns.push_back(c.second); + } + + int rowcount, rowkey; + stream.read((char *)&rowcount, sizeof(rowcount)); + for (int i = 0; i < rowcount; i++) { + stream.read((char *)&rowkey, sizeof(rowkey)); + auto row = std::unique_ptr(new AttributeRowImpl(*this)); + row->read(stream); + m_rows.insert(std::make_pair(AttributeKey(rowkey),std::move(row))); + } + + // ref column display params + stream.read((char *)&m_displayParams,sizeof(DisplayParams)); +} + +void AttributeTable::write(std::ostream &stream, const LayerManager &layerManager) +{ + layerManager.write(stream); + int colCount = (int)m_columns.size(); + stream.write((char *)&colCount, sizeof(int)); + + // TODO: For binary compatibility write the columns in alphabetical order + // but the physical columns in the order inserted + + std::vector indices(m_columns.size()); + std::iota(indices.begin(), indices.end(), static_cast(0)); + + std::sort(indices.begin(), indices.end(), + [&](size_t a, size_t b) { + return m_columns[a].getName() < m_columns[b].getName(); + }); + + for (int idx: indices) { + m_columns[idx].write(stream, m_columnMapping[m_columns[idx].getName()]); + } + + int rowcount = (int)m_rows.size(); + stream.write((char *)&rowcount, sizeof(int)); + for ( auto &kvp : m_rows) + { + kvp.first.write(stream); + kvp.second->write(stream); + } + stream.write((const char *)&m_displayParams, sizeof(DisplayParams)); +} + +void AttributeTable::clear() { + m_rows.clear(); + m_columns.clear(); + m_columnMapping.clear(); +} + +size_t AttributeTable::getColumnIndex(const std::string &name) const +{ + auto iter = m_columnMapping.find(name); + if (iter == m_columnMapping.end()) + { + std::stringstream message; + message << "Unknown column name " << name; + throw std::out_of_range(message.str()); + } + return iter->second; + +} + +// TODO: Compatibility. Method to retreive a column's index +// if the set of columns was sorted +size_t AttributeTable::getColumnSortedIndex(size_t index) const +{ + if(index == size_t(-1) || index == size_t(-2)) return index; + if(index >= m_columns.size()) return -1; + + return std::distance(m_columnMapping.begin(), m_columnMapping.find(getColumnName(index))); +} + + +const AttributeColumn &AttributeTable::getColumn(size_t index) const +{ + if(index == size_t(-1)) { + return m_keyColumn; + } + checkColumnIndex(index); + return m_columns[index]; +} + +const std::string &AttributeTable::getColumnName(size_t index) const +{ + return getColumn(index).getName(); +} + +size_t AttributeTable::getNumColumns() const +{ + return m_columns.size(); +} + +bool AttributeTable::hasColumn(const std::string &name) const +{ + auto iter = m_columnMapping.find(name); + return(iter != m_columnMapping.end()); +} + +void AttributeTable::checkColumnIndex(size_t index) const +{ + if (index >= m_columns.size()) + { + throw std::out_of_range("ColumnIndex out of range"); + } +} + +size_t AttributeTable::addColumnInternal(const std::string &name, const std::string &formula) +{ + size_t colIndex = m_columns.size(); + m_columns.push_back(AttributeColumnImpl(name, formula)); + m_columnMapping[name] = colIndex; + for (auto& elem : m_rows) + { + elem.second->addColumn(); + } + return colIndex; +} diff --git a/salalib/attributetable.h b/salalib/attributetable.h new file mode 100644 index 00000000..fecbcc93 --- /dev/null +++ b/salalib/attributetable.h @@ -0,0 +1,483 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#pragma once +#include "layermanager.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/// +/// Interface to an attribute row +/// +class AttributeRow : public LayerAware +{ +public: + virtual float getValue(const std::string &column) const = 0; + virtual float getValue(size_t index) const = 0; + virtual float getNormalisedValue(size_t index) const = 0; + virtual AttributeRow& setValue(const std::string &column, float value ) = 0; + virtual AttributeRow& setValue(size_t index, float value) = 0; + virtual AttributeRow& incrValue(size_t index, float value = 1.0f) = 0; + virtual AttributeRow& incrValue(const std::string &colName, float value = 1.0f) = 0; + virtual AttributeRow& setSelection(bool selected) = 0; + virtual bool isSelected() const = 0; + + virtual ~AttributeRow(){} +}; + + +/// +/// Container for attribute column stats - really just POD to pass them around +/// +struct AttributeColumnStats +{ + AttributeColumnStats( double minimum, double maximum, double tot, double vTot, double vMin, double vMax ): min(minimum), max(maximum), total(tot), visibleTotal(vTot), visibleMin(vMin), visibleMax(vMax) + {} + + AttributeColumnStats() : AttributeColumnStats(-1.0, -1.0, -1.0, -1.0, -1.0, -1.0) + { + } + + double min; + double max; + double total; + double visibleTotal; + double visibleMin; + double visibleMax; +}; + + +/// +/// Interface to an attribute column +/// +class AttributeColumn +{ +public: + virtual const std::string& getName() const = 0; + virtual bool isLocked() const = 0; + virtual void setLock(bool lock) = 0; + virtual bool isHidden() const = 0; + virtual void setHidden(bool hidden) = 0; + virtual void setDisplayParams(const DisplayParams& params ) = 0; + virtual const DisplayParams& getDisplayParams() const = 0; + + virtual const std::string& getFormula() const = 0; + virtual void setFormula(std::string newFormula) = 0; + + virtual const AttributeColumnStats& getStats() const = 0; + + // stats are mutable - we need to be able to update them all the time, + // even when not allowed to modify the column settings + virtual void updateStats(float val, float oldVal = 0.0f) const = 0; + + virtual ~AttributeColumn(){} + +}; + + +/// +/// Interface to an Attribute Column Manager +/// This handles the mapping from column name to index and actually storing the column implementations +/// Implemented by AttributeTable +/// +class AttributeColumnManager +{ +public: + virtual size_t getNumColumns() const = 0; + virtual size_t getColumnIndex(const std::string& name) const = 0; + virtual const AttributeColumn& getColumn(size_t index) const = 0; + virtual const std::string& getColumnName(size_t index) const = 0; +}; + + + +// Implementation of AttributeColumn + +class AttributeColumnImpl: public AttributeColumn, AttributeColumnStats +{ + // AttributeColumn interface +public: + AttributeColumnImpl(const std::string &name, const std::string &formula = std::string()) : m_name(name), m_locked(false), m_hidden(false), m_formula(formula) + { + } + + AttributeColumnImpl() : m_locked(false), m_hidden(false) + {} + virtual const std::string &getName() const; + virtual bool isLocked() const; + virtual void setLock(bool lock); + virtual bool isHidden() const; + virtual void setHidden(bool hidden); + virtual const std::string &getFormula() const; + virtual void setFormula(std::string newFormula); + virtual const AttributeColumnStats& getStats() const; + virtual void setDisplayParams(const DisplayParams ¶ms){ m_displayParams = params; } + virtual const DisplayParams &getDisplayParams() const{return m_displayParams;} + + virtual void updateStats(float val, float oldVal = 0.0f) const; + +public: + // stats are mutable - we need to be able to update them all the time, + // even when not allowed to modify the column settings + mutable AttributeColumnStats m_stats; + + void setName(const std::string &name); + // returns the physical column for comaptibility with the old attribute table + size_t read(std::istream &stream); + void write(std::ostream& stream, int physicalCol); + +private: + std::string m_name; + bool m_locked; + bool m_hidden; + std::string m_formula; + DisplayParams m_displayParams; +}; + +// Implementation of AttributeColumn that actually links to the keys of the table + +class KeyColumn : public AttributeColumnImpl +{ +public: + KeyColumn() : AttributeColumnImpl(), m_name("Ref") + {} +private: + std::string m_name; +}; + + +// Implementation of AttributeRow +class AttributeRowImpl : public AttributeRow +{ +public: + AttributeRowImpl(const AttributeColumnManager& colManager) : m_data(colManager.getNumColumns(), -1.0), m_colManager(colManager), m_selected(false) + { + m_layerKey = 1; + } + + // AttributeRow interface +public: + virtual float getValue(const std::string &column) const; + virtual float getValue(size_t index) const; + virtual float getNormalisedValue(size_t index) const; + virtual AttributeRow& setValue(const std::string &column, float value); + virtual AttributeRow& setValue(size_t index, float value); + virtual AttributeRow& incrValue(const std::string &column, float value); + virtual AttributeRow& incrValue(size_t index, float value); + virtual AttributeRow& setSelection(bool selected); + virtual bool isSelected() const; + + void addColumn(); + void removeColumn(size_t index); + + void read(std::istream &stream); + void write(std::ostream &stream); + +private: + std::vector m_data; + const AttributeColumnManager& m_colManager; + bool m_selected; + + void checkIndex(size_t index) const; + +}; + +/// +/// \brief Small struct to make an attribute key distinguishable from an int +/// PixelRefs are serialised into an int (2 bytes x, 2 bytes y) for historic reason. This seems dangerous +/// and confusing as these are by no means indices, but look the same to the compiler and the reader. +/// This struct should disambiguate this... +/// +struct AttributeKey +{ + explicit AttributeKey(int val) : value(val) + {} + int value; + + bool operator < (const AttributeKey& other ) const + { + return value < other.value; + } + + void write(std::ostream &stream) const + { + stream.write((char *)&value, sizeof(int)); + } + + void read(std::istream &stream) + { + stream.read((char *)&value, sizeof(int)); + } +}; + +/// +/// AttributeTable +/// +class AttributeTable : public AttributeColumnManager +{ + // AttributeTable "interface" - the actual table handling +public: + AttributeTable(){} + virtual ~AttributeTable(){} + AttributeTable(AttributeTable&&) = default; + AttributeTable& operator =(AttributeTable&&) = default; + AttributeTable(const AttributeTable& ) = delete; + AttributeTable& operator =(const AttributeTable&) = delete; + + /// + /// \brief Get a row reference + /// \param key of the row + /// \return reference to row, throws if key not found + /// + AttributeRow& getRow(const AttributeKey& key ); + + /// + /// \brief Get a row const reference + /// \param key of the row + /// \return const reference to row, throws if key not found + /// + const AttributeRow& getRow(const AttributeKey& key) const; + + /// + /// \brief Get a row pointer + /// \param key of the row + /// \return pointer to row, null if key not found + /// + AttributeRow* getRowPtr(const AttributeKey& key); + + /// + /// \brief Get a row const pointer + /// \param key of the row + /// \return const pointer to row, null if key not found + /// + const AttributeRow* getRowPtr(const AttributeKey& key)const; + AttributeRow &addRow(const AttributeKey& key); + AttributeColumn& getColumn(size_t index); + size_t insertOrResetColumn(const std::string& columnName, const std::string &formula = std::string()); + size_t insertOrResetLockedColumn(const std::string& columnName, const std::string &formula = std::string()); + size_t getOrInsertColumn(const std::string& columnName, const std::string &formula = std::string()); + size_t getOrInsertLockedColumn(const std::string& columnName, const std::string &formula = std::string()); + void removeRow(const AttributeKey& key); + void removeColumn(size_t colIndex); + void renameColumn(const std::string& oldName, const std::string& newName); + size_t getNumRows() const { return m_rows.size(); } + void deselectAllRows(); + const DisplayParams& getDisplayParams() const { return m_displayParams; } + void setDisplayParams(const DisplayParams& params){m_displayParams = params;} + void setDisplayParamsForAllAttributes(const DisplayParams& params); + void read(std::istream &stream, LayerManager &layerManager); + void write(std::ostream &stream, const LayerManager &layerManager); + void clear(); + float getSelAvg(size_t columnIndex) { + float selTotal = 0; + int selNum = 0; + for(auto& pair: m_rows) { + if(pair.second->isSelected()) { + selTotal += pair.second->getValue(columnIndex); + selNum++; + } + } + if(selNum == 0) { + return(-1); + } + return(selTotal/selNum); + } + +// interface AttributeColumnManager +public: + virtual size_t getColumnIndex(const std::string& name) const; + virtual const AttributeColumn& getColumn(size_t index) const; + virtual const std::string& getColumnName(size_t index) const; + virtual size_t getNumColumns() const; + virtual bool hasColumn(const std::string &name) const; + + // TODO: Compatibility. Very inefficient method to retreive a column's index + // if the set of columns was sorted + size_t getColumnSortedIndex(size_t index) const; + +private: + typedef std::map> StorageType; + StorageType m_rows; + std::map m_columnMapping; + std::vector m_columns; + KeyColumn m_keyColumn; + DisplayParams m_displayParams; + +private: + void checkColumnIndex(size_t index) const; + size_t addColumnInternal(const std::string &name, const std::string &formula); + +// warning - here be dragons! +// This is the implementation of stl style iterators on attribute table, allowing efficient +// iteration of rows without resorting to log(n) access via the map + + +public: + /// + /// \brief The iterator_item class + /// The value of an iterator over the table - we want to hide the actual storage details and just + /// return references to rows and keys. + class iterator_item + { + public: + virtual const AttributeKey& getKey() const = 0; + virtual const AttributeRow& getRow() const = 0; + virtual AttributeRow& getRow() = 0; + virtual ~iterator_item(){} + }; +private: + // implementation of the iterator_item, templated on iterator type to allow const and non-const iterator + template + class iterator_item_impl : public iterator_item + { + public: + iterator_item_impl( const iterator_type & iter) : m_iter(iter) + {} + template iterator_item_impl(const iterator_item_impl& other) : m_iter(other.m_iter) + {} + + template iterator_item_impl& operator = (const iterator_item_impl& other) + { + m_iter = other.m_iter; + return *this; + } + + + const AttributeKey& getKey() const + { + return m_iter->first; + } + + const AttributeRow& getRow() const + { + return *m_iter->second; + } + + AttributeRow& getRow() + { + return *m_iter->second; + } + + void forward() const + { + ++m_iter; + } + + void back() const + { + --m_iter; + } + + template bool operator == (const iterator_item_impl &other) const + { + return m_iter == other.m_iter; + } + public: + mutable iterator_type m_iter; + }; + + + // iterator implementation - templated on iterator type for const/non-const + template + class const_iterator_impl : public std::iterator + { + template friend class const_iterator_impl; + public: + const_iterator_impl( const iterator_type& iter) : m_item(iter) + {} + template const_iterator_impl(const const_iterator_impl& other) : m_item(other.m_item) + {} + template const_iterator_impl& operator =(const const_iterator_impl &other) + { + m_item = other.m_item; + return *this; + } + + const_iterator_impl& operator++() {m_item.forward();return *this;} + const_iterator_impl operator++(int) {const_iterator_impl tmp(*this); operator++(); return tmp;} + const_iterator_impl& operator--() {m_item.back();return *this;} + const_iterator_impl operator--(int) {const_iterator_impl tmp(*this); operator--(); return tmp;} + template bool operator==(const const_iterator_impl& rhs) const {return m_item == rhs.m_item;} + template bool operator!=(const const_iterator_impl& rhs) const {return !(m_item==rhs.m_item);} + const iterator_item& operator*() const {return m_item;} + const iterator_item* operator->() const {return &m_item;} + + protected: + iterator_item_impl m_item; + }; + +public: + // const iterator is just a typedef on the impl + typedef const_iterator_impl const_iterator; + + // non const iterator needs some extra methods + class iterator : public const_iterator_impl + { + public: + iterator(const typename StorageType::iterator& iter) : const_iterator_impl(iter) + {} + template iterator(const const_iterator_impl& other) : const_iterator_impl(other.item){ + // m_item = other.m_item; + } + template iterator& operator =(const const_iterator_impl &other) + { + const_iterator_impl::m_item = other.m_item; + return *this; + } + iterator_item& operator*() {return const_iterator_impl::m_item;} + iterator_item* operator->() {return &(const_iterator_impl::m_item);} + }; + + // stl style iteration methods + const_iterator begin() const + { + return const_iterator(m_rows.begin()); + } + + iterator begin() + { + return iterator(m_rows.begin()); + } + + const_iterator end() const + { + return const_iterator(m_rows.end()); + } + + iterator end() + { + return iterator(m_rows.end()); + } + + iterator find(AttributeKey key) + { + return iterator(m_rows.find(key)); + } + + std::pair>& back() + { + return *m_rows.rbegin(); + } +}; + diff --git a/salalib/attributetablehelpers.h b/salalib/attributetablehelpers.h new file mode 100644 index 00000000..a59cd1d4 --- /dev/null +++ b/salalib/attributetablehelpers.h @@ -0,0 +1,84 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once +#include "attributetable.h" +#include "attributetableview.h" +#include "pafcolor.h" +#include "mgraph_consts.h" + +namespace dXreimpl{ + inline void pushSelectionToLayer(AttributeTable &table, LayerManager& layerManager, const std::string &layerName) + { + size_t layerIndex = layerManager.addLayer(layerName); + LayerManager::KeyType layerKey = layerManager.getKey(layerIndex); + for (auto & item: table) + { + auto& row = item.getRow(); + if (isObjectVisible(layerManager, row) && row.isSelected()) + { + addLayerToObject(item.getRow(), layerKey); + } + } + + layerManager.setLayerVisible(layerIndex); + } + + inline PafColor getDisplayColor( const AttributeKey& key, const AttributeRow& row, const AttributeTableView& tableView, bool checkSelectionStatus = false) + { + if ( checkSelectionStatus && row.isSelected()) + { + return PafColor(SALA_SELECTED_COLOR); + } + + PafColor color; + return color.makeColor(tableView.getNormalisedValue(key, row), tableView.getDisplayParams()); + + } + +} + +struct OrderedIntPair +{ + int a; + int b; + OrderedIntPair(int x = -1, int y = -1) { + a = (int) x < y ? x : y; + b = (int) x < y ? y : x; + } + // inlined at end of file + friend bool operator == (const OrderedIntPair& x, const OrderedIntPair& y); + friend bool operator != (const OrderedIntPair& x, const OrderedIntPair& y); + friend bool operator < (const OrderedIntPair& x, const OrderedIntPair& y); + friend bool operator > (const OrderedIntPair& x, const OrderedIntPair& y); +}; + +// note: these are made with a is always less than b +inline bool operator == (const OrderedIntPair& x, const OrderedIntPair& y) +{ + return (x.a == y.a && x.b == y.b); +} +inline bool operator != (const OrderedIntPair& x, const OrderedIntPair& y) +{ + return (x.a != y.a || x.b != y.b); +} +inline bool operator < (const OrderedIntPair& x, const OrderedIntPair& y) +{ + return ( (x.a == y.a) ? x.b < y.b : x.a < y.a ); +} +inline bool operator > (const OrderedIntPair& x, const OrderedIntPair& y) +{ + return ( (x.a == y.a) ? x.b > y.b : x.a > y.a ); +} diff --git a/salalib/attributetableindex.cpp b/salalib/attributetableindex.cpp new file mode 100644 index 00000000..21e1bfaf --- /dev/null +++ b/salalib/attributetableindex.cpp @@ -0,0 +1,113 @@ +// Copyright (C) 2018 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#include "salalib/attributetableindex.h" + +std::vector makeAttributeIndex(const AttributeTable &table, int colIndex) +{ + std::vector index; + size_t numRows = table.getNumRows(); + if (numRows == 0) + { + return index; + } + index.reserve(numRows); + // perturb the values to be sorted by so same values will be in order of appearence in the map + size_t idx = 0; + if ( colIndex == -1 ) + { + double perturbationFactor = 1e-9 / numRows; + for (auto& item: table) + { + double value = (double)item.getKey().value; + value += idx * perturbationFactor; + + index.push_back(ConstAttributeIndexItem(item.getKey(), value, item.getRow())); + ++idx; + } + } + else if (colIndex >= 0 ) + { + double perturbationFactor = table.getColumn(colIndex).getStats().max * 1e-9 / numRows; + for (auto & item : table) + { + double value = item.getRow().getValue(colIndex); + value += idx * perturbationFactor; + + index.push_back(ConstAttributeIndexItem(item.getKey(), value, item.getRow())); + ++idx; + } + } + else + { + throw std::out_of_range("Column index out of range"); + } + std::sort(index.begin(), index.end()); + return index; +} + +std::vector makeAttributeIndex(AttributeTable &table, int colIndex) +{ + std::vector index; + size_t numRows = table.getNumRows(); + if (numRows == 0) + { + return index; + } + index.reserve(numRows); + // perturb the values to be sorted by so same values will be in order of appearence in the map + size_t idx = 0; + if ( colIndex == -1 ) + { + double perturbationFactor = 1e-9 / numRows; + for (auto& item: table) + { + double value = (double)item.getKey().value; + value += idx * perturbationFactor; + + index.push_back(AttributeIndexItem(item.getKey(), value, item.getRow())); + ++idx; + } + } + else if (colIndex >= 0 ) + { + double perturbationFactor = table.getColumn(colIndex).getStats().max * 1e-9 / numRows; + for (auto & item : table) + { + double value = item.getRow().getValue(colIndex); + value += idx * perturbationFactor; + + index.push_back(AttributeIndexItem(item.getKey(), value, item.getRow())); + ++idx; + } + } + else + { + throw std::out_of_range("Column index out of range"); + } + std::sort(index.begin(), index.end()); + return index; +} + +std::pair::iterator, std::vector::iterator> +getIndexItemsInValueRange(std::vector &index, AttributeTable &table, float fromValue, + float toValue) { + AttributeKey dummykey(-1); + AttributeRowImpl dummyrow(table); + return std::pair::iterator, std::vector::iterator>( + std::lower_bound(index.begin(), index.end(), AttributeIndexItem(dummykey, fromValue, dummyrow)), + std::upper_bound(index.begin(), index.end(), AttributeIndexItem(dummykey, toValue, dummyrow))); +} diff --git a/salalib/attributetableindex.h b/salalib/attributetableindex.h new file mode 100644 index 00000000..0af1daa3 --- /dev/null +++ b/salalib/attributetableindex.h @@ -0,0 +1,75 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once +#include "attributetable.h" +#include + +class ConstAttributeIndexItem +{ +public: + ConstAttributeIndexItem(const AttributeKey &k, double v, const AttributeRow &r) : key(k), value(v), row(&r) + {} + + ConstAttributeIndexItem(const ConstAttributeIndexItem& other) : key(other.key), value(other.value), row(other.row) + {} + ConstAttributeIndexItem &operator = (const ConstAttributeIndexItem& other) + { + if ( this == &other) + { + return *this; + } + key = other.key; + value = other.value; + row = other.row; + return *this; + } + + AttributeKey key; + double value; + const AttributeRow * row; +}; + +class AttributeIndexItem : public ConstAttributeIndexItem +{ +public: + AttributeIndexItem( const AttributeKey &k, double v, AttributeRow &r) : ConstAttributeIndexItem(k,v,r), mutable_row(&r) + {} + AttributeIndexItem( const AttributeIndexItem &other) : ConstAttributeIndexItem(other), mutable_row(other.mutable_row) + {} + AttributeIndexItem &operator = (const AttributeIndexItem &other) + { + if ( this == &other) + { + return *this; + } + ConstAttributeIndexItem::operator =(other); + mutable_row = other.mutable_row; + return *this; + } + + AttributeRow *mutable_row; +}; + +inline bool operator < (const ConstAttributeIndexItem &lhs, const ConstAttributeIndexItem &rhs) +{ + return lhs.value < rhs.value; +} + +std::vector makeAttributeIndex(const AttributeTable &table, int colIndex); +std::vector makeAttributeIndex(AttributeTable &table, int colIndex); +std::pair::iterator, std::vector::iterator> +getIndexItemsInValueRange(std::vector &index, AttributeTable &table, float fromValue, + float toValue); diff --git a/salalib/attributetableview.cpp b/salalib/attributetableview.cpp new file mode 100644 index 00000000..cda99514 --- /dev/null +++ b/salalib/attributetableview.cpp @@ -0,0 +1,72 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "attributetableview.h" + +AttributeTableView::AttributeTableView(const AttributeTable &table) : m_table(table), m_displayColumn(-1) +{} + +void AttributeTableView::setDisplayColIndex(int columnIndex){ + if (columnIndex < -1) + { + m_displayColumn = -2; + m_index.clear(); + return; + } + // recalculate the index even if it's the same column in case stuff has changed + m_index = makeAttributeIndex(m_table, columnIndex); + m_displayColumn = columnIndex; +} + +float AttributeTableView::getNormalisedValue(const AttributeKey &key, const AttributeRow &row) const +{ + if ( m_displayColumn < 0) + { + auto endIter = m_table.end(); + --endIter; + return (float)key.value /(float) endIter->getKey().value; + } + return row.getNormalisedValue(m_displayColumn); +} + +const DisplayParams &AttributeTableView::getDisplayParams() const +{ + if (m_displayColumn < 0) + { + return m_table.getDisplayParams(); + } + return m_table.getColumn(m_displayColumn).getDisplayParams(); +} + +void AttributeTableHandle::setDisplayColIndex(int columnIndex){ + if (columnIndex < -1) + { + m_mutableIndex.clear(); + } + else + { + // recalculate the index even if it's the same column in case stuff has changed + m_mutableIndex = makeAttributeIndex(m_mutableTable, columnIndex); + } + AttributeTableView::setDisplayColIndex(columnIndex); +} +int AttributeTableHandle::findInIndex(const AttributeKey &key) { + + auto iter = std::find_if(m_mutableIndex.begin(), m_mutableIndex.end(), index_item_key(key)); + if (iter != m_mutableIndex.end()) { + return(std::distance(m_mutableIndex.begin(), iter)); + } + return -1; +} diff --git a/salalib/attributetableview.h b/salalib/attributetableview.h new file mode 100644 index 00000000..77353f5e --- /dev/null +++ b/salalib/attributetableview.h @@ -0,0 +1,64 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "attributetable.h" +#include "attributetableindex.h" + +class AttributeTableView +{ +public: + AttributeTableView(const AttributeTable& table ); + + const AttributeTable &m_table; + + // columnIndex < 0 -> not set + virtual void setDisplayColIndex(int columnIndex); + int getDisplayColIndex() const{ return m_displayColumn;} + + float getNormalisedValue(const AttributeKey& key, const AttributeRow &row) const; + const DisplayParams& getDisplayParams() const; + + typedef std::vector ConstIndex; + const ConstIndex& getConstTableIndex() const{return m_index;} + + const AttributeColumn& getDisplayedColumn() const; + +private: + ConstIndex m_index; + int m_displayColumn; +}; + +class AttributeTableHandle : public AttributeTableView +{ +public: + AttributeTableHandle(AttributeTable &table) : AttributeTableView(table), m_mutableTable(table){} + virtual ~AttributeTableHandle(){} + typedef std::vector Index; + const Index& getTableIndex() const {return m_mutableIndex;} + virtual void setDisplayColIndex(int columnIndex); + int findInIndex(const AttributeKey &key); +private: + AttributeTable& m_mutableTable; + Index m_mutableIndex; + +}; + +struct index_item_key : public std::unary_function { + explicit index_item_key(const AttributeKey &baseline) : m_baseline(baseline) {} + bool operator() (const AttributeIndexItem &arg) { return arg.key.value == m_baseline.value; } + const AttributeKey& m_baseline; +}; diff --git a/salalib/axialmap.cpp b/salalib/axialmap.cpp index d5a57fc5..2c4f362b 100644 --- a/salalib/axialmap.cpp +++ b/salalib/axialmap.cpp @@ -18,2857 +18,250 @@ // This is my code to make a set of axial lines from a set of boundary lines -#include -#include -#include -#include -#include // For communicator - -#include // purely for the version info --- as phased out should replace -#include - -#include // need the pointdata for the convert boundary graph to axial map routine -#include // ditto ngraph -#include "MapInfoData.h" - -#ifndef _WIN32 -#define _finite finite -#endif - -static const double TOLERANCE_A = 1e-9; -static const double TOLERANCE_B = 1e-12; -static const double TOLERANCE_C = 1e-6; - -//////////////////////////////////////////////////////////////////////////////////////////// - -static int compareValueTriplet(const void *p1, const void *p2) -{ - ValueTriplet *vp1 = (ValueTriplet *) p1; - ValueTriplet *vp2 = (ValueTriplet *) p2; - int v = vp1->value1 - vp2->value1; - return (vp1->value1 > vp2->value1 ? 1 : vp1->value1 < vp2->value1 ? -1 : - (vp1->value2 > vp2->value2 ? 1 : vp1->value2 < vp2->value2 ? -1 : 0)); -} - -static pstring makeFloatRadiusText(double radius) -{ - pstring radius_text; - if (radius > 100.0) { - radius_text = pstringify(radius,"%.f"); - } - else if (radius < 0.1) { - radius_text = pstringify(radius,"%.4f"); - } - else { - radius_text = pstringify(radius,"%.2f"); - } - return radius_text; -} - -//////////////////////////////////////////////////////////////////////////////////////////// - -AxialPolygons::AxialPolygons() -{ - m_pixel_polys = NULL; -} - -AxialPolygons::~AxialPolygons() -{ - if (m_pixel_polys) { - for (int i = 0; i < m_cols; i++) { - delete [] m_pixel_polys[i]; - } - delete [] m_pixel_polys; - m_pixel_polys = NULL; - } -} - -AxialVertex AxialPolygons::makeVertex(const AxialVertexKey& vertexkey, const Point2f& openspace) -{ - AxialVertex av(vertexkey, m_vertex_possibles.key(vertexkey.m_ref_key), openspace); - - // n.b., at this point, vertex key m_a and m_b are unfixed - pvecpoint& pointlist = m_vertex_possibles.value(vertexkey.m_ref_key); - if (pointlist.size() < 2) { - return av; - } - - Point2f o = av.m_point - av.m_openspace; - - // using an anglemap means that there are now no anti-clockwise vertices... - pmap anglemap; - for (size_t i = 0; i < pointlist.size(); i++) { - anglemap.add( angle(openspace,av.m_point,pointlist[i]), i ); - } - - av.m_ref_a = anglemap.head(); - av.m_ref_a = anglemap.tail(); - Point2f a = av.m_point - pointlist.at( anglemap.head() ); - Point2f b = pointlist.at( anglemap.tail() ) - av.m_point; - av.m_a = a; - av.m_b = b; - a.normalise(); - b.normalise(); - - double oa = det(o,a); - double ob = det(o,b); - double ab = det(a,b); - - // can't handle these cases - if (fabs(oa) < TOLERANCE_A || fabs(ob) < TOLERANCE_A || fabs(ab) < TOLERANCE_A) { - // although note that if ab == 0 and you've already checked intersection, it can't be convex - return av; - } - - // ADDED 4-Nov-04 -- In order to stop too many lines being generated, don't include - // points that do not change surface direction: -- notice: will create problems with circles - if (fabs(dot(a,b)) > 0.999) { - return av; - } - - - if (sgn(oa) == sgn(ob)) { - // headon collision - if (sgn(oa) == 1) { - if (sgn(ab) == 1) { - // convex clockwise - av.m_convex = true; - av.m_clockwise = true; - av.m_axial = true; - } - else { - // n.b., these are turned away for axial formation - // concave clockwise - av.m_convex = false; - av.m_clockwise = true; - av.m_axial = false; - } - } - } - else { - // glancing blow - // concave clockwise - av.m_convex = false; - av.m_clockwise = true; - av.m_axial = true; - } - - av.m_initialised = true; - - return av; -} - -/////////////////////////////////////////////////////////////////////////////////////////////// - -void AxialPolygons::clear() -{ - // clear any existing data - if (m_pixel_polys) { - for (int i = 0; i < m_cols; i++) { - delete [] m_pixel_polys[i]; - } - delete [] m_pixel_polys; - m_pixel_polys = NULL; - } - - m_vertex_possibles.clear(); - m_vertex_polys.clear(); - m_handled_list.clear(); -} - -void AxialPolygons::init(prefvec& lines, const QtRegion& region) -{ - // init pixelbase members - m_region = region; - - // now tidy - TidyLines tidier; - tidier.tidy(lines, m_region); - - // for easier debugging, the axial code is reused to make segments - ShapeGraph firstpass; - firstpass.init(lines.size(),m_region); // used to be double density - size_t i; - for (i = 0; i < lines.size(); i++) { - firstpass.makeLineShape(lines[i]); - } - firstpass.makeConnections(); - - lines.clear(); - prefvec connectionset; - - // interesting... 1.0 may or may not work as intended - firstpass.makeSegmentMap(lines, connectionset, 1.0); - - // now we have a set of lines and a set of connections... - // ...for the second pass, a bit of retro fitting to my original code is - // required - makeVertexPossibles(lines, connectionset); - - initLines(lines.size(), m_region.bottom_left, m_region.top_right, 2); - // need to init before making pixel polys... - makePixelPolys(); - // now also add lines - for (i = 0; i < m_vertex_possibles.size(); i++) { - for (size_t j = 0; j < m_vertex_possibles.value(i).size(); j++) { - addLine(Line(m_vertex_possibles.key(i),m_vertex_possibles.value(i).at(j))); - } - } - sortPixelLines(); -} - -void AxialPolygons::makeVertexPossibles(const prefvec& lines, const prefvec& connectionset) -{ - m_vertex_possibles.clear(); - m_vertex_polys.clear(); - int currpoly = -1; - - size_t i = 0; - - int *found[2]; - found[0] = new int [lines.size()]; - found[1] = new int [lines.size()]; - for (i = 0; i < lines.size(); i++) { - found[0][i] = -1; - found[1][i] = -1; - } - pvecpoint pointlookup; - // three pass operation: (1) stack the lines - for (i = 0; i < lines.size(); i++) { - if (found[0][i] == -1) { - pointlookup.push_back(lines[i].start()); - m_vertex_possibles.add(pointlookup.tail(),pvecpoint()); - m_vertex_polys.push_back(-1); // <- n.b., dummy entry for now, maintain with vertex possibles - found[0][i] = pointlookup.size() - 1; - for (size_t j = 0; j < connectionset[i].m_back_segconns.size(); j++) { - const SegmentRef& segref = connectionset[i].m_back_segconns.key(j); - int forwback = (segref.dir == 1) ? 0 : 1; - found[forwback][segref.ref] = found[0][i]; - } - } - if (found[1][i] == -1) { - pointlookup.push_back(lines[i].end()); - m_vertex_possibles.add(pointlookup.tail(),pvecpoint()); - m_vertex_polys.push_back(-1); // <- n.b., dummy entry for now, maintain with vertex possibles - found[1][i] = pointlookup.size() - 1; - for (size_t j = 0; j < connectionset[i].m_forward_segconns.size(); j++) { - const SegmentRef& segref = connectionset[i].m_forward_segconns.key(j); - int forwback = (segref.dir == 1) ? 0 : 1; - found[forwback][segref.ref] = found[1][i]; - } - } - } - // three pass operation: (2) connect up vertex possibles - for (i = 0; i < lines.size(); i++) { - if (found[0][i] == -1 || found[1][i] == -1) { - throw 1; - } - size_t index0 = m_vertex_possibles.searchindex(pointlookup.at(found[0][i])); - size_t index1 = m_vertex_possibles.searchindex(pointlookup.at(found[1][i])); - if (index0 == paftl::npos || index1 == paftl::npos) { - throw 2; - } - m_vertex_possibles.value(index0).add(pointlookup.at(found[1][i])); - m_vertex_possibles.value(index1).add(pointlookup.at(found[0][i])); - } - delete [] found[0]; - delete [] found[1]; - // three pass operation: (3) create vertex poly entries - int current_poly = -1; - for (i = 0; i < m_vertex_possibles.size(); i++) { - if (m_vertex_polys[i] == -1) { - current_poly++; - pvecint addlist; - addlist.push_back(i); - while (addlist.size()) { - m_vertex_polys[addlist.tail()] = current_poly; - pvecpoint& connections = m_vertex_possibles.value(addlist.tail()); - addlist.pop_back(); - for (size_t j = 0; j < connections.size(); j++) { - size_t index = m_vertex_possibles.searchindex(connections[j]); - if (index == paftl::npos) { - throw 3; - } - if (m_vertex_polys[index] == -1) { - addlist.push_back(index); - } - } - } - } - } -} - -void AxialPolygons::makePixelPolys() -{ - int i = 0; - - // record all of this onto the pixel polygons - if (m_pixel_polys) - { - for (i = 0; i < m_cols; i++) { - delete [] m_pixel_polys[i]; - } - delete [] m_pixel_polys; - m_pixel_polys = NULL; - } - m_pixel_polys = new pvecint *[m_cols]; - for (i = 0; i < m_cols; i++) { - m_pixel_polys[i] = new pvecint[m_rows]; - } - // now register the vertices in each pixel... - for (size_t j = 0; j < m_vertex_possibles.size(); j++) { - PixelRef pix = pixelate(m_vertex_possibles.key(j)); - m_pixel_polys[pix.x][pix.y].push_back(j); - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////// - -// almost identical to original! - -AxialVertexKey AxialPolygons::seedVertex(const Point2f& seed) -{ - AxialVertexKey seedvertex = NoVertex; - PixelRef seedref = pixelate(seed); - bool foundvertex = false; - // for spiralling outwards to find a vertex: - int dir = PixelRef::HORIZONTAL; - int sidelength = 1; - int runlength = 0; - int allboundaries = 0; - - while (!foundvertex) { - for (size_t i = 0; i < m_pixel_polys[seedref.x][seedref.y].size(); i++) { - int vertexref = m_pixel_polys[seedref.x][seedref.y][i]; - const Point2f& trialpoint = m_vertex_possibles.key(vertexref); - if (!intersect_exclude(Line(seed,trialpoint))) { - // yay... ...but wait... we need to see if it's a proper polygon vertex first... - seedvertex = vertexref; - foundvertex = true; - } - } - if (!foundvertex) { - seedref = seedref.move(dir); - // spiral outwards: - if (++runlength == sidelength) { - switch (dir) { - case PixelRef::HORIZONTAL: - dir = PixelRef::VERTICAL; runlength = 0; - break; - case PixelRef::VERTICAL: - dir = PixelRef::NEGHORIZONTAL; runlength = 0; sidelength++; - break; - case PixelRef::NEGHORIZONTAL: - dir = PixelRef::NEGVERTICAL; runlength = 0; - break; - case PixelRef::NEGVERTICAL: - dir = PixelRef::HORIZONTAL; runlength = 0; sidelength++; - break; - } - } - // check to make sure not off edge of system: - if (seedref.x < 0) { - allboundaries |= 0x01; seedref.x = 0; - } - if (seedref.y < 0) { - allboundaries |= 0x02; seedref.y = 0; - } - if (seedref.x >= m_cols) { - allboundaries |= 0x04; seedref.x = m_cols - 1; - } - if (seedref.y >= m_rows) { - allboundaries |= 0x08; seedref.y = m_rows - 1; - } - if (allboundaries == 0x0f) { - return NoVertex; - } - } - } - return seedvertex; -} - -// adds any axial lines from this point to the list of lines, adds any unhandled visible vertices it finds to the openvertices list -// axial lines themselves are added to the lines list - the axial line is only there to record the key vertices that comprise the line -void AxialPolygons::makeAxialLines(pqvector& openvertices, prefvec& lines, prefvec& keyvertices, prefvec& poly_connections, pqvector& radial_lines) -{ - AxialVertex vertex = openvertices.tail(); - openvertices.pop_back(); - - m_handled_list.add(vertex); - - for (size_t i = 0; i < m_vertex_possibles.size(); i++) { - if (i == vertex.m_ref_key) { - continue; - } - bool possible = false, stubpossible = false; - Point2f p = m_vertex_possibles.key(i) - vertex.m_point; - if (vertex.m_convex) { - if (det(vertex.m_a,p) > 0 && det(vertex.m_b,p) > 0) { - possible = true; - } - } - else { - // left of b and right of a or left of a and right of b - if (det(p,vertex.m_a) * det(p,vertex.m_b) < 0) { - possible = true; - } - else if (det(p,vertex.m_a) < TOLERANCE_A && det(p,vertex.m_b) < TOLERANCE_A) { - stubpossible = true; - } - } - if (possible || stubpossible) { - Line line(m_vertex_possibles.key(i),vertex.m_point); - if (!intersect_exclude(line)) { - AxialVertex next_vertex = makeVertex(AxialVertexKey(i),vertex.m_point); - if (next_vertex.m_initialised && m_handled_list.searchindex(next_vertex) == paftl::npos) { - openvertices.add(next_vertex); // <- note, add ignores duplicate adds (each vertex tends to be added multiple times before this vertex is handled itself) - bool shortline_segend = false; - Line shortline = line; - if (!vertex.m_convex && possible) { - Line ext(line.t_end(), line.t_end() + (line.t_end() - line.t_start())); - ext.ray(1, m_region); - cutLine(ext, 1); - line = Line(line.t_start(), ext.t_end()); - // for radial line segend calc: - if (det(-p,vertex.m_b) < 0) { - shortline_segend = true; - } - } - if (m_vertex_polys[vertex.m_ref_key] != m_vertex_polys[next_vertex.m_ref_key]) { // must be on separate polygons - // radial line(s) (for new point) - RadialLine radialshort(next_vertex, shortline_segend, vertex.m_point,next_vertex.m_point,next_vertex.m_point+next_vertex.m_b); - poly_connections.push_back( PolyConnector(shortline, (RadialKey)radialshort) ); - radial_lines.add(radialshort); - if (!vertex.m_convex && possible) { - Line longline = Line(m_vertex_possibles.key(i),line.t_end()); - RadialLine radiallong(radialshort); - radiallong.segend = shortline_segend ? 0 : 1; - poly_connections.push_back( PolyConnector(longline, (RadialKey)radiallong) ); - radial_lines.add(radiallong); - } - } - shortline_segend = false; - if (!next_vertex.m_convex && next_vertex.m_axial) { - Line ext(line.t_start() - (line.t_end() - line.t_start()), line.t_start()); - ext.ray(0, m_region); - cutLine(ext, 0); - line = Line(ext.t_start(), line.t_end()); - // for radial line segend calc: - if (det(p,next_vertex.m_b) < 0) { - shortline_segend = true; - } - } - if (m_vertex_polys[vertex.m_ref_key] != m_vertex_polys[next_vertex.m_ref_key]) { // must be on separate polygons - // radial line(s) (for original point) - RadialLine radialshort(vertex, shortline_segend, next_vertex.m_point,vertex.m_point,vertex.m_point+vertex.m_b); - poly_connections.push_back( PolyConnector(shortline, (RadialKey)radialshort) ); - radial_lines.add(radialshort); - if (!next_vertex.m_convex && next_vertex.m_axial) { - Line longline = Line(line.t_start(),vertex.m_point); - RadialLine radiallong(radialshort); - radiallong.segend = shortline_segend ? 0 : 1; - poly_connections.push_back( PolyConnector(longline, (RadialKey)radiallong) ); - radial_lines.add(radiallong); - } - } - if (possible && next_vertex.m_axial) { - // axial line - lines.push_back(line); - keyvertices.push_back(pvecint()); - if (vertex.m_convex) { - keyvertices.tail().add(vertex.m_ref_key); - } - if (next_vertex.m_convex) { - keyvertices.tail().add(next_vertex.m_ref_key); - } - } - } - } - } - } -} - -/////////////////////////////////////////////////////////////////////////////////////////// - -// not really used as yet, a feature to make all the polygons from the vertex -// possibles list - -void AxialPolygons::makePolygons(prefvec& polygons) -{ - prefvec handled_list; - for (size_t j = 0; j < m_vertex_possibles.size(); j++) { - handled_list.push_back(pvecint()); - } - - for (size_t i = 0; i < m_vertex_possibles.size(); i++) { - if (m_vertex_possibles.value(i).size() == 1) { - continue; - } - for (size_t j = 0; j < m_vertex_possibles.value(i).size(); j++) { - if (handled_list[i].findindex(j) != paftl::npos) { - continue; - } - handled_list[i].push_back(j); - Point2f& key = m_vertex_possibles.key(i); - pvecpoint polygon; - polygon.push_back(key); - Point2f curr = m_vertex_possibles.value(i).at(j); - Point2f last = key; - bool good = true; - while (curr != key) { - size_t n = m_vertex_possibles.searchindex(curr); - polygon.push_back(curr); - // hunt down left most - int winner = -1, wayback = -1; - double minangle = 2 * M_PI; - for (size_t k = 0; k < m_vertex_possibles.value(n).size(); k++) { - Point2f next = m_vertex_possibles.value(n).at(k); - if (last != next) { - double thisangle = angle(last,curr,next); - if (thisangle < minangle) { - // check not going to a dead end: - if (m_vertex_possibles.search(m_vertex_possibles.value(n).at(k)).size() > 1) { - minangle = thisangle; - winner = k; - } - } - } - else { - wayback = k; - } - } - if (winner == -1) { - // this happens when you follow a false trail -- go back the way you came! - winner = wayback; - } - handled_list[n].push_back(winner); - last = curr; - curr = m_vertex_possibles.value(n).at(winner); - } - if (good) { - polygons.push_back(polygon); - } - good = true; - } - } -} - -/////////////////////////////////////////////////////////////////////////////////////////// - -bool RadialLine::cuts(const Line& l) const -{ - if (fabs(det(l.end() - keyvertex,l.end() - l.start())) < TOLERANCE_A) { - // point on line, check that openspace and next vertex are on opposite sides of the line - Point2f x = l.end() - keyvertex; - Point2f y = nextvertex - keyvertex; - Point2f z = openspace - keyvertex; - x.normalise(); - y.normalise(); - z.normalise(); - if (sgn(det(x, y)) == sgn(det(x, z)) && fabs(det(x, z)) > TOLERANCE_A) { - return false; - } - } - // keyvertex not on line... the line's been cut: - return true; -} - -/////////////////////////////////////////////////////////////////////////////////////////// - -// for this to work, your polygons should not intersect each other! - -bool ShapeGraphs::makeAllLineMap(Communicator *comm, SuperSpacePixel& superspacepix, const Point2f& seed) -{ - if (comm) { - comm->CommPostMessage( Communicator::NUM_STEPS, 3 ); - comm->CommPostMessage( Communicator::CURRENT_STEP, 1 ); - } - - // this has a nasty habit of crashing if reused... - // reset everything at the top level, including any existing all-line map: - m_polygons.clear(); - m_poly_connections.clear(); - m_radial_lines.clear(); - - // this is an index to look up the all line map, used by UI to determine if can make fewest line map - // note: it is not saved for historical reasons - if (m_all_line_map != -1) { - removeMap(m_all_line_map); - m_all_line_map = -1; - } - - // starting off... finding a polygon... - // for ease, I'm just going to make a construction line set from all the visible lines... - - QtRegion region; - int size = 0; - - prefvec lines; - - // add all visible layers to the set of polygon lines... - for (size_t i = 0; i < superspacepix.size(); i++) { - for (size_t j = 0; j < superspacepix.at(i).size(); j++) { - if (superspacepix.at(i).at(j).isShown()) { - if (region.isNull()) { - region = superspacepix.at(i).at(j).getRegion(); - } - else { - region = runion(region,superspacepix.at(i).at(j).getRegion()); - } - - for (size_t k = 0; k < superspacepix.at(i).at(j).getAllShapes().size(); k++) { - SalaShape& shape = superspacepix.at(i).at(j).getAllShapes().at(k); - if (shape.isLine()) { - lines.push_back(shape.getLine()); - } - else if (shape.isPolyLine() || shape.isPolygon()) { - for (size_t n = 0; n < shape.size() - 1; n++) { - lines.push_back(Line(shape[n],shape[n+1])); - } - if (shape.isPolygon()) { - lines.push_back(Line(shape.tail(),shape.head())); - } - } - } - } - } - } - - region.grow(1.30); - m_polygons.init(lines, region); - m_polygons.m_handled_list.clear(); - - // find a corner visible from the seed: - AxialVertexKey seedvertex = m_polygons.seedVertex( seed ); - - if (seedvertex == NoVertex) { - // oops... can't find a visible vertex - return false; - } - - // okay, we've got as far as finding a seed corner, now the real fun begins... - // test outwards from corner, add other corners to - // test set... - prefvec axiallines; - prefvec preaxialdata; - // also poly_connections used in fewest line axial map construction: - m_poly_connections.clear(); - m_radial_lines.clear(); - - AxialVertex vertex = m_polygons.makeVertex(seedvertex, seed); - if (!vertex.m_initialised) { - // oops... can't init for some reason - return false; - } - - // Quick mod - TV -#if defined(_WIN32) - __time64_t atime = 0; -#else - time_t atime = 0; -#endif - int count = 0; - if (comm) { - qtimer( atime, 0 ); - comm->CommPostMessage( Communicator::CURRENT_STEP, 2 ); - comm->CommPostMessage( Communicator::NUM_RECORDS, m_polygons.m_vertex_possibles.size() ); - } - - pqvector openvertices; - openvertices.add(vertex); - while (openvertices.size()) { - m_polygons.makeAxialLines(openvertices, axiallines, preaxialdata, m_poly_connections, m_radial_lines); - count++; - // - if (comm) { - if (qtimer( atime, 500 )) { - if (comm->IsCancelled()) { - throw Communicator::CancelledException(); - } - comm->CommPostMessage( Communicator::CURRENT_RECORD, count ); - } - } - - } - - if (comm) { - comm->CommPostMessage( Communicator::CURRENT_STEP, 3 ); - comm->CommPostMessage( Communicator::CURRENT_RECORD, 0 ); - } - - // cut out duplicates: - int removed = 0; // for testing purposes - for (size_t j = 0; j < axiallines.size(); j++) { - for (size_t k = axiallines.size() - 1; k > j; k--) { - double maxdim = __max(region.width(),region.height()); - if (approxeq(axiallines[j].start(), axiallines[k].start(), maxdim * TOLERANCE_B) && approxeq(axiallines[j].end(), axiallines[k].end(), maxdim * TOLERANCE_B)) { - for (size_t m = 0; m < preaxialdata[k].size(); m++) { - preaxialdata[j].add(preaxialdata[k][m]); - } - preaxialdata.remove_at(k); - axiallines.remove_at(k); - removed++; - } - } - } - -/* - // No longer required for ShapeMaps version: - if (!m_length) { - // now add to the space pixel: - m_region = m_polygons.m_region; - } - else { - m_region = runion(m_region, m_polygons.m_region); - } - // End No longer required -*/ - - // create the all line map layer... - m_all_line_map = addMap("All-Line Map", ShapeMap::ALLLINEMAP); - - ShapeGraph& alllinemap = at(m_all_line_map); - // make sure it's cleared fully - alllinemap.clearAll(); - -/* - // temp: - alllinemap.initLines(m_polygons.m_lines.size(),m_polygons.m_region.bottom_left,m_polygons.m_region.top_right,2); - for (int k = 0; k < m_polygons.m_lines.size(); k++) { - alllinemap.makeLineShape(m_polygons.m_lines[k].line); - } - alllinemap.sortPixelLines(); - // end temp -*/ - region.grow(0.99); // <- this paired with crop code below to prevent error - alllinemap.init(axiallines.size(),m_polygons.m_region); // used to be double density here - for (size_t k = 0; k < axiallines.size(); k++) { - axiallines[k].crop(region); // <- should be cropped anyway, but causing an error - alllinemap.makeLineShape(axiallines[k]); - } - - // n.b. make connections also initialises attributes - // -> don't know what this was for: alllinemap.sortBins(m_poly_connections); - alllinemap.makeConnections(preaxialdata); - - alllinemap.m_keyvertexcount = m_polygons.m_vertex_possibles.size(); - - // we can stop here for all line axial map! - setDisplayedMapRef(m_all_line_map); - - return true; -} - -bool ShapeGraphs::makeFewestLineMap(Communicator *comm, bool replace_existing) -{ - // no all line map - if (m_all_line_map == -1) { - return false; - } - - if (comm) { - comm->CommPostMessage( Communicator::NUM_STEPS, 2 ); - comm->CommPostMessage( Communicator::CURRENT_STEP, 1 ); - } - - pafsrand((unsigned int)time(NULL)); - - // make one rld for each radial line... - pqmap radialdivisions; - size_t i; - for (i = 0; i < m_radial_lines.size(); i++) { - radialdivisions.add( (RadialKey) m_radial_lines[i], pvecint() ); - } - - // also, a list of radial lines cut by each axial line - pqmap ax_radial_cuts; - pqmap ax_seg_cuts; - for (i = 0; i < at(m_all_line_map).m_shapes.size(); i++) { - ax_radial_cuts.add(at(m_all_line_map).m_shapes.key(i),pvecint()); - ax_seg_cuts.add(at(m_all_line_map).m_shapes.key(i),pvecint()); - } - - // make divisions -- this is the slow part and the comm updates - at(m_all_line_map).makeDivisions(m_poly_connections, m_radial_lines, radialdivisions, ax_radial_cuts, comm); - - // the slow part is over, we're into the final straight... reset the current record flag: - if (comm) { - comm->CommPostMessage( Communicator::CURRENT_STEP, 2 ); - comm->CommPostMessage( Communicator::CURRENT_RECORD, 0 ); - } - - // a little further setting up is still required... - pqmap radialsegs; - - // now make radial segments from the radial lines... (note, start at 1) - for (i = 1; i < m_radial_lines.size(); i++) { - if (m_radial_lines[i].vertex == m_radial_lines[i-1].vertex) { - if (m_radial_lines[i].ang == m_radial_lines[i-1].ang) { - continue; - } - else { - // Quick mod - TV -#if defined(_WIN32) - radialsegs.add( (RadialKey)m_radial_lines[i], (RadialKey)m_radial_lines[i-1]); -#else - radialsegs.add( (RadialKey)m_radial_lines[i], (RadialSegment)m_radial_lines[i-1]); -#endif - } - } - } - - // and segment divisors from the axial lines... - for (i = 0; i < at(m_all_line_map).m_shapes.size(); i++) { - for (size_t j = 1; j < ax_radial_cuts[i].size(); j++) { - // note similarity to loop above - RadialKey rk_end = m_radial_lines[ax_radial_cuts[i][j]]; - RadialKey rk_start = m_radial_lines[ax_radial_cuts[i][j-1]]; - if (rk_start.vertex == rk_end.vertex) { - size_t index = radialsegs.searchindex(rk_end); - if (index != paftl::npos && rk_start == radialsegs[index].radial_b) { - radialsegs[index].add(ax_radial_cuts.key(i)); - ax_seg_cuts[i].add(index); - } - } - } - } - - // and a little more setting up: key vertex relationships - prefvec keyvertexconns; - int *keyvertexcounts = new int [at(m_all_line_map).m_keyvertexcount]; - for (int x = 0; x < at(m_all_line_map).m_keyvertexcount; x++) { - keyvertexcounts[x] = 0; - } - // this sets up a two step relationship: looks for the key vertices for all lines connected to you - for (size_t y = 0; y < at(m_all_line_map).m_connectors.size(); y++) { - keyvertexconns.push_back(pvecint()); - Connector& axa = at(m_all_line_map).m_connectors[y]; - for (size_t z = 0; z < axa.m_connections.size(); z++) { - pvecint& axb = at(m_all_line_map).m_keyvertices[axa.m_connections[z]]; - for (size_t zz = 0; zz < axb.size(); zz++) { - if (keyvertexconns[y].searchindex(axb[zz]) == paftl::npos) { - keyvertexconns[y].add(axb[zz],paftl::ADD_HERE); - keyvertexcounts[axb[zz]] += 1; - } - } - } - } - - // ok, after this fairly tedious set up, we are ready to go... - // note axradialcuts aren't required anymore... - - AxialMinimiser minimiser(at(m_all_line_map), ax_seg_cuts, radialsegs); - - prefvec lines_s, lines_m; - - minimiser.removeSubsets(ax_seg_cuts, radialsegs, radialdivisions, m_radial_lines, keyvertexconns, keyvertexcounts); - - // make new lines here (assumes line map has only lines) - size_t k; - for (k = 0; k < at(m_all_line_map).m_shapes.size(); k++) { - if (!minimiser.removed(k)) { - lines_s.push_back( at(m_all_line_map).m_shapes[k].getLine() ); - } - } - - minimiser.fewestLongest(ax_seg_cuts, radialsegs, radialdivisions, m_radial_lines, keyvertexconns, keyvertexcounts); - - // make new lines here (assumes line map has only lines - for (k = 0; k < at(m_all_line_map).m_shapes.size(); k++) { - if (!minimiser.removed(k)) { - lines_m.push_back( at(m_all_line_map).m_shapes[k].getLine() ); - } - } - - delete [] keyvertexcounts; - - int subsetmapindex = getMapRef("Fewest-Line Map (Subsets)"); - if (subsetmapindex == -1) { - // didn't used to have hyphenation, try once more: - subsetmapindex = getMapRef("Fewest Line Map (Subsets)"); - } - if (subsetmapindex == -1) { - // create the fewest line map layer... - subsetmapindex = addMap("Fewest-Line Map (Subsets)",ShapeMap::AXIALMAP); - // note: new map has replace_existing set to true to ensure "init" - replace_existing = true; - } - ShapeGraph& fewestlinemap_subsets = at(subsetmapindex); - // note: new map has replace_existing set to true to ensure "init" - if (replace_existing) { - fewestlinemap_subsets.clearAll(); - fewestlinemap_subsets.init(lines_s.size(),m_polygons.m_region); // used to have a '2' for double pixel density - } - for (k = 0; k < lines_s.size(); k++) { - fewestlinemap_subsets.makeLineShape(lines_s[k]); - } - fewestlinemap_subsets.makeConnections(); - - int minimalmapindex = getMapRef("Fewest-Line Map (Minimal)"); - if (minimalmapindex == -1) { - // didn't used to have hyphenation, try once more: - minimalmapindex = getMapRef("Fewest Line Map (Minimal)"); - } - if (minimalmapindex == -1) { - // create the fewest line map layer... - minimalmapindex = addMap("Fewest-Line Map (Minimal)",ShapeMap::AXIALMAP); - // note: new map has replace_existing set to true to ensure "init" - replace_existing = true; - } - ShapeGraph& fewestlinemap_minimal = at(minimalmapindex); - // note: new map has replace_existing set to true to ensure "init" - if (replace_existing) { - fewestlinemap_minimal.clearAll(); - fewestlinemap_minimal.init(lines_m.size(),m_polygons.m_region); // used to have a '2' for double pixel density - } - for (k = 0; k < lines_m.size(); k++) { - fewestlinemap_minimal.makeLineShape(lines_m[k]); - } - fewestlinemap_minimal.makeConnections(); - - setDisplayedMapRef(subsetmapindex); - - return true; -} - -/////////////////////////////////////////////////////////////////////////////////////////// - -AxialMinimiser::AxialMinimiser(const ShapeGraph& alllinemap, pqmap& axsegcuts, pqmap& radialsegs) -{ - m_alllinemap = (ShapeGraph *) &alllinemap; - - m_vps = new ValueTriplet[axsegcuts.size()]; - m_removed = new bool [axsegcuts.size()]; - m_affected = new bool [axsegcuts.size()]; - m_vital = new bool [axsegcuts.size()]; - m_radialsegcounts = new int [radialsegs.size()]; -} - -AxialMinimiser::~AxialMinimiser() -{ - delete [] m_vital; - delete [] m_affected; - delete [] m_radialsegcounts; - delete [] m_vps; - delete [] m_removed; -} - -// Alan and Bill's algo... - -void AxialMinimiser::removeSubsets(pqmap& axsegcuts, pqmap& radialsegs, pqmap& rlds, pqvector& radial_lines, prefvec& keyvertexconns, int *keyvertexcounts) -{ - bool removedflag = true; - int counterrors = 0; - - m_axialconns = m_alllinemap->m_connectors; - - for (size_t x = 0; x < radialsegs.size(); x++) { - m_radialsegcounts[x] = 0; - } - for (size_t y = 0; y < axsegcuts.size(); y++) { - for (size_t z = 0; z < axsegcuts[y].size(); z++) { - m_radialsegcounts[axsegcuts[y][z]] += 1; - } - m_removed[y] = false; - m_vital[y] = false; - m_affected[y] = true; - m_vps[y].index = y; - double length = m_axialconns[y].m_connections.size(); - m_vps[y].value1 = (int) length; - length = m_alllinemap->m_shapes[y].getLine().length(); - m_vps[y].value2 = (float) length; - } - - // sort according to number of connections then length - qsort(m_vps,m_axialconns.size(),sizeof(ValueTriplet),compareValueTriplet); - - while (removedflag) { - - removedflag = false; - for (size_t i = 0; i < m_axialconns.size(); i++) { - int ii = m_vps[i].index; - if (m_removed[ii] || !m_affected[ii] || m_vital[ii]) { - continue; - } - // vital connections code (uses original unaltered connections) - { - bool vitalconn = false; - for (size_t j = 0; j < keyvertexconns[ii].size(); j++) { - // first check to see if removing this line will cause elimination of a vital connection - if (keyvertexcounts[keyvertexconns[ii][j]] <= 1) { - // connect vital... just go on to the next one: - vitalconn = true; - break; - } - } - if (vitalconn) { - m_vital[ii] = true; - continue; - } - } - // - Connector& axa = m_axialconns[ii]; - m_affected[ii] = false; - bool subset = false; - for (size_t j = 0; j < axa.m_connections.size(); j++) { - int indextob = axa.m_connections[j]; - if (indextob == ii || m_removed[indextob]) { // <- removed[indextob] should never happen as it should have been removed below - continue; - } - Connector& axb = m_axialconns[indextob]; - if (axa.m_connections.size() <= axb.m_connections.size()) { - // change to 10.08, coconnecting is 1 -> connection to other line is implicitly handled - int coconnecting = 1; - // first check it's a connection subset - // note that changes in 10.08 mean that lines no longer connect to themselves - // this means that the subset 1 connects {2,3} and 2 connects {1,3} are equivalent - for (size_t axai = 0, axbi = 0; axai < axa.m_connections.size() && axbi < axb.m_connections.size(); axai++, axbi++) { - // extra 10.08 -> step over connection to b - if (axa.m_connections[axai] == indextob) { - axai++; - } - // extra 10.08 add axb.m_connections[axbi] == ii -> step over connection to a - while (axbi < axb.m_connections.size() && (axb.m_connections[axbi] == ii || axa.m_connections[axai] > axb.m_connections[axbi])) { - axbi++; - } - if (axbi >= axb.m_connections.size()) { - break; - } - else if (axa.m_connections[axai] == axb.m_connections[axbi]) { - coconnecting++; - } - else if (axa.m_connections[axai] < axb.m_connections[axbi]) { - break; - } - } - if (coconnecting >= (int)axa.m_connections.size()) { - subset = true; - break; - } - } - } - if (subset) { - size_t removeindex = ii; - // now check removing it won't break any topological loops - bool presumedvital = false; - for (size_t k = 0; k < axsegcuts[removeindex].size(); k++) { - if (m_radialsegcounts[axsegcuts[removeindex][k]] <= 1) { - presumedvital = true; - break; - } - } - if (presumedvital) { - presumedvital = checkVital(removeindex,axsegcuts[removeindex],radialsegs,rlds,radial_lines); - } - if (presumedvital) { - m_vital[removeindex] = true; - } - // if not, remove it... - if (!m_vital[removeindex]) { - m_removed[removeindex] = true; - pvecint& affectedconnections = m_axialconns[removeindex].m_connections; - size_t k; - for (k = 0; k < affectedconnections.size(); k++) { - if (!m_removed[affectedconnections[k]]) { - pvecint& connections = m_axialconns[affectedconnections[k]].m_connections; - size_t index = connections.searchindex(removeindex); - if (index != paftl::npos) { - connections.remove_at(index); - } - m_affected[affectedconnections[k]] = true; - } - } - removedflag = true; - for (k = 0; k < axsegcuts[removeindex].size(); k++) { - m_radialsegcounts[axsegcuts[removeindex][k]] -= 1; - } - // vital connections - for (k = 0; k < keyvertexconns[removeindex].size(); k++) { - keyvertexcounts[keyvertexconns[removeindex][k]] -= 1; - } - } - } - } - } -} - -/////////////////////////////////////////////////////////////////////////////////////////// - -// My algo... v. simple... fewest longest - -void AxialMinimiser::fewestLongest(pqmap& axsegcuts, pqmap& radialsegs, pqmap& rlds, pqvector& radial_lines, prefvec& keyvertexconns, int *keyvertexcounts) -{ - //m_axialconns = m_alllinemap->m_connectors; - int livecount = 0; - - for (size_t y = 0; y < m_axialconns.size(); y++) { - if (!m_removed[y] && !m_vital[y]) { - m_vps[livecount].index = (int) y; - m_vps[livecount].value1 = (int) m_axialconns[y].m_connections.size(); - m_vps[livecount].value2 = (float) m_alllinemap->m_shapes[y].getLine().length(); - livecount++; - } - } - - qsort(m_vps,livecount,sizeof(ValueTriplet),compareValueTriplet); - - for (int i = 0; i < livecount; i++) { - - int j = m_vps[i].index; - // vital connections code (uses original unaltered connections) - bool vitalconn = false; - size_t k; - for (k = 0; k < keyvertexconns[j].size(); k++) { - // first check to see if removing this line will cause elimination of a vital connection - if (keyvertexcounts[keyvertexconns[j][k]] <= 1) { - // connect vital... just go on to the next one: - vitalconn = true; - break; - } - } - if (vitalconn) { - continue; - } - // - bool presumedvital = false; - for (k = 0; k < axsegcuts[j].size(); k++) { - if (m_radialsegcounts[axsegcuts[j][k]] <= 1) { - presumedvital = true; - break; - } - } - if (presumedvital) { - presumedvital = checkVital(j,axsegcuts[j],radialsegs,rlds,radial_lines); - } - if (!presumedvital) { - // don't let anything this is connected to go down to zero connections - pvecint& affectedconnections = m_axialconns[j].m_connections; - for (size_t k = 0; k < affectedconnections.size(); k++) { - if (!m_removed[affectedconnections[k]]) { - pvecint& connections = m_axialconns[affectedconnections[k]].m_connections; - if (connections.size() <= 2) { // <- note number of connections includes itself... so you and one other - presumedvital = true; - break; - } - } - } - } - if (!presumedvital) { - m_removed[j] = true; - pvecint& affectedconnections = m_axialconns[j].m_connections; - size_t k; - for (k = 0; k < affectedconnections.size(); k++) { - if (!m_removed[affectedconnections[k]]) { - pvecint& connections = m_axialconns[affectedconnections[k]].m_connections; - size_t index = connections.searchindex(j); - if (index != paftl::npos) { - connections.remove_at(index); - } - m_affected[affectedconnections[k]] = true; - } - } - for (k = 0; k < axsegcuts[j].size(); k++) { - m_radialsegcounts[axsegcuts[j][k]] -= 1; - } - // vital connections - for (k = 0; k < keyvertexconns[j].size(); k++) { - keyvertexcounts[keyvertexconns[j][k]] -= 1; - } - } - } -} - -/////////////////////////////////////////////////////////////////////////////////////////// - -bool AxialMinimiser::checkVital(int checkindex, pvecint& axsegcuts, pqmap& radialsegs, pqmap& rlds, pqvector& radial_lines) -{ - pqmap& axiallines = m_alllinemap->m_shapes; - - bool presumedvital = true; - int nonvitalcount = 0, vitalsegs = 0; - // again, this time more rigourously... check any connected pairs don't cover the link... - for (size_t k = 0; k < axsegcuts.size(); k++) { - if (m_radialsegcounts[axsegcuts[k]] <= 1) { - bool nonvitalseg = false; - vitalsegs++; - RadialKey& key = radialsegs.key(axsegcuts[k]); - RadialSegment& seg = radialsegs.value(axsegcuts[k]); - pvecint& divisorsa = rlds.search(key); - pvecint& divisorsb = rlds.search(seg.radial_b); - RadialLine& rlinea = radial_lines.search(key); - RadialLine& rlineb = radial_lines.search(seg.radial_b); - for (size_t divi = 0; divi < divisorsa.size(); divi++) { - if (divisorsa[divi] == checkindex || m_removed[divisorsa[divi]]) { - continue; - } - for (size_t divj = 0; divj < divisorsb.size(); divj++) { - if (divisorsb[divj] == checkindex || m_removed[divisorsb[divj]]) { - continue; - } - if (m_axialconns[divisorsa[divi]].m_connections.searchindex(divisorsb[divj]) != paftl::npos) { - // as a further challenge, they must link within in the zone of interest, not on the far side of it... arg! - Point2f p = intersection_point(axiallines[divisorsa[divi]].getLine(),axiallines[divisorsb[divj]].getLine(),TOLERANCE_A); - if (p.insegment(rlinea.keyvertex,rlinea.openspace,rlineb.openspace,TOLERANCE_A)) { - nonvitalseg = true; - } - } - } - } - if (nonvitalseg) { - nonvitalcount++; - } - } - } - if (nonvitalcount == vitalsegs) { - presumedvital = false; - } - return presumedvital; -} - -/////////////////////////////////////////////////////////////////////////////////////////// - -// convert line layers to an axial map - -int ShapeGraphs::convertDrawingToAxial(Communicator *comm, const pstring& name, SuperSpacePixel& superspacepix) -{ - if (comm) { - comm->CommPostMessage( Communicator::NUM_STEPS, 2 ); - comm->CommPostMessage( Communicator::CURRENT_STEP, 1 ); - } - - QtRegion region; - pqmap lines; // map required for tidy lines, otherwise acts like vector - pmap layers; // this is used to say which layer it originated from - - bool recordlayer = false; - - // add all visible layers to the set of polygon lines... - int count = 0; - for (size_t i = 0; i < superspacepix.size(); i++) { - for (size_t j = 0; j < superspacepix.at(i).size(); j++) { - if (superspacepix.at(i).at(j).isShown()) { - if (region.isNull()) { - region = superspacepix.at(i).at(j).getRegion(); - } - else { - region = runion(region,superspacepix.at(i).at(j).getRegion()); - } - for (size_t k = 0; k < superspacepix.at(i).at(j).getAllShapes().size(); k++) { - SalaShape& shape = superspacepix.at(i).at(j).getAllShapes().at(k); - if (shape.isLine()) { - lines.add(count,shape.getLine()); - layers.add(count,j); - count++; - } - else if (shape.isPolyLine() || shape.isPolygon()) { - for (size_t n = 0; n < shape.size() - 1; n++) { - lines.add(count,Line(shape[n],shape[n+1])); - layers.add(count,j); - count++; - } - if (shape.isPolygon()) { - lines.add(count,Line(shape.tail(),shape.head())); - layers.add(count,j); - count++; - } - } - } - superspacepix.at(i).at(j).setShow(false); - } - if (j > 0) { - recordlayer = true; - } - } - } - if (count == 0) { - return -1; - } - - // quick tidy removes very short and duplicate lines, but does not merge overlapping lines - TidyLines tidier; - tidier.quicktidy(lines, region); - if (lines.size() == 0) { - return -1; - } - - - /* - // No longer required - if (!m_length) { - // now add to the space pixel: - m_region = region; - } - else { - m_region = runion(region, m_region); - } - // End no longer required - */ - - if (comm) { - comm->CommPostMessage( Communicator::CURRENT_STEP, 2 ); - } - - /* - // No longer required - // now add to the space pixel: - if (m_region.isempty()) { - m_region = region; - } - else { - m_region = runion(region,m_region); - } - */ - - // create map layer... - int mapref = addMap(name,ShapeMap::AXIALMAP); - // we can stop here for all line axial map! - ShapeGraph& usermap = tail(); - - usermap.init(lines.size(),region); // used to be double density - for (size_t k = 0; k < lines.size(); k++) { - usermap.makeLineShape(lines[k]); - } - - // n.b. make connections also initialises attributes - usermap.makeConnections(); - - // record origin layer only if more than one layer: - if (recordlayer) { - AttributeTable& table = usermap.getAttributeTable(); - int col = table.insertColumn("Drawing Layer"); - for (size_t k = 0; k < lines.size(); k++) { - table.setValue(k,col,float(layers.search(lines.key(k)))); - } - } - - // we can stop here! - setDisplayedMapRef(mapref); - - return mapref; -} - -// create axial map directly from data maps -// note that actually should be able to merge this code with the line layers, now both use similar code - -int ShapeGraphs::convertDataToAxial(Communicator *comm, const pstring& name, ShapeMap& shapemap, bool copydata) -{ - if (comm) { - comm->CommPostMessage( Communicator::NUM_STEPS, 2 ); - comm->CommPostMessage( Communicator::CURRENT_STEP, 1 ); - } - - // add all visible layers to the set of polygon lines... - - pqmap lines; - pmap keys; - - //m_region = shapemap.getRegion(); - QtRegion region = shapemap.getRegion(); - - // add all visible layers to the set of polygon lines... - - int count = 0; - for (size_t i = 0; i < shapemap.getAllShapes().size(); i++) { - int key = shapemap.getAllShapes().key(i); - const SalaShape& poly = shapemap.getAllShapes().at(i); - if (poly.isLine()) { - lines.add(count,poly.getLine()); - keys.add(count,key); - count++; - } - else if (poly.isPolyLine()) { - for (size_t j = 0; j < poly.size() - 1; j++) { - lines.add(count,Line(poly[j],poly[j+1])); - keys.add(count,key); - count++; - } - } - } - if (lines.size() == 0) { - return -1; - } - - // quick tidy removes very short and duplicate lines, but does not merge overlapping lines - TidyLines tidier; - tidier.quicktidy(lines, region); - if (lines.size() == 0) { - return -1; - } - - if (comm) { - comm->CommPostMessage( Communicator::CURRENT_STEP, 2 ); - } - - // create map layer... - int mapref = addMap(name,ShapeMap::AXIALMAP); - // we can stop here for all line axial map! - ShapeGraph& usermap = tail(); - - usermap.init(lines.size(),region); // used to be double density - for (size_t k = 0; k < lines.size(); k++) { - usermap.makeLineShape(lines[k]); - } - - // n.b. make connections also initialises attributes - usermap.makeConnections(); - - // use property that segments are still in same order as input in order to copy - // data across from ShapeMap - if (copydata) { - AttributeTable& input = shapemap.getAttributeTable(); - AttributeTable& output = usermap.getAttributeTable(); - for (int i = 0; i < input.getColumnCount(); i++) { - pstring colname = input.getColumnName(i); - for (size_t k = 1; output.getColumnIndex(colname) != -1; k++) - colname = pstringify((int)k,input.getColumnName(i) + " %d"); - int outcol = output.insertColumn(colname); - for (size_t j = 0; j < lines.size(); j++) { - int inrow = input.getRowid(keys.search(lines.key(j))); - output.setValue(j,outcol,input.getValue(inrow,i)); - } - } - } - - // if we are inheriting from a mapinfo map, pass on the coordsys and bounds: - if (shapemap.getMapInfoData()) { - usermap.m_mapinfodata = new MapInfoData; - usermap.m_mapinfodata->m_coordsys = shapemap.getMapInfoData()->m_coordsys; - usermap.m_mapinfodata->m_bounds = shapemap.getMapInfoData()->m_bounds; - } - - usermap.m_displayed_attribute = -2; // <- override if it's already showing - usermap.setDisplayedAttribute( usermap.m_attributes.getColumnIndex("Connectivity") ); - - // we can stop here! - setDisplayedMapRef(mapref); - - return mapref; -} - -///////////////////////////////////////////////////////////////////////////////////////////////// - -// yet more conversions, this time polygons to shape elements - -int ShapeGraphs::convertDrawingToConvex(Communicator *comm, const pstring& name, SuperSpacePixel& superspacepix) -{ - QtRegion region; - pvecint polygon_refs; - - int mapref = addMap(name,ShapeMap::CONVEXMAP); - ShapeGraph& usermap = tail(); - int conn_col = usermap.m_attributes.insertLockedColumn("Connectivity"); - - size_t count = 0; - size_t i = 0; - for (i = 0; i < superspacepix.size(); i++) { - for (size_t j = 0; j < superspacepix.at(i).size(); j++) { - if (superspacepix.at(i).at(j).isShown()) { - for (size_t k = 0; k < superspacepix.at(i).at(j).getAllShapes().size(); k++) { - SalaShape& shape = superspacepix.at(i).at(j).getAllShapes().at(k); - if (shape.isPolygon()) { - usermap.makeShape(shape); - usermap.m_connectors.push_back( Connector() ); - usermap.m_attributes.setValue(count,conn_col,0); - count++; - } - } - } - } - } - if (count == 0) { - removeMap(mapref); - return -1; - } - - for (i = 0; i < superspacepix.size(); i++) { - for (size_t j = 0; j < superspacepix.at(i).size(); j++) { - superspacepix.at(i).at(j).setShow(false); - } - } - - usermap.m_displayed_attribute = -2; // <- override if it's already showing - usermap.setDisplayedAttribute( -1 ); - // we can stop here! - setDisplayedMapRef(mapref); - - return mapref; -} - -int ShapeGraphs::convertDataToConvex(Communicator *comm, const pstring& name, ShapeMap& shapemap, bool copydata) -{ - pvecint polygon_refs; - - int mapref = addMap(name,ShapeMap::CONVEXMAP); - ShapeGraph& usermap = getMap(mapref); - int conn_col = usermap.m_attributes.insertLockedColumn("Connectivity"); - - pvecint lookup; - - for (size_t k = 0; k < shapemap.getAllShapes().size(); k++) { - SalaShape& shape = shapemap.getAllShapes().at(k); - if (shape.isPolygon()) { - int n = usermap.makeShape(shape); - usermap.m_connectors.push_back( Connector() ); - usermap.m_attributes.setValue(n,conn_col,0); - lookup.push_back(k); - } - } - if (lookup.size() == 0) { - removeMap(mapref); - return -1; - } - - if (copydata) { - AttributeTable& input = shapemap.getAttributeTable(); - AttributeTable& output = usermap.getAttributeTable(); - for (int i = 0; i < input.getColumnCount(); i++) { - pstring colname = input.getColumnName(i); - for (int k = 1; output.getColumnIndex(colname) != -1; k++) - colname = pstringify(k,input.getColumnName(i) + " %d"); - int outcol = output.insertColumn(colname); - for (size_t j = 0; j < lookup.size(); j++) { - output.setValue(j,outcol,input.getValue(lookup[j],i)); - } - } - } - - usermap.m_displayed_attribute = -2; // <- override if it's already showing - usermap.setDisplayedAttribute( -1 ); - // we can stop here! - setDisplayedMapRef(mapref); - - return mapref; -} - -///////////////////////////////////////////////////////////////////////////////////////////////// - -// create segment map directly from line layers - -int ShapeGraphs::convertDrawingToSegment(Communicator *comm, const pstring& name, SuperSpacePixel& superspacepix) -{ - if (comm) { - comm->CommPostMessage( Communicator::NUM_STEPS, 2 ); - comm->CommPostMessage( Communicator::CURRENT_STEP, 1 ); - } - - pqmap lines; // pqmap for tidier, does not matter elsewhere... - pmap layers; // this is used to say which layer it originated from - bool recordlayer = false; - - QtRegion region; - - // add all visible layers to the set of polygon lines... - int count = 0; - for (size_t i = 0; i < superspacepix.size(); i++) { - for (size_t j = 0; j < superspacepix.at(i).size(); j++) { - if (superspacepix.at(i).at(j).isShown()) { - if (region.isNull()) { - region = superspacepix.at(i).at(j).getRegion(); - } - else { - region = runion(region,superspacepix.at(i).at(j).getRegion()); - } - - for (size_t k = 0; k < superspacepix.at(i).at(j).getAllShapes().size(); k++) { - SalaShape& shape = superspacepix.at(i).at(j).getAllShapes().at(k); - if (shape.isLine()) { - lines.add(count,shape.getLine()); - layers.add(count,j); - count++; - } - else if (shape.isPolyLine() || shape.isPolygon()) { - for (size_t n = 0; n < shape.size() - 1; n++) { - lines.add(count,Line(shape[n],shape[n+1])); - layers.add(count,j); - count++; - } - if (shape.isPolygon()) { // add closing line - lines.add(count,Line(shape.tail(),shape.head())); - layers.add(count,j); - count++; - } - } - } - superspacepix.at(i).at(j).setShow(false); - } - if (j > 0) { - recordlayer = true; - } - } - } - if (count == 0) { - return -1; - } - - // quick tidy removes very short and duplicate lines, but does not merge overlapping lines - TidyLines tidier; - tidier.quicktidy(lines, region); - if (lines.size() == 0) { - return -1; - } - - /* - // No longer required for ShapeMaps version: - if (!m_length) { - // now add to the space pixel: - m_region = region; - } - else { - m_region = runion(region, m_region); - } - // End No longer required - */ - - if (comm) { - comm->CommPostMessage( Communicator::CURRENT_STEP, 2 ); - } - - // create map layer... - int mapref = addMap(name,ShapeMap::SEGMENTMAP); - // we can stop here for all line axial map! - ShapeGraph& usermap = tail(); - - usermap.init(lines.size(),region); - - for (size_t k = 0; k < lines.size(); k++) { - usermap.makeLineShape(lines[k]); - } - - // make it! - usermap.makeNewSegMap(); - - // record origin layer only if more than one layer: - if (recordlayer) { - AttributeTable& table = usermap.getAttributeTable(); - int col = table.insertColumn("Drawing Layer"); - for (size_t k = 0; k < lines.size(); k++) { - table.setValue(k,col,float(layers.search(lines.key(k)))); - } - } - - // we can stop here! - setDisplayedMapRef(mapref); - - return mapref; -} - -// create segment map directly from data maps (ultimately, this will replace the line layers version) - -int ShapeGraphs::convertDataToSegment(Communicator *comm, const pstring& name, ShapeMap& shapemap, bool copydata) -{ - if (comm) { - comm->CommPostMessage( Communicator::NUM_STEPS, 2 ); - comm->CommPostMessage( Communicator::CURRENT_STEP, 1 ); - } - - pqmap lines; - pmap keys; - - // no longer requires m_region - //m_region = shapemap.getRegion(); - QtRegion region = shapemap.getRegion(); - - // add all visible layers to the set of polygon lines... - - int count = 0; - for (size_t i = 0; i < shapemap.getAllShapes().size(); i++) { - int key = shapemap.getAllShapes().key(i); - const SalaShape& poly = shapemap.getAllShapes().at(i); - if (poly.isLine()) { - lines.add(count,poly.getLine()); - keys.add(count,key); - count++; - } - else if (poly.isPolyLine()) { - for (size_t j = 0; j < poly.size() - 1; j++) { - lines.add(count,Line(poly[j],poly[j+1])); - keys.add(count,key); - count++; - } - } - } - if (lines.size() == 0) { - return -1; - } - - // quick tidy removes very short and duplicate lines, but does not merge overlapping lines - TidyLines tidier; - tidier.quicktidy(lines, region); - - if (lines.size() == 0) { - return -1; - } - - if (comm) { - comm->CommPostMessage( Communicator::CURRENT_STEP, 2 ); - } - - // create map layer... - int mapref = addMap(name,ShapeMap::SEGMENTMAP); - - // note, I may need to reuse this: - ShapeGraph& usermap = tail(); - - // if we are inheriting from a mapinfo map, pass on the coordsys and bounds: - if (shapemap.getMapInfoData()) { - usermap.m_mapinfodata = new MapInfoData; - usermap.m_mapinfodata->m_coordsys = shapemap.getMapInfoData()->m_coordsys; - usermap.m_mapinfodata->m_bounds = shapemap.getMapInfoData()->m_bounds; - } - - usermap.init(lines.size(),region); - for (size_t k = 0; k < lines.size(); k++) { - usermap.makeLineShape(lines[k]); - } - - // start to be a little bit more efficient about memory now we are hitting the limits - // from time to time: - if (!copydata) { - lines.clear(); - } - - // make it! - usermap.makeNewSegMap(); - - // use property that segments are still in same order as input in order to copy - // data across from ShapeMap - if (copydata) { - AttributeTable& input = shapemap.getAttributeTable(); - AttributeTable& output = usermap.getAttributeTable(); - // - for (int i = 0; i < input.getColumnCount(); i++) { - pstring colname = input.getColumnName(i); - for (int k = 1; output.getColumnIndex(colname) != -1; k++) - colname = pstringify(k,input.getColumnName(i) + " %d"); - int outcol = output.insertColumn(colname); - for (size_t j = 0; j < lines.size(); j++) { - int inrow = input.getRowid(keys.search(lines.key(j))); - output.setValue(j,outcol,input.getValue(inrow,i)); - } - } - } - - usermap.m_displayed_attribute = -2; // <- override if it's already showing - usermap.setDisplayedAttribute( usermap.m_attributes.getColumnIndex("Connectivity") ); - - // we can stop here! - setDisplayedMapRef(mapref); - - return mapref; -} - -#if defined(_WIN32) -#include -#endif - -// stubremoval is fraction of overhanging line length before axial "stub" is removed -int ShapeGraphs::convertAxialToSegment(Communicator *comm, const pstring& name, bool keeporiginal, bool copydata, double stubremoval) -{ - if (m_displayed_map == -1) { - return -1; - } - - prefvec lines; - prefvec connectionset; - - ShapeGraph& dispmap = getDisplayedMap(); - dispmap.makeSegmentMap(lines, connectionset, stubremoval); - - // destroy unnecessary parts of axial map as quickly as possible in order not to overload memory - if (!keeporiginal) { - dispmap.m_shapes.clear(); - dispmap.m_connectors.clear(); - } - - // create map layer... - int mapref = addMap(name,ShapeMap::SEGMENTMAP); - ShapeGraph& segmap = getMap(mapref); - - segmap.init(lines.size(),dispmap.m_region); - for (size_t k = 0; k < lines.size(); k++) { - segmap.makeLineShape(lines[k]); - } - - // clear data as soon as we do not need it: - lines.clear(); - - // if we are inheriting from a mapinfo map, pass on the coordsys and bounds: - if (dispmap.m_mapinfodata) { - segmap.m_mapinfodata = new MapInfoData; - segmap.m_mapinfodata->m_coordsys = dispmap.m_mapinfodata->m_coordsys; - segmap.m_mapinfodata->m_bounds = dispmap.m_mapinfodata->m_bounds; - } - - // initialise attributes now separated from making the connections - segmap.initSegmentAttributes(connectionset); - - if (copydata) { - segmap.pushAxialValues(dispmap); - } - // destroy unnecessary parts of axial map as quickly as possible in order not to overload memory - if (!keeporiginal) { - dispmap.m_attributes.clear(); - } - - // only now make connections, once some memory has been freed - segmap.makeSegmentConnections(connectionset); - - segmap.m_displayed_attribute = -2; // <- override if it's already showing - segmap.setDisplayedAttribute( segmap.m_attributes.getColumnIndex("Connectivity") ); - - // we can stop here! - setDisplayedMapRef(mapref); - - return mapref; -} - -/////////////////////////////////////////////////////////////////////////////////////////// - -bool ShapeGraphs::read( ifstream& stream, int version ) -{ - // base class read - if (version >= VERSION_AXIAL_SHAPES) { - ShapeMaps::read(stream,version); - } - else { - readold(stream,version); - } - - // these are additional essentially for all line axial maps - // should probably be kept *with* the all line axial map... - m_poly_connections.clear(); - m_poly_connections.read(stream); - m_radial_lines.clear(); - m_radial_lines.read(stream); - - // this is an index to look up the all line map, used by UI to determine if can make fewest line map - // note: it is not saved for historical reasons - // will get confused by more than one all line map - m_all_line_map = getMapRef("All-Line Map"); - if (m_all_line_map == -1) { - // used to be called All Line Map - m_all_line_map = getMapRef("All Line Map"); - } - if (m_all_line_map != -1) { - at(m_all_line_map).m_map_type = ShapeMap::ALLLINEMAP; - } - - // VERSION_AXIAL_REGION_FIX -- this fix is now deprecated - // some awful things could have gone wrong in the past, but the shapemap read should fix automatically - - return true; -} - -// for backward compatibility only: -bool ShapeGraphs::readold( ifstream& stream, int version ) -{ - // this read is based on SpacePixelGroup::read(stream, version); - pstring dummyname; - dummyname.read(stream); - QtRegion dummyregion; - stream.read( (char *) &dummyregion, sizeof(dummyregion) ); - int count; - stream.read( (char *) &count, sizeof(count) ); - for (int i = 0; i < count; i++) { - push_back(ShapeGraph()); - tail().read(stream,version); - } - stream.read((char *)&m_displayed_map,sizeof(m_displayed_map)); - - return true; -} - -bool ShapeGraphs::write( ofstream& stream, int version, bool displayedmaponly ) -{ - // base class write - ShapeMaps::write(stream, version, displayedmaponly); - - m_poly_connections.write(stream); - m_radial_lines.write(stream); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////////////////// - -// Axial map helper: convert a radius for angular analysis - -static pstring makeRadiusText(int radius_type, double radius) -{ - pstring radius_text; - if (radius != -1) { - if (radius_type == Options::RADIUS_STEPS) { - radius_text = pstring(" R") + pstringify(int(radius),"%d") + pstring(" step"); - } - else if (radius_type == Options::RADIUS_METRIC) { - radius_text = pstring(" R") + makeFloatRadiusText(radius) + pstring(" metric"); - } - else { // radius angular - radius_text = pstring(" R") + makeFloatRadiusText(radius); - } - } - return radius_text; -} - -////////////////////////////////////////////////////////////////////////////////////////// - -ShapeGraph::ShapeGraph(const pstring& name, int type) : ShapeMap(name,type) -{ - m_keyvertexcount = 0; - m_hasgraph = true; -} - -//////////////////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////////////////////////////// - -// n.b., also initialises attributes, you must make connections before display map! - -void ShapeGraph::makeConnections(const prefvec& keyvertices) -{ - m_connectors.clear(); - m_attributes.clear(); - m_links.clear(); - m_unlinks.clear(); - m_keyvertices.clear(); - - // note, expects these to be numbered 0, 1... - int conn_col = m_attributes.insertLockedColumn("Connectivity"); - int leng_col = m_attributes.insertLockedColumn("Line Length"); - - for (size_t i = 0; i < m_shapes.size(); i++) { - int key = m_shapes.key(i); - int rowid = m_attributes.insertRow(key); - // all indices should match... - m_connectors.push_back( Connector() ); - int connectivity = getLineConnections( key, m_connectors[i].m_connections, TOLERANCE_B*__max(m_region.height(),m_region.width())); - m_attributes.setValue(rowid, conn_col, (float) connectivity ); - m_attributes.setValue(rowid, leng_col, (float) m_shapes[i].getLine().length() ); - if (keyvertices.size()) { - // note: depends on lines being recorded in same order as keyvertices... - m_keyvertices.push_back( keyvertices[i] ); - } - } - - m_displayed_attribute = -1; // <- override if it's already showing - setDisplayedAttribute(conn_col); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// explicit initialisation of attributes for a gates layer -/* -void ShapeGraph::initAttributes() -{ - m_connectors.clear(); - m_attributes.clear(); - - for (int i = 0; i < m_lines.size(); i++) { - int key = m_lines.key(i); - // all indices should match... - int index1 = m_connectors.add( key, Connector() ); - int index2 = m_attributes.insertRow(key); - // I am going to use this to set the text size soon: - float textsize = (float) m_lines[i].line.length(); - } - - m_displayed_attribute = -2; // <- override if it's already showing - // Note: -1 sets it show the ID column: - setDisplayedAttribute(-1); -} -*/ - -///////////////////////////////////////////////////////////////////////////////////////// - -bool ShapeGraph::outputMifPolygons(ostream& miffile, ostream& midfile) const -{ - // take lines from lines layer and make into regions (using the axial polygons) - prefvec lines; - for (size_t i = 0; i < m_shapes.size(); i++) { - lines.push_back(m_shapes[i].getLine()); - } - AxialPolygons polygons; - polygons.init(lines, m_region); - - prefvec newpolygons; - polygons.makePolygons(newpolygons); - - MapInfoData mapinfodata; - if (m_mapinfodata) { - mapinfodata.m_coordsys = m_mapinfodata->m_coordsys; - mapinfodata.m_bounds = m_mapinfodata->m_bounds; - } - mapinfodata.exportPolygons(miffile, midfile, newpolygons, m_region); - - return true; -} - -void ShapeGraph::outputNet(ostream& netfile) const -{ - double maxdim = __max(m_region.width(),m_region.height()); - Point2f offset = Point2f((maxdim - m_region.width())/(2.0*maxdim),(maxdim - m_region.height())/(2.0*maxdim)); - if (isSegmentMap()) { - netfile << "*Vertices " << m_shapes.size() * 2 << endl; - for (size_t i = 0; i < m_shapes.size(); i++) { - Line li = m_shapes[i].getLine(); - Point2f p1 = li.start(); - Point2f p2 = li.end(); - p1.x = offset.x + (p1.x - m_region.bottom_left.x) / maxdim; - p2.x = offset.x + (p2.x - m_region.bottom_left.x) / maxdim; - p1.y = 1.0 - (offset.y + (p1.y - m_region.bottom_left.y) / maxdim); - p2.y = 1.0 - (offset.y + (p2.y - m_region.bottom_left.y) / maxdim); - netfile << (i * 2 + 1) << " \"" << i << "a\" " << p1.x << " " << p1.y << endl; - netfile << (i * 2 + 2) << " \"" << i << "b\" " << p2.x << " " << p2.y << endl; - } - netfile << "*Edges" << endl; - for (size_t i = 0; i < m_shapes.size(); i++) { - netfile << (i * 2 + 1) << " " << (i * 2 + 2) << " 2" << endl; - } - netfile << "*Arcs" << endl; - // this makes an assumption about which is the "start" and which is the "end" - // it works for an automatically converted axial map, I'm not sure it works for others... - for (size_t j = 0; j < m_connectors.size(); j++) { - const Connector& conn = m_connectors[j]; - for (size_t k1 = 0; k1 < conn.m_forward_segconns.size(); k1++) { - SegmentRef ref = conn.m_forward_segconns.key(k1); - float weight = conn.m_forward_segconns.value(k1); - netfile << (j * 2 + 1) << " " << (ref.ref * 2 + ((ref.dir == 1) ? 1 : 2)) << " " << weight << endl; - } - for (size_t k2 = 0; k2 < conn.m_back_segconns.size(); k2++) { - SegmentRef ref = conn.m_back_segconns.key(k2); - float weight = conn.m_back_segconns.value(k2); - netfile << (j * 2 + 2) << " " << (ref.ref * 2 + ((ref.dir == 1) ? 1 : 2)) << " " << weight << endl; - } - } - } - else { - netfile << "*Vertices " << m_shapes.size() << endl; - for (size_t i = 0; i < m_shapes.size(); i++) { - Point2f p = m_shapes[i].getCentroid(); - p.x = offset.x + (p.x - m_region.bottom_left.x) / maxdim; - p.y = 1.0 - (offset.y + (p.y - m_region.bottom_left.y) / maxdim); - netfile << (i + 1) << " \"" << i << "\" " << p.x << " " << p.y << endl; - } - netfile << "*Edges" << endl; - for (size_t j = 0; j < m_connectors.size(); j++) { - const Connector& conn = m_connectors[j]; - for (size_t k = 0; k < conn.m_connections.size(); k++) { - size_t to = conn.m_connections[k]; - if (j < to) { - netfile << (j+1) << " " << (to + 1) << " 1" << endl; - } - } - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void ShapeGraph::makeDivisions(const prefvec& polyconnections, const pqvector& radiallines, pqmap& radialdivisions, pqmap& axialdividers, Communicator *comm) -{ - // Quick mod - TV -#if defined(_WIN32) - __time64_t atime = 0; -#else - time_t atime = 0; -#endif - if (comm) { - qtimer( atime, 0 ); - comm->CommPostMessage( Communicator::NUM_RECORDS, polyconnections.size() ); - } - - for (size_t i = 0; i < polyconnections.size(); i++) { - PixelRefList pixels = pixelateLine(polyconnections[i].line); - pvecint testedshapes; - size_t connindex = radialdivisions.searchindex(polyconnections[i].key); - double tolerance = sqrt(TOLERANCE_A);// * polyconnections[i].line.length(); - for (size_t j = 0; j < pixels.size(); j++) { - PixelRef pix = pixels[j]; - pqvector &shapes = m_pixel_shapes[pix.x][pix.y]; - for (size_t k = 0; k < shapes.size(); k++) { - ShapeRef& shape = shapes[k]; - if (testedshapes.searchindex(shape.m_shape_ref) != paftl::npos) { - continue; - } - testedshapes.add(shape.m_shape_ref); - const Line& line = m_shapes.search(shape.m_shape_ref).getLine(); - // - if (intersect_region(line, polyconnections[i].line, tolerance * line.length()) ) { - switch ( intersect_line_distinguish(line, polyconnections[i].line, tolerance * line.length()) ) { - case 0: - break; - case 2: - { - size_t index = axialdividers.searchindex(shape.m_shape_ref); - if (int(index) != shape.m_shape_ref) { - throw 1; // for the code to work later this can't be true! - } - axialdividers[index].add(connindex); - radialdivisions[connindex].add(shape.m_shape_ref); - } - break; - case 1: - { - size_t index = axialdividers.searchindex(shape.m_shape_ref); - if (int(index) != shape.m_shape_ref) { - throw 1; // for the code to work later this can't be true! - } - // - // this makes sure actually crosses between the line and the openspace properly - if (radiallines[connindex].cuts(line)) { - axialdividers[index].add(connindex); - radialdivisions[connindex].add(shape.m_shape_ref); - } - } - break; - default: - break; - } - } - } - } - if (comm) { - if (qtimer( atime, 500 )) { - if (comm->IsCancelled()) { - throw Communicator::CancelledException(); - } - comm->CommPostMessage( Communicator::CURRENT_RECORD, i ); - } - } - } -} - -void ShapeGraph::cutLines(const prefvec& lines, pqmap& axcuts) -{ - for (size_t i = 0; i < lines.size(); i ++) { - PixelRefList pixels = pixelateLine(lines[i]); - pvecint testedshapes; - for (size_t j = 0; j < pixels.size(); j++) { - PixelRef pix = pixels[j]; - pqvector &shapes = m_pixel_shapes[pix.x][pix.y]; - for (size_t k = 0; k < shapes.size(); k++) { - ShapeRef& shape = shapes[k]; - if (testedshapes.searchindex(shape.m_shape_ref) != paftl::npos) { - continue; - } - testedshapes.add(shape.m_shape_ref); - const Line& line = m_shapes.search(shape.m_shape_ref).getLine(); - // - if (intersect_region(line, lines[i], TOLERANCE_B * line.length()) ) { - if (intersect_line(line, lines[i], TOLERANCE_B * line.length())) { - axcuts.search(shape.m_shape_ref).add(i); - } - } - } - } - } -} - -typedef pvector IntPairVector; - -// n.b., translate radius list before entry -bool ShapeGraph::integrate(Communicator *comm, const pvecint& radius_list, bool choice, bool local, bool fulloutput, int weighting_col, bool simple_version) -{ - // note, from 10.0, Depthmap no longer includes *self* connections on axial lines - // self connections are stripped out on loading graph files, as well as no longer made - - // Quick mod - TV -#if defined(_WIN32) - __time64_t atime = 0; -#else - time_t atime = 0; -#endif - if (comm) { - qtimer( atime, 0 ); - comm->CommPostMessage( Communicator::NUM_RECORDS, m_connectors.size() ); - } - - // note: radius must be sorted lowest to highest, but if -1 occurs ("radius n") it needs to be last... - // ...to ensure no mess ups, we'll re-sort here: - bool radius_n = false; - pvecint radius; - for (size_t i = 0; i < radius_list.size(); i++) { - if (radius_list[i] == -1) { - radius_n = true; - } - else { - radius.add(radius_list[i]); - } - } - if (radius_n) { - radius.push_back(-1); - } - - // retrieve weighted col data, as this may well be overwritten in the new analysis: - pvecdouble weights; - pstring weighting_col_text; - if (weighting_col != -1) { - weighting_col_text = m_attributes.getColumnName(weighting_col); - for (size_t i = 0; i < m_connectors.size(); i++) { - weights.push_back(m_attributes.getValue(i,weighting_col)); - } - } +#include "salalib/axialmap.h" +#include "salalib/alllinemap.h" +#include "salalib/tolerances.h" +#include "salalib/pointdata.h" // need the pointdata for the convert boundary graph to axial map routine +#include "salalib/ngraph.h" // ditto ngraph +#include "salalib/parsers/mapinfodata.h" + +#include "genlib/comm.h" // For communicator +#include "genlib/stringutils.h" +#include "genlib/containerutils.h" +#include "genlib/readwritehelpers.h" +#include "genlib/pflipper.h" - // first enter the required attribute columns: - size_t r; - for (r = 0; r < radius.size(); r++) { - pstring radius_text; - if (radius[r] != -1) { - radius_text = pstring(" R") + pstringify(int(radius[r]),"%d"); - } - if (choice) { - pstring choice_col_text = pstring("Choice") + radius_text; - m_attributes.insertColumn(choice_col_text.c_str()); - pstring n_choice_col_text = pstring("Choice [Norm]") + radius_text; - m_attributes.insertColumn(n_choice_col_text.c_str()); - if (weighting_col != -1) { - pstring w_choice_col_text = pstring("Choice [") + weighting_col_text + pstring(" Wgt]") + radius_text; - m_attributes.insertColumn(w_choice_col_text.c_str()); - pstring nw_choice_col_text = pstring("Choice [") + weighting_col_text + pstring(" Wgt][Norm]") + radius_text; - m_attributes.insertColumn(nw_choice_col_text.c_str()); - } - } +#include +#include +#include -// dX simple version test // TV -//#define _COMPILE_dX_SIMPLE_VERSION -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - pstring entropy_col_text = pstring("Entropy") + radius_text; - m_attributes.insertColumn(entropy_col_text.c_str()); - } +#ifndef _WIN32 +#define _finite finite #endif - pstring integ_dv_col_text = pstring("Integration [HH]") + radius_text; - m_attributes.insertColumn(integ_dv_col_text.c_str()); - -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - pstring integ_pv_col_text = pstring("Integration [P-value]") + radius_text; - m_attributes.insertColumn(integ_pv_col_text.c_str()); - pstring integ_tk_col_text = pstring("Integration [Tekl]") + radius_text; - m_attributes.insertColumn(integ_tk_col_text.c_str()); - pstring intensity_col_text = pstring("Intensity") + radius_text; - m_attributes.insertColumn(intensity_col_text.c_str()); - pstring harmonic_col_text = pstring("Harmonic Mean Depth") + radius_text; - m_attributes.insertColumn(harmonic_col_text.c_str()); - } -#endif +//////////////////////////////////////////////////////////////////////////////////////////// - pstring depth_col_text = pstring("Mean Depth") + radius_text; - m_attributes.insertColumn(depth_col_text.c_str()); - pstring count_col_text = pstring("Node Count") + radius_text; - m_attributes.insertColumn(count_col_text.c_str()); +ShapeGraph::ShapeGraph(const std::string& name, int type) : ShapeMap(name,type) +{ + m_keyvertexcount = 0; + m_hasgraph = true; +} -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - pstring rel_entropy_col_text = pstring("Relativised Entropy") + radius_text; - m_attributes.insertColumn(rel_entropy_col_text); - } -#endif +//////////////////////////////////////////////////////////////////////////////////////////////////////// - if (weighting_col != -1) { - pstring w_md_col_text = pstring("Mean Depth [") + weighting_col_text + pstring(" Wgt]") + radius_text; - m_attributes.insertColumn(w_md_col_text.c_str()); - pstring total_weight_text = pstring("Total ") + weighting_col_text + radius_text; - m_attributes.insertColumn(total_weight_text.c_str()); - } - if (fulloutput) { +void ShapeGraph::initialiseAttributesAxial() +{ + m_attributes->clear(); + // note, expects these to be numbered 0, 1... + m_attributes->insertOrResetLockedColumn("Connectivity"); + m_attributes->insertOrResetLockedColumn("Line Length"); -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - pstring penn_norm_text = pstring("RA [Penn]") + radius_text; - m_attributes.insertColumn(penn_norm_text); - } -#endif - pstring ra_col_text = pstring("RA") + radius_text; - m_attributes.insertColumn(ra_col_text.c_str()); +} -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - pstring rra_col_text = pstring("RRA") + radius_text; - m_attributes.insertColumn(rra_col_text.c_str()); - } -#endif +void ShapeGraph::makeConnections(const KeyVertices &keyvertices) +{ + m_connectors.clear(); + m_links.clear(); + m_unlinks.clear(); + m_keyvertices.clear(); - pstring td_col_text = pstring("Total Depth") + radius_text; - m_attributes.insertColumn(td_col_text.c_str()); - } - // - } - if (local) { -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - m_attributes.insertColumn("Control"); - m_attributes.insertColumn("Controllability"); + // note, expects these to be numbered 0, 1... + int conn_col = m_attributes->getColumnIndex("Connectivity"); + int leng_col = m_attributes->getColumnIndex("Line Length"); + + int i = -1; + for (auto shape: m_shapes) { + i++; + int key = shape.first; + AttributeRow &row = + m_attributes->getRow(AttributeKey(key)); + // all indices should match... + m_connectors.push_back( Connector() ); + m_connectors[i].m_connections = getLineConnections( key, TOLERANCE_B*__max(m_region.height(),m_region.width())); + row.setValue(conn_col, float(m_connectors[i].m_connections.size()) ); + row.setValue(leng_col, float(shape.second.getLine().length()) ); + if (keyvertices.size()) { + // note: depends on lines being recorded in same order as keyvertices... + m_keyvertices.push_back( keyvertices[i] ); } -#endif } - // then look up all the columns... eek: - pvecint choice_col, n_choice_col, w_choice_col, nw_choice_col, entropy_col, integ_dv_col, integ_pv_col, integ_tk_col, intensity_col, - depth_col, count_col, rel_entropy_col, penn_norm_col, w_depth_col, total_weight_col, ra_col, rra_col, td_col, harmonic_col; - for (r = 0; r < radius.size(); r++) { - pstring radius_text; - if (radius[r] != -1) { - radius_text = pstring(" R") + pstringify(int(radius[r]),"%d"); - } - if (choice) { - pstring choice_col_text = pstring("Choice") + radius_text; - choice_col.push_back(m_attributes.getColumnIndex(choice_col_text.c_str())); - pstring n_choice_col_text = pstring("Choice [Norm]") + radius_text; - n_choice_col.push_back(m_attributes.getColumnIndex(n_choice_col_text.c_str())); - if (weighting_col != -1) { - pstring w_choice_col_text = pstring("Choice [") + weighting_col_text + pstring(" Wgt]") + radius_text; - w_choice_col.push_back(m_attributes.getColumnIndex(w_choice_col_text.c_str())); - pstring nw_choice_col_text = pstring("Choice [") + weighting_col_text + pstring(" Wgt][Norm]") + radius_text; - nw_choice_col.push_back(m_attributes.getColumnIndex(nw_choice_col_text.c_str())); - } - } -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - pstring entropy_col_text = pstring("Entropy") + radius_text; - entropy_col.push_back(m_attributes.getColumnIndex(entropy_col_text.c_str())); - } -#endif - - pstring integ_dv_col_text = pstring("Integration [HH]") + radius_text; - integ_dv_col.push_back(m_attributes.getColumnIndex(integ_dv_col_text.c_str())); - -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - pstring integ_pv_col_text = pstring("Integration [P-value]") + radius_text; - integ_pv_col.push_back(m_attributes.getColumnIndex(integ_pv_col_text.c_str())); - pstring integ_tk_col_text = pstring("Integration [Tekl]") + radius_text; - integ_tk_col.push_back(m_attributes.getColumnIndex(integ_tk_col_text.c_str())); - pstring intensity_col_text = pstring("Intensity") + radius_text; - intensity_col.push_back(m_attributes.getColumnIndex(intensity_col_text.c_str())); - pstring harmonic_col_text = pstring("Harmonic Mean Depth") + radius_text; - harmonic_col.push_back(m_attributes.getColumnIndex(harmonic_col_text.c_str())); - } -#endif - - pstring depth_col_text = pstring("Mean Depth") + radius_text; - depth_col.push_back(m_attributes.getColumnIndex(depth_col_text.c_str())); - pstring count_col_text = pstring("Node Count") + radius_text; - count_col.push_back(m_attributes.getColumnIndex(count_col_text.c_str())); - -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - pstring rel_entropy_col_text = pstring("Relativised Entropy") + radius_text; - rel_entropy_col.push_back(m_attributes.getColumnIndex(rel_entropy_col_text.c_str())); - } -#endif - if (weighting_col != -1) { - pstring w_md_col_text = pstring("Mean Depth [") + weighting_col_text + pstring(" Wgt]") + radius_text; - w_depth_col.push_back(m_attributes.getColumnIndex(w_md_col_text.c_str())); - pstring total_weight_col_text = pstring("Total ") + weighting_col_text + radius_text; - total_weight_col.push_back(m_attributes.getColumnIndex(total_weight_col_text.c_str())); - } - if (fulloutput) { - pstring ra_col_text = pstring("RA") + radius_text; - ra_col.push_back(m_attributes.getColumnIndex(ra_col_text.c_str())); - -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - pstring penn_norm_text = pstring("RA [Penn]") + radius_text; - penn_norm_col.push_back(m_attributes.getColumnIndex(penn_norm_text)); - pstring rra_col_text = pstring("RRA") + radius_text; - rra_col.push_back(m_attributes.getColumnIndex(rra_col_text.c_str())); - } -#endif + m_displayed_attribute = -1; // <- override if it's already showing + setDisplayedAttribute(conn_col); +} - pstring td_col_text = pstring("Total Depth") + radius_text; - td_col.push_back(m_attributes.getColumnIndex(td_col_text.c_str())); - } - } - int control_col, controllability_col; - if (local) { -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - control_col = m_attributes.getColumnIndex("Control"); - controllability_col = m_attributes.getColumnIndex("Controllability"); - } -#endif - } +///////////////////////////////////////////////////////////////////////////////////////// - // for choice - AnalysisInfo **audittrail; - if (choice) { - audittrail = new AnalysisInfo *[m_connectors.size()]; - for (size_t i = 0; i < m_connectors.size(); i++) { - audittrail[i] = new AnalysisInfo [radius.size()]; - } +bool ShapeGraph::outputMifPolygons(std::ostream& miffile, std::ostream& midfile) const +{ + // take lines from lines layer and make into regions (using the axial polygons) + std::vector lines; + for (auto shape: m_shapes) { + lines.push_back(shape.second.getLine()); } + AxialPolygons polygons; + polygons.init(lines, m_region); - // n.b., for this operation we assume continuous line referencing from zero (this is silly?) - // has already failed due to this! when intro hand drawn fewest line (where user may have deleted) - // it's going to get worse... + std::vector> newpolygons; + polygons.makePolygons(newpolygons); - bool *covered = new bool [m_connectors.size()]; - for (size_t i = 0; i < m_connectors.size(); i++) { - for (size_t j = 0; j < m_connectors.size(); j++) { - covered[j] = false; - } - if (choice) { - for (size_t k = 0; k < m_connectors.size(); k++) { - audittrail[k][0].previous.ref = -1; // note, 0th member used as radius doesn't matter - // note, choice columns are not cleared, but cummulative over all shortest path pairs - } - } + MapInfoData mapinfodata; + if (m_hasMapInfoData) { + mapinfodata.m_coordsys = m_mapinfodata.m_coordsys; + mapinfodata.m_bounds = m_mapinfodata.m_bounds; + } + mapinfodata.exportPolygons(miffile, midfile, newpolygons, m_region); - if (local) { - double control = 0.0; - pvecint& connections = m_connectors[i].m_connections; - pvecint totalneighbourhood; - for (size_t j = 0; j < connections.size(); j++) { - // n.b., as of Depthmap 10.0, connections[j] and i cannot coexist - // if (connections[j] != i) { - totalneighbourhood.add(connections[j]); // <- note add does nothing if member already exists - int intersect_size = 0, retro_size = 0; - pvecint retconnectors = m_connectors[connections[j]].m_connections; - for (size_t k = 0; k < retconnectors.size(); k++) { - //if (connections[j] != retconnectors[k]) { - retro_size++; - /* - // used for clustering coeff, but clustering coeff next to useless - if (connections.searchindex(retconnectors[k]) != paftl::npos) { - intersect_size++; - } - */ - totalneighbourhood.add(retconnectors[k]); // <- note add does nothing if member already exists - //} - } - control += 1.0 / double(retro_size); - //} - } + return true; +} -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - if (connections.size() > 0) { - m_attributes.setValue(i, control_col, float(control) ); - m_attributes.setValue(i, controllability_col, float( double(connections.size()) / double(totalneighbourhood.size()-1)) ); - } - else { - m_attributes.setValue(i, control_col, -1 ); - m_attributes.setValue(i, controllability_col, -1 ); - } - } -#endif +void ShapeGraph::outputNet(std::ostream& netfile) const +{ + double maxdim = __max(m_region.width(),m_region.height()); + Point2f offset = Point2f((maxdim - m_region.width())/(2.0*maxdim),(maxdim - m_region.height())/(2.0*maxdim)); + if (isSegmentMap()) { + netfile << "*Vertices " << m_shapes.size() * 2 << std::endl; + int i = -1; + for (auto shape: m_shapes) { + i++; + Line li = shape.second.getLine(); + Point2f p1 = li.start(); + Point2f p2 = li.end(); + p1.x = offset.x + (p1.x - m_region.bottom_left.x) / maxdim; + p2.x = offset.x + (p2.x - m_region.bottom_left.x) / maxdim; + p1.y = 1.0 - (offset.y + (p1.y - m_region.bottom_left.y) / maxdim); + p2.y = 1.0 - (offset.y + (p2.y - m_region.bottom_left.y) / maxdim); + netfile << (i * 2 + 1) << " \"" << i << "a\" " << p1.x << " " << p1.y << std::endl; + netfile << (i * 2 + 2) << " \"" << i << "b\" " << p2.x << " " << p2.y << std::endl; } - - pvecint depthcounts; - depthcounts.push_back(0); - Connector& thisline = m_connectors[i]; - pflipper foundlist; - foundlist.a().push_back(IntPair(i,-1)); - covered[i] = true; - int total_depth = 0, depth = 1, node_count = 1, pos = -1, previous = -1; // node_count includes this 1 - double weight = 0.0, rootweight = 0.0, total_weight = 0.0, w_total_depth = 0.0; - if (weighting_col != -1) { - rootweight = weights[i]; - // include this line in total weights (as per nodecount) - total_weight += rootweight; + netfile << "*Edges" << std::endl; + for (size_t i = 0; i < m_shapes.size(); i++) { + netfile << (i * 2 + 1) << " " << (i * 2 + 2) << " 2" << std::endl; } - register int index = -1; - for (size_t r = 0; r < radius.size(); r++) { - while (foundlist.a().size()) { - if (!choice) { - index = foundlist.a().tail().a; - } - else { - pos = pafrand() % foundlist.a().size(); - index = foundlist.a().at(pos).a; - previous = foundlist.a().at(pos).b; - audittrail[index][0].previous.ref = previous; // note 0th member used here: can be used individually different radius previous - } - Connector& line = m_connectors[index]; - double control = 0; - for (size_t k = 0; k < line.m_connections.size(); k++) { - if (!covered[line.m_connections[k]]) { - covered[line.m_connections[k]] = true; - foundlist.b().push_back(IntPair(line.m_connections[k],index)); - if (weighting_col != -1) { - // the weight is taken from the discovered node: - weight = weights[line.m_connections[k]]; - total_weight += weight; - w_total_depth += depth * weight; - } - if (choice && previous != -1) { - // both directional paths are now recorded for choice - // (coincidentally fixes choice problem which was completely wrong) - int here = index; // note: start counting from index as actually looking ahead here - while (here != i) { // not i means not the current root for the path - audittrail[here][r].choice += 1; - audittrail[here][r].weighted_choice += weight * rootweight; - here = audittrail[here][0].previous.ref; // <- note, just using 0th position: radius for the previous doesn't matter in this analysis - } - if (weighting_col != -1) { - // in weighted choice, root node and current node receive values: - audittrail[i][r].weighted_choice += (weight * rootweight) * 0.5; - audittrail[line.m_connections[k]][r].weighted_choice += (weight * rootweight) * 0.5; - } - } - total_depth += depth; - node_count++; - depthcounts.tail() += 1; - } - } - if (!choice) - foundlist.a().pop_back(); - else - foundlist.a().remove_at(pos); - if (!foundlist.a().size()) { - foundlist.flip(); - depth++; - depthcounts.push_back(0); - if (radius[r] != -1 && depth > radius[r]) { - break; - } - } - } - // set the attributes for this node: - m_attributes.setValue(i,count_col[r],float(node_count)); - if (weighting_col != -1) { - m_attributes.setValue(i,total_weight_col[r],float(total_weight)); - } - // node count > 1 to avoid divide by zero (was > 2) - if (node_count > 1) { - // note -- node_count includes this one -- mean depth as per p.108 Social Logic of Space - double mean_depth = double(total_depth) / double(node_count - 1); - m_attributes.setValue(i,depth_col[r],float(mean_depth)); - if (weighting_col != -1) { - // weighted mean depth: - m_attributes.setValue(i,w_depth_col[r],float(w_total_depth/total_weight)); - } - // total nodes > 2 to avoid divide by 0 (was > 3) - if (node_count > 2 && mean_depth > 1.0) { - double ra = 2.0 * (mean_depth - 1.0) / double(node_count - 2); - // d-value / p-value from Depthmap 4 manual, note: node_count includes this one - double rra_d = ra / dvalue(node_count); - double rra_p = ra / dvalue(node_count); - double integ_tk = teklinteg(node_count, total_depth); - m_attributes.setValue(i,integ_dv_col[r],float(1.0/rra_d)); - -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - m_attributes.setValue(i,integ_pv_col[r],float(1.0/rra_p)); - if (total_depth - node_count + 1 > 1) { - m_attributes.setValue(i,integ_tk_col[r],float(integ_tk)); - } - else { - m_attributes.setValue(i,integ_tk_col[r],-1.0f); - } - } -#endif - - if (fulloutput) { - m_attributes.setValue(i,ra_col[r],float(ra)); - -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - m_attributes.setValue(i,rra_col[r],float(rra_d)); - } -#endif - m_attributes.setValue(i,td_col[r],float(total_depth)); - -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - // alan's palm-tree normalisation: palmtree - double dmin = node_count - 1; - double dmax = palmtree(node_count, depth - 1); - if (dmax != dmin) { - m_attributes.setValue(i,penn_norm_col[r],float((dmax - total_depth)/(dmax - dmin))); - } - } -#endif - } - } - else { - m_attributes.setValue(i,integ_dv_col[r],-1.0f); - -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - m_attributes.setValue(i,integ_pv_col[r],-1.0f); - m_attributes.setValue(i,integ_tk_col[r],-1.0f); - } -#endif - if (fulloutput) { - m_attributes.setValue(i,ra_col[r],-1.0f); - -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - m_attributes.setValue(i,rra_col[r],-1.0f); - } -#endif - - m_attributes.setValue(i,td_col[r],-1.0f); - -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - m_attributes.setValue(i,penn_norm_col[r],-1.0f); - } -#endif - } - } - -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - double entropy = 0.0, intensity = 0.0, rel_entropy = 0.0, factorial = 1.0, harmonic = 0.0; - for (size_t k = 0; k < depthcounts.size(); k++) { - if (depthcounts[k] != 0) { - // some debate over whether or not this should be node count - 1 - // (i.e., including or not including the node itself) - double prob = double(depthcounts[k]) / double(node_count); - entropy -= prob * log2( prob ); - // Formula from Turner 2001, "Depthmap" - factorial *= double(k + 1); - double q = (pow( mean_depth, double(k) ) / double(factorial)) * exp(-mean_depth); - rel_entropy += (double) prob * log2( prob / q ); - // - harmonic += 1.0 / double(depthcounts[k]); - } - } - harmonic = double(depthcounts.size()) / harmonic; - if (total_depth > node_count) { - intensity = node_count * entropy / (total_depth - node_count); - } - else { - intensity = -1; - } - m_attributes.setValue(i,entropy_col[r],float(entropy)); - m_attributes.setValue(i,rel_entropy_col[r],float(rel_entropy)); - m_attributes.setValue(i,intensity_col[r],float(intensity)); - m_attributes.setValue(i,harmonic_col[r],float(harmonic)); - } -#endif + netfile << "*Arcs" << std::endl; + // this makes an assumption about which is the "start" and which is the "end" + // it works for an automatically converted axial map, I'm not sure it works for others... + for (size_t j = 0; j < m_connectors.size(); j++) { + const Connector& conn = m_connectors[j]; + for (auto& segconn: conn.m_forward_segconns) { + SegmentRef ref = segconn.first; + float weight = segconn.second; + netfile << (j * 2 + 1) << " " << (ref.ref * 2 + ((ref.dir == 1) ? 1 : 2)) << " " << weight << std::endl; } - else { - m_attributes.setValue(i,depth_col[r],-1.0f); - m_attributes.setValue(i,integ_dv_col[r],-1.0f); - -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - m_attributes.setValue(i,integ_pv_col[r],-1.0f); - m_attributes.setValue(i,integ_tk_col[r],-1.0f); - m_attributes.setValue(i,entropy_col[r],-1.0f); - m_attributes.setValue(i,rel_entropy_col[r],-1.0f); - m_attributes.setValue(i,harmonic_col[r],-1.0f); - } -#endif + for (auto& segconn: conn.m_back_segconns) { + SegmentRef ref = segconn.first; + float weight = segconn.second; + netfile << (j * 2 + 2) << " " << (ref.ref * 2 + ((ref.dir == 1) ? 1 : 2)) << " " << weight << std::endl; } - - } - // - if (comm) { - if (qtimer( atime, 500 )) { - if (comm->IsCancelled()) { - delete [] covered; - throw Communicator::CancelledException(); - } - comm->CommPostMessage( Communicator::CURRENT_RECORD, i ); - } } } - delete [] covered; - if (choice) { - for (size_t i = 0; i < m_connectors.size(); i++) { - double total_choice = 0.0, w_total_choice = 0.0; - for (size_t r = 0; r < radius.size(); r++) { - total_choice += audittrail[i][r].choice; - w_total_choice += audittrail[i][r].weighted_choice; - // n.b., normalise choice according to (n-1)(n-2)/2 (maximum possible through routes) - double node_count = m_attributes.getValue(i,count_col[r]); - double total_weight; - if (weighting_col != -1) { - total_weight = m_attributes.getValue(i,total_weight_col[r]); - } - if (node_count > 2) { - m_attributes.setValue(i,choice_col[r],float(total_choice)); - m_attributes.setValue(i,n_choice_col[r],float(2.0*total_choice/((node_count-1)*(node_count-2)))); - if (weighting_col != -1) { - m_attributes.setValue(i,w_choice_col[r],float(w_total_choice)); - m_attributes.setValue(i,nw_choice_col[r],float(2.0*w_total_choice/(total_weight*total_weight))); - } - } - else { - m_attributes.setValue(i,choice_col[r],-1); - m_attributes.setValue(i,n_choice_col[r],-1); - if (weighting_col != -1) { - m_attributes.setValue(i,w_choice_col[r],-1); - m_attributes.setValue(i,nw_choice_col[r],-1); - } - } - } - } - for (size_t i = 0; i < m_connectors.size(); i++) { - delete [] audittrail[i]; + else { + netfile << "*Vertices " << m_shapes.size() << std::endl; + int i = -1; + for (auto shape: m_shapes) { + i++; + Point2f p = shape.second.getCentroid(); + p.x = offset.x + (p.x - m_region.bottom_left.x) / maxdim; + p.y = 1.0 - (offset.y + (p.y - m_region.bottom_left.y) / maxdim); + netfile << (i + 1) << " \"" << i << "\" " << p.x << " " << p.y << std::endl; } - delete [] audittrail; - } - - m_displayed_attribute = -1; // <- override if it's already showing - setDisplayedAttribute(integ_dv_col.tail()); - - return true; -} - -bool ShapeGraph::stepdepth(Communicator *comm) -{ - pstring stepdepth_col_text = pstring("Step Depth"); - int stepdepth_col = m_attributes.insertColumn(stepdepth_col_text.c_str()); - - bool *covered = new bool [m_connectors.size()]; - for (size_t i = 0; i < m_connectors.size(); i++) { - covered[i] = false; - } - pflipper foundlist; - for (size_t j = 0; j < m_selection_set.size(); j++) { - int lineindex = m_selection_set[j]; - foundlist.a().push_back(lineindex); - covered[lineindex] = true; - m_attributes.setValue(lineindex,stepdepth_col,0.0f); - } - int depth = 1; - while (foundlist.a().size()) { - Connector& line = m_connectors[foundlist.a().tail()]; - for (size_t k = 0; k < line.m_connections.size(); k++) { - if (!covered[line.m_connections[k]]) { - covered[line.m_connections[k]] = true; - foundlist.b().push_back(line.m_connections[k]); - m_attributes.setValue(line.m_connections[k],stepdepth_col,float(depth)); + netfile << "*Edges" << std::endl; + for (size_t j = 0; j < m_connectors.size(); j++) { + const Connector& conn = m_connectors[j]; + for (size_t k = 0; k < conn.m_connections.size(); k++) { + size_t to = conn.m_connections[k]; + if (j < to) { + netfile << (j+1) << " " << (to + 1) << " 1" << std::endl; + } } } - foundlist.a().pop_back(); - if (!foundlist.a().size()) { - foundlist.flip(); - depth++; - } } - delete [] covered; - - m_displayed_attribute = -1; // <- override if it's already showing - setDisplayedAttribute(stepdepth_col); - - return true; } -////////////////////////////////////////////////////////////////////////////////////////// - -bool ShapeGraph::read( ifstream& stream, int version ) +bool ShapeGraph::read(std::istream &stream) { - m_attributes.clear(); + m_attributes->clear(); m_connectors.clear(); m_selection = false; m_map_type = ShapeMap::EMPTYMAP; - // the old version used SpacePixel as base class - // actually easiest to read and translate, rather than try to use new method - if (version < VERSION_AXIAL_SHAPES) { - readold(stream, version); - } - else { - bool segmentmap = false; - if (version < VERSION_MAP_TYPES) { - // axial specific reads -- segment map flag and keyvertices (part of all line map functionality) - // note, now stored in the "map_type", and read / written with shape map - char segmentmapc = stream.get(); - if (segmentmapc == '1') { - segmentmap = true; - } - } - // note that keyvertexcount and keyvertices are different things! (length keyvertices not the same as keyvertexcount!) - stream.read((char *)&m_keyvertexcount,sizeof(m_keyvertexcount)); - int size; - stream.read((char *)&size,sizeof(size)); - for (int i = 0; i < size; i++) { - m_keyvertices.push_back(pvecint()); - m_keyvertices[i].read(stream); - } - // now base class read: - ShapeMap::read(stream,version); - // - // override shapemap map type designation if necessary: - if (version < VERSION_MAP_TYPES) { - if (segmentmap) { - m_map_type = ShapeMap::SEGMENTMAP; - } - else { - m_map_type = ShapeMap::AXIALMAP; - } - } + // note that keyvertexcount and keyvertices are different things! (length keyvertices not the same as keyvertexcount!) + stream.read((char *)&m_keyvertexcount,sizeof(m_keyvertexcount)); + int size; + stream.read((char *)&size,sizeof(size)); + for (int i = 0; i < size; i++) { + std::vector tempVec; + dXreadwrite::readIntoVector(stream, tempVec); + m_keyvertices.push_back(std::set(tempVec.begin(), tempVec.end())); } + // now base class read: + ShapeMap::read(stream); return true; } -bool ShapeGraph::readold( ifstream& stream, int version ) +bool ShapeGraph::readold( std::istream& stream) { // read in from old base class SpacePixel linemap; - linemap.read(stream, version); - const pmap& lines = linemap.getAllLines(); + linemap.read(stream); + const std::map& lines = linemap.getAllLines(); m_name = linemap.getName(); // now copy to new base class: init(lines.size(),linemap.getRegion()); - for (size_t i = 0; i < lines.size(); i++) { - makeLineShape(lines[i].line); + for (auto line: lines) { + makeLineShape(line.second.line); } // n.b., we now have to reclear attributes! - m_attributes.clear(); + m_attributes->clear(); // continue old read: int pushmap = -1; - if (version >= VERSION_SEGMENT_MAPS) { - char segmentmapc = stream.get(); - if (segmentmapc == '1') { - m_map_type = ShapeMap::SEGMENTMAP; - } - else { - m_map_type = ShapeMap::AXIALMAP; - } + + char segmentmapc = stream.get(); + if (segmentmapc == '1') { + m_map_type = ShapeMap::SEGMENTMAP; } - if (version >= VERSION_GATE_MAPS) { - char gatemapc = stream.get(); - if (gatemapc == '1') { - m_map_type = ShapeMap::DATAMAP; - } - stream.read((char *)&pushmap,sizeof(pushmap)); + else { + m_map_type = ShapeMap::AXIALMAP; + } + + char gatemapc = stream.get(); + if (gatemapc == '1') { + m_map_type = ShapeMap::DATAMAP; } + stream.read((char *)&pushmap,sizeof(pushmap)); + int displayed_attribute; // n.b., temp variable necessary to force recalc below stream.read((char *)&displayed_attribute,sizeof(displayed_attribute)); - m_attributes.read(stream,version); + m_attributes->read(stream, m_layers); int size; stream.read((char *)&size,sizeof(size)); for (int j = 0; j < size; j++) { - m_keyvertices.push_back(pvecint()); // <- these were stored with the connector + m_keyvertices.push_back(std::set()); // <- these were stored with the connector int key; stream.read((char *)&key,sizeof(key)); // <- key deprecated m_connectors.push_back(Connector()); - m_connectors[j].read(stream,version,&(m_keyvertices[j])); + m_connectors[size_t(j)].read(stream); } stream.read((char *)&m_keyvertexcount,sizeof(m_keyvertexcount)); - if (version >= VERSION_AXIAL_LINKS) { - m_links.read(stream); - m_unlinks.read(stream); - } - // some miscellaneous extra data for mapinfo files - if (m_mapinfodata) { - delete m_mapinfodata; - m_mapinfodata = NULL; - } - if (version >= VERSION_MAPINFO_DATA) { - char x = stream.get(); - if (x == 'm') { - m_mapinfodata = new MapInfoData; - m_mapinfodata->read(stream,version); - } + + dXreadwrite::readIntoVector(stream,m_links); + dXreadwrite::readIntoVector(stream,m_unlinks); + + char x = stream.get(); + if (x == 'm') { + m_mapinfodata = MapInfoData(); + m_mapinfodata.read(stream); + m_hasMapInfoData = true; } + // now, as soon as loaded, must recalculate our screen display: // note m_displayed_attribute should be -2 in order to force recalc... m_displayed_attribute = -2; @@ -2877,23 +270,124 @@ bool ShapeGraph::readold( ifstream& stream, int version ) return true; } -bool ShapeGraph::write( ofstream& stream, int version ) +bool ShapeGraph::write( std::ofstream& stream ) { // note keyvertexcount and keyvertices are different things! (length keyvertices not the same as keyvertexcount!) stream.write((char *)&m_keyvertexcount,sizeof(m_keyvertexcount)); int size = m_keyvertices.size(); stream.write((char *)&size,sizeof(size)); for (size_t i = 0; i < m_keyvertices.size(); i++) { - m_keyvertices[i].write(stream); + dXreadwrite::writeVector(stream, std::vector( m_keyvertices[i].begin(), m_keyvertices[i].end() )); } // now simply run base class write: - ShapeMap::write(stream,version); + ShapeMap::write(stream); return true; } +void ShapeGraph::writeAxialConnectionsAsDotGraph(std::ostream &stream) +{ + const std::vector& connectors = ShapeMap::getConnections(); + + stream << "strict graph {" << std::endl; + + stream.precision(12); + + for (size_t i = 0; i < connectors.size(); i++) { + const std::vector& connections = connectors[i].m_connections; + for (int connection: connections) { + stream << " " << i << " -- " << connection << std::endl; + } + } + stream << "}" << std::endl; +} + +void ShapeGraph::writeAxialConnectionsAsPairsCSV(std::ostream &stream) +{ + const std::vector& connectors = ShapeMap::getConnections(); + + stream.precision(12); + + stream << "refA,refB" << std::endl; + + for (size_t i = 0; i < connectors.size(); i++) { + auto& connections = connectors[i].m_connections; + if (i != 0) stream << std::endl; + for (auto iter = connections.begin(); iter != connections.end(); ++iter) { + if (iter != connections.begin()) stream << std::endl; + stream << i << "," << *iter; + } + } +} + +void ShapeGraph::writeSegmentConnectionsAsPairsCSV(std::ostream &stream) +{ + const std::vector& connectors = ShapeMap::getConnections(); + + stream.precision(12); + stream << "refA,refB,ss_weight,for_back,dir"; + + // directed links + for (size_t i = 0; i < connectors.size(); i++) { + for (auto& segconn: connectors[i].m_forward_segconns) { + stream << std::endl; + stream << i << "," << segconn.first.ref + << "," << segconn.second + << "," << 0 // forward + << "," << int(segconn.first.dir); + } + + for (auto& segconn: connectors[i].m_back_segconns) { + stream << std::endl; + stream << i << "," << segconn.first.ref + << "," << segconn.second + << "," << 1 // back + << "," << int(segconn.first.dir); + } + } +} + +void ShapeGraph::unlinkAtPoint(const Point2f& unlinkPoint) { + std::vector closepoints; + std::vector> intersections; + PixelRef pix = pixelate(unlinkPoint); + std::vector& pix_shapes = m_pixel_shapes(static_cast(pix.y), static_cast(pix.x)); + auto iter = pix_shapes.begin(); + for (; iter != pix_shapes.end(); ++iter) { + for (auto jter = iter; jter != pix_shapes.end(); ++jter) { + auto aIter = m_shapes.find(int(iter->m_shape_ref)); + auto bIter = m_shapes.find(int(jter->m_shape_ref)); + int a = int(std::distance(m_shapes.begin(), aIter)); + int b = int(std::distance(m_shapes.begin(), bIter)); + auto& connections = m_connectors[size_t(a)].m_connections; + if (aIter != m_shapes.end() && bIter != m_shapes.end() + && aIter->second.isLine() && bIter->second.isLine() + && std::find(connections.begin(), connections.end(), b) != connections.end()) { + closepoints.push_back( intersection_point(aIter->second.getLine(), bIter->second.getLine(), TOLERANCE_A) ); + intersections.push_back( std::pair(a,b) ); + } + } + } + double mindist = -1.0; + int minpair = -1; + int j = 0; + for (auto& closepoint: closepoints) { + if (minpair == -1 || dist(unlinkPoint,closepoint) < mindist) { + mindist = dist(unlinkPoint,closepoint); + minpair = j; + } + j++; + } + if (minpair != -1) { + auto& intersection = intersections[size_t(minpair)]; + unlinkShapes(intersection.first, intersection.second, false); + } + else { + std::cerr << "eek!"; + } +} //////////////////////////////////////////////////////////////////////////// // this unlink options was originally excised on the version 7 recode @@ -2906,44 +400,16 @@ void ShapeGraph::unlinkFromShapeMap(const ShapeMap& shapemap) // find lines in rough vincinity of unlink point, and check for the closest // pair to unlink: - const pqmap& polygons = shapemap.getAllShapes(); - for (size_t i = 0; i < polygons.size(); i++) { - // just use the points: - if (polygons[i].isPoint()) { - pvecpoint closepoints; - prefvec intersections; - PixelRef pix = pixelate(polygons[i].getPoint()); - pqvector& pix_shapes = m_pixel_shapes[pix.x][pix.y]; - size_t j; - for (j = 0; j < pix_shapes.size(); j++) { - for (size_t k = j + 1; k < pix_shapes.size(); k++) { - size_t a = m_shapes.searchindex(pix_shapes[j].m_shape_ref); - size_t b = m_shapes.searchindex(pix_shapes[k].m_shape_ref); - if (a != paftl::npos && b != paftl::npos && m_shapes[a].isLine() && m_shapes[b].isLine() && m_connectors[a].m_connections.searchindex(b) != -1) { - closepoints.push_back( intersection_point(m_shapes[a].getLine(), m_shapes[b].getLine(), TOLERANCE_A) ); - intersections.push_back( IntPair((int)a,(int)b) ); - } - } - } - double mindist = -1.0; - int minpair = -1; - for (j = 0; j < closepoints.size(); j++) { - if (minpair == -1 || dist(polygons[i].getPoint(),closepoints[j]) < mindist) { - mindist = dist(polygons[i].getPoint(),closepoints[j]); - minpair = j; - } - } - if (minpair != -1) { - unlinkShapes(intersections[minpair].a, intersections[minpair].b, false); - } - else { - cerr << "eek!"; - } + const std::map& polygons = shapemap.getAllShapes(); + for (auto polygon: polygons) { + // just use the points: + if (polygon.second.isPoint()) { + unlinkAtPoint(polygon.second.getPoint()); } } // reset displayed attribute if it happens to be "Connectivity": - int conn_col = m_attributes.getColumnIndex("Connectivity"); + int conn_col = m_attributes->getColumnIndex("Connectivity"); if (getDisplayedAttribute() == conn_col) { invalidateDisplayedAttribute(); setDisplayedAttribute(conn_col); // <- reflect changes to connectivity counts @@ -2961,112 +427,125 @@ void ShapeGraph::unlinkFromShapeMap(const ShapeMap& shapemap) void ShapeGraph::makeNewSegMap() { // now make a connection set from the ends of lines: - prefvec connectionset; - pmap lineset; - for (size_t m = 0; m < m_shapes.size(); m++) { - if (m_shapes[m].isLine()) { + std::vector connectionset; + std::map lineset; + for (auto shape: m_shapes) { + if (shape.second.isLine()) { connectionset.push_back(Connector()); - lineset.add(m_shapes.key(m),m_shapes[m].getLine()); + lineset[shape.first] = shape.second.getLine(); } } double maxdim = __max(m_region.width(),m_region.height()); - for (size_t seg_a = 0; seg_a < lineset.size(); seg_a++) { + int seg_a = -1; + for (auto seg_a_line: lineset) { + seg_a++; // n.b., vector() is based on t_start and t_end, so we must use t_start and t_end here and throughout - PixelRef pix1 = pixelate(lineset[seg_a].t_start()); - pqvector &shapes1 = m_pixel_shapes[pix1.x][pix1.y]; - for (size_t j1 = 0; j1 < shapes1.size(); j1++) { - size_t seg_b = lineset.searchindex(shapes1[j1].m_shape_ref); - if (seg_b != paftl::npos && seg_a < seg_b) { - Point2f alpha = lineset[seg_a].vector(); - Point2f beta = lineset[seg_b].vector(); + PixelRef pix1 = pixelate(seg_a_line.second.t_start()); + std::vector &shapes1 = m_pixel_shapes(static_cast(pix1.y), + static_cast(pix1.x)); + for (auto& shape: shapes1) { + auto seg_b_iter = lineset.find(int(shape.m_shape_ref)); + int seg_b = int(std::distance(lineset.begin(), seg_b_iter)); + if (seg_b_iter != lineset.end() && seg_a < seg_b) { + Point2f alpha = seg_a_line.second.vector(); + Point2f beta = seg_b_iter->second.vector(); alpha.normalise(); beta.normalise(); - if (approxeq(lineset[seg_a].t_start(),lineset[seg_b].t_start(),(maxdim*TOLERANCE_B))) { + if (approxeq(seg_a_line.second.t_start(),seg_b_iter->second.t_start(),(maxdim*TOLERANCE_B))) { float x = float(2.0 * acos(__min(__max(-dot(alpha,beta),-1.0),1.0)) / M_PI); - connectionset[seg_a].m_back_segconns.add(SegmentRef(1,seg_b),x); - connectionset[seg_b].m_back_segconns.add(SegmentRef(1,seg_a),x); + depthmapX::addIfNotExists(connectionset[size_t(seg_a)].m_back_segconns, SegmentRef(1,seg_b), x); + depthmapX::addIfNotExists(connectionset[size_t(seg_b)].m_back_segconns, SegmentRef(1,seg_a), x); } - if (approxeq(lineset[seg_a].t_start(),lineset[seg_b].t_end(),(maxdim*TOLERANCE_B))) { + if (approxeq(seg_a_line.second.t_start(),seg_b_iter->second.t_end(),(maxdim*TOLERANCE_B))) { float x = float(2.0 * acos(__min(__max(-dot(alpha,-beta),-1.0),1.0)) / M_PI); - connectionset[seg_a].m_back_segconns.add(SegmentRef(-1,seg_b),x); - connectionset[seg_b].m_forward_segconns.add(SegmentRef(1,seg_a),x); + depthmapX::addIfNotExists(connectionset[size_t(seg_a)].m_back_segconns, SegmentRef(-1,seg_b), x); + depthmapX::addIfNotExists(connectionset[size_t(seg_b)].m_forward_segconns, SegmentRef(1,seg_a), x); } } } - PixelRef pix2 = pixelate(m_shapes[seg_a].getLine().t_end()); - pqvector &shapes2 = m_pixel_shapes[pix2.x][pix2.y]; - for (size_t j2 = 0; j2 < shapes2.size(); j2++) { - size_t seg_b = lineset.searchindex(shapes2[j2].m_shape_ref); - if (seg_b != paftl::npos && seg_a < seg_b) { - Point2f alpha = lineset[seg_a].vector(); - Point2f beta = lineset[seg_b].vector(); + + PixelRef pix2 = pixelate(seg_a_line.second.t_end()); + std::vector &shapes2 = m_pixel_shapes(static_cast(pix2.y), + static_cast(pix2.x)); + for (auto& shape: shapes2) { + auto seg_b_iter = lineset.find(int(shape.m_shape_ref)); + int seg_b = int(std::distance(lineset.begin(), seg_b_iter)); + if (seg_b_iter != lineset.end() && seg_a < seg_b) { + Point2f alpha = seg_a_line.second.vector(); + Point2f beta = seg_b_iter->second.vector(); alpha.normalise(); beta.normalise(); - if (approxeq(lineset[seg_a].t_end(),lineset[seg_b].t_start(),(maxdim*TOLERANCE_B))) { + if (approxeq(seg_a_line.second.t_end(),seg_b_iter->second.t_start(),(maxdim*TOLERANCE_B))) { float x = float(2.0 * acos(__min(__max(-dot(-alpha,beta),-1.0),1.0)) / M_PI); - connectionset[seg_a].m_forward_segconns.add(SegmentRef(1,seg_b),x); - connectionset[seg_b].m_back_segconns.add(SegmentRef(-1,seg_a),x); + depthmapX::addIfNotExists(connectionset[size_t(seg_a)].m_forward_segconns, SegmentRef(1,seg_b), x); + depthmapX::addIfNotExists(connectionset[size_t(seg_b)].m_back_segconns, SegmentRef(-1,seg_a), x); } - if (approxeq(lineset[seg_a].t_end(),lineset[seg_b].t_end(),(maxdim*TOLERANCE_B))) { + if (approxeq(seg_a_line.second.t_end(),seg_b_iter->second.t_end(),(maxdim*TOLERANCE_B))) { float x = float(2.0 * acos(__min(__max(-dot(-alpha,-beta),-1.0),1.0)) / M_PI); - connectionset[seg_a].m_forward_segconns.add(SegmentRef(-1,seg_b),x); - connectionset[seg_b].m_forward_segconns.add(SegmentRef(-1,seg_a),x); + depthmapX::addIfNotExists(connectionset[size_t(seg_a)].m_forward_segconns, SegmentRef(-1,seg_b), x); + depthmapX::addIfNotExists(connectionset[size_t(seg_b)].m_forward_segconns, SegmentRef(-1,seg_a), x); } } } } // initialise attributes now separated from making the connections - initSegmentAttributes(connectionset); makeSegmentConnections(connectionset); } // Method 2: Making a segment map (in two stages) -// One: take the original axial map and split it up +// One: take the original axial map and split it up // (note: you need to start from an axial map, // but the map could have been created from a road-centre-line -// graph or equivalent -- reason is that you might want to +// graph or equivalent -- reason is that you might want to // preserve unlinks in your angular mapping) // A "linetest" is used in order to use the test component to -// identify the original axial line this line segment is +// identify the original axial line this line segment is // associated with -void ShapeGraph::makeSegmentMap(prefvec& lineset, prefvec& connectionset, double stubremoval) +void ShapeGraph::makeSegmentMap(std::vector& lines, std::vector& connectors, double stubremoval) { // the first (key) pair is the line / line intersection, second is the pair of associated segments for the first line - pqmap segmentlist; + std::map> segmentlist; // this code relies on the polygon order being the same as the connections + auto iter = m_shapes.begin(); for (size_t i = 0; i < m_connectors.size(); i++) { - if (!m_shapes[i].isLine()) { + auto shape = iter->second; + iter++; + if (!shape.isLine()) { continue; } - const Line& line = m_shapes[i].getLine(); - pmap breaks; + const Line& line = shape.getLine(); + std::vector > breaks; // this is a vector instead of a map because the + // original code allowed for duplicate keys int axis = line.width() >= line.height() ? XAXIS : YAXIS; // we need the breaks ordered from start to end of the line // this is automatic for XAXIS, but on YAXIS, need to know // if the line is ascending or decending int parity = (axis == XAXIS) ? 1 : line.sign(); - pvecint& connections = m_connectors[i].m_connections; + auto& connections = m_connectors[i].m_connections; for (size_t j = 0; j < connections.size(); j++) { // find the intersection point and add... // note: more than one break at the same place allowed - if (i != connections[j] && m_shapes[connections[j]].isLine()) { - breaks.add( parity * line.intersection_point( m_shapes[connections[j]].getLine(), axis, TOLERANCE_A ), connections[j], paftl::ADD_DUPLICATE ); + auto shapeJ = depthmapX::getMapAtIndex(m_shapes, connections[j])->second; + if (static_cast(i) != connections[j] && shapeJ.isLine()) { + breaks.push_back(std::make_pair(parity * line.intersection_point( shapeJ.getLine(), axis, TOLERANCE_A ), + connections[j])); } } + std::sort(breaks.begin(), breaks.end()); // okay, now we have a list from one end of the other of lines this line connects with Point2f lastpoint = line.start(); int seg_a = -1, seg_b = -1; double neardist; - // TOLERANCE_C is introduced as of 01.08.2008 although it is a fix to a bug first + // TOLERANCE_C is introduced as of 01.08.2008 although it is a fix to a bug first // found in July 2006. It has been set "high" deliberately (1e-6 = a millionth of the line height / width) // in order to catch small errors made by operators or floating point errors in other systems // when drawing, for example, three axial lines intersecting @@ -3077,44 +556,44 @@ void ShapeGraph::makeSegmentMap(prefvec& lineset, prefvec& conn neardist = (axis == XAXIS) ? (line.width() * stubremoval) : (line.height() * stubremoval); double overlapdist = (axis == XAXIS) ? (line.width() * TOLERANCE_C) : (line.height() * TOLERANCE_C); // - for (size_t k = 0; k < breaks.size(); ) { - pvecint keylist; + for (auto breaksIter = breaks.begin(); breaksIter != breaks.end();) { + std::vector keylist; if (seg_a == -1) { - Point2f thispoint = line.point_on_line(parity * breaks.key(k),axis); - if (fabs(parity * breaks.key(k) - line.start()[axis]) < neardist) { + Point2f thispoint = line.point_on_line(parity * breaksIter->first,axis); + if (fabs(parity * breaksIter->first - line.start()[axis]) < neardist) { seg_a = -1; lastpoint = thispoint; } else { Line segment_a(line.start(),thispoint); - lineset.push_back(segment_a); - connectionset.push_back(Connector(i)); - seg_a = lineset.size() - 1; + lines.push_back(segment_a); + connectors.push_back(Connector(i)); + seg_a = lines.size() - 1; } lastpoint = thispoint; } // - double here = parity * breaks.key(k); - while (k < breaks.size() && fabs(parity * breaks.key(k) - here) < overlapdist) { - keylist.push_back(breaks.value(k)); - k++; + double here = parity * breaksIter->first; + while (breaksIter != breaks.end() && fabs(parity * breaksIter->first - here) < overlapdist) { + keylist.push_back(breaksIter->second); + ++breaksIter; } // - if (k == breaks.size() && fabs(line.end()[axis] - parity * breaks.key(k-1)) < neardist) { + if (breaksIter == breaks.end() && fabs(line.end()[axis] - parity * breaks.rbegin()->first) < neardist) { seg_b = -1; } else { Point2f thispoint; - if (k < breaks.size()) { - thispoint = line.point_on_line(parity * breaks.key(k),axis); + if (breaksIter != breaks.end()) { + thispoint = line.point_on_line(parity * breaksIter->first,axis); } else { thispoint = line.end(); } Line segment_b(lastpoint,thispoint); - lineset.push_back(segment_b); - connectionset.push_back(Connector(i)); - seg_b = lineset.size() - 1; + lines.push_back(segment_b); + connectors.push_back(Connector(i)); + seg_b = lines.size() - 1; // lastpoint = thispoint; } @@ -3124,48 +603,48 @@ void ShapeGraph::makeSegmentMap(prefvec& lineset, prefvec& conn if (keylist[j] < (int)i) { // other line already segmented, look up in segment list, // and join segments together nicely - size_t index = segmentlist.searchindex(OrderedIntPair(keylist[j],i)); - if (index != paftl::npos) { // <- if it isn't -1 something has gone badly wrong! - int seg_1 = segmentlist[index].a; - int seg_2 = segmentlist[index].b; + auto segIter = segmentlist.find(OrderedIntPair(keylist[j],i)); + if (segIter != segmentlist.end()) { // <- if it isn't -1 something has gone badly wrong! + int seg_1 = segIter->second.first; + int seg_2 = segIter->second.second; if (seg_a != -1) { if (seg_1 != -1) { - Point2f alpha = lineset[seg_a].start() - lineset[seg_a].end(); - Point2f beta = lineset[seg_1].start() - lineset[seg_1].end(); + Point2f alpha = lines[size_t(seg_a)].start() - lines[size_t(seg_a)].end(); + Point2f beta = lines[size_t(seg_1)].start() - lines[size_t(seg_1)].end(); alpha.normalise(); beta.normalise(); float x = float(2.0 * acos(__min(__max(-dot(alpha,beta),-1.0),1.0)) / M_PI); - connectionset[seg_a].m_forward_segconns.add(SegmentRef(-1,seg_1),x); - connectionset[seg_1].m_forward_segconns.add(SegmentRef(-1,seg_a),x); + depthmapX::addIfNotExists(connectors[size_t(seg_a)].m_forward_segconns, SegmentRef(-1,seg_1), x); + depthmapX::addIfNotExists(connectors[size_t(seg_1)].m_forward_segconns, SegmentRef(-1,seg_a), x); } if (seg_2 != -1) { - Point2f alpha = lineset[seg_a].start() - lineset[seg_a].end(); - Point2f beta = lineset[seg_2].end() - lineset[seg_2].start(); + Point2f alpha = lines[size_t(seg_a)].start() - lines[size_t(seg_a)].end(); + Point2f beta = lines[size_t(seg_2)].end() - lines[size_t(seg_2)].start(); alpha.normalise(); beta.normalise(); float x = float(2.0 * acos(__min(__max(-dot(alpha,beta),-1.0),1.0)) / M_PI); - connectionset[seg_a].m_forward_segconns.add(SegmentRef(1,seg_2),x); - connectionset[seg_2].m_back_segconns.add(SegmentRef(-1,seg_a),x); + depthmapX::addIfNotExists(connectors[size_t(seg_a)].m_forward_segconns, SegmentRef(1,seg_2), x); + depthmapX::addIfNotExists(connectors[size_t(seg_2)].m_back_segconns, SegmentRef(-1,seg_a), x); } } if (seg_b != -1) { if (seg_1 != -1) { - Point2f alpha = lineset[seg_b].end() - lineset[seg_b].start(); - Point2f beta = lineset[seg_1].start() - lineset[seg_1].end(); + Point2f alpha = lines[size_t(seg_b)].end() - lines[size_t(seg_b)].start(); + Point2f beta = lines[size_t(seg_1)].start() - lines[size_t(seg_1)].end(); alpha.normalise(); beta.normalise(); float x = float(2.0 * acos(__min(__max(-dot(alpha,beta),-1.0),1.0)) / M_PI); - connectionset[seg_b].m_back_segconns.add(SegmentRef(-1,seg_1),x); - connectionset[seg_1].m_forward_segconns.add(SegmentRef(1,seg_b),x); + depthmapX::addIfNotExists(connectors[size_t(seg_b)].m_back_segconns, SegmentRef(-1,seg_1), x); + depthmapX::addIfNotExists(connectors[size_t(seg_1)].m_forward_segconns, SegmentRef(1,seg_b), x); } if (seg_2 != -1) { - Point2f alpha = lineset[seg_b].end() - lineset[seg_b].start(); - Point2f beta = lineset[seg_2].end() - lineset[seg_2].start(); + Point2f alpha = lines[size_t(seg_b)].end() - lines[size_t(seg_b)].start(); + Point2f beta = lines[size_t(seg_2)].end() - lines[size_t(seg_2)].start(); alpha.normalise(); beta.normalise(); float x = float(2.0 * acos(__min(__max(-dot(alpha,beta),-1.0),1.0)) / M_PI); - connectionset[seg_b].m_back_segconns.add(SegmentRef(1,seg_2),x); - connectionset[seg_2].m_back_segconns.add(SegmentRef(1,seg_b),x); + depthmapX::addIfNotExists(connectors[size_t(seg_b)].m_back_segconns, SegmentRef(1,seg_2), x); + depthmapX::addIfNotExists(connectors[size_t(seg_2)].m_back_segconns, SegmentRef(1,seg_b), x); } } } @@ -3173,61 +652,64 @@ void ShapeGraph::makeSegmentMap(prefvec& lineset, prefvec& conn else { // other line still to be segmented, add ourselves to segment list // to be added later - segmentlist.add( OrderedIntPair(i,keylist[j]), IntPair(seg_a,seg_b) ); + segmentlist.insert(std::make_pair( OrderedIntPair(i,keylist[j]), std::pair(seg_a,seg_b) )); } } if (seg_a != -1 && seg_b != -1) { - connectionset[seg_a].m_forward_segconns.add(SegmentRef(1,seg_b),0.0f); - connectionset[seg_b].m_back_segconns.add(SegmentRef(-1,seg_a),0.0f); + depthmapX::addIfNotExists(connectors[size_t(seg_a)].m_forward_segconns, SegmentRef(1,seg_b), 0.0f); + depthmapX::addIfNotExists(connectors[size_t(seg_b)].m_back_segconns, SegmentRef(-1,seg_a), 0.0f); } seg_a = seg_b; } } } +void ShapeGraph::initialiseAttributesSegment() +{ + m_attributes->clear(); + + // note, expects these in alphabetical order to preserve numbering: + m_attributes->insertOrResetLockedColumn("Axial Line Ref"); + m_attributes->insertOrResetLockedColumn("Segment Length"); +} + // now segments and connections are listed separately... // put them together in a new map -void ShapeGraph::initSegmentAttributes(prefvec& connectionset) +void ShapeGraph::makeSegmentConnections(std::vector& connectionset) { - m_attributes.clear(); + m_connectors.clear(); // note, expects these in alphabetical order to preserve numbering: - int ref_col = m_attributes.insertLockedColumn("Axial Line Ref"); - int leng_col = m_attributes.insertLockedColumn("Segment Length"); + int w_conn_col = m_attributes->getOrInsertColumn("Angular Connectivity"); + int uw_conn_col = m_attributes->getOrInsertLockedColumn("Connectivity"); - for (size_t i = 0; i < m_shapes.size(); i++) { - int key = m_shapes.key(i); - int rowid = m_attributes.insertRow(key); - // - m_attributes.setValue(rowid, ref_col, (float) connectionset[i].m_segment_axialref ); - m_attributes.setValue(rowid, leng_col, (float) m_shapes[i].getLine().length() ); - } -} + int ref_col = m_attributes->getColumnIndex("Axial Line Ref"); + int leng_col = m_attributes->getColumnIndex("Segment Length"); -void ShapeGraph::makeSegmentConnections(prefvec& connectionset) -{ - m_connectors.clear(); + int i = -1; + for (auto shape: m_shapes) { + i++; + Connector& connector = connectionset[size_t(i)]; + AttributeRow& row = m_attributes->getRow(AttributeKey(shape.first)); - // note, expects these in alphabetical order to preserve numbering: - int w_conn_col = m_attributes.insertColumn("Angular Connectivity"); - int uw_conn_col = m_attributes.insertLockedColumn("Connectivity"); + row.setValue(ref_col, float(connector.m_segment_axialref)); + row.setValue(leng_col, float(shape.second.getLine().length())); - for (size_t i = 0; i < m_shapes.size(); i++) { // all indices should match... (including lineset/connectionset versus m_shapes) - m_connectors.push_back( connectionset[i] ); + m_connectors.push_back( connector ); float total_weight = 0.0f; - for (size_t j = 0; j < connectionset[i].m_forward_segconns.size(); j++) { - total_weight += connectionset[i].m_forward_segconns.value(j); + for (auto iter = connector.m_forward_segconns.begin(); iter != connector.m_forward_segconns.end(); ++iter) { + total_weight += iter->second; } - for (size_t k = 0; k < connectionset[i].m_back_segconns.size(); k++) { - total_weight += connectionset[i].m_back_segconns.value(k); + for (auto iter = connector.m_back_segconns.begin(); iter != connector.m_back_segconns.end(); ++iter) { + total_weight += iter->second; } - m_attributes.setValue(i, w_conn_col, (float) total_weight ); - m_attributes.setValue(i, uw_conn_col, (float) (connectionset[i].m_forward_segconns.size() + connectionset[i].m_back_segconns.size())); + row.setValue(w_conn_col, float(total_weight)); + row.setValue(uw_conn_col, float(connector.m_forward_segconns.size() + connector.m_back_segconns.size())); // free up connectionset as we go along: - connectionset.free_at(i); + connectionset[size_t(i)] = Connector(); } m_displayed_attribute = -2; // <- override if it's already showing @@ -3239,1041 +721,26 @@ void ShapeGraph::makeSegmentConnections(prefvec& connectionset) void ShapeGraph::pushAxialValues(ShapeGraph& axialmap) { - if (m_attributes.getColumnIndex("Axial Line Ref") == -1) { + if (!m_attributes->hasColumn("Axial Line Ref")) { // this should never happen // AT: I am converting this to throw an error - throw MetaGraph::Error("Axial line ref does not exist"); + throw depthmapX::RuntimeException("Axial line ref does not exist"); } - pvecint colindices; - for (int i = 0; i < axialmap.m_attributes.getColumnCount(); i++) { - pstring colname = pstring("Axial ") + axialmap.m_attributes.getColumnName(i); - colindices.push_back(m_attributes.insertColumn(colname)); + std::vector colindices; + for (size_t i = 0; i < axialmap.m_attributes->getNumColumns(); i++) { + std::string colname = std::string("Axial ") + axialmap.m_attributes->getColumnName(i); + colindices.push_back(m_attributes->getOrInsertColumn(colname)); } - for (int j = 0; j < m_attributes.getRowCount(); j++) { - int axialref = (int) m_attributes.getValue(j,"Axial Line Ref"); - for (int k = 0; k < axialmap.m_attributes.getColumnCount(); k++) { - float val = axialmap.m_attributes.getValue(axialref,k); + for (auto iter = m_attributes->begin(); iter != m_attributes->end(); iter++) { + int axialref = (int) iter->getRow().getValue("Axial Line Ref"); + // P.K: The original code here got the index of the row, but the column + // "Axial Line Ref" should actually contain keys, not indices + AttributeRow& row = axialmap.m_attributes->getRow(AttributeKey(axialref)); + for (size_t k = 0; k < axialmap.m_attributes->getNumColumns(); k++) { + float val = row.getValue(k); // need to look up the column index: - m_attributes.setValue(j,colindices[k],val); - } - } -} - -bool ShapeGraph::analyseAngular(Communicator *comm, const pvecdouble& radius_list) -{ - if (m_map_type != ShapeMap::SEGMENTMAP) { - return false; - } - - // Quick mod - TV -#if defined(_WIN32) - __time64_t atime = 0; -#else - time_t atime = 0; -#endif - if (comm) { - qtimer( atime, 0 ); - comm->CommPostMessage( Communicator::NUM_RECORDS, m_connectors.size() ); - } - - // note: radius must be sorted lowest to highest, but if -1 occurs ("radius n") it needs to be last... - // ...to ensure no mess ups, we'll re-sort here: - bool radius_n = false; - pvecdouble radius; - for (size_t i = 0; i < radius_list.size(); i++) { - if (radius_list[i] == -1.0) { - radius_n = true; - } - else { - radius.add(radius_list[i]); - } - } - if (radius_n) { - radius.push_back(-1.0); - } - - pvecint depth_col, count_col, total_col; - // first enter table values - size_t r; - for (r = 0; r < radius.size(); r++) { - pstring radius_text = makeRadiusText(Options::RADIUS_ANGULAR,radius[r]); - pstring depth_col_text = pstring("Angular Mean Depth") + radius_text; - m_attributes.insertColumn(depth_col_text.c_str()); - pstring count_col_text = pstring("Angular Node Count") + radius_text; - m_attributes.insertColumn(count_col_text.c_str()); - pstring total_col_text = pstring("Angular Total Depth") + radius_text; - m_attributes.insertColumn(total_col_text.c_str()); - } - - for (r = 0; r < radius.size(); r++) { - pstring radius_text = makeRadiusText(Options::RADIUS_ANGULAR,radius[r]); - pstring depth_col_text = pstring("Angular Mean Depth") + radius_text; - depth_col.push_back(m_attributes.getColumnIndex(depth_col_text.c_str())); - pstring count_col_text = pstring("Angular Node Count") + radius_text; - count_col.push_back(m_attributes.getColumnIndex(count_col_text.c_str())); - pstring total_col_text = pstring("Angular Total Depth") + radius_text; - total_col.push_back(m_attributes.getColumnIndex(total_col_text.c_str())); - } - - - bool *covered = new bool [m_connectors.size()]; - for (size_t i = 0; i < m_connectors.size(); i++) { - for (size_t j = 0; j < m_connectors.size(); j++) { - covered[j] = false; - } - pmap anglebins; - anglebins.add(0.0f,SegmentData(0,i,SegmentRef(),0,0.0,0)); - Connector& thisline = m_connectors[i]; - pvecdouble total_depth; - pvecint node_count; - size_t r; - for (r = 0; r < radius.size(); r++) { - total_depth.push_back(0.0); - node_count.push_back(0); - } - // node_count includes this one, but will be added in next algo: - while (anglebins.size()) { - SegmentData lineindex = anglebins.value(0); - if (!covered[lineindex.ref]) { - covered[lineindex.ref] = true; - double depth_to_line = anglebins.key(0); - total_depth[lineindex.coverage] += depth_to_line; - node_count[lineindex.coverage] += 1; - anglebins.remove_at(0); - Connector& line = m_connectors[lineindex.ref]; - if (lineindex.dir != -1) { - for (size_t k = 0; k < line.m_forward_segconns.size(); k++) { - if (!covered[line.m_forward_segconns.key(k).ref]) { - double angle = depth_to_line + line.m_forward_segconns.value(k); - int rbin = lineindex.coverage; - while (rbin != radius.size() && radius[rbin] != -1 && angle > radius[rbin]) { - rbin++; - } - if (rbin != radius.size()) { - anglebins.add(angle, SegmentData(line.m_forward_segconns.key(k),SegmentRef(),0,0.0,rbin), paftl::ADD_DUPLICATE); - } - } - } - } - if (lineindex.dir != 1) { - for (size_t k = 0; k < line.m_back_segconns.size(); k++) { - if (!covered[line.m_back_segconns.key(k).ref]) { - double angle = depth_to_line + line.m_back_segconns.value(k); - int rbin = lineindex.coverage; - while (rbin != radius.size() && radius[rbin] != -1 && angle > radius[rbin]) { - rbin++; - } - if (rbin != radius.size()) { - anglebins.add(angle, SegmentData(line.m_back_segconns.key(k),SegmentRef(),0,0.0,rbin), paftl::ADD_DUPLICATE); - } - } - } - } - } - else { - anglebins.remove_at(0); - } - } - // set the attributes for this node: - int curs_node_count = 0; - double curs_total_depth = 0.0; - for (r = 0; r < radius.size(); r++) { - curs_node_count += node_count[r]; - curs_total_depth += total_depth[r]; - m_attributes.setValue(i,count_col[r],float(curs_node_count)); - if (curs_node_count > 1) { - // note -- node_count includes this one -- mean depth as per p.108 Social Logic of Space - double mean_depth = curs_total_depth / double(curs_node_count - 1); - m_attributes.setValue(i,depth_col[r],float(mean_depth)); - m_attributes.setValue(i,total_col[r],float(curs_total_depth)); - } - else { - m_attributes.setValue(i,depth_col[r],-1); - m_attributes.setValue(i,total_col[r],-1); - } - } - // - if (comm) { - if (qtimer( atime, 500 )) { - if (comm->IsCancelled()) { - delete [] covered; - throw Communicator::CancelledException(); - } - comm->CommPostMessage( Communicator::CURRENT_RECORD, i ); - } - } - } - delete [] covered; - - m_displayed_attribute = -2; // <- override if it's already showing - setDisplayedAttribute(depth_col.tail()); - - return true; -} - -// extra parameters for selection_only and interactive are for parallel process extensions -int ShapeGraph::analyseTulip(Communicator *comm, int tulip_bins, bool choice, int radius_type, const pvecdouble& radius_list, int weighting_col, int weighting_col2, int routeweight_col, bool selection_only, bool interactive) -{ - int processed_rows = 0; - - if (m_map_type != ShapeMap::SEGMENTMAP) { - return processed_rows; - } - - // Quick mod - TV -#if defined(_WIN32) - __time64_t atime = 0; -#else - time_t atime = 0; -#endif - - if (comm) { - qtimer( atime, 0 ); - comm->CommPostMessage( Communicator::NUM_RECORDS, (selection_only ? m_selection_set.size() : m_connectors.size()) ); - } - - // note: radius must be sorted lowest to highest, but if -1 occurs ("radius n") it needs to be last... - // ...to ensure no mess ups, we'll re-sort here: - bool radius_n = false; - pvecdouble radius_unconverted; - for (size_t i = 0; i < radius_list.size(); i++) { - if (radius_list[i] == -1.0) { - radius_n = true; - } - else { - radius_unconverted.add(radius_list[i]); - } - } - if (radius_n) { - radius_unconverted.push_back(-1.0); - } - - // retrieve weighted col data, as this may well be overwritten in the new analysis: - pvecfloat weights; - pvecfloat routeweights; //EF - pstring weighting_col_text; - - if (weighting_col != -1) { - weighting_col_text = m_attributes.getColumnName(weighting_col); - for (size_t i = 0; i < m_connectors.size(); i++) { - weights.push_back(m_attributes.getValue(i,weighting_col)); - } - } - else { // Normal run // TV - for (size_t i = 0; i < m_connectors.size(); i++) { - weights.push_back(1.0f); - } - } - //EF routeweight* - pstring routeweight_col_text; - if (routeweight_col != -1) { - //we normalise the column values between 0 and 1 and reverse it so that high values can be treated as a 'low cost' - similar to the angular cost - double max_value = m_attributes.getMaxValue(routeweight_col); - routeweight_col_text = m_attributes.getColumnName(routeweight_col); - for (size_t i = 0; i < m_connectors.size(); i++) { - routeweights.push_back(1.0-(m_attributes.getValue(i, routeweight_col)/max_value)); //scale and revert! - } - } - else { // Normal run // TV - for (size_t i = 0; i < m_connectors.size(); i++) { - routeweights.push_back(1.0f); - } - } - //*EF routeweight - - //EFEF* - //for origin-destination weighting - pvecfloat weights2; - pstring weighting_col_text2; - if (weighting_col2 != -1) { - weighting_col_text2 = m_attributes.getColumnName(weighting_col2); - for (size_t i = 0; i < m_connectors.size(); i++) { - weights2.push_back(m_attributes.getValue(i,weighting_col2)); - } - } - else { // Normal run // TV - for (size_t i = 0; i < m_connectors.size(); i++) { - weights2.push_back(1.0f); - } - } - //*EFEF - - pstring tulip_text = pstring("T") + pstringify(tulip_bins,"%d"); - - // first enter the required attribute columns: - size_t r; - for (r = 0; r < radius_unconverted.size(); r++) { - pstring radius_text = makeRadiusText(radius_type, radius_unconverted[r]); - int choice_col = -1, n_choice_col = -1, w_choice_col = -1, nw_choice_col = -1; - if (choice) { - //EF routeweight * - if (routeweight_col != -1) { - pstring choice_col_text = tulip_text + pstring(" Choice [Route weight by ") + routeweight_col_text + pstring("]")+ radius_text; - m_attributes.insertColumn(choice_col_text.c_str()); - if (weighting_col != -1) { - pstring w_choice_col_text = tulip_text + pstring(" Choice [[Route weight by ") + routeweight_col_text + pstring("][") + weighting_col_text + pstring(" Wgt]]") + radius_text; - - m_attributes.insertColumn(w_choice_col_text.c_str()); - } - //EFEF* - if (weighting_col2 != -1) { - pstring w_choice_col_text2 = tulip_text + pstring(" Choice [[Route weight by ") + routeweight_col_text + pstring("][") + weighting_col_text + "-" + weighting_col_text2 + pstring(" Wgt]]") + radius_text; - - m_attributes.insertColumn(w_choice_col_text2.c_str()); - } - //*EFEF - } - //*EF routeweight - else { // Normal run // TV - pstring choice_col_text = tulip_text + pstring(" Choice") + radius_text; - m_attributes.insertColumn(choice_col_text.c_str()); - if (weighting_col != -1) { - pstring w_choice_col_text = tulip_text + pstring(" Choice [") + weighting_col_text + pstring(" Wgt]") + radius_text; - m_attributes.insertColumn(w_choice_col_text.c_str()); - } - //EFEF* - if (weighting_col2 != -1) { - pstring w_choice_col_text2 = tulip_text + pstring(" Choice [") + weighting_col_text + "-" + weighting_col_text2 + pstring(" Wgt]") + radius_text; - m_attributes.insertColumn(w_choice_col_text2.c_str()); - } - //*EFEF - } - } - - //EF routeweight * - if (routeweight_col != -1) { - pstring integ_col_text = tulip_text + pstring(" Integration [Route weight by ") + routeweight_col_text + pstring("]")+ radius_text; // <- note, the fact this is a tulip is unnecessary - pstring w_integ_col_text = tulip_text + pstring(" Integration [[Route weight by ") + routeweight_col_text + pstring("][") + weighting_col_text + pstring(" Wgt]]") + radius_text; - - pstring count_col_text = tulip_text + pstring(" Node Count [Route weight by ") + routeweight_col_text + pstring("]")+ radius_text; // <- note, the fact this is a tulip is unnecessary - pstring td_col_text = tulip_text + pstring(" Total Depth [Route weight by ") + routeweight_col_text + pstring("]")+ radius_text; // <- note, the fact this is a tulip is unnecessary - // '[' comes after 'R' in ASCII, so this column will come after Mean Depth R... - pstring w_td_text = tulip_text + pstring(" Total Depth [[Route weight by ") + routeweight_col_text + pstring("][") + weighting_col_text + pstring(" Wgt]]") + radius_text; - pstring total_weight_text = tulip_text + pstring(" Total " + weighting_col_text + " [Route weight by ") + routeweight_col_text + pstring("]") +radius_text; - - m_attributes.insertColumn(integ_col_text.c_str()); - m_attributes.insertColumn(count_col_text.c_str()); - m_attributes.insertColumn(td_col_text.c_str()); - if (weighting_col != -1) { - m_attributes.insertColumn(w_integ_col_text.c_str()); - m_attributes.insertColumn(w_td_text.c_str()); - m_attributes.insertColumn(total_weight_text.c_str()); - } - } - //*EF routeweight - else { // Normal run // TV - pstring integ_col_text = tulip_text + pstring(" Integration") + radius_text; // <- note, the fact this is a tulip is unnecessary - pstring w_integ_col_text = tulip_text + pstring(" Integration [") + weighting_col_text + pstring(" Wgt]") + radius_text; - - pstring count_col_text = tulip_text + pstring(" Node Count") + radius_text; // <- note, the fact this is a tulip is unnecessary - pstring td_col_text = tulip_text + pstring(" Total Depth") + radius_text; // <- note, the fact this is a tulip is unnecessary - // '[' comes after 'R' in ASCII, so this column will come after Mean Depth R... - pstring w_td_text = tulip_text + pstring(" Total Depth [") + weighting_col_text + pstring(" Wgt]") + radius_text; - pstring total_weight_text = tulip_text + pstring(" Total ") + weighting_col_text + radius_text; - - m_attributes.insertColumn(integ_col_text.c_str()); - m_attributes.insertColumn(count_col_text.c_str()); - m_attributes.insertColumn(td_col_text.c_str()); - if (weighting_col != -1) { - m_attributes.insertColumn(w_integ_col_text.c_str()); - m_attributes.insertColumn(w_td_text.c_str()); - m_attributes.insertColumn(total_weight_text.c_str()); - } - } - } - pvecint choice_col, w_choice_col, w_choice_col2, count_col, integ_col, w_integ_col, td_col, w_td_col, total_weight_col; - // then look them up! eek.... - for (r = 0; r < radius_unconverted.size(); r++) { - pstring radius_text = makeRadiusText(radius_type, radius_unconverted[r]); - if (choice) { - //EF routeweight * - if (routeweight_col != -1) { - pstring choice_col_text = tulip_text + pstring(" Choice [Route weight by ") + routeweight_col_text + pstring("]")+ radius_text; - choice_col.push_back(m_attributes.getColumnIndex(choice_col_text.c_str())); - if (weighting_col != -1) { - pstring w_choice_col_text = tulip_text + pstring(" Choice [[Route weight by ") + routeweight_col_text + pstring("][") + weighting_col_text + pstring(" Wgt]]") + radius_text; - w_choice_col.push_back(m_attributes.getColumnIndex(w_choice_col_text.c_str())); - } - //EFEF* - if (weighting_col2 != -1) { - pstring w_choice_col_text2 = tulip_text + pstring(" Choice [[Route weight by ") + routeweight_col_text + pstring("][") + weighting_col_text + "-" + weighting_col_text2 + pstring(" Wgt]]") + radius_text; - w_choice_col2.push_back(m_attributes.getColumnIndex(w_choice_col_text2.c_str())); - } - //*EFEF - } - //* EF routeweight - else { // Normal run // TV - pstring choice_col_text = tulip_text + pstring(" Choice") + radius_text; - choice_col.push_back(m_attributes.getColumnIndex(choice_col_text.c_str())); - if (weighting_col != -1) { - pstring w_choice_col_text = tulip_text + pstring(" Choice [") + weighting_col_text + pstring(" Wgt]") + radius_text; - w_choice_col.push_back(m_attributes.getColumnIndex(w_choice_col_text.c_str())); - } - //EFEF* - if (weighting_col2 != -1) { - pstring w_choice_col_text2 = tulip_text + pstring(" Choice [") + weighting_col_text + "-" + weighting_col_text2 + pstring(" Wgt]") + radius_text; - w_choice_col2.push_back(m_attributes.getColumnIndex(w_choice_col_text2.c_str())); - } - //*EFEF - } - - } - //EF routeweight * - if (routeweight_col != -1) { - pstring integ_col_text = tulip_text + pstring(" Integration [Route weight by ") + routeweight_col_text + pstring("]")+ radius_text; // <- note, the fact this is a tulip is unnecessary - pstring w_integ_col_text = tulip_text + pstring(" Integration [[Route weight by ") + routeweight_col_text + pstring("][") + weighting_col_text + pstring(" Wgt]]") + radius_text; - - pstring count_col_text = tulip_text + pstring(" Node Count [Route weight by ") + routeweight_col_text + pstring("]")+ radius_text; // <- note, the fact this is a tulip is unnecessary - pstring td_col_text = tulip_text + pstring(" Total Depth [Route weight by ") + routeweight_col_text + pstring("]")+ radius_text; // <- note, the fact this is a tulip is unnecessary - pstring w_td_text = tulip_text + pstring(" Total Depth [[Route weight by ") + routeweight_col_text + pstring("][") + weighting_col_text + pstring(" Wgt]]") + radius_text; - pstring total_weight_col_text = tulip_text + pstring(" Total " + weighting_col_text + " [Route weight by ") + routeweight_col_text + pstring("]") +radius_text; - - integ_col.push_back(m_attributes.getColumnIndex(integ_col_text.c_str())); - count_col.push_back(m_attributes.getColumnIndex(count_col_text.c_str())); - td_col.push_back(m_attributes.getColumnIndex(td_col_text.c_str())); - if (weighting_col != -1) { - // '[' comes after 'R' in ASCII, so this column will come after Mean Depth R... - w_integ_col.push_back(m_attributes.getColumnIndex(w_integ_col_text.c_str())); - w_td_col.push_back(m_attributes.getColumnIndex(w_td_text.c_str())); - total_weight_col.push_back(m_attributes.getColumnIndex(total_weight_col_text.c_str())); - } - } - //* EF routeweight - else { // Normal run // TV - pstring integ_col_text = tulip_text + pstring(" Integration") + radius_text; // <- note, the fact this is a tulip is unnecessary - pstring w_integ_col_text = tulip_text + pstring(" Integration [") + weighting_col_text + pstring(" Wgt]") + radius_text; - - pstring count_col_text = tulip_text + pstring(" Node Count") + radius_text; // <- note, the fact this is a tulip is unnecessary - pstring td_col_text = tulip_text + pstring(" Total Depth") + radius_text; // <- note, the fact this is a tulip is unnecessary - pstring w_td_text = tulip_text + pstring(" Total Depth [") + weighting_col_text + pstring(" Wgt]") + radius_text; - pstring total_weight_col_text = tulip_text + pstring(" Total ") + weighting_col_text + radius_text; - - integ_col.push_back(m_attributes.getColumnIndex(integ_col_text.c_str())); - count_col.push_back(m_attributes.getColumnIndex(count_col_text.c_str())); - td_col.push_back(m_attributes.getColumnIndex(td_col_text.c_str())); - if (weighting_col != -1) { - // '[' comes after 'R' in ASCII, so this column will come after Mean Depth R... - w_integ_col.push_back(m_attributes.getColumnIndex(w_integ_col_text.c_str())); - w_td_col.push_back(m_attributes.getColumnIndex(w_td_text.c_str())); - total_weight_col.push_back(m_attributes.getColumnIndex(total_weight_col_text.c_str())); - } - } - } - - tulip_bins /= 2; // <- actually use semicircle of tulip bins - tulip_bins += 1; - - pqvector *bins = new pqvector[tulip_bins]; - - AnalysisInfo ***audittrail; - unsigned int **uncovered; - audittrail = new AnalysisInfo **[m_connectors.size()]; - uncovered = new unsigned int *[m_connectors.size()]; - for (size_t i = 0; i < m_connectors.size(); i++) { - audittrail[i] = new AnalysisInfo *[radius_unconverted.size()]; - for (size_t j = 0; j < radius_unconverted.size(); j++) { - audittrail[i][j] = new AnalysisInfo[2]; - } - uncovered[i] = new unsigned int [2]; - - } - pvecdouble radius; - for (r = 0; r < radius_unconverted.size(); r++) { - if (radius_type == Options::RADIUS_ANGULAR && radius_unconverted[r] != -1) { - radius.push_back(floor(radius_unconverted[r] * tulip_bins * 0.5)); - } - else { - radius.push_back(radius_unconverted[r]); - } - } - // entered once for each segment - int length_col = m_attributes.getColumnIndex("Segment Length"); - pvecfloat lengths; - if (length_col != -1) { - for (size_t i = 0; i < m_connectors.size(); i++) { - lengths.push_back(m_attributes.getValue(i,length_col)); - } - } - - int radiussize = radius.size(); - int radiusmask = 0; - for (int i = 0; i < radiussize; i++) { - radiusmask |= (1 << i); - } - - for (size_t rowid = 0; rowid < m_connectors.size(); rowid++) { - - if (selection_only) { - // could use m_selection_set.searchindex(rowid) to find - // if this row is selected as m_selection_set is ordered for axial and segment maps, etc - // BUT, actually quicker to check the tag in the attributes that shows it's selected - if (!m_attributes.isSelected(rowid)) { - continue; - } - } - - for (int k = 0; k < tulip_bins; k++) { - bins[k].clear(); - } - for (size_t j = 0; j < m_connectors.size(); j++) { - for (int dir = 0; dir < 2; dir++) { - for (int k = 0; k < radiussize; k++) { - audittrail[j][k][dir].clearLine(); - } - uncovered[j][dir] = radiusmask; - } + iter->getRow().setValue(colindices[k],val); } - - double rootseglength = m_attributes.getValue(rowid,length_col); - double rootweight = (weighting_col != -1) ? weights[rowid] : 0.0; - //EFEF - double rootweight2 = (weighting_col2 != -1) ? weights2[rowid] : 0.0; - //EFEF - - // setup: direction 0 (both ways), segment i, previous -1, segdepth (step depth) 0, metricdepth 0.5 * rootseglength, bin 0 - bins[0].add(SegmentData(0,rowid,SegmentRef(),0,0.5*rootseglength,radiusmask)); - // this version below is only designed to be used temporarily -- - // could be on an option? - //bins[0].push_back(SegmentData(0,rowid,SegmentRef(),0,0.0,radiusmask)); - Connector& thisline = m_connectors[rowid]; - pvecint node_count; - double weight = 0.0; - int depthlevel = 0; - int opencount = 1; - int currentbin = 0; - while (opencount) { - while (!bins[currentbin].size()) { - depthlevel++; - currentbin++; - if (currentbin == tulip_bins) { - currentbin = 0; - } - } - SegmentData lineindex = bins[currentbin].tail(); - bins[currentbin].pop_back(); - // - opencount--; - - int ref = lineindex.ref; - int dir = (lineindex.dir == 1) ? 0 : 1; - int coverage = lineindex.coverage & uncovered[ref][dir]; - if (coverage != 0) { - register int rbin = 0; - int rbinbase; - if (lineindex.previous.ref != -1) { - uncovered[ref][dir] &= ~coverage; - while (((coverage >> rbin) & 0x1) == 0) - rbin++; - rbinbase = rbin; - while (rbin < radiussize) { - if (((coverage >> rbin) & 0x1) == 1) { - audittrail[ref][rbin][dir].depth = depthlevel; - audittrail[ref][rbin][dir].previous = lineindex.previous; - audittrail[lineindex.previous.ref][rbin][(lineindex.previous.dir == 1) ? 0 : 1].leaf = false; - } - rbin++; - } - } - else { - rbinbase = 0; - uncovered[ref][0] &= ~coverage; - uncovered[ref][1] &= ~coverage; - } - Connector& line = m_connectors[ref]; - float seglength; - register int extradepth; - if (lineindex.dir != -1) { - for (size_t k = 0; k < line.m_forward_segconns.size(); k++) { - rbin = rbinbase; - SegmentRef conn = line.m_forward_segconns.key(k); - if ((uncovered[conn.ref][(conn.dir == 1 ? 0 : 1)] & coverage) != 0) { - //EF routeweight* - if (routeweight_col != -1) { //EF here we do the weighting of the angular cost by the weight of the next segment - //note that the content of the routeweights array is scaled between 0 and 1 and is reversed - // such that: = 1.0-(m_attributes.getValue(i, routeweight_col)/max_value) - extradepth = (int) floor(line.m_forward_segconns.value(k) * tulip_bins * 0.5 * routeweights[conn.ref]); - } - //*EF routeweight - else { - extradepth = (int) floor(line.m_forward_segconns.value(k) * tulip_bins * 0.5); - } - seglength = lengths[conn.ref]; - switch (radius_type) { - case Options::RADIUS_ANGULAR: - while (rbin != radiussize && radius[rbin] != -1 && depthlevel+extradepth > (int) radius[rbin]) { - rbin++; - } - break; - case Options::RADIUS_METRIC: - while (rbin != radiussize && radius[rbin] != -1 && lineindex.metricdepth+seglength*0.5 > radius[rbin]) { - rbin++; - } - break; - case Options::RADIUS_STEPS: - if (rbin != radiussize && radius[rbin] != -1 && lineindex.segdepth >= (int) radius[rbin]) { - rbin++; - } - break; - } - if ((coverage >> rbin) != 0) { - bins[(currentbin + tulip_bins + extradepth) % tulip_bins].add( - SegmentData(conn,SegmentRef(1,lineindex.ref),lineindex.segdepth+1,lineindex.metricdepth+seglength,(coverage >> rbin) << rbin), paftl::ADD_DUPLICATE); - opencount++; - } - } - } - } - if (lineindex.dir != 1) { - for (size_t k = 0; k < line.m_back_segconns.size(); k++) { - rbin = rbinbase; - SegmentRef conn = line.m_back_segconns.key(k); - if ((uncovered[conn.ref][(conn.dir == 1 ? 0 : 1)] & coverage) != 0) { - //EF routeweight* - if (routeweight_col != -1) { //EF here we do the weighting of the angular cost by the weight of the next segment - //note that the content of the routeweights array is scaled between 0 and 1 and is reversed - // such that: = 1.0-(m_attributes.getValue(i, routeweight_col)/max_value) - extradepth = (int) floor(line.m_back_segconns.value(k) * tulip_bins * 0.5 * routeweights[conn.ref]); - } - //*EF routeweight - else { - extradepth = (int) floor(line.m_back_segconns.value(k) * tulip_bins * 0.5); - } - seglength = lengths[conn.ref]; - switch (radius_type) { - case Options::RADIUS_ANGULAR: - while (rbin != radiussize && radius[rbin] != -1 && depthlevel+extradepth > (int) radius[rbin]) { - rbin++; - } - break; - case Options::RADIUS_METRIC: - while (rbin != radiussize && radius[rbin] != -1 && lineindex.metricdepth+seglength*0.5 > radius[rbin]) { - rbin++; - } - break; - case Options::RADIUS_STEPS: - if (rbin != radiussize && radius[rbin] != -1 && lineindex.segdepth >= (int) radius[rbin]) { - rbin++; - } - break; - } - if ((coverage >> rbin) != 0) { - bins[(currentbin + tulip_bins + extradepth) % tulip_bins].add( - SegmentData(conn,SegmentRef(-1,lineindex.ref),lineindex.segdepth+1,lineindex.metricdepth+seglength,(coverage >> rbin) << rbin), paftl::ADD_DUPLICATE); - opencount++; - } - } - } - } - } - } - // set the attributes for this node: - for (int k = 0; k < radiussize; k++) { - // note, curs_total_depth must use double as mantissa can get too long for int in large systems - double curs_node_count = 0.0, curs_total_depth = 0.0; - double curs_total_weight = 0.0, curs_total_weighted_depth = 0.0; - size_t j; - for (j = 0; j < m_connectors.size(); j++) { - // find dir according - bool m0 = ((uncovered[j][0] >> k) & 0x1) == 0; - bool m1 = ((uncovered[j][1] >> k) & 0x1) == 0; - if ((m0 | m1) != 0) { - int dir; - if (m0 & m1) { - // dir is the one with the lowest depth: - if (audittrail[j][k][0].depth < audittrail[j][k][1].depth) - dir = 0; - else - dir = 1; - } - else { - // dir is simply the one that's filled in: - dir = m0 ? 0 : 1; - } - curs_node_count++; - curs_total_depth += audittrail[j][k][dir].depth; - curs_total_weight += weights[j]; - curs_total_weighted_depth += audittrail[j][k][dir].depth * weights[j]; - // - if (choice && audittrail[j][k][dir].leaf) { - // note, graph may be directed (e.g., for one way streets), so both ways must be included from now on: - SegmentRef here = SegmentRef(dir == 0 ? 1 : -1,j); - if (here.ref != rowid) { - int choicecount = 0; - double choiceweight = 0.0; - //EFEF* - double choiceweight2 = 0.0; - //*EFEF - while (here.ref != rowid) { // not rowid means not the current root for the path - int heredir = (here.dir == 1) ? 0 : 1; - // each node has the existing choicecount and choiceweight from previously encountered nodes added to it - audittrail[here.ref][k][heredir].choice += choicecount; - // nb, weighted values calculated anyway to save time on 'if' - audittrail[here.ref][k][heredir].weighted_choice += choiceweight; - //EFEF* - audittrail[here.ref][k][heredir].weighted_choice2 += choiceweight2; - //*EFEF - // if the node hasn't been encountered before, the choicecount and choiceweight is - // incremented for all remaining nodes to be encountered on the backwards route from it - if (!audittrail[here.ref][k][heredir].choicecovered) { - // this node has not been encountered before: this adds the choicecount and weight for this - // node, and flags it as visited - choicecount++; - choiceweight += weights[here.ref] * rootweight; - //EFEF* - choiceweight2 += weights2[here.ref] * rootweight;//rootweight! - //*EFEF - - audittrail[here.ref][k][heredir].choicecovered = true; - // note, for weighted choice, the start and end points have choice added to them: - if (weighting_col != -1) { - audittrail[here.ref][k][heredir].weighted_choice += (weights[here.ref] * rootweight) / 2.0; - //EFEF* - if (weighting_col2 != -1) { - audittrail[here.ref][k][heredir].weighted_choice2 += (weights2[here.ref] * rootweight) / 2.0; //rootweight! - } - //*EFEF - } - } - here = audittrail[here.ref][k][heredir].previous; - } - // note, for weighted choice, the start and end points have choice added to them: - // (this is the summed weight for all starting nodes encountered in this path) - if (weighting_col != -1) { - audittrail[here.ref][k][(here.dir == 1) ? 0 : 1].weighted_choice += choiceweight / 2.0; - //EFEF* - if (weighting_col2 != -1) { - audittrail[here.ref][k][(here.dir == 1) ? 0 : 1].weighted_choice2 += choiceweight2 / 2.0; - } - //*EFEF - } - } - } - } - } - double total_depth_conv = curs_total_depth / ((tulip_bins - 1.0f) * 0.5f); - double total_weighted_depth_conv = curs_total_weighted_depth / ((tulip_bins - 1.0f) * 0.5f); - // - m_attributes.setValue(rowid,count_col[k],float(curs_node_count)); - if (curs_node_count > 1) { - // for dmap 8 and above, mean depth simply isn't calculated as for radius measures it is meaningless - m_attributes.setValue(rowid,td_col[k],total_depth_conv); - if (weighting_col != -1) { - m_attributes.setValue(rowid,total_weight_col[k],float(curs_total_weight)); - m_attributes.setValue(rowid,w_td_col[k],float(total_weighted_depth_conv)); - } - } - else { - m_attributes.setValue(rowid,td_col[k],-1); - if (weighting_col != -1) { - m_attributes.setValue(rowid,total_weight_col[k],-1.0f); - m_attributes.setValue(rowid,w_td_col[k],-1.0f); - } - } - // for dmap 10 an above, integration is included! - if (total_depth_conv > 1e-9) { - m_attributes.setValue(rowid,integ_col[k],(float)(curs_node_count*curs_node_count/total_depth_conv)); - if (weighting_col != -1) { - m_attributes.setValue(rowid,w_integ_col[k],(float)(curs_total_weight*curs_total_weight/total_weighted_depth_conv)); - } - } - else { - m_attributes.setValue(rowid,integ_col[k],-1); - if (weighting_col != -1) { - m_attributes.setValue(rowid,w_integ_col[k],-1.0f); - } - } - } - // - processed_rows++; - // - if (comm) { - if (qtimer( atime, 500 )) { - if (comm->IsCancelled()) { - // interactive is usual Depthmap: throw an exception if cancelled - if (interactive) { - for (size_t i = 0; i < m_connectors.size(); i++) { - for (size_t j = 0; j < size_t(radiussize); j++) { - delete [] audittrail[i][j]; - } - delete [] audittrail [i]; - delete [] uncovered [i]; - } - delete [] audittrail; - delete [] uncovered; - delete [] bins; - throw Communicator::CancelledException(); - } - else { - // in non-interactive mode, retain what's been processed already - break; - } - } - comm->CommPostMessage( Communicator::CURRENT_RECORD, rowid ); - } - } - } - if (choice) { - for (size_t rowid = 0; rowid < m_connectors.size(); rowid++) { - for (size_t r = 0; r < radius.size(); r++) { - // according to Eva's correction, total choice and total weighted choice - // should already have been accumulated by radius at this stage - double total_choice = audittrail[rowid][r][0].choice + audittrail[rowid][r][1].choice; - double total_weighted_choice = audittrail[rowid][r][0].weighted_choice + audittrail[rowid][r][1].weighted_choice; - //EFEF* - double total_weighted_choice2 = audittrail[rowid][r][0].weighted_choice2 + audittrail[rowid][r][1].weighted_choice2; - //*EFEF - - // normalised choice now excluded for two reasons: - // a) not useful measure, b) in parallel calculations, cannot be calculated at this stage - // n.b., it is possible through the front end: the new choice takes into account bidirectional routes, - // so it should be normalised according to (n-1)(n-2) (maximum possible through routes) not (n-1)(n-2)/2 - // the relativised segment length weighted choice equation was (total_seg_length*total_seg_length-seg_length*seg_length)/2 - // again, drop the divide by 2 for the new implementation - // - // - m_attributes.setValue(rowid,choice_col[r],float(total_choice)); - if (weighting_col != -1) { - m_attributes.setValue(rowid,w_choice_col[r],float(total_weighted_choice)); - //EFEF* - if (weighting_col2 != -1) { - m_attributes.setValue(rowid,w_choice_col2[r],float(total_weighted_choice2)); - } - //*EFEF - } - } - } - } - for (size_t i = 0; i < m_connectors.size(); i++) { - for (int j = 0; j < radiussize; j++) { - delete [] audittrail[i][j]; - } - delete [] audittrail [i]; - delete [] uncovered [i]; - } - delete [] audittrail; - delete [] uncovered; - delete [] bins; - - m_displayed_attribute = -2; // <- override if it's already showing - if (choice) { - setDisplayedAttribute(choice_col.tail()); - } - else { - setDisplayedAttribute(td_col.tail()); } - return processed_rows; } - -// revised to use tulip bins for faster analysis of large spaces - -bool ShapeGraph::angularstepdepth(Communicator *comm) -{ - pstring stepdepth_col_text = pstring("Angular Step Depth"); - int stepdepth_col = m_attributes.insertColumn(stepdepth_col_text.c_str()); - - int tulip_bins = 1024; - // calc so duplicate code above - tulip_bins /= 2; // <- actually use semicircle of tulip bins - tulip_bins += 1; - - bool *covered = new bool [m_connectors.size()]; - for (size_t i = 0; i < m_connectors.size(); i++) { - covered[i] = false; - } - pqvector *bins = new pqvector[tulip_bins]; - - int opencount = 0; - for (size_t j = 0; j < m_selection_set.size(); j++) { - int row = m_attributes.getRowid(m_selection_set[j]); - if (row != -1) { - bins[0].push_back(SegmentData(0,row,SegmentRef(),0,0.0,0)); - opencount++; - } - } - int depthlevel = 0; - int currentbin = 0; - while (opencount) { - while (!bins[currentbin].size()) { - depthlevel++; - currentbin++; - if (currentbin == tulip_bins) { - currentbin = 0; - } - } - SegmentData lineindex; - if (bins[currentbin].size() > 1) { - // it is slightly slower to delete from an arbitrary place in the bin, - // but it is necessary to use random paths to even out the number of times through equal paths - int curr = pafrand() % bins[currentbin].size(); - lineindex = bins[currentbin][curr]; - bins[currentbin].remove_at(curr); - // note: do not clear choice values here! - } - else { - lineindex = bins[currentbin][0]; - bins[currentbin].pop_back(); - } - opencount--; - if (!covered[lineindex.ref]) { - covered[lineindex.ref] = true; - Connector& line = m_connectors[lineindex.ref]; - // convert depth from tulip_bins normalised to standard angle - // (note the -1) - double depth_to_line = depthlevel / ((tulip_bins - 1) * 0.5); - m_attributes.setValue(lineindex.ref,stepdepth_col,depth_to_line); - register int extradepth; - if (lineindex.dir != -1) { - for (size_t k = 0; k < line.m_forward_segconns.size(); k++) { - if (!covered[line.m_forward_segconns.key(k).ref]) { - extradepth = (int) floor(line.m_forward_segconns.value(k) * tulip_bins * 0.5); - bins[(currentbin + tulip_bins + extradepth) % tulip_bins].push_back( - SegmentData(line.m_forward_segconns.key(k),lineindex.ref,lineindex.segdepth+1,0.0,0)); - opencount++; - } - } - } - if (lineindex.dir != 1) { - for (size_t k = 0; k < line.m_back_segconns.size(); k++) { - if (!covered[line.m_back_segconns.key(k).ref]) { - extradepth = (int) floor(line.m_back_segconns.value(k) * tulip_bins * 0.5); - bins[(currentbin + tulip_bins + extradepth) % tulip_bins].push_back( - SegmentData(line.m_back_segconns.key(k),lineindex.ref,lineindex.segdepth+1,0.0,0)); - opencount++; - } - } - } - } - } - delete [] covered; - delete [] bins; - - m_displayed_attribute = -2; // <- override if it's already showing - setDisplayedAttribute(stepdepth_col); - - return true; -} - -/////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////// - -// helper -- a little class to tidy up a set of lines - -void TidyLines::tidy(prefvec& lines, const QtRegion& region) -{ - size_t i = 0; - m_region = region; - double maxdim = __max(m_region.width(),m_region.height()); - - // simple first pass -- remove very short lines - pvecint removelist; - for (i = 0; i < lines.size(); i++) { - if (lines[i].length() < maxdim * TOLERANCE_B) { - removelist.add(i); - } - } - lines.remove_at(removelist); - removelist.clear(); // always clear this list, it's reused - - // now load up m_lines... - initLines(lines.size(),m_region.bottom_left,m_region.top_right); - for (i = 0; i < lines.size(); i++) { - addLine(lines[i]); - } - sortPixelLines(); - - for (i = 0; i < lines.size(); i++) { - // n.b., as m_lines have just been made, note that what's in m_lines matches whats in lines - // we will use this later! - m_test++; - m_lines[i].test = m_test; - PixelRefList list = pixelateLine( m_lines[i].line ); - for (size_t a = 0; a < list.size(); a++) { - for (size_t b = 0; b < m_pixel_lines[ list[a].x ][ list[a].y ].size(); b++) { - int j = m_pixel_lines[ list[a].x ][ list[a].y ][b]; - if (m_lines[j].test != m_test && j > (int)i && intersect_region(lines[i],lines[j],TOLERANCE_B * maxdim)) { - m_lines[j].test = m_test; - int axis_i = (lines[i].width() >= lines[i].height()) ? XAXIS : YAXIS; - int axis_j = (lines[j].width() >= lines[j].height()) ? XAXIS : YAXIS; - int axis_reverse = (axis_i == XAXIS) ? YAXIS : XAXIS; - if (axis_i == axis_j && fabs(lines[i].grad(axis_reverse) - lines[j].grad(axis_reverse)) < TOLERANCE_A - && fabs(lines[i].constant(axis_reverse) - lines[j].constant(axis_reverse)) < (TOLERANCE_B * maxdim)) { - // check for overlap and merge - int parity = (axis_i == XAXIS) ? 1 : lines[i].sign(); - if ((lines[i].start()[axis_i] * parity + TOLERANCE_B * maxdim) > (lines[j].start()[axis_j] * parity) && - (lines[i].start()[axis_i] * parity) < (lines[j].end()[axis_j] * parity + TOLERANCE_B * maxdim)) { - int end = ((lines[i].end()[axis_i] * parity) > (lines[j].end()[axis_j] * parity)) ? i : j; - lines[j].bx() = lines[end].bx(); - lines[j].by() = lines[end].by(); - removelist.add(i); - continue; // <- don't do this any more, we've zapped it and replaced it with the later line - } - if ((lines[j].start()[axis_j] * parity + TOLERANCE_B * maxdim) > (lines[i].start()[axis_i] * parity) && - (lines[j].start()[axis_j] * parity) < (lines[i].end()[axis_i] * parity + TOLERANCE_B * maxdim)) { - int end = ((lines[i].end()[axis_i] * parity) > (lines[j].end()[axis_j] * parity)) ? i : j; - lines[j].ax() = lines[i].ax(); - lines[j].ay() = lines[i].ay(); - lines[j].bx() = lines[end].bx(); - lines[j].by() = lines[end].by(); - removelist.add(i); - continue; // <- don't do this any more, we've zapped it and replaced it with the later line - } - } - } - } - } - } - lines.remove_at(removelist); - removelist.clear(); // always clear this list, it's reused -} - -void TidyLines::quicktidy(pqmap& lines, const QtRegion& region) -{ - m_region = region; - - double avglen = 0.0; - size_t i; - for (i = 0; i < lines.size(); i++) { - avglen += lines[i].length(); - } - avglen /= lines.size(); - - double tolerance = avglen * 10e-6; - - // simple first pass -- remove very short lines - pvecint removelist; - for (i = 0; i < lines.size(); i++) { - if (lines[i].length() < tolerance) { - removelist.add(i); - } - } - if (removelist.size()) { - lines.remove_at(removelist); - } - removelist.clear(); // always clear this list, it's reused - - // now load up m_lines... - initLines(lines.size(),m_region.bottom_left,m_region.top_right); - for (i = 0; i < lines.size(); i++) { - addLine(lines[i]); - } - sortPixelLines(); - - // and chop duplicate lines: - for (i = 0; i < lines.size(); i++) { - PixelRef start = pixelate(lines[i].start()); - for (size_t j = 0; j < m_pixel_lines[start.x][start.y].size(); j++) { - int k = m_pixel_lines[start.x][start.y][j]; - if (k > (int)i && approxeq(m_lines[i].line.start(),m_lines[k].line.start(),tolerance)) { - if (approxeq(m_lines[i].line.end(),m_lines[k].line.end(),tolerance)) { - removelist.add(i); - break; - } - } - } - } - lines.remove_at(removelist); - removelist.clear(); // always clear this list, it's reused} -} - -///////////////////////////////////////////////////// diff --git a/salalib/axialmap.h b/salalib/axialmap.h index 64e0fa69..70862453 100644 --- a/salalib/axialmap.h +++ b/salalib/axialmap.h @@ -15,142 +15,17 @@ // along with this program. If not, see . -#ifndef __SHAPEGRAPH_H__ -#define __SHAPEGRAPH_H__ +#pragma once + +#include "salalib/spacepixfile.h" +#include "salalib/spacepix.h" +#include "salalib/connector.h" struct AxialVertex; struct AxialVertexKey; struct RadialLine; struct PolyConnector; -struct ValuePair; -struct ValueTriplet; - -class AxialPolygons : public SpacePixel -{ - friend class ShapeGraphs; -protected: - pqmap m_vertex_possibles; - pvecint m_vertex_polys; - pvecint **m_pixel_polys; - pqvector m_handled_list; -public: - AxialPolygons(); - virtual ~AxialPolygons(); - // - void clear(); - void init(prefvec& lines, const QtRegion& region); - void makeVertexPossibles(const prefvec& lines, const prefvec& connectionset); - void makePixelPolys(); - // - AxialVertex makeVertex(const AxialVertexKey& vertexkey, const Point2f& openspace); - // find a polygon corner visible from seed: - AxialVertexKey seedVertex(const Point2f& seed); - // make axial lines from corner vertices, visible from openspace - void makeAxialLines(pqvector& openvertices, prefvec& lines, prefvec& keyvertices, prefvec& poly_connections, pqvector& radial_lines); - // extra: make all the polygons possible from the set of m_vertex_possibles - void makePolygons(prefvec& polygons); -}; - -struct AxialVertexKey -{ - int m_ref_key; - short m_ref_a; - short m_ref_b; - AxialVertexKey(int ref = -1, short a = -1, short b = -1) - { m_ref_key = ref; m_ref_a = a; m_ref_b = b; } - friend bool operator == (const AxialVertexKey& a, const AxialVertexKey& b); - friend bool operator != (const AxialVertexKey& a, const AxialVertexKey& b); - friend bool operator > (const AxialVertexKey& a, const AxialVertexKey& b); - friend bool operator < (const AxialVertexKey& a, const AxialVertexKey& b); -}; -inline bool operator == (const AxialVertexKey& a, const AxialVertexKey& b) -{ return (a.m_ref_key == b.m_ref_key && a.m_ref_a == b.m_ref_a && a.m_ref_b == b.m_ref_b); } -inline bool operator != (const AxialVertexKey& a, const AxialVertexKey& b) -{ return (a.m_ref_key != b.m_ref_key || a.m_ref_a != b.m_ref_a || a.m_ref_b != b.m_ref_b); } -inline bool operator > (const AxialVertexKey& a, const AxialVertexKey& b) -{ return (a.m_ref_key > b.m_ref_key || (a.m_ref_key == b.m_ref_key && (a.m_ref_a > b.m_ref_a || (a.m_ref_a == b.m_ref_a && a.m_ref_b > b.m_ref_b)))); } -inline bool operator < (const AxialVertexKey& a, const AxialVertexKey& b) -{ return (a.m_ref_key < b.m_ref_key || (a.m_ref_key == b.m_ref_key && (a.m_ref_a < b.m_ref_a || (a.m_ref_a == b.m_ref_a && a.m_ref_b < b.m_ref_b)))); } - -const AxialVertexKey NoVertex(-1,-1,-1); - -struct AxialVertex : public AxialVertexKey -{ - Point2f m_point; - Point2f m_openspace; - Point2f m_a; - Point2f m_b; - bool m_clockwise; - bool m_convex; - bool m_initialised; - bool m_axial; - AxialVertex(const AxialVertexKey& vertex_key = NoVertex, const Point2f& point = Point2f(), const Point2f& openspace = Point2f()) : AxialVertexKey(vertex_key) - { m_point = point; m_openspace = openspace; m_initialised = false; m_axial = false; } -}; - -struct RadialKey { - AxialVertexKey vertex; - float ang; - bool segend; - RadialKey(const AxialVertexKey& v = NoVertex, float a = -1.0f, bool se = false) - { vertex = v; ang = a; segend = se; } - RadialKey(const RadialKey& rk) - { vertex = rk.vertex; ang = rk.ang; segend = rk.segend; } - friend bool operator < (const RadialKey& a, const RadialKey& b); - friend bool operator > (const RadialKey& a, const RadialKey& b); - friend bool operator == (const RadialKey& a, const RadialKey& b); -}; -inline bool operator < (const RadialKey& a, const RadialKey& b) -{ return a.vertex < b.vertex || (a.vertex == b.vertex && (a.ang < b.ang || (a.ang == b.ang && a.segend < b.segend))); } -inline bool operator > (const RadialKey& a, const RadialKey& b) -{ return a.vertex > b.vertex || (a.vertex == b.vertex && (a.ang > b.ang || (a.ang == b.ang && a.segend > b.segend))); } -inline bool operator == (const RadialKey& a, const RadialKey& b) -{ return a.vertex == b.vertex && a.ang == b.ang && a.segend == b.segend; } - -struct RadialLine : public RadialKey -{ - Point2f openspace; - Point2f keyvertex; - Point2f nextvertex; - RadialLine(const RadialKey& rk = RadialKey()) : RadialKey(rk) {;} - RadialLine(const AxialVertexKey& v, bool se, const Point2f& o, const Point2f& k, const Point2f& n) - { vertex = v; ang = (float) angle(o,k,n); segend = se; openspace = o; keyvertex = k; nextvertex = n; } - RadialLine(const RadialLine& rl) : RadialKey(rl) - { openspace = rl.openspace; keyvertex = rl.keyvertex; nextvertex = rl.nextvertex; } - bool cuts(const Line& l) const; -}; - -typedef pqvector RadialKeyList; - -struct RadialSegment : public pvecint -{ - RadialKey radial_b; - - // Quick mod - TV -#if defined(_WIN32) - RadialSegment(RadialKey& rb = RadialKey()) : pvecint() - { radial_b = rb; } -#else - RadialSegment(RadialKey& rb /*= RadialKey()*/) : pvecint() - { radial_b = rb; } -#endif - - // Quick mod - TV - RadialSegment() : pvecint() - { - radial_b = RadialKey(); - } - -}; - -struct PolyConnector { - Line line; - RadialKey key; - PolyConnector(const Line& l = Line(), const RadialKey& k = RadialKey()) - { line = l; key = k; } -}; - // used during angular analysis struct AnalysisInfo { @@ -172,159 +47,38 @@ struct AnalysisInfo class MapInfoData; +typedef std::vector> KeyVertices; + class ShapeGraph : public ShapeMap { - friend class ShapeGraphs; friend class AxialMinimiser; friend class MapInfoData; protected: - prefvec m_keyvertices; // but still need to return keyvertices here + KeyVertices m_keyvertices; // but still need to return keyvertices here int m_keyvertexcount; protected: public: - bool outputMifPolygons(ostream& miffile, ostream& midfile) const; - void outputNet(ostream& netfile) const; + bool outputMifPolygons(std::ostream& miffile, std::ostream& midfile) const; + void outputNet(std::ostream& netfile) const; public: - ShapeGraph(const pstring& name = "", int type = ShapeMap::AXIALMAP); + ShapeGraph(const std::string& name = "", int type = ShapeMap::AXIALMAP); virtual ~ShapeGraph() {;} - void makeConnections(const prefvec& keyvertices = prefvec()); - //void initAttributes(); - void makeDivisions(const prefvec& polyconnections, const pqvector& radiallines, pqmap& radialdivisions, pqmap& axialdividers, Communicator *comm); - void cutLines(const prefvec& lines, pqmap& axcuts); - bool integrate(Communicator *comm = NULL, const pvecint& radius = pvecint(), bool choice = false, bool local = false, bool fulloutput = false, int weighting_col = -1, bool simple_version = true); + void initialiseAttributesAxial(); + void makeConnections(const KeyVertices &keyvertices = KeyVertices()); bool stepdepth(Communicator *comm = NULL); - bool analyseAngular(Communicator *comm, const pvecdouble& radius); - // extra parameters for selection_only and interactive are for parallel process extensions - int analyseTulip(Communicator *comm, int tulip_bins, bool choice, int radius_type, const pvecdouble& radius, int weighting_col, int weighting_col2 = -1, int routeweight_col = -1, bool selection_only = false, bool interactive = true); - bool angularstepdepth(Communicator *comm); - // the two topomet analyses can be found in topomet.cpp: - bool analyseTopoMet(Communicator *comm, int analysis_type, double radius, bool sel_only); - bool analyseTopoMetPD(Communicator *comm, int analysis_type); // lineset and connectionset are filled in by segment map void makeNewSegMap(); - void makeSegmentMap(prefvec& lineset, prefvec& connectionset, double stubremoval); - void initSegmentAttributes(prefvec& connectionset); - void makeSegmentConnections(prefvec& connectionset); + void makeSegmentMap(std::vector &lines, std::vector &connectors, double stubremoval); + void initialiseAttributesSegment(); + void makeSegmentConnections(std::vector &connectionset); void pushAxialValues(ShapeGraph& axialmap); // - virtual bool read( ifstream& stream, int version ); - bool readold( ifstream& stream, int version ); - virtual bool write( ofstream& stream, int version ); - // + virtual bool read(std::istream& stream); + bool readold(std::istream& stream); + virtual bool write(std::ofstream& stream); + void writeAxialConnectionsAsDotGraph(std::ostream &stream); + void writeAxialConnectionsAsPairsCSV(std::ostream &stream); + void writeSegmentConnectionsAsPairsCSV(std::ostream &stream); + void unlinkAtPoint(const Point2f& unlinkPoint); void unlinkFromShapeMap(const ShapeMap& shapemap); }; - -class ShapeGraphs : public ShapeMaps -{ -protected: - // helpful to know this for creating fewest line maps, although has to be reread at input - int m_all_line_map; - // - // For all line map work: - AxialPolygons m_polygons; - prefvec m_poly_connections; - pqvector m_radial_lines; -public: - ShapeGraphs() { m_all_line_map = -1; } - virtual ~ShapeGraphs() {;} - // - // ShapeGraphs just have extra functionality over ShapeMaps here: - bool makeAllLineMap(Communicator *comm, SuperSpacePixel& superspacepix, const Point2f& seed); - bool makeFewestLineMap(Communicator *comm, bool replace_existing); - int convertDrawingToAxial(Communicator *comm, const pstring& name, SuperSpacePixel& superspacepix); - int convertDataToAxial(Communicator *comm, const pstring& name, ShapeMap& shapemap, bool copydata = false); - int convertDrawingToConvex(Communicator *comm, const pstring& name, SuperSpacePixel& superspacepix); - int convertDataToConvex(Communicator *comm, const pstring& name, ShapeMap& shapemap, bool copydata = false); - int convertDrawingToSegment(Communicator *comm, const pstring& name, SuperSpacePixel& superspacepix); - int convertDataToSegment(Communicator *comm, const pstring& name, ShapeMap& shapemap, bool copydata = false); - int convertAxialToSegment(Communicator *comm, const pstring& name, bool keeporiginal = true, bool pushvalues = false, double stubremoval = 0.0); - // - bool hasAllLineMap() - { return m_all_line_map != -1; } - // - bool read( ifstream& stream, int version ); - bool readold( ifstream& stream, int version ); - bool write( ofstream& stream, int version, bool displayedmaponly = false ); -}; - -// helpers... a class to tidy up ugly maps people may give me... - -class TidyLines : public SpacePixel -{ -public: - TidyLines() {;} - virtual ~TidyLines() {;} - void tidy(prefvec& lines, const QtRegion& region); - void quicktidy(pqmap& lines, const QtRegion& region); -}; - -// helpers... a class to reduce all line maps to fewest line maps - -class AxialMinimiser -{ -protected: - ShapeGraph *m_alllinemap; - // - ValueTriplet *m_vps; - bool *m_removed; - bool *m_affected; - bool *m_vital; - int *m_radialsegcounts; - int *m_keyvertexcounts; - prefvec m_axialconns; // <- uses a copy of axial lines as it will remove connections -public: - AxialMinimiser(const ShapeGraph& alllinemap, pqmap& axsegcuts, pqmap& radialsegs); - ~AxialMinimiser(); - void removeSubsets(pqmap& axsegcuts, pqmap& radialsegs, pqmap& rlds, pqvector& radial_lines, prefvec& keyvertexconns, int *keyvertexcounts); - void fewestLongest(pqmap& axsegcuts, pqmap& radialsegs, pqmap& rlds, pqvector& radial_lines, prefvec& keyvertexconns, int *keyvertexcounts); - // advanced topological testing: - bool checkVital(int checkindex,pvecint& axsegcuts, pqmap& radialsegs, pqmap& rlds, pqvector& radial_lines); - // - bool removed(int i) const - { return m_removed[i]; } -}; - -struct ValueTriplet -{ - int value1; - float value2; - int index; -}; - -// note: these are unordered, but in 'a' takes priority over 'b' -inline bool operator == (const IntPair& x, const IntPair& y) -{ - return (x.a == y.a && x.b == y.b); -} -inline bool operator != (const IntPair& x, const IntPair& y) -{ - return (x.a != y.a || x.b != y.b); -} -inline bool operator < (const IntPair& x, const IntPair& y) -{ - return ( (x.a == y.a) ? x.b < y.b : x.a < y.a ); -} -inline bool operator > (const IntPair& x, const IntPair& y) -{ - return ( (x.a == y.a) ? x.b > y.b : x.a > y.a ); -} - -// note: these are made with a is always less than b -inline bool operator == (const OrderedIntPair& x, const OrderedIntPair& y) -{ - return (x.a == y.a && x.b == y.b); -} -inline bool operator != (const OrderedIntPair& x, const OrderedIntPair& y) -{ - return (x.a != y.a || x.b != y.b); -} -inline bool operator < (const OrderedIntPair& x, const OrderedIntPair& y) -{ - return ( (x.a == y.a) ? x.b < y.b : x.a < y.a ); -} -inline bool operator > (const OrderedIntPair& x, const OrderedIntPair& y) -{ - return ( (x.a == y.a) ? x.b > y.b : x.a > y.a ); -} - -#endif diff --git a/salalib/axialminimiser.cpp b/salalib/axialminimiser.cpp new file mode 100644 index 00000000..f82665b6 --- /dev/null +++ b/salalib/axialminimiser.cpp @@ -0,0 +1,313 @@ +#include "salalib/axialminimiser.h" +#include "salalib/tolerances.h" + +static int compareValueTriplet(const void *p1, const void *p2) +{ + ValueTriplet *vp1 = (ValueTriplet *) p1; + ValueTriplet *vp2 = (ValueTriplet *) p2; + return (vp1->value1 > vp2->value1 ? 1 : vp1->value1 < vp2->value1 ? -1 : + (vp1->value2 > vp2->value2 ? 1 : vp1->value2 < vp2->value2 ? -1 : 0)); +} + +AxialMinimiser::AxialMinimiser(const AllLineMap& alllinemap, int no_of_axsegcuts, int no_of_radialsegs) +{ + m_alllinemap = (AllLineMap *) &alllinemap; + + m_vps = new ValueTriplet[no_of_axsegcuts]; + m_removed = new bool [no_of_axsegcuts]; + m_affected = new bool [no_of_axsegcuts]; + m_vital = new bool [no_of_axsegcuts]; + m_radialsegcounts = new int [no_of_radialsegs]; +} + +AxialMinimiser::~AxialMinimiser() +{ + delete [] m_vital; + delete [] m_affected; + delete [] m_radialsegcounts; + delete [] m_vps; + delete [] m_removed; +} + +// Alan and Bill's algo... + +void AxialMinimiser::removeSubsets(std::map >& axsegcuts, std::map& radialsegs, + std::map > &rlds, std::vector &radial_lines, + std::vector >& keyvertexconns, std::vector& keyvertexcounts) +{ + bool removedflag = true; + + m_axialconns = m_alllinemap->m_connectors; + + for (size_t x = 0; x < radialsegs.size(); x++) { + m_radialsegcounts[x] = 0; + } + int y = -1; + for (auto axSegCut: axsegcuts) { + y++; + for (int cut: axSegCut.second) { + m_radialsegcounts[cut] += 1; + } + m_removed[y] = false; + m_vital[y] = false; + m_affected[y] = true; + m_vps[y].index = y; + double length = m_axialconns[y].m_connections.size(); + m_vps[y].value1 = (int) length; + length = depthmapX::getMapAtIndex(m_alllinemap->m_shapes, y)->second.getLine().length(); + m_vps[y].value2 = (float) length; + } + + // sort according to number of connections then length + qsort(m_vps,m_axialconns.size(),sizeof(ValueTriplet),compareValueTriplet); + + while (removedflag) { + + removedflag = false; + for (size_t i = 0; i < m_axialconns.size(); i++) { + int ii = m_vps[i].index; + if (m_removed[ii] || !m_affected[ii] || m_vital[ii]) { + continue; + } + // vital connections code (uses original unaltered connections) + { + bool vitalconn = false; + for (size_t j = 0; j < keyvertexconns[ii].size(); j++) { + // first check to see if removing this line will cause elimination of a vital connection + if (keyvertexcounts[keyvertexconns[ii][j]] <= 1) { + // connect vital... just go on to the next one: + vitalconn = true; + break; + } + } + if (vitalconn) { + m_vital[ii] = true; + continue; + } + } + // + Connector& axa = m_axialconns[ii]; + m_affected[ii] = false; + bool subset = false; + for (size_t j = 0; j < axa.m_connections.size(); j++) { + int indextob = axa.m_connections[j]; + if (indextob == ii || m_removed[indextob]) { // <- removed[indextob] should never happen as it should have been removed below + continue; + } + Connector& axb = m_axialconns[indextob]; + if (axa.m_connections.size() <= axb.m_connections.size()) { + // change to 10.08, coconnecting is 1 -> connection to other line is implicitly handled + int coconnecting = 1; + // first check it's a connection subset + // note that changes in 10.08 mean that lines no longer connect to themselves + // this means that the subset 1 connects {2,3} and 2 connects {1,3} are equivalent + for (size_t axai = 0, axbi = 0; axai < axa.m_connections.size() && axbi < axb.m_connections.size(); axai++, axbi++) { + // extra 10.08 -> step over connection to b + if (axa.m_connections[axai] == indextob) { + axai++; + } + // extra 10.08 add axb.m_connections[axbi] == ii -> step over connection to a + while (axbi < axb.m_connections.size() && (axb.m_connections[axbi] == ii || axa.m_connections[axai] > axb.m_connections[axbi])) { + axbi++; + } + if (axbi >= axb.m_connections.size()) { + break; + } + else if (axa.m_connections[axai] == axb.m_connections[axbi]) { + coconnecting++; + } + else if (axa.m_connections[axai] < axb.m_connections[axbi]) { + break; + } + } + if (coconnecting >= (int)axa.m_connections.size()) { + subset = true; + break; + } + } + } + if (subset) { + size_t removeindex = ii; + // now check removing it won't break any topological loops + bool presumedvital = false; + auto& axSegCut = depthmapX::getMapAtIndex(axsegcuts, removeindex)->second; + for (int cut: axSegCut) { + if (m_radialsegcounts[cut] <= 1) { + presumedvital = true; + break; + } + } + if (presumedvital) { + presumedvital = checkVital(removeindex,axSegCut,radialsegs,rlds,radial_lines); + } + if (presumedvital) { + m_vital[removeindex] = true; + } + // if not, remove it... + if (!m_vital[removeindex]) { + m_removed[removeindex] = true; + auto& affectedconnections = m_axialconns[removeindex].m_connections; + for (auto affectedconnection: affectedconnections) { + if (!m_removed[affectedconnection]) { + auto& connections = m_axialconns[affectedconnection].m_connections; + depthmapX::findAndErase(connections, int(removeindex)); + m_affected[affectedconnection] = true; + } + } + removedflag = true; + for (int cut: axSegCut) { + m_radialsegcounts[cut] -= 1; + } + // vital connections + for (size_t k = 0; k < keyvertexconns[removeindex].size(); k++) { + keyvertexcounts[keyvertexconns[removeindex][k]] -= 1; + } + } + } + } + } +} + +/////////////////////////////////////////////////////////////////////////////////////////// + +// My algo... v. simple... fewest longest + +void AxialMinimiser::fewestLongest(std::map > &axsegcuts, std::map& radialsegs, + std::map > &rlds, std::vector &radial_lines, + std::vector > &keyvertexconns, std::vector& keyvertexcounts) +{ + //m_axialconns = m_alllinemap->m_connectors; + int livecount = 0; + + for (size_t y = 0; y < m_axialconns.size(); y++) { + if (!m_removed[y] && !m_vital[y]) { + m_vps[livecount].index = (int) y; + m_vps[livecount].value1 = (int) m_axialconns[y].m_connections.size(); + m_vps[livecount].value2 = (float) depthmapX::getMapAtIndex(m_alllinemap->m_shapes, y)->second.getLine().length(); + livecount++; + } + } + + qsort(m_vps,livecount,sizeof(ValueTriplet),compareValueTriplet); + + for (int i = 0; i < livecount; i++) { + + int j = m_vps[i].index; + // vital connections code (uses original unaltered connections) + bool vitalconn = false; + size_t k; + for (k = 0; k < keyvertexconns[j].size(); k++) { + // first check to see if removing this line will cause elimination of a vital connection + if (keyvertexcounts[keyvertexconns[j][k]] <= 1) { + // connect vital... just go on to the next one: + vitalconn = true; + break; + } + } + if (vitalconn) { + continue; + } + // + bool presumedvital = false; + auto &axSegCut = depthmapX::getMapAtIndex(axsegcuts, j)->second; + for (int cut: axSegCut) { + if (m_radialsegcounts[cut] <= 1) { + presumedvital = true; + break; + } + } + if (presumedvital) { + presumedvital = checkVital(j,axSegCut,radialsegs,rlds,radial_lines); + } + if (!presumedvital) { + // don't let anything this is connected to go down to zero connections + auto& affectedconnections = m_axialconns[j].m_connections; + for (auto affectedconnection: affectedconnections) { + if (!m_removed[affectedconnection]) { + auto& connections = m_axialconns[size_t(affectedconnection)].m_connections; + if (connections.size() <= 2) { // <- note number of connections includes itself... so you and one other + presumedvital = true; + break; + } + } + } + } + if (!presumedvital) { + m_removed[j] = true; + auto& affectedconnections = m_axialconns[size_t(j)].m_connections; + for (auto affectedconnection: affectedconnections) { + if (!m_removed[affectedconnection]) { + auto& connections = m_axialconns[size_t(affectedconnection)].m_connections; + depthmapX::findAndErase(connections, int(j)); + m_affected[affectedconnection] = true; + } + } + for (auto cut: axSegCut) { + m_radialsegcounts[cut] -= 1; + } + // vital connections + for (size_t k = 0; k < keyvertexconns[j].size(); k++) { + keyvertexcounts[keyvertexconns[j][k]] -= 1; + } + } + } +} + +/////////////////////////////////////////////////////////////////////////////////////////// + +bool AxialMinimiser::checkVital(int checkindex, std::set &axSegCut, std::map& radialsegs, + std::map > &rlds, std::vector& radial_lines) +{ + std::map& axiallines = m_alllinemap->m_shapes; + + bool presumedvital = true; + int nonvitalcount = 0, vitalsegs = 0; + // again, this time more rigourously... check any connected pairs don't cover the link... + for (int cut: axSegCut) { + if (m_radialsegcounts[cut] <= 1) { + bool nonvitalseg = false; + vitalsegs++; + auto radialSegIter = depthmapX::getMapAtIndex(radialsegs, cut); + const RadialKey& key = radialSegIter->first; + RadialSegment& seg = radialSegIter->second; + std::set& divisorsa = rlds.find(key)->second; + std::set& divisorsb = rlds.find(seg.radial_b)->second; + auto iterKey = std::find(radial_lines.begin(), radial_lines.end(), key); + if(iterKey == radial_lines.end()) { + throw depthmapX::RuntimeException("Radial key not found in radial lines"); + } + const RadialLine& rlinea = *iterKey; + + auto iterSegB = std::find(radial_lines.begin(), radial_lines.end(), seg.radial_b); + if(iterSegB == radial_lines.end()) { + throw depthmapX::RuntimeException("Radial key not found in radial lines"); + } + const RadialLine& rlineb = *iterSegB; + for (int diva: divisorsa) { + if (diva == checkindex || m_removed[diva]) { + continue; + } + for (int divb: divisorsb) { + if (divb == checkindex || m_removed[divb]) { + continue; + } + auto& connections = m_axialconns[size_t(diva)].m_connections; + if (std::find(connections.begin(), connections.end(), divb) != connections.end()) { + // as a further challenge, they must link within in the zone of interest, not on the far side of it... arg! + Point2f p = intersection_point(axiallines[diva].getLine(),axiallines[divb].getLine(),TOLERANCE_A); + if (p.insegment(rlinea.keyvertex,rlinea.openspace,rlineb.openspace,TOLERANCE_A)) { + nonvitalseg = true; + } + } + } + } + if (nonvitalseg) { + nonvitalcount++; + } + } + } + if (nonvitalcount == vitalsegs) { + presumedvital = false; + } + return presumedvital; +} diff --git a/salalib/axialminimiser.h b/salalib/axialminimiser.h new file mode 100644 index 00000000..0a2d985d --- /dev/null +++ b/salalib/axialminimiser.h @@ -0,0 +1,39 @@ +#pragma once + +#include "salalib/alllinemap.h" + +struct ValueTriplet +{ + int value1; + float value2; + int index; +}; + +class AxialMinimiser +{ +protected: + AllLineMap *m_alllinemap; + // + ValueTriplet *m_vps; + bool *m_removed; + bool *m_affected; + bool *m_vital; + int *m_radialsegcounts; + int *m_keyvertexcounts; + std::vector m_axialconns; // <- uses a copy of axial lines as it will remove connections +public: + AxialMinimiser(const AllLineMap& alllinemap, int no_of_axsegcuts, int no_of_radialsegs); + ~AxialMinimiser(); + void removeSubsets(std::map > &axsegcuts, std::map& radialsegs, + std::map >& rlds, std::vector &radial_lines, + std::vector > &keyvertexconns, std::vector& keyvertexcounts); + void fewestLongest(std::map >& axsegcuts, std::map& radialsegs, + std::map > &rlds, std::vector& radial_lines, + std::vector >& keyvertexconns, std::vector& keyvertexcounts); + // advanced topological testing: + bool checkVital(int checkindex, std::set &axSegCut, std::map& radialsegs, + std::map > &rlds, std::vector &radial_lines); + // + bool removed(int i) const + { return m_removed[i]; } +}; diff --git a/salalib/axialmodules/CMakeLists.txt b/salalib/axialmodules/CMakeLists.txt new file mode 100644 index 00000000..fa3e14c1 --- /dev/null +++ b/salalib/axialmodules/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(salalib + PRIVATE + axialintegration.cpp + axialstepdepth.cpp + PUBLIC + axialintegration.h + axialstepdepth.h) diff --git a/salalib/axialmodules/axialintegration.cpp b/salalib/axialmodules/axialintegration.cpp new file mode 100644 index 00000000..ee6e4acc --- /dev/null +++ b/salalib/axialmodules/axialintegration.cpp @@ -0,0 +1,517 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "salalib/axialmodules/axialintegration.h" + +#include "genlib/pflipper.h" +#include "genlib/stringutils.h" + +bool AxialIntegration::run(Communicator *comm, ShapeGraph &map, bool simple_version) { + // note, from 10.0, Depthmap no longer includes *self* connections on axial lines + // self connections are stripped out on loading graph files, as well as no longer made + + time_t atime = 0; + if (comm) { + qtimer(atime, 0); + comm->CommPostMessage(Communicator::NUM_RECORDS, map.getShapeCount()); + } + + AttributeTable &attributes = map.getAttributeTable(); + + // note: radius must be sorted lowest to highest, but if -1 occurs ("radius n") it needs to be last... + // ...to ensure no mess ups, we'll re-sort here: + bool radius_n = false; + std::vector radii; + for (double radius : m_radius_set) { + if (radius < 0) { + radius_n = true; + } else { + radii.push_back(static_cast(radius)); + } + } + if (radius_n) { + radii.push_back(-1); + } + + // retrieve weighted col data, as this may well be overwritten in the new analysis: + std::vector weights; + std::string weighting_col_text; + if (m_weighted_measure_col != -1) { + weighting_col_text = attributes.getColumnName(m_weighted_measure_col); + for (size_t i = 0; i < map.getShapeCount(); i++) { + weights.push_back(map.getAttributeRowFromShapeIndex(i).getValue(m_weighted_measure_col)); + } + } + + // first enter the required attribute columns: + for (int radius : radii) { + std::string radius_text; + if (radius != -1) { + radius_text = dXstring::formatString(radius, " R%d"); + } + if (m_choice) { + std::string choice_col_text = std::string("Choice") + radius_text; + attributes.insertOrResetColumn(choice_col_text.c_str()); + std::string n_choice_col_text = std::string("Choice [Norm]") + radius_text; + attributes.insertOrResetColumn(n_choice_col_text.c_str()); + if (m_weighted_measure_col != -1) { + std::string w_choice_col_text = std::string("Choice [") + weighting_col_text + " Wgt]" + radius_text; + attributes.insertOrResetColumn(w_choice_col_text.c_str()); + std::string nw_choice_col_text = + std::string("Choice [") + weighting_col_text + " Wgt][Norm]" + radius_text; + attributes.insertOrResetColumn(nw_choice_col_text.c_str()); + } + } + + if (!simple_version) { + std::string entropy_col_text = std::string("Entropy") + radius_text; + attributes.insertOrResetColumn(entropy_col_text.c_str()); + } + + std::string integ_dv_col_text = std::string("Integration [HH]") + radius_text; + attributes.insertOrResetColumn(integ_dv_col_text.c_str()); + + if (!simple_version) { + std::string integ_pv_col_text = std::string("Integration [P-value]") + radius_text; + attributes.insertOrResetColumn(integ_pv_col_text.c_str()); + std::string integ_tk_col_text = std::string("Integration [Tekl]") + radius_text; + attributes.insertOrResetColumn(integ_tk_col_text.c_str()); + std::string intensity_col_text = std::string("Intensity") + radius_text; + attributes.insertOrResetColumn(intensity_col_text.c_str()); + std::string harmonic_col_text = std::string("Harmonic Mean Depth") + radius_text; + attributes.insertOrResetColumn(harmonic_col_text.c_str()); + } + + std::string depth_col_text = std::string("Mean Depth") + radius_text; + attributes.insertOrResetColumn(depth_col_text.c_str()); + std::string count_col_text = std::string("Node Count") + radius_text; + attributes.insertOrResetColumn(count_col_text.c_str()); + + if (!simple_version) { + std::string rel_entropy_col_text = std::string("Relativised Entropy") + radius_text; + attributes.insertOrResetColumn(rel_entropy_col_text); + } + + if (m_weighted_measure_col != -1) { + std::string w_md_col_text = std::string("Mean Depth [") + weighting_col_text + " Wgt]" + radius_text; + attributes.insertOrResetColumn(w_md_col_text.c_str()); + std::string total_weight_text = std::string("Total ") + weighting_col_text + radius_text; + attributes.insertOrResetColumn(total_weight_text.c_str()); + } + if (m_fulloutput) { + if (!simple_version) { + std::string penn_norm_text = std::string("RA [Penn]") + radius_text; + attributes.insertOrResetColumn(penn_norm_text); + } + std::string ra_col_text = std::string("RA") + radius_text; + attributes.insertOrResetColumn(ra_col_text.c_str()); + + if (!simple_version) { + std::string rra_col_text = std::string("RRA") + radius_text; + attributes.insertOrResetColumn(rra_col_text.c_str()); + } + + std::string td_col_text = std::string("Total Depth") + radius_text; + attributes.insertOrResetColumn(td_col_text.c_str()); + } + // + } + if (m_local) { + if (!simple_version) { + attributes.insertOrResetColumn("Control"); + attributes.insertOrResetColumn("Controllability"); + } + } + // then look up all the columns... eek: + std::vector choice_col, n_choice_col, w_choice_col, nw_choice_col, entropy_col, integ_dv_col, integ_pv_col, + integ_tk_col, intensity_col, depth_col, count_col, rel_entropy_col, penn_norm_col, w_depth_col, + total_weight_col, ra_col, rra_col, td_col, harmonic_col; + for (int radius : radii) { + std::string radius_text; + if (radius != -1) { + radius_text = std::string(" R") + dXstring::formatString(int(radius), "%d"); + } + if (m_choice) { + std::string choice_col_text = std::string("Choice") + radius_text; + choice_col.push_back(attributes.getColumnIndex(choice_col_text.c_str())); + std::string n_choice_col_text = std::string("Choice [Norm]") + radius_text; + n_choice_col.push_back(attributes.getColumnIndex(n_choice_col_text.c_str())); + if (m_weighted_measure_col != -1) { + std::string w_choice_col_text = std::string("Choice [") + weighting_col_text + " Wgt]" + radius_text; + w_choice_col.push_back(attributes.getColumnIndex(w_choice_col_text.c_str())); + std::string nw_choice_col_text = + std::string("Choice [") + weighting_col_text + " Wgt][Norm]" + radius_text; + nw_choice_col.push_back(attributes.getColumnIndex(nw_choice_col_text.c_str())); + } + } + if (!simple_version) { + std::string entropy_col_text = std::string("Entropy") + radius_text; + entropy_col.push_back(attributes.getColumnIndex(entropy_col_text.c_str())); + } + + std::string integ_dv_col_text = std::string("Integration [HH]") + radius_text; + integ_dv_col.push_back(attributes.getColumnIndex(integ_dv_col_text.c_str())); + + if (!simple_version) { + std::string integ_pv_col_text = std::string("Integration [P-value]") + radius_text; + integ_pv_col.push_back(attributes.getColumnIndex(integ_pv_col_text.c_str())); + std::string integ_tk_col_text = std::string("Integration [Tekl]") + radius_text; + integ_tk_col.push_back(attributes.getColumnIndex(integ_tk_col_text.c_str())); + std::string intensity_col_text = std::string("Intensity") + radius_text; + intensity_col.push_back(attributes.getColumnIndex(intensity_col_text.c_str())); + std::string harmonic_col_text = std::string("Harmonic Mean Depth") + radius_text; + harmonic_col.push_back(attributes.getColumnIndex(harmonic_col_text.c_str())); + } + + std::string depth_col_text = std::string("Mean Depth") + radius_text; + depth_col.push_back(attributes.getColumnIndex(depth_col_text.c_str())); + std::string count_col_text = std::string("Node Count") + radius_text; + count_col.push_back(attributes.getColumnIndex(count_col_text.c_str())); + + if (!simple_version) { + std::string rel_entropy_col_text = std::string("Relativised Entropy") + radius_text; + rel_entropy_col.push_back(attributes.getColumnIndex(rel_entropy_col_text.c_str())); + } + + if (m_weighted_measure_col != -1) { + std::string w_md_col_text = std::string("Mean Depth [") + weighting_col_text + " Wgt]" + radius_text; + w_depth_col.push_back(attributes.getColumnIndex(w_md_col_text.c_str())); + std::string total_weight_col_text = std::string("Total ") + weighting_col_text + radius_text; + total_weight_col.push_back(attributes.getColumnIndex(total_weight_col_text.c_str())); + } + if (m_fulloutput) { + std::string ra_col_text = std::string("RA") + radius_text; + ra_col.push_back(attributes.getColumnIndex(ra_col_text.c_str())); + + if (!simple_version) { + std::string penn_norm_text = std::string("RA [Penn]") + radius_text; + penn_norm_col.push_back(attributes.getColumnIndex(penn_norm_text)); + std::string rra_col_text = std::string("RRA") + radius_text; + rra_col.push_back(attributes.getColumnIndex(rra_col_text.c_str())); + } + + std::string td_col_text = std::string("Total Depth") + radius_text; + td_col.push_back(attributes.getColumnIndex(td_col_text.c_str())); + } + } + int control_col = -1, controllability_col = -1; + if (m_local) { + if (!simple_version) { + control_col = attributes.getColumnIndex("Control"); + controllability_col = attributes.getColumnIndex("Controllability"); + } + } + + // for choice + AnalysisInfo **audittrail; + if (m_choice) { + audittrail = new AnalysisInfo *[map.getShapeCount()]; + for (size_t i = 0; i < map.getShapeCount(); i++) { + audittrail[i] = new AnalysisInfo[radii.size()]; + } + } + + // n.b., for this operation we assume continuous line referencing from zero (this is silly?) + // has already failed due to this! when intro hand drawn fewest line (where user may have deleted) + // it's going to get worse... + + bool *covered = new bool[map.getShapeCount()]; + + size_t i = -1; + for (auto & iter : attributes) { + i++; + AttributeRow &row = iter.getRow(); + for (size_t j = 0; j < map.getShapeCount(); j++) { + covered[j] = false; + } + if (m_choice) { + for (size_t k = 0; k < map.getShapeCount(); k++) { + audittrail[k][0].previous.ref = -1; // note, 0th member used as radius doesn't matter + // note, choice columns are not cleared, but cummulative over all shortest path pairs + } + } + + if (m_local) { + double control = 0.0; + const std::vector &connections = map.getConnections()[i].m_connections; + std::vector totalneighbourhood; + for (int connection : connections) { + // n.b., as of Depthmap 10.0, connections[j] and i cannot coexist + // if (connections[j] != i) { + depthmapX::addIfNotExists(totalneighbourhood, connection); + int retro_size = 0; + auto &retconnectors = map.getConnections()[size_t(connection)].m_connections; + for (auto retconnector : retconnectors) { + retro_size++; + depthmapX::addIfNotExists(totalneighbourhood, retconnector); + } + control += 1.0 / double(retro_size); + //} + } + + if (!simple_version) { + if (connections.size() > 0) { + row.setValue(control_col, float(control)); + row.setValue(controllability_col, + float(double(connections.size()) / double(totalneighbourhood.size() - 1))); + } else { + row.setValue(control_col, -1); + row.setValue(controllability_col, -1); + } + } + } + + std::vector depthcounts; + depthcounts.push_back(0); + + pflipper>> foundlist; + foundlist.a().push_back(std::pair(i, -1)); + covered[i] = true; + int total_depth = 0, depth = 1, node_count = 1, pos = -1, previous = -1; // node_count includes this 1 + double weight = 0.0, rootweight = 0.0, total_weight = 0.0, w_total_depth = 0.0; + if (m_weighted_measure_col != -1) { + rootweight = weights[i]; + // include this line in total weights (as per nodecount) + total_weight += rootweight; + } + int index = -1; + int r = 0; + for (int radius : radii) { + while (foundlist.a().size()) { + if (!m_choice) { + index = foundlist.a().back().first; + } else { + pos = pafrand() % foundlist.a().size(); + index = foundlist.a().at(pos).first; + previous = foundlist.a().at(pos).second; + audittrail[index][0].previous.ref = + previous; // note 0th member used here: can be used individually different radius previous + } + Connector &line = map.getConnections()[index]; + for (size_t k = 0; k < line.m_connections.size(); k++) { + if (!covered[line.m_connections[k]]) { + covered[line.m_connections[k]] = true; + foundlist.b().push_back(std::pair(line.m_connections[k], index)); + if (m_weighted_measure_col != -1) { + // the weight is taken from the discovered node: + weight = weights[line.m_connections[k]]; + total_weight += weight; + w_total_depth += depth * weight; + } + if (m_choice && previous != -1) { + // both directional paths are now recorded for choice + // (coincidentally fixes choice problem which was completely wrong) + size_t here = index; // note: start counting from index as actually looking ahead here + while (here != i) { // not i means not the current root for the path + audittrail[here][r].choice += 1; + audittrail[here][r].weighted_choice += weight * rootweight; + here = + audittrail[here][0].previous.ref; // <- note, just using 0th position: radius for + // the previous doesn't matter in this analysis + } + if (m_weighted_measure_col != -1) { + // in weighted choice, root node and current node receive values: + audittrail[i][r].weighted_choice += (weight * rootweight) * 0.5; + audittrail[line.m_connections[k]][r].weighted_choice += (weight * rootweight) * 0.5; + } + } + total_depth += depth; + node_count++; + depthcounts.back() += 1; + } + } + if (!m_choice) + foundlist.a().pop_back(); + else + foundlist.a().erase(foundlist.a().begin() + pos); + if (!foundlist.a().size()) { + foundlist.flip(); + depth++; + depthcounts.push_back(0); + if (radius != -1 && depth > radius) { + break; + } + } + } + // set the attributes for this node: + row.setValue(count_col[r], float(node_count)); + if (m_weighted_measure_col != -1) { + row.setValue(total_weight_col[r], float(total_weight)); + } + // node count > 1 to avoid divide by zero (was > 2) + if (node_count > 1) { + // note -- node_count includes this one -- mean depth as per p.108 Social Logic of Space + double mean_depth = double(total_depth) / double(node_count - 1); + row.setValue(depth_col[r], float(mean_depth)); + if (m_weighted_measure_col != -1) { + // weighted mean depth: + row.setValue(w_depth_col[r], float(w_total_depth / total_weight)); + } + // total nodes > 2 to avoid divide by 0 (was > 3) + if (node_count > 2 && mean_depth > 1.0) { + double ra = 2.0 * (mean_depth - 1.0) / double(node_count - 2); + // d-value / p-value from Depthmap 4 manual, note: node_count includes this one + double rra_d = ra / dvalue(node_count); + double rra_p = ra / dvalue(node_count); + double integ_tk = teklinteg(node_count, total_depth); + row.setValue(integ_dv_col[r], float(1.0 / rra_d)); + + if (!simple_version) { + row.setValue(integ_pv_col[r], float(1.0 / rra_p)); + if (total_depth - node_count + 1 > 1) { + row.setValue(integ_tk_col[r], float(integ_tk)); + } else { + row.setValue(integ_tk_col[r], -1.0f); + } + } + + if (m_fulloutput) { + row.setValue(ra_col[r], float(ra)); + + if (!simple_version) { + row.setValue(rra_col[r], float(rra_d)); + } + row.setValue(td_col[r], float(total_depth)); + + if (!simple_version) { + // alan's palm-tree normalisation: palmtree + double dmin = node_count - 1; + double dmax = palmtree(node_count, depth - 1); + if (dmax != dmin) { + row.setValue(penn_norm_col[r], float((dmax - total_depth) / (dmax - dmin))); + } + } + } + } else { + row.setValue(integ_dv_col[r], -1.0f); + + if (!simple_version) { + row.setValue(integ_pv_col[r], -1.0f); + row.setValue(integ_tk_col[r], -1.0f); + } + if (m_fulloutput) { + row.setValue(ra_col[r], -1.0f); + + if (!simple_version) { + row.setValue(rra_col[r], -1.0f); + } + + row.setValue(td_col[r], -1.0f); + + if (!simple_version) { + row.setValue(penn_norm_col[r], -1.0f); + } + } + } + + if (!simple_version) { + double entropy = 0.0, intensity = 0.0, rel_entropy = 0.0, factorial = 1.0, harmonic = 0.0; + for (size_t k = 0; k < depthcounts.size(); k++) { + if (depthcounts[k] != 0) { + // some debate over whether or not this should be node count - 1 + // (i.e., including or not including the node itself) + double prob = double(depthcounts[k]) / double(node_count); + entropy -= prob * log2(prob); + // Formula from Turner 2001, "Depthmap" + factorial *= double(k + 1); + double q = (pow(mean_depth, double(k)) / double(factorial)) * exp(-mean_depth); + rel_entropy += (double)prob * log2(prob / q); + // + harmonic += 1.0 / double(depthcounts[k]); + } + } + harmonic = double(depthcounts.size()) / harmonic; + if (total_depth > node_count) { + intensity = node_count * entropy / (total_depth - node_count); + } else { + intensity = -1; + } + row.setValue(entropy_col[r], float(entropy)); + row.setValue(rel_entropy_col[r], float(rel_entropy)); + row.setValue(intensity_col[r], float(intensity)); + row.setValue(harmonic_col[r], float(harmonic)); + } + } else { + row.setValue(depth_col[r], -1.0f); + row.setValue(integ_dv_col[r], -1.0f); + + if (!simple_version) { + row.setValue(integ_pv_col[r], -1.0f); + row.setValue(integ_tk_col[r], -1.0f); + row.setValue(entropy_col[r], -1.0f); + row.setValue(rel_entropy_col[r], -1.0f); + row.setValue(harmonic_col[r], -1.0f); + } + } + ++r; + } + // + if (comm) { + if (qtimer(atime, 500)) { + if (comm->IsCancelled()) { + delete[] covered; + throw Communicator::CancelledException(); + } + comm->CommPostMessage(Communicator::CURRENT_RECORD, i); + } + } + } + delete[] covered; + if (m_choice) { + i = -1; + for (auto & iter: attributes) { + i++; + AttributeRow &row = iter.getRow(); + double total_choice = 0.0, w_total_choice = 0.0; + for (size_t r = 0; r < radii.size(); r++) { + total_choice += audittrail[i][r].choice; + w_total_choice += audittrail[i][r].weighted_choice; + // n.b., normalise choice according to (n-1)(n-2)/2 (maximum possible through routes) + double node_count = row.getValue(count_col[r]); + double total_weight = 0; + if (m_weighted_measure_col != -1) { + total_weight = row.getValue(total_weight_col[r]); + } + if (node_count > 2) { + row.setValue(choice_col[r], float(total_choice)); + row.setValue(n_choice_col[r], float(2.0 * total_choice / ((node_count - 1) * (node_count - 2)))); + if (m_weighted_measure_col != -1) { + row.setValue(w_choice_col[r], float(w_total_choice)); + row.setValue(nw_choice_col[r], float(2.0 * w_total_choice / (total_weight * total_weight))); + } + } else { + row.setValue(choice_col[r], -1); + row.setValue(n_choice_col[r], -1); + if (m_weighted_measure_col != -1) { + row.setValue(w_choice_col[r], -1); + row.setValue(nw_choice_col[r], -1); + } + } + } + } + for (size_t i = 0; i < map.getShapeCount(); i++) { + delete[] audittrail[i]; + } + delete[] audittrail; + } + + map.setDisplayedAttribute(-1); // <- override if it's already showing + map.setDisplayedAttribute(integ_dv_col.back()); + + return true; +} diff --git a/salalib/axialmodules/axialintegration.h b/salalib/axialmodules/axialintegration.h new file mode 100644 index 00000000..0611d59f --- /dev/null +++ b/salalib/axialmodules/axialintegration.h @@ -0,0 +1,37 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/iaxial.h" + +class AxialIntegration : IAxial { + private: + std::set m_radius_set; + int m_weighted_measure_col; + bool m_choice; + bool m_fulloutput; + bool m_local; + + public: + std::string getAnalysisName() const override { return "Angular Analysis"; } + bool run(Communicator *, ShapeGraph &map, bool) override; + AxialIntegration(std::set radius_set, int weighted_measure_col, bool choice, bool fulloutput, bool local) + : m_radius_set(radius_set), m_weighted_measure_col(weighted_measure_col), m_choice(choice), + m_fulloutput(fulloutput), m_local(local) {} +}; diff --git a/salalib/axialmodules/axialstepdepth.cpp b/salalib/axialmodules/axialstepdepth.cpp new file mode 100644 index 00000000..45e6d56d --- /dev/null +++ b/salalib/axialmodules/axialstepdepth.cpp @@ -0,0 +1,63 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "salalib/axialmodules/axialstepdepth.h" + +#include "genlib/pflipper.h" +#include "genlib/stringutils.h" + +bool AxialStepDepth::run(Communicator *, ShapeGraph &map, bool) { + + AttributeTable &attributes = map.getAttributeTable(); + + std::string stepdepth_col_text = std::string("Step Depth"); + int stepdepth_col = attributes.insertOrResetColumn(stepdepth_col_text.c_str()); + + bool *covered = new bool [map.getConnections().size()]; + for (size_t i = 0; i < map.getConnections().size(); i++) { + covered[i] = false; + } + pflipper > foundlist; + for(auto& lineindex: map.getSelSet()) { + foundlist.a().push_back(lineindex); + covered[lineindex] = true; + map.getAttributeRowFromShapeIndex(lineindex).setValue(stepdepth_col,0.0f); + } + int depth = 1; + while (foundlist.a().size()) { + Connector& line = map.getConnections()[foundlist.a().back()]; + for (size_t k = 0; k < line.m_connections.size(); k++) { + if (!covered[line.m_connections[k]]) { + covered[line.m_connections[k]] = true; + foundlist.b().push_back(line.m_connections[k]); + map.getAttributeRowFromShapeIndex(line.m_connections[k]).setValue(stepdepth_col,float(depth)); + } + } + foundlist.a().pop_back(); + if (!foundlist.a().size()) { + foundlist.flip(); + depth++; + } + } + delete [] covered; + + map.setDisplayedAttribute(-1); // <- override if it's already showing + map.setDisplayedAttribute(stepdepth_col); + + return true; +} diff --git a/salalib/gmlmap.h b/salalib/axialmodules/axialstepdepth.h similarity index 62% rename from salalib/gmlmap.h rename to salalib/axialmodules/axialstepdepth.h index e16e4ccf..3a09ebf5 100644 --- a/salalib/gmlmap.h +++ b/salalib/axialmodules/axialstepdepth.h @@ -1,39 +1,30 @@ -// sala - a component of the depthmapX - spatial network analysis platform -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef __GMLMAP_H__ -#define __GMLMAP_H__ - -typedef prefvec polyset; - -class GMLMap -{ -protected: - QtRegion m_region; -public: - pqmap m_keys; -public: - GMLMap() {;} - bool parse(const pvecstring& fileset, Communicator *communicator); - Point2f getBottomLeft() - { return m_region.bottom_left; } - Point2f getTopRight() - { return m_region.top_right; } - QtRegion getRegion() - { return m_region; } -}; - -#endif \ No newline at end of file +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/iaxial.h" + +class AxialStepDepth : IAxial +{ +public: + std::string getAnalysisName() const override { + return "Angular Analysis"; + } + bool run(Communicator *comm, ShapeGraph &map, bool simple_version) override; +}; diff --git a/salalib/axialpolygons.cpp b/salalib/axialpolygons.cpp new file mode 100644 index 00000000..93a9a4e1 --- /dev/null +++ b/salalib/axialpolygons.cpp @@ -0,0 +1,493 @@ +#include "salalib/axialpolygons.h" +#include "salalib/tidylines.h" +#include "salalib/tolerances.h" + +#include "genlib/containerutils.h" + +AxialVertex AxialPolygons::makeVertex(const AxialVertexKey& vertexkey, const Point2f& openspace) +{ + auto vertPossIter = depthmapX::getMapAtIndex(m_vertex_possibles, vertexkey.m_ref_key); + AxialVertex av(vertexkey, vertPossIter->first, openspace); + + // n.b., at this point, vertex key m_a and m_b are unfixed + std::vector& pointlist = vertPossIter->second; + if (pointlist.size() < 2) { + return av; + } + + Point2f o = av.m_point - av.m_openspace; + + // using an anglemap means that there are now no anti-clockwise vertices... + // TODO: (CS) Double as key is problematic - books have been written about double equality... + std::map anglemap; + for (size_t i = 0; i < pointlist.size(); ++i) { + anglemap.insert(std::make_pair( angle(openspace,av.m_point, pointlist[i]), i )); + } + + av.m_ref_a = anglemap.begin()->second; + // TODO: is this supposed to be av.m_ref_b? + av.m_ref_a = anglemap.rbegin()->second; + Point2f a = av.m_point - pointlist[size_t(anglemap.begin()->second)]; + Point2f b = pointlist[size_t(anglemap.rbegin()->second)] - av.m_point; + av.m_a = a; + av.m_b = b; + a.normalise(); + b.normalise(); + + double oa = det(o,a); + double ob = det(o,b); + double ab = det(a,b); + + // can't handle these cases + if (fabs(oa) < TOLERANCE_A || fabs(ob) < TOLERANCE_A || fabs(ab) < TOLERANCE_A) { + // although note that if ab == 0 and you've already checked intersection, it can't be convex + return av; + } + + // ADDED 4-Nov-04 -- In order to stop too many lines being generated, don't include + // points that do not change surface direction: -- notice: will create problems with circles + if (fabs(dot(a,b)) > 0.999) { + return av; + } + + + if (sgn(oa) == sgn(ob)) { + // headon collision + if (sgn(oa) == 1) { + if (sgn(ab) == 1) { + // convex clockwise + av.m_convex = true; + av.m_clockwise = true; + av.m_axial = true; + } + else { + // n.b., these are turned away for axial formation + // concave clockwise + av.m_convex = false; + av.m_clockwise = true; + av.m_axial = false; + } + } + } + else { + // glancing blow + // concave clockwise + av.m_convex = false; + av.m_clockwise = true; + av.m_axial = true; + } + + av.m_initialised = true; + + return av; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +void AxialPolygons::clear() +{ + // clear any existing data + m_vertex_possibles.clear(); + m_vertex_polys.clear(); + m_handled_list.clear(); + m_pixel_polys.reset(0,0); +} + +void AxialPolygons::init(std::vector& lines, const QtRegion& region) +{ + // init pixelbase members + m_region = region; + + // now tidy + TidyLines tidier; + tidier.tidy(lines, m_region); + + // for easier debugging, the axial code is reused to make segments + ShapeGraph firstpass; + firstpass.init(lines.size(),m_region); // used to be double density + firstpass.initialiseAttributesAxial(); + size_t i; + for (i = 0; i < lines.size(); i++) { + firstpass.makeLineShape(lines[i]); + } + firstpass.makeConnections(); + + lines.clear(); + std::vector connectionset; + + // interesting... 1.0 may or may not work as intended + firstpass.makeSegmentMap(lines, connectionset, 1.0); + + // now we have a set of lines and a set of connections... + // ...for the second pass, a bit of retro fitting to my original code is + // required + makeVertexPossibles(lines, connectionset); + + initLines(lines.size(), m_region.bottom_left, m_region.top_right, 2); + // need to init before making pixel polys... + makePixelPolys(); + // now also add lines + for (auto& vertexPoss: m_vertex_possibles) { + for (auto poss: vertexPoss.second) { + addLine(Line(vertexPoss.first,poss)); + } + } + sortPixelLines(); +} + +void AxialPolygons::makeVertexPossibles(const std::vector& lines, const std::vector& connectionset) +{ + m_vertex_possibles.clear(); + m_vertex_polys.clear(); + + size_t i = 0; + + // TODO: (CS) these should be vectors, not raw pointers. + depthmapX::RowMatrix found(2, lines.size()); + for (i = 0; i < lines.size(); i++) { + found(0, i) = -1; + found(1, i) = -1; + } + std::vector pointlookup; + // three pass operation: (1) stack the lines + for (i = 0; i < lines.size(); i++) { + if (found(0, i) == -1) { + pointlookup.push_back(lines[i].start()); + m_vertex_possibles.insert(std::make_pair(pointlookup.back(),std::vector())); + m_vertex_polys.push_back(-1); // <- n.b., dummy entry for now, maintain with vertex possibles + found(0, i) = static_cast(pointlookup.size() - 1); + for (auto& segconn: connectionset[i].m_back_segconns) { + int forwback = (segconn.first.dir == 1) ? 0 : 1; + found(static_cast(forwback), static_cast(segconn.first.ref)) = found(0, i); + } + } + if (found(1, i) == -1) { + pointlookup.push_back(lines[i].end()); + m_vertex_possibles.insert(std::make_pair(pointlookup.back(),std::vector())); + m_vertex_polys.push_back(-1); // <- n.b., dummy entry for now, maintain with vertex possibles + found(1, i) = static_cast(pointlookup.size() - 1); + for (auto& segconn: connectionset[i].m_forward_segconns) { + int forwback = (segconn.first.dir == 1) ? 0 : 1; + found(static_cast(forwback), static_cast(segconn.first.ref)) = found(1, i); + } + } + } + // three pass operation: (2) connect up vertex possibles + for (i = 0; i < lines.size(); i++) { + if (found(0, i) == -1 || found(1, i) == -1) { + // TODO: (CS) What are these integers being thrown?! + throw 1; + } + auto index0 = m_vertex_possibles.find(pointlookup[size_t(found(0, i))]); + auto index1 = m_vertex_possibles.find(pointlookup[size_t(found(1, i))]); + if (index0 == m_vertex_possibles.end() || index1 == m_vertex_possibles.end()) { + // TODO: (CS) What are these integers being thrown?! + throw 2; + } + + index0->second.push_back(pointlookup[size_t(found(1, i))]); + index1->second.push_back(pointlookup[size_t(found(0, i))]); + } + for(auto& possible: m_vertex_possibles) { + sort( possible.second.begin(), possible.second.end() ); + possible.second.erase( unique( possible.second.begin(), possible.second.end() ), possible.second.end() ); + } + + // three pass operation: (3) create vertex poly entries + int current_poly = -1; + for (i = 0; i < m_vertex_possibles.size(); i++) { + if (m_vertex_polys[i] == -1) { + current_poly++; + std::vector addlist; + addlist.push_back(int(i)); + while (addlist.size()) { + m_vertex_polys[size_t(addlist.back())] = current_poly; + std::vector& connections = depthmapX::getMapAtIndex(m_vertex_possibles, addlist.back())->second; + addlist.pop_back(); + for (size_t j = 0; j < connections.size(); j++) { + int index = depthmapX::findIndexFromKey(m_vertex_possibles, connections[j]); + if (index == -1) { + throw 3; + } + if (m_vertex_polys[size_t(index)] == -1) { + addlist.push_back(index); + } + } + } + } + } +} + +void AxialPolygons::makePixelPolys() +{ + // record all of this onto the pixel polygons + + m_pixel_polys = depthmapX::ColumnMatrix>(m_rows, m_cols); + // now register the vertices in each pixel... + int j = -1; + for (auto vertPoss: m_vertex_possibles) { + j++; + PixelRef pix = pixelate(vertPoss.first); + m_pixel_polys(static_cast(pix.y), static_cast(pix.x)).push_back(j); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +// almost identical to original! + +AxialVertexKey AxialPolygons::seedVertex(const Point2f& seed) +{ + AxialVertexKey seedvertex = NoVertex; + PixelRef seedref = pixelate(seed); + bool foundvertex = false; + // for spiralling outwards to find a vertex: + int dir = PixelRef::HORIZONTAL; + int sidelength = 1; + int runlength = 0; + int allboundaries = 0; + + while (!foundvertex) { + for (int vertexref: m_pixel_polys(static_cast(seedref.y), static_cast(seedref.x))) { + const Point2f& trialpoint = depthmapX::getMapAtIndex(m_vertex_possibles, vertexref)->first; + if (!intersect_exclude(Line(seed,trialpoint))) { + // yay... ...but wait... we need to see if it's a proper polygon vertex first... + seedvertex = vertexref; + foundvertex = true; + } + } + if (!foundvertex) { + seedref = seedref.move(dir); + // spiral outwards: + if (++runlength == sidelength) { + switch (dir) { + case PixelRef::HORIZONTAL: + dir = PixelRef::VERTICAL; runlength = 0; + break; + case PixelRef::VERTICAL: + dir = PixelRef::NEGHORIZONTAL; runlength = 0; sidelength++; + break; + case PixelRef::NEGHORIZONTAL: + dir = PixelRef::NEGVERTICAL; runlength = 0; + break; + case PixelRef::NEGVERTICAL: + dir = PixelRef::HORIZONTAL; runlength = 0; sidelength++; + break; + } + } + // check to make sure not off edge of system: + if (seedref.x < 0) { + allboundaries |= 0x01; seedref.x = 0; + } + if (seedref.y < 0) { + allboundaries |= 0x02; seedref.y = 0; + } + if (seedref.x >= static_cast(m_cols)) { + allboundaries |= 0x04; seedref.x = m_cols - 1; + } + if (seedref.y >= static_cast(m_rows)) { + allboundaries |= 0x08; seedref.y = m_rows - 1; + } + if (allboundaries == 0x0f) { + return NoVertex; + } + } + } + return seedvertex; +} + +// adds any axial lines from this point to the list of lines, adds any unhandled visible vertices it finds to the openvertices list +// axial lines themselves are added to the lines list - the axial line is only there to record the key vertices that comprise the line +void AxialPolygons::makeAxialLines(std::set& openvertices, std::vector& lines, + KeyVertices& keyvertices, std::vector& poly_connections, + std::vector& radial_lines) +{ + auto it = openvertices.rbegin(); + AxialVertex vertex = *it; + openvertices.erase(std::next(it).base()); + + m_handled_list.insert(vertex); + + int i = -1; + for (auto vertPoss: m_vertex_possibles) { + i++; + if (i == vertex.m_ref_key) { + continue; + } + bool possible = false, stubpossible = false; + Point2f p = vertPoss.first - vertex.m_point; + if (vertex.m_convex) { + if (det(vertex.m_a,p) > 0 && det(vertex.m_b,p) > 0) { + possible = true; + } + } + else { + // left of b and right of a or left of a and right of b + if (det(p,vertex.m_a) * det(p,vertex.m_b) < 0) { + possible = true; + } + else if (det(p,vertex.m_a) < TOLERANCE_A && det(p,vertex.m_b) < TOLERANCE_A) { + stubpossible = true; + } + } + if (possible || stubpossible) { + Line line(vertPoss.first,vertex.m_point); + if (!intersect_exclude(line)) { + AxialVertex next_vertex = makeVertex(AxialVertexKey(i),vertex.m_point); + if (next_vertex.m_initialised && std::find(m_handled_list.begin(), m_handled_list.end(), next_vertex) == m_handled_list.end()) { + openvertices.insert(next_vertex); // <- note, add ignores duplicate adds (each vertex tends to be added multiple times before this vertex is handled itself) + bool shortline_segend = false; + Line shortline = line; + if (!vertex.m_convex && possible) { + Line ext(line.t_end(), line.t_end() + (line.t_end() - line.t_start())); + ext.ray(1, m_region); + cutLine(ext, 1); + line = Line(line.t_start(), ext.t_end()); + // for radial line segend calc: + if (det(-p,vertex.m_b) < 0) { + shortline_segend = true; + } + } + if (m_vertex_polys[vertex.m_ref_key] != m_vertex_polys[next_vertex.m_ref_key]) { // must be on separate polygons + // radial line(s) (for new point) + RadialLine radialshort(next_vertex, shortline_segend, vertex.m_point,next_vertex.m_point,next_vertex.m_point+next_vertex.m_b); + poly_connections.push_back( PolyConnector(shortline, (RadialKey)radialshort) ); + radial_lines.push_back(radialshort); + if (!vertex.m_convex && possible) { + Line longline = Line(vertPoss.first,line.t_end()); + RadialLine radiallong(radialshort); + radiallong.segend = shortline_segend ? 0 : 1; + poly_connections.push_back( PolyConnector(longline, (RadialKey)radiallong) ); + radial_lines.push_back(radiallong); + } + } + shortline_segend = false; + if (!next_vertex.m_convex && next_vertex.m_axial) { + Line ext(line.t_start() - (line.t_end() - line.t_start()), line.t_start()); + ext.ray(0, m_region); + cutLine(ext, 0); + line = Line(ext.t_start(), line.t_end()); + // for radial line segend calc: + if (det(p,next_vertex.m_b) < 0) { + shortline_segend = true; + } + } + if (m_vertex_polys[vertex.m_ref_key] != m_vertex_polys[next_vertex.m_ref_key]) { // must be on separate polygons + // radial line(s) (for original point) + RadialLine radialshort(vertex, shortline_segend, next_vertex.m_point,vertex.m_point,vertex.m_point+vertex.m_b); + poly_connections.push_back( PolyConnector(shortline, (RadialKey)radialshort) ); + radial_lines.push_back(radialshort); + if (!next_vertex.m_convex && next_vertex.m_axial) { + Line longline = Line(line.t_start(),vertex.m_point); + RadialLine radiallong(radialshort); + radiallong.segend = shortline_segend ? 0 : 1; + poly_connections.push_back( PolyConnector(longline, (RadialKey)radiallong) ); + radial_lines.push_back(radiallong); + } + } + if (possible && next_vertex.m_axial) { + // axial line + lines.push_back(line); + keyvertices.push_back(std::set()); + if (vertex.m_convex) { + keyvertices.back().insert(vertex.m_ref_key); + } + if (next_vertex.m_convex) { + keyvertices.back().insert(next_vertex.m_ref_key); + } + } + } + } + } + } + std::sort( radial_lines.begin(), radial_lines.end() ); + radial_lines.erase( std::unique( radial_lines.begin(), radial_lines.end() ), radial_lines.end() ); +} + +/////////////////////////////////////////////////////////////////////////////////////////// + +// not really used as yet, a feature to make all the polygons from the vertex +// possibles list + +void AxialPolygons::makePolygons(std::vector>& polygons) +{ + std::vector > handled_list; + for (size_t j = 0; j < m_vertex_possibles.size(); j++) { + handled_list.push_back(std::vector()); + } + + int i = -1; + for (auto vertPoss: m_vertex_possibles) { + i++; + std::vector& currList = handled_list[size_t(i)]; + if (vertPoss.second.size() == 1) { + continue; + } + for (size_t j = 0; j < vertPoss.second.size(); j++) { + if (std::find(currList.begin(), currList.end(), j) != currList.end()) { + continue; + } + currList.push_back(int(j)); + const Point2f& key = vertPoss.first; + std::vector polygon; + polygon.push_back(key); + Point2f curr = vertPoss.second.at(j); + Point2f last = key; + bool good = true; + while (curr != key) { + auto vertPossIter = m_vertex_possibles.find(curr); + polygon.push_back(curr); + // hunt down left most + int winner = -1, wayback = -1; + double minangle = 2 * M_PI; + for (size_t k = 0; k < vertPossIter->second.size(); k++) { + Point2f next = vertPossIter->second.at(k); + if (last != next) { + double thisangle = angle(last,curr,next); + if (thisangle < minangle) { + // check not going to a dead end: + if (m_vertex_possibles.find(vertPossIter->second.at(k))->second.size() > 1) { + minangle = thisangle; + winner = k; + } + } + } + else { + wayback = k; + } + } + if (winner == -1) { + // this happens when you follow a false trail -- go back the way you came! + winner = wayback; + } + handled_list[std::distance(m_vertex_possibles.begin(), vertPossIter)].push_back(winner); + last = curr; + curr = vertPossIter->second.at(winner); + } + if (good) { + polygons.push_back(polygon); + } + good = true; + } + } +} + +/////////////////////////////////////////////////////////////////////////////////////////// + +bool RadialLine::cuts(const Line& l) const +{ + if (fabs(det(l.end() - keyvertex,l.end() - l.start())) < TOLERANCE_A) { + // point on line, check that openspace and next vertex are on opposite sides of the line + Point2f x = l.end() - keyvertex; + Point2f y = nextvertex - keyvertex; + Point2f z = openspace - keyvertex; + x.normalise(); + y.normalise(); + z.normalise(); + if (sgn(det(x, y)) == sgn(det(x, z)) && fabs(det(x, z)) > TOLERANCE_A) { + return false; + } + } + // keyvertex not on line... the line's been cut: + return true; +} diff --git a/salalib/axialpolygons.h b/salalib/axialpolygons.h new file mode 100644 index 00000000..2e928341 --- /dev/null +++ b/salalib/axialpolygons.h @@ -0,0 +1,127 @@ +#pragma once + +#include "salalib/spacepix.h" +#include "salalib/axialmap.h" +#include "salalib/connector.h" + +#include "genlib/simplematrix.h" +#include "genlib/p2dpoly.h" + +struct AxialVertexKey +{ + int m_ref_key; + short m_ref_a; + short m_ref_b; + AxialVertexKey(int ref = -1, short a = -1, short b = -1) + { m_ref_key = ref; m_ref_a = a; m_ref_b = b; } + friend bool operator == (const AxialVertexKey& a, const AxialVertexKey& b); + friend bool operator != (const AxialVertexKey& a, const AxialVertexKey& b); + friend bool operator > (const AxialVertexKey& a, const AxialVertexKey& b); + friend bool operator < (const AxialVertexKey& a, const AxialVertexKey& b); +}; +inline bool operator == (const AxialVertexKey& a, const AxialVertexKey& b) +{ return (a.m_ref_key == b.m_ref_key && a.m_ref_a == b.m_ref_a && a.m_ref_b == b.m_ref_b); } +inline bool operator != (const AxialVertexKey& a, const AxialVertexKey& b) +{ return (a.m_ref_key != b.m_ref_key || a.m_ref_a != b.m_ref_a || a.m_ref_b != b.m_ref_b); } +inline bool operator > (const AxialVertexKey& a, const AxialVertexKey& b) +{ return (a.m_ref_key > b.m_ref_key || (a.m_ref_key == b.m_ref_key && (a.m_ref_a > b.m_ref_a || (a.m_ref_a == b.m_ref_a && a.m_ref_b > b.m_ref_b)))); } +inline bool operator < (const AxialVertexKey& a, const AxialVertexKey& b) +{ return (a.m_ref_key < b.m_ref_key || (a.m_ref_key == b.m_ref_key && (a.m_ref_a < b.m_ref_a || (a.m_ref_a == b.m_ref_a && a.m_ref_b < b.m_ref_b)))); } + +const AxialVertexKey NoVertex(-1,-1,-1); + +struct AxialVertex : public AxialVertexKey +{ + Point2f m_point; + Point2f m_openspace; + Point2f m_a; + Point2f m_b; + bool m_clockwise; + bool m_convex; + bool m_initialised; + bool m_axial; + AxialVertex(const AxialVertexKey& vertex_key = NoVertex, const Point2f& point = Point2f(), const Point2f& openspace = Point2f()) : AxialVertexKey(vertex_key) + { m_point = point; m_openspace = openspace; m_initialised = false; m_axial = false; } +}; + +struct RadialKey { + AxialVertexKey vertex; + float ang; + bool segend; + // padding the remaining three bytes behind the bool - don't use int : 24 as this will grab the next 4 byte block + char pad1 : 8; + short pad2 : 16; + + RadialKey(const AxialVertexKey& v = NoVertex, float a = -1.0f, bool se = false) : pad1(0), pad2(0) + { vertex = v; ang = a; segend = se; } + RadialKey(const RadialKey& rk) : pad1(0), pad2(0) + { vertex = rk.vertex; ang = rk.ang; segend = rk.segend; } +}; +inline bool operator < (const RadialKey& a, const RadialKey& b) +{ return a.vertex < b.vertex || (a.vertex == b.vertex && (a.ang < b.ang || (a.ang == b.ang && a.segend < b.segend))); } +inline bool operator > (const RadialKey& a, const RadialKey& b) +{ return a.vertex > b.vertex || (a.vertex == b.vertex && (a.ang > b.ang || (a.ang == b.ang && a.segend > b.segend))); } +inline bool operator == (const RadialKey& a, const RadialKey& b) +{ return a.vertex == b.vertex && a.ang == b.ang && a.segend == b.segend; } + +struct RadialLine : public RadialKey +{ + Point2f openspace; + Point2f keyvertex; + Point2f nextvertex; + RadialLine(const RadialKey& rk = RadialKey()) : RadialKey(rk) {;} + RadialLine(const AxialVertexKey& v, bool se, const Point2f& o, const Point2f& k, const Point2f& n) + { vertex = v; ang = (float) angle(o,k,n); segend = se; openspace = o; keyvertex = k; nextvertex = n; } + RadialLine(const RadialLine& rl) : RadialKey(rl) + { openspace = rl.openspace; keyvertex = rl.keyvertex; nextvertex = rl.nextvertex; } + bool cuts(const Line& l) const; +}; + +struct RadialSegment +{ + std::set indices; + RadialKey radial_b; + + RadialSegment(RadialKey& rb) + { radial_b = rb; } + RadialSegment(const RadialKey& rb) + { radial_b = rb; } + RadialSegment() + { radial_b = RadialKey(); } + +}; + +struct PolyConnector { + Line line; + RadialKey key; + PolyConnector(const Line& l = Line(), const RadialKey& k = RadialKey()) + { line = l; key = k; } +}; + + +class AxialPolygons : public SpacePixel +{ + friend class ShapeGraphs; +protected: + std::vector m_vertex_polys; + depthmapX::ColumnMatrix > m_pixel_polys; +public: + AxialPolygons(): m_pixel_polys(0,0) {} + std::set m_handled_list; + std::map> m_vertex_possibles; + + void clear(); + void init(std::vector &lines, const QtRegion& region); + void makeVertexPossibles(const std::vector &lines, const std::vector &connectionset); + void makePixelPolys(); + // + AxialVertex makeVertex(const AxialVertexKey& vertexkey, const Point2f& openspace); + // find a polygon corner visible from seed: + AxialVertexKey seedVertex(const Point2f& seed); + // make axial lines from corner vertices, visible from openspace + void makeAxialLines(std::set &openvertices, std::vector& lines, + KeyVertices &keyvertices, std::vector& poly_connections, + std::vector &radial_lines); + // extra: make all the polygons possible from the set of m_vertex_possibles + void makePolygons(std::vector > &polygons); +}; diff --git a/salalib/connector.cpp b/salalib/connector.cpp index 1126b8d8..bbf16630 100644 --- a/salalib/connector.cpp +++ b/salalib/connector.cpp @@ -15,48 +15,41 @@ // along with this program. If not, see . +#include "salalib/connector.h" + +#include "genlib/containerutils.h" +#include "genlib/readwritehelpers.h" +#include "genlib/comm.h" // for communicator + #include #include #include -#include -#include // for communicator -#include // purely for the version info --- as phased out should replace -#include - -bool Connector::read( ifstream& stream, int version, pvecint *keyvertices ) +bool Connector::read( std::istream& stream) { m_connections.clear(); m_forward_segconns.clear(); m_back_segconns.clear(); // n.b., must set displayed attribute as soon as loaded... - m_connections.read(stream); + dXreadwrite::readIntoVector(stream, m_connections); - // keyvertices now stored with axial map itself, but need this read for backward compatibility - if (version < VERSION_AXIAL_SHAPES && keyvertices != NULL) { - keyvertices->read(stream); - } + stream.read((char *)&m_segment_axialref, sizeof(m_segment_axialref)); - if (version >= VERSION_SEGMENT_MAPS) { - stream.read((char *)&m_segment_axialref, sizeof(m_segment_axialref)); - m_forward_segconns.read(stream); - } - if (version >= VERSION_SEGMENT_MAPS_FIX) { - m_back_segconns.read(stream); - } + dXreadwrite::readIntoMap(stream, m_forward_segconns); + dXreadwrite::readIntoMap(stream, m_back_segconns); return true; } -bool Connector::write( ofstream& stream ) +bool Connector::write( std::ofstream& stream ) { // n.b., must set displayed attribute as soon as loaded... - m_connections.write(stream); - // m_keyvertices.write(stream); + dXreadwrite::writeVector(stream, m_connections); stream.write((char *)&m_segment_axialref, sizeof(m_segment_axialref)); - m_forward_segconns.write(stream); - m_back_segconns.write(stream); + + dXreadwrite::writeMap(stream, m_forward_segconns); + dXreadwrite::writeMap(stream, m_back_segconns); return true; } @@ -84,82 +77,79 @@ int Connector::count(int mode) const } return c; } -int Connector::cursor(int mode) const +int Connector::getConnectedRef(int cursor, int mode) const { int cur = -1; - if (m_cursor != -1) { + if (cursor != -1) { switch (mode) { case CONN_ALL: - if (m_cursor < (int)m_connections.size()) { - cur = m_connections[m_cursor]; + if (cursor < int(m_connections.size())) { + cur = m_connections[size_t(cursor)]; } break; case SEG_CONN_ALL: - if (m_cursor < (int)m_back_segconns.size()) { - cur = m_back_segconns.key(m_cursor).ref; + if (cursor < int(m_back_segconns.size())) { + cur = depthmapX::getMapAtIndex(m_back_segconns, cursor)->first.ref; } - else if (m_cursor - m_back_segconns.size() < m_forward_segconns.size()) { - cur = m_forward_segconns.key(m_cursor - m_back_segconns.size()).ref; + else if (size_t(cursor) - m_back_segconns.size() < m_forward_segconns.size()) { + cur = depthmapX::getMapAtIndex(m_forward_segconns, cursor - int(m_back_segconns.size()))->first.ref; } break; case SEG_CONN_FW: - if (m_cursor < (int)m_forward_segconns.size()) { - cur = m_forward_segconns.key(m_cursor).ref; + if (cursor < int(m_forward_segconns.size())) { + cur = depthmapX::getMapAtIndex(m_forward_segconns, cursor)->first.ref; } break; case SEG_CONN_BK: - if (m_cursor < (int)m_back_segconns.size()) { - cur = m_back_segconns.key(m_cursor).ref; + if (cursor < int(m_back_segconns.size())) { + cur = depthmapX::getMapAtIndex(m_back_segconns, cursor)->first.ref; } break; } } - if (cur == -1) { - m_cursor = -1; - } return cur; } -int Connector::direction(int mode) const +int Connector::direction(int cursor, int mode) const { int direction = 0; - if (m_cursor != -1) { + if (cursor != -1) { switch (mode) { case SEG_CONN_ALL: - if (m_cursor < (int)m_back_segconns.size()) { - direction = m_back_segconns.key(m_cursor).dir; + if (cursor < (int)m_back_segconns.size()) { + direction = depthmapX::getMapAtIndex(m_back_segconns, cursor)->first.dir; } - else if (m_cursor - m_back_segconns.size() < m_forward_segconns.size()) { - direction = m_forward_segconns.key(m_cursor - m_back_segconns.size()).dir; + else if (size_t(cursor) - m_back_segconns.size() < m_forward_segconns.size()) { + direction = depthmapX::getMapAtIndex(m_forward_segconns, cursor - int(m_back_segconns.size()))->first.dir; } break; case SEG_CONN_FW: - direction = m_forward_segconns.key(m_cursor).dir; + direction = depthmapX::getMapAtIndex(m_forward_segconns, cursor)->first.dir; break; case SEG_CONN_BK: - direction = m_back_segconns.key(m_cursor).dir; + direction = depthmapX::getMapAtIndex(m_back_segconns, cursor)->first.dir; break; } } return direction; } -float Connector::weight(int mode) const +float Connector::weight(int cursor, int mode) const { float weight = 0.0f; - if (m_cursor != -1) { + if (cursor != -1) { switch (mode) { case SEG_CONN_ALL: - if (m_cursor < (int)m_back_segconns.size()) { - weight = m_back_segconns.value(m_cursor); + if (cursor < int(m_back_segconns.size())) { + weight = depthmapX::getMapAtIndex(m_back_segconns, cursor)->second; } - else if (m_cursor - m_back_segconns.size() < m_forward_segconns.size()) { - weight = m_forward_segconns.value(m_cursor - m_back_segconns.size()); + else if (size_t(cursor) - m_back_segconns.size() < m_forward_segconns.size()) { + weight = depthmapX::getMapAtIndex(m_forward_segconns, cursor - int(m_back_segconns.size()))->second; } break; case SEG_CONN_FW: - weight = m_forward_segconns.value(m_cursor); + weight = depthmapX::getMapAtIndex(m_forward_segconns, cursor)->second; break; case SEG_CONN_BK: - weight = m_back_segconns.value(m_cursor); + weight = depthmapX::getMapAtIndex(m_back_segconns, cursor)->second; break; } } diff --git a/salalib/connector.h b/salalib/connector.h index 245a21d3..2f57a2cb 100644 --- a/salalib/connector.h +++ b/salalib/connector.h @@ -15,22 +15,25 @@ // along with this program. If not, see . -#ifndef __CONNECTOR_H__ -#define __CONNECTOR_H__ +#pragma once +#include +#include +#include +#include ///////////////////////////////////////////////////////////////////////////// // Additional for segment analysis struct SegmentRef { - char dir; int ref; - SegmentRef(char d = 0, int r = -1) + char dir; + // padding the remaining three bytes behind the char + char pad1 : 8; + short pad2 : 16; + int ref; + SegmentRef(char d = 0, int r = -1): pad1(0), pad2(0) { dir = d; ref = r; } - friend bool operator < (SegmentRef a, SegmentRef b); - friend bool operator > (SegmentRef a, SegmentRef b); - friend bool operator == (SegmentRef a, SegmentRef b); - friend bool operator != (SegmentRef a, SegmentRef b); }; // note, the dir is only a direction indicator, the ref should always be unique inline bool operator < (SegmentRef a, SegmentRef b) { return a.ref < b.ref; } @@ -66,32 +69,31 @@ inline bool operator != (SegmentData a, SegmentData b) { return a.metricdepth != struct Connector { - // cursor included purely to make this compatible with DLL functionality - mutable int m_cursor; // if this is a segment, this is the key for the axial line: int m_segment_axialref; // use one or other of these - pvecint m_connections; + std::vector m_connections; // - pmap m_back_segconns; - pmap m_forward_segconns; + std::map m_back_segconns; + std::map m_forward_segconns; // Connector(int axialref = -1) - { m_segment_axialref = axialref; m_cursor = -1; } + { m_segment_axialref = axialref; } void clear() { m_connections.clear(); m_back_segconns.clear(); m_forward_segconns.clear(); } // - bool read( ifstream& stream, int version, pvecint *keyvertices = NULL ); - bool write( ofstream& stream ); + bool read(std::istream &stream); + bool write( std::ofstream& stream ); // // Cursor extras enum { CONN_ALL, SEG_CONN_ALL, SEG_CONN_FW, SEG_CONN_BK }; + + // PK: These functions have been stripped of state and left + // here for salaprogram which seems to be the only place they + // are used. salaprogram seems to also be the only place where + // the last two modes (SEG_CONN_FW, SEG_CONN_BK) are used int count(int mode = CONN_ALL) const; - int cursor(int mode = CONN_ALL) const; - int direction(int mode = SEG_CONN_ALL) const; - float weight(int mode = SEG_CONN_ALL) const; - void first() const { m_cursor = 0; } - void next() const { m_cursor++; } + int getConnectedRef(int cursor, int mode = CONN_ALL) const; + int direction(int cursor, int mode = SEG_CONN_ALL) const; + float weight(int cursor, int mode = SEG_CONN_ALL) const; }; - -#endif diff --git a/salalib/displayparams.h b/salalib/displayparams.h new file mode 100644 index 00000000..6b1cd22a --- /dev/null +++ b/salalib/displayparams.h @@ -0,0 +1,11 @@ +#pragma once + +struct DisplayParams +{ + enum { AXMANESQUE = 0, GREYSCALE = 1, MONOCHROME = 2, DEPTHMAPCLASSIC = 3, PURPLEORANGE = 4, BLUERED = 5, HUEONLYAXMANESQUE = 6 }; + float blue; + float red; + int colorscale; + DisplayParams() + { blue = 0.0f; red = 1.0f; colorscale = 0; } +}; diff --git a/salalib/entityparsing.cpp b/salalib/entityparsing.cpp new file mode 100644 index 00000000..7d0642a9 --- /dev/null +++ b/salalib/entityparsing.cpp @@ -0,0 +1,384 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "entityparsing.h" +#include +#include +#include + +#include "genlib/stringutils.h" + +namespace EntityParsing { + + std::vector parseLines(std::istream& stream, char delimiter = '\t') { + + std::vector lines; + + std::string inputline; + std::getline(stream, inputline); + + std::vector strings = dXstring::split(inputline, delimiter); + + if (strings.size() < 4) + { + throw EntityParseException("Badly formatted header (should contain x1, y1, x2 and y2)"); + } + + size_t i; + for (i = 0; i < strings.size(); i++) + { + if (!strings[i].empty()) + { + std::transform(strings[i].begin(), strings[i].end(), strings[i].begin(), ::tolower); + //strings[i].ltrim('\"'); + //strings[i].rtrim('\"'); + } + } + + int x1col = -1, y1col = -1, x2col = -1, y2col = -1; + for (i = 0; i < strings.size(); i++) { + if (strings[i] == "x1") + { + x1col = i; + } + else if (strings[i] == "x2") + { + x2col = i; + } + else if (strings[i] == "y1") + { + y1col = i; + } + else if (strings[i] == "y2") + { + y2col = i; + } + } + + if(x1col == -1 || y1col == -1 || x2col == -1 || y2col == -1) + { + throw EntityParseException("Badly formatted header (should contain x1, y1, x2 and y2)"); + } + + Point2f p1, p2; + + while (!stream.eof()) { + std::getline(stream, inputline); + if (!inputline.empty()) { + strings = dXstring::split(inputline, delimiter); + if (!strings.size()) + { + continue; + } + if (strings.size() < 4) + { + std::stringstream message; + message << "Error parsing line: " << inputline << std::flush; + throw EntityParseException(message.str().c_str()); + } + for (i = 0; i < strings.size(); i++) + { + if (static_cast(i) == x1col) + { + p1.x = std::atof(strings[i].c_str()); + } + else if (static_cast(i) == y1col) + { + p1.y = std::atof(strings[i].c_str()); + } + else if (static_cast(i) == x2col) + { + p2.x = std::atof(strings[i].c_str()); + } + else if (static_cast(i) == y2col) + { + p2.y = std::atof(strings[i].c_str()); + } + } + lines.push_back(Line(p1,p2)); + } + } + return lines; + } + + std::vector parsePoints(std::istream& stream, char delimiter = '\t') { + + std::vector points; + + std::string inputline; + std::getline(stream, inputline); + + std::vector strings = dXstring::split(inputline, delimiter); + + if (strings.size() < 2) + { + throw EntityParseException("Badly formatted header (should contain x and y)"); + } + + size_t i; + for (i = 0; i < strings.size(); i++) + { + if (!strings[i].empty()) + { + std::transform(strings[i].begin(), strings[i].end(), strings[i].begin(), ::tolower); + //strings[i].ltrim('\"'); + //strings[i].rtrim('\"'); + } + } + + int xcol = -1, ycol = -1; + for (i = 0; i < strings.size(); i++) { + if (strings[i] == "x") + { + xcol = i; + } + else if (strings[i] == "y") + { + ycol = i; + } + } + + if(xcol == -1 || ycol == -1) + { + throw EntityParseException("Badly formatted header (should contain x and y)"); + } + + Point2f p; + + while (!stream.eof()) { + std::getline(stream, inputline); + if (!inputline.empty()) { + strings = dXstring::split(inputline, delimiter); + if (!strings.size()) + { + continue; + } + if (strings.size() < 2) + { + std::stringstream message; + message << "Error parsing line: " << inputline << std::flush; + throw EntityParseException(message.str().c_str()); + } + for (i = 0; i < strings.size(); i++) + { + if (static_cast(i) == xcol) + { + p.x = std::atof(strings[i].c_str()); + } + else if (static_cast(i) == ycol) + { + p.y = std::atof(strings[i].c_str()); + } + } + points.push_back(p); + } + } + return points; + } + + Point2f parsePoint(const std::string &point, char delimiter) + { + std::vector strings = dXstring::split(point, delimiter); + + if (strings.size() != 2) + { + std::stringstream message; + message << "Badly formatted point data, should be " << delimiter << ", was " << point << std::flush; + throw EntityParseException(message.str()); + } + return Point2f(atof(strings[0].c_str()), atof(strings[1].c_str())); + } + + std::vector parseIsovists(std::istream &stream, char delimiter) + { + std::vector isovists; + + std::string inputline; + std::getline(stream, inputline); + + std::vector strings = dXstring::split(inputline, delimiter); + + if (strings.size() < 2) + { + throw EntityParseException("Badly formatted header (should contain x, y, can also have angle and viewangle for partial isovists)"); + } + + size_t i; + for (i = 0; i < strings.size(); i++) + { + if (!strings[i].empty()) + { + std::transform(strings[i].begin(), strings[i].end(), strings[i].begin(), ::tolower); + } + } + + int xcol = -1, ycol = -1, anglecol = -1, viewcol = -1; + for (i = 0; i < strings.size(); i++) { + if (strings[i] == "x") + { + xcol = i; + } + else if (strings[i] == "y") + { + ycol = i; + } + else if (strings[i] == "angle") + { + anglecol = i; + } + else if (strings[i] == "viewangle") + { + viewcol = i; + } + } + + if(xcol == -1 || ycol == -1 ) + { + throw EntityParseException("Badly formatted header (should contain x and y, might also have angle and viewangle for partial isovists)"); + } + + + bool partialIsovists = anglecol != -1 && viewcol != -1; + int maxCol = std::max({xcol, ycol, anglecol, viewcol}); + while ( !stream.eof()) + { + std::getline(stream, inputline); + if (!inputline.empty()) + { + strings = dXstring::split(inputline, delimiter); + if (!strings.size()) + { + continue; + } + if (static_cast(strings.size()) <= maxCol) + { + std::stringstream message; + message << "Error parsing line: " << inputline << std::flush; + throw EntityParseException(message.str().c_str()); + } + + double x = std::atof(strings[xcol].c_str()); + double y = std::atof(strings[ycol].c_str()); + + if (partialIsovists) + { + double angle = std::atof(strings[anglecol].c_str()) / 180.0 * M_PI; + double viewAngle = std::atof(strings[viewcol].c_str())/180.0 * M_PI; + isovists.push_back(IsovistDefinition(x,y,angle,viewAngle)); + } + else + { + isovists.push_back(IsovistDefinition(x,y)); + } + } + } + return isovists; + } + + IsovistDefinition parseIsovist(const std::string &isovist) + { + auto parts = dXstring::split(isovist, ','); + if (parts.size() == 2) + { + return IsovistDefinition(std::atof(parts[0].c_str()), std::atof(parts[1].c_str())); + } + else if (parts.size() == 4) + { + double angle = std::atof(parts[2].c_str()) / 180.0 * M_PI; + double viewAngle = std::atof(parts[3].c_str())/180.0 * M_PI; + return IsovistDefinition(std::atof(parts[0].c_str()), std::atof(parts[1].c_str()), angle, viewAngle); + } + std::stringstream message; + message << "Failed to parse '" << isovist << "' to an isovist definition"; + throw EntityParseException(message.str()); + } + + std::vector > parseRefPairs(std::istream& stream, char delimiter = '\t') { + + std::vector > pairs; + + std::string inputline; + std::getline(stream, inputline); + + std::vector strings = dXstring::split(inputline, delimiter); + + if (strings.size() < 2) + { + throw EntityParseException("Badly formatted header (should contain reffrom and refto)"); + } + + size_t i; + for (i = 0; i < strings.size(); i++) + { + if (!strings[i].empty()) + { + std::transform(strings[i].begin(), strings[i].end(), strings[i].begin(), ::tolower); + //strings[i].ltrim('\"'); + //strings[i].rtrim('\"'); + } + } + + int fromcol = -1, tocol = -1; + for (i = 0; i < strings.size(); i++) { + if (strings[i] == "reffrom") + { + fromcol = int(i); + } + else if (strings[i] == "refto") + { + tocol = int(i); + } + } + + if(fromcol == -1 || tocol == -1) + { + throw EntityParseException("Badly formatted header (should contain reffrom and refto)"); + } + + + while (!stream.eof()) { + std::getline(stream, inputline); + if (!inputline.empty()) { + strings = dXstring::split(inputline, delimiter); + if (!strings.size()) + { + continue; + } + if (strings.size() < 2) + { + std::stringstream message; + message << "Error parsing line: " << inputline << std::flush; + throw EntityParseException(message.str().c_str()); + } + int from = -1, to = -1; + for (i = 0; i < strings.size(); i++) + { + if (i == size_t(fromcol)) + { + from = std::atoi(strings[i].c_str()); + } + else if (i == size_t(tocol)) + { + to = std::atoi(strings[i].c_str()); + } + } + pairs.push_back(std::make_pair(from, to)); + } + } + return pairs; + } + + +} diff --git a/salalib/entityparsing.h b/salalib/entityparsing.h new file mode 100644 index 00000000..4d60e833 --- /dev/null +++ b/salalib/entityparsing.h @@ -0,0 +1,44 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef ENTITYPARSING_H +#define ENTITYPARSING_H + +#include "genlib/p2dpoly.h" +#include "genlib/exceptions.h" +#include "isovistdef.h" +#include +#include +#include + +namespace EntityParsing { + + class EntityParseException : public depthmapX::BaseException + { + public: + EntityParseException(std::string message) : depthmapX::BaseException(message) + {} + }; + + std::vector split(const std::string &s, char delim); + std::vector parseLines(std::istream& stream, char delimiter); + std::vector parsePoints(std::istream& stream, char delimiter); + Point2f parsePoint(const std::string &point, char delimiter = ','); + std::vector parseIsovists(std::istream &stream, char delimiter); + IsovistDefinition parseIsovist(const std::string &isovist); + std::vector > parseRefPairs(std::istream& stream, char delimiter); +} + +#endif // ENTITYPARSING_H diff --git a/salalib/fileproperties.h b/salalib/fileproperties.h index fff3005a..b7631ef3 100644 --- a/salalib/fileproperties.h +++ b/salalib/fileproperties.h @@ -18,70 +18,71 @@ #ifndef __FILEPROPERTIES_H__ #define __FILEPROPERTIES_H__ +#include "genlib/stringutils.h" class FileProperties { protected: - pstring m_create_person; - pstring m_create_organization; - pstring m_create_date; - pstring m_create_program; - pstring m_title; - pstring m_location; - pstring m_description; + std::string m_create_person; + std::string m_create_organization; + std::string m_create_date; + std::string m_create_program; + std::string m_title; + std::string m_location; + std::string m_description; public: FileProperties() {;} virtual ~FileProperties() {;} // - void setProperties(const pstring& person, const pstring& organization, const pstring& date, const pstring& program) + void setProperties(const std::string& person, const std::string& organization, const std::string& date, const std::string& program) { m_create_person = person; m_create_organization = organization; m_create_date = date; m_create_program = program; } - void setTitle(const pstring& title) + void setTitle(const std::string& title) { m_title = title; } - void setLocation(const pstring& location) + void setLocation(const std::string& location) { m_location = location; } - void setDescription(const pstring& description) + void setDescription(const std::string& description) { m_description = description; } // - const pstring& getPerson() const + const std::string& getPerson() const { return m_create_person; } - const pstring& getOrganization() const + const std::string& getOrganization() const { return m_create_organization; } - const pstring& getDate() const + const std::string& getDate() const { return m_create_date; } - const pstring& getProgram() const + const std::string& getProgram() const { return m_create_program; } - const pstring& getTitle() const + const std::string& getTitle() const { return m_title; } - const pstring& getLocation() const + const std::string& getLocation() const { return m_location; } - const pstring& getDescription() const + const std::string& getDescription() const { return m_description; } // - bool read( ifstream& stream, int version ); - bool write( ofstream& stream ); + bool read(std::istream &stream); + bool write(std::ostream& stream); }; -inline bool FileProperties::read(ifstream& stream, int version) +inline bool FileProperties::read(std::istream& stream) { - m_create_person.read(stream); - m_create_organization.read(stream); - m_create_date.read(stream); - m_create_program.read(stream); - m_title.read(stream); - m_location.read(stream); - m_description.read(stream); + m_create_person=dXstring::readString(stream); + m_create_organization=dXstring::readString(stream); + m_create_date=dXstring::readString(stream); + m_create_program=dXstring::readString(stream); + m_title=dXstring::readString(stream); + m_location=dXstring::readString(stream); + m_description=dXstring::readString(stream); return true; } -inline bool FileProperties::write(ofstream& stream) +inline bool FileProperties::write(std::ostream& stream) { - m_create_person.write(stream); - m_create_organization.write(stream); - m_create_date.write(stream); - m_create_program.write(stream); - m_title.write(stream); - m_location.write(stream); - m_description.write(stream); + dXstring::writeString(stream, m_create_person); + dXstring::writeString(stream, m_create_organization); + dXstring::writeString(stream, m_create_date); + dXstring::writeString(stream, m_create_program); + dXstring::writeString(stream, m_title); + dXstring::writeString(stream, m_location); + dXstring::writeString(stream, m_description); return true; } diff --git a/salalib/geometrygenerators.cpp b/salalib/geometrygenerators.cpp new file mode 100644 index 00000000..f2bd2d5d --- /dev/null +++ b/salalib/geometrygenerators.cpp @@ -0,0 +1,82 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "geometrygenerators.h" + +std::vector GeometryGenerators::generateDiskTriangles(int sides, float radius, Point2f position) { + std::vector diskTriangles; + for(int i = 0; i < sides; i++) { + diskTriangles.push_back(Point2f(position.x, position.y)); + diskTriangles.push_back(Point2f(position.x + radius*sin(2*M_PI*(i+1)/sides), position.y + radius*cos(2*M_PI*(i+1)/sides))); + diskTriangles.push_back(Point2f(position.x + radius*sin(2*M_PI*i/sides), position.y + radius*cos(2*M_PI*i/sides))); + } + return diskTriangles; +} + +std::vector GeometryGenerators::generateMultipleDiskTriangles(int sides, float radius, std::vector positions) { + std::vector diskTriangles = generateDiskTriangles(sides , radius); + + std::vector mulitpleDiskTriangles; + + std::vector::const_iterator iter = positions.begin(), end = + positions.end(); + for ( ; iter != end; ++iter ) + { + Point2f position = *iter; + std::vector::const_iterator iterDiskVertices = diskTriangles.begin(), endDiskPoints = + diskTriangles.end(); + for ( ; iterDiskVertices != endDiskPoints; ++iterDiskVertices ) + { + Point2f vertex = *iterDiskVertices; + mulitpleDiskTriangles.push_back(Point2f(position.x + vertex.x,position.y + vertex.y)); + } + } + return mulitpleDiskTriangles; +} + +std::vector GeometryGenerators::generateCircleLines(int sides, float radius, Point2f position) { + std::vector cirleLines; + for(int i = 0; i < sides; i++) { + cirleLines.push_back(SimpleLine( + Point2f(position.x + radius*sin(2*M_PI*(i+1)/sides), position.y + radius*cos(2*M_PI*(i+1)/sides)), + Point2f(position.x + radius*sin(2*M_PI*i/sides), position.y + radius*cos(2*M_PI*i/sides)) + )); + } + return cirleLines; +} + +std::vector GeometryGenerators::generateMultipleCircleLines(int sides, float radius, std::vector positions) { + std::vector circleLines = generateCircleLines(sides , radius); + + std::vector mulitpleCircleLines; + + std::vector::const_iterator iter = positions.begin(), end = + positions.end(); + for ( ; iter != end; ++iter ) + { + Point2f position = *iter; + std::vector::const_iterator iterCircleLines = circleLines.begin(), endCircleLines = + circleLines.end(); + for ( ; iterCircleLines != endCircleLines; ++iterCircleLines ) + { + SimpleLine line = *iterCircleLines; + mulitpleCircleLines.push_back(SimpleLine( + Point2f(position.x + line.start().x, position.y + line.start().y), + Point2f(position.x + line.end().x, position.y + line.end().y) + )); + } + } + return mulitpleCircleLines; +} diff --git a/salalib/geometrygenerators.h b/salalib/geometrygenerators.h new file mode 100644 index 00000000..3302a379 --- /dev/null +++ b/salalib/geometrygenerators.h @@ -0,0 +1,29 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "genlib/p2dpoly.h" +#include + +class GeometryGenerators +{ +public: + static std::vector generateDiskTriangles(int sides, float radius, Point2f position = Point2f(0,0)); + static std::vector generateMultipleDiskTriangles(int sides, float radius, std::vector positions); + + static std::vector generateCircleLines(int sides, float radius, Point2f position = Point2f(0,0)); + static std::vector generateMultipleCircleLines(int sides, float radius, std::vector positions); +}; diff --git a/salalib/gmlmap.cpp b/salalib/gmlmap.cpp deleted file mode 100644 index d4c13be7..00000000 --- a/salalib/gmlmap.cpp +++ /dev/null @@ -1,148 +0,0 @@ -// sala - a component of the depthmapX - spatial network analysis platform -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// Feasibilty study for GML loader - -#include -#include - -using namespace std; - -#include -#include // For communicator - -#include -#include "gmlmap.h" - -bool GMLMap::parse(const pvecstring& fileset, Communicator *comm) -{ - __time64_t time = 0; - qtimer( time, 0 ); - - bool firstever = true; - int tracking = 0; - int linecount = 0; - int feature = -1; - pstring key; - - for (int i = 0; i < fileset.size(); i++) { - - ifstream stream(fileset[i].c_str()); - - while (!stream.eof()) - { - pstring line(4096); - stream >> line; - linecount++; - - if (line.length()) { - switch (tracking) { - case 0: - if (compare(line,"",22)) { - // pick out description (might not be only one) - int begin = line.findindex('>'); - int end = line.findindexreverse('<'); - if (begin != -1 && end != -1) { - pstring thisdesc = line.substr(begin+1,end-begin-1); - if (key.empty()) { - key = thisdesc; - } - else { - key = key + pstring(" / ") + thisdesc; - } - } - } - else if (compare(line," - int x = tokens[j].findindexreverse('<'); - tokens[j] = tokens[j].substr(0,x); - } - if (j == 0) { - // strip - int x = tokens[j].findindex('>'); - tokens[j] = tokens[j].substr(x+1); - } - pvecstring subtokens = tokens[j].tokenize(','); - if (subtokens.size() == 2) { - poly.push_back( Point2f(subtokens[0].c_double(),subtokens[1].c_double()) ); - if (!firstever) { - m_region.encompass(poly.tail()); - } - else { - m_region = QtRegion(poly.head(),poly.head()); - firstever = false; - } - } - } - if (poly.size()) { - if (key.empty()) { - key = "Miscellaneous"; - } - int n = m_keys.searchindex(key); - if (n == -1) { - n = m_keys.add(key,polyset(),paftl::ADD_HERE); - } - m_keys.value(n).push_back(poly); - } - } - break; - } - } - - if (comm) - { - if (qtimer( time, 500 )) { - if (comm->IsCancelled()) { - throw Communicator::CancelledException(); - } - } - } - } - } - - return !firstever; -} diff --git a/salalib/gridproperties.cpp b/salalib/gridproperties.cpp new file mode 100644 index 00000000..26193d21 --- /dev/null +++ b/salalib/gridproperties.cpp @@ -0,0 +1,13 @@ +#include "gridproperties.h" +#include + +GridProperties::GridProperties(double maxDimension) +{ + int maxexponent = (int) floor(log10(maxDimension)) - 1; + int minexponent = maxexponent - 2; + int mantissa = (int) floor(maxDimension / pow(10.0,double(maxexponent+1))); + + m_default = (double) mantissa * pow(10.0, double(maxexponent - 1)); + m_max = (double) 2 * mantissa * pow(10.0, double(maxexponent)); + m_min = (double) mantissa * pow(10.0, double(minexponent)); +} diff --git a/salalib/gridproperties.h b/salalib/gridproperties.h new file mode 100644 index 00000000..ad3d5714 --- /dev/null +++ b/salalib/gridproperties.h @@ -0,0 +1,31 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +class GridProperties +{ +public: + GridProperties(double maxDimension); + double getMin() const{return m_min;} + double getMax() const{return m_max;} + double getDefault() const{return m_default;} +private: + double m_max; + double m_min; + double m_default; + +}; + diff --git a/salalib/iaxial.h b/salalib/iaxial.h new file mode 100644 index 00000000..c7bc648f --- /dev/null +++ b/salalib/iaxial.h @@ -0,0 +1,32 @@ +// Copyright (C) 2018 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +// Interface to handle different kinds of Axial analysis + +#include "salalib/axialmap.h" + +#include "genlib/comm.h" + +#include + +class IAxial +{ +public: + virtual std::string getAnalysisName() const = 0; + virtual bool run(Communicator *comm, ShapeGraph &map, bool simple_version) = 0; + virtual ~IAxial(){} +}; diff --git a/salalib/idepthmap.cpp b/salalib/idepthmap.cpp deleted file mode 100644 index ab0fe8a7..00000000 --- a/salalib/idepthmap.cpp +++ /dev/null @@ -1,1768 +0,0 @@ -// sala - a component of the depthmapX - spatial network analysis platform -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// this is the Depthmap interface -// definition - -// Quick mod - TV -#ifndef _WIN32 -#include -#endif -#include - -#include -#include -#include - -#include -#include - -////////////////////////////////////////////////////////////////////////////////////// - -// setData takes a "MetaGraph *" as the parameter, but: -// m_data for an IGraphFile is an "IGraphOrganizer *" (local) - -IGraphFile::IGraphFile() -{ - m_data = (void *) new IGraphOrganizer; -} - -IGraphFile::~IGraphFile() -{ - if (m_data != NULL) { - delete ((IGraphOrganizer *)m_data); - m_data = NULL; - } -} - -void IGraphFile::setData(void *data) -{ - if (m_data != NULL) { - ((IGraphOrganizer *)m_data)->m_graph = (MetaGraph *) data; - } -} - -IGraphFile *newGraphFile() -{ - IGraphFile *graphfile = NULL; - MetaGraph *graph = new MetaGraph(); - // REMINDER: fill in some more details here: - pstring version = "Sala.dll version"; - char tmpbuf[9]; - // Quick mod - TV -#if defined(_WIN32) - pstring date = pstring(_strdate(tmpbuf)); -#else - char nowDate[20]; - { - int datelen = 0; - struct timeval tv; - gettimeofday(&tv, NULL); - datelen = strftime(nowDate, 20, "%m/%d/%y", localtime(&tv.tv_sec)); - } - pstring date = pstring(nowDate); -#endif - - graph->setProperties(pstring("Name"),pstring("Organisation"),pstring(date),pstring(version)); - graphfile = new IGraphFile(); - graphfile->setData(graph); - // ensure the graph is labelled for deletion after use - ((IGraphOrganizer *)graphfile->m_data)->setDeleteFlag(); - return graphfile; -} - -IGraphFile *openGraphFile(const char *filename) -{ - if (filename == NULL) { - return NULL; - } - IGraphFile *graphfile = NULL; - MetaGraph *graph = new MetaGraph(); - if (graph->read( pstring(filename) ) == MetaGraph::OK) { - graphfile = new IGraphFile(); - graphfile->setData(graph); - // ensure the graph is labelled for deletion after use - ((IGraphOrganizer *)graphfile->m_data)->setDeleteFlag(); - } - else { - delete graph; - } - return graphfile; -} - -void closeGraphFile(IGraphFile *& file) -{ - if (file != NULL) { - delete file; - } - file = NULL; -} - -///////////////////////////////////////////////////////////////////// - -bool IGraphFile::save(const char *filename) -{ - if (filename == NULL) { - return false; - } - - MetaGraph *graph = ((IGraphOrganizer *)m_data)->m_graph; - - // there's a little issue with the state variable which needs to be written - // ...this is an explicit set before save according to what's in the file: - int state = graph->getState(); - if (graph->PointMaps::size() > 0) { - state |= MetaGraph::POINTMAPS; - } - if (graph->m_data_maps.getMapCount() > 0) { - state |= MetaGraph::DATAMAPS; - } - if (graph->m_shape_graphs.getMapCount() > 0) { - state |= MetaGraph::SHAPEGRAPHS; - } - graph->setState(state); - - return (graph->write(filename, METAGRAPH_VERSION) == MetaGraph::OK); -} - -int IGraphFile::getVGAMapCount() -{ - return ((IGraphOrganizer *)m_data)->getIVGAMapCount(); -} - -IVGAMap *IGraphFile::getFirstVGAMap() -{ - return ((IGraphOrganizer *)m_data)->getFirstIVGAMap(); -} - -IVGAMap *IGraphFile::getNextVGAMap() -{ - return ((IGraphOrganizer *)m_data)->getNextIVGAMap(); -} - -// Shape layers: used for segment and axial maps - -int IGraphFile::getShapeMapCount() -{ - return ((IGraphOrganizer *)m_data)->getIShapeMapCount(); -} - -IShapeMap *IGraphFile::getFirstShapeMap() -{ - return ((IGraphOrganizer *)m_data)->getFirstIShapeMap(); -} - -IShapeMap *IGraphFile::getNextShapeMap() -{ - return ((IGraphOrganizer *)m_data)->getNextIShapeMap(); -} - -IShapeMap *IGraphFile::insertShapeMap(const char *name, int type) -{ - IShapeMap *map = NULL; - - switch (type) { - // can't handle drawing maps yet - case IShapeMap::IDRAWINGMAP: - map = NULL; - break; - // should be able to handle these: else - case IShapeMap::IDATAMAP: - case IShapeMap::ICONVEXMAP: - case IShapeMap::IAXIALMAP: - case IShapeMap::ISEGMENTMAP: - case IShapeMap::ISHAPEMAP: - map = ((IGraphOrganizer *)m_data)->addShapeMap(name, type); - break; - default: - map = NULL; - break; - } - - return map; -} - -// retrieve the attribute table for either vga or shape layer interfaces: -IAttributes *IGraphFile::getAttributes(IVGAMap *ivga) -{ - return ((IGraphOrganizer *)m_data)->getIAttributes(ivga); -} - -IAttributes *IGraphFile::getAttributes(IShapeMap *ishape) -{ - return ((IGraphOrganizer *)m_data)->getIAttributes(ishape); -} - -int IGraphFile::getViewOrder(IVGAMap *ivga) -{ - return ((IGraphOrganizer *)m_data)->getViewOrder(ivga); -} - -int IGraphFile::getViewOrder(IShapeMap *ishape) -{ - return ((IGraphOrganizer *)m_data)->getViewOrder(ishape); -} - -///////////////////////////////////////////////////////////////////////////////////// - -// This is a bit of a mess, as it's not been programmed to work like this from the start... - -bool IGraphFile::pushValuesToMap(IShapeMap *source, IShapeMap *dest, const char *source_attribute, const char *dest_attribute, int push_type) -{ - int source_type = 0, dest_type = 0; - if (source->isDataMap()) { - source_type = MetaGraph::VIEWDATA; - } - else { - source_type = MetaGraph::VIEWAXIAL; - } - if (dest->isDataMap()) { - dest_type = MetaGraph::VIEWDATA; - } - else { - dest_type = MetaGraph::VIEWAXIAL; - } - - IGraphOrganizer *data = ((IGraphOrganizer *)m_data); - - int source_layer = data->getMapRef(source); - int dest_layer = data->getMapRef(dest); - - if (source_layer == -1 || dest_layer == -1) { - return false; - } - - AttributeTable *source_table = data->getAttributeTable(source); - AttributeTable *dest_table = data->getAttributeTable(dest); - if (source_table == NULL || dest_table == NULL) { - return false; - } - int source_col; - if (strcmp(source_attribute,"Ref Number") == 0) { - source_col = -1; - } - else { - source_col = source_table->getColumnIndex(source_attribute); - if (source_col == -1) { - return false; - } - } - int dest_col = -2; - if (dest_attribute != NULL) { - if (strcmp(dest_attribute,"Ref Number") == 0) { - // cannot overwrite - return false; - } - else { - dest_col = dest_table->getColumnIndex(dest_attribute); - if (dest_col == -1) { - dest_col = dest_table->insertColumn(dest_attribute); - } - else if (dest_table->isColumnLocked(dest_col)) { - // cannot overwrite - return false; - } - } - } - - // note that for push_type, IPUSH_MAX should match PUSH_FUNC_MAX, etc - // -2 singles automatic naming of push column - data->m_graph->pushValuesToLayer(source_type,source_layer,dest_type,dest_layer,source_col,dest_col,push_type,false); - - return true; -} - -bool IGraphFile::pushValuesToMap(IVGAMap *source, IShapeMap *dest, const char *source_attribute, const char *dest_attribute, int push_type) -{ - int source_type = MetaGraph::VIEWVGA; - int dest_type; - if (dest->isDataMap()) { - dest_type = MetaGraph::VIEWDATA; - } - else { - dest_type = MetaGraph::VIEWAXIAL; - } - - IGraphOrganizer *data = ((IGraphOrganizer *)m_data); - - int source_layer = data->getMapRef(source); - int dest_layer = data->getMapRef(dest); - - if (source_layer == -1 || dest_layer == -1) { - return false; - } - - AttributeTable *source_table = data->getAttributeTable(source); - AttributeTable *dest_table = data->getAttributeTable(dest); - if (source_table == NULL || dest_table == NULL) { - return false; - } - int source_col; - if (strcmp(source_attribute,"Ref Number") == 0) { - source_col = -1; - } - else { - source_col = source_table->getColumnIndex(source_attribute); - if (source_col == -1) { - return false; - } - } - int dest_col = -2; - if (dest_attribute != NULL) { - if (strcmp(dest_attribute,"Ref Number") == 0) { - // cannot overwrite - return false; - } - else { - dest_col = dest_table->getColumnIndex(dest_attribute); - if (dest_col == -1) { - dest_col = dest_table->insertColumn(dest_attribute); - } - else if (dest_table->isColumnLocked(dest_col)) { - // cannot overwrite - return false; - } - } - } - - // note that for push_type, IPUSH_MAX should match PUSH_FUNC_MAX, etc - // -2 singles automatic naming of push column - data->m_graph->pushValuesToLayer(source_type,source_layer,dest_type,dest_layer,source_col,dest_col,push_type,false); - - return true; -} - -bool IGraphFile::pushValuesToMap(IShapeMap *source, IVGAMap *dest, const char *source_attribute, const char *dest_attribute, int push_type) -{ - int source_type; - if (source->isDataMap()) { - source_type = MetaGraph::VIEWDATA; - } - else { - source_type = MetaGraph::VIEWAXIAL; - } - int dest_type = MetaGraph::VIEWVGA; - - IGraphOrganizer *data = ((IGraphOrganizer *)m_data); - - int source_layer = data->getMapRef(source); - int dest_layer = data->getMapRef(dest); - - if (source_layer == -1 || dest_layer == -1) { - return false; - } - - AttributeTable *source_table = data->getAttributeTable(source); - AttributeTable *dest_table = data->getAttributeTable(dest); - if (source_table == NULL || dest_table == NULL) { - return false; - } - int source_col; - if (strcmp(source_attribute,"Ref Number") == 0) { - source_col = -1; - } - else { - source_col = source_table->getColumnIndex(source_attribute); - if (source_col == -1) { - return false; - } - } - int dest_col = -2; - if (dest_attribute != NULL) { - if (strcmp(dest_attribute,"Ref Number") == 0) { - // cannot overwrite - return false; - } - else { - dest_col = dest_table->getColumnIndex(dest_attribute); - if (dest_col == -1) { - dest_col = dest_table->insertColumn(dest_attribute); - } - else if (dest_table->isColumnLocked(dest_col)) { - // cannot overwrite - return false; - } - } - } - - // note that for push_type, IPUSH_MAX should match PUSH_FUNC_MAX, etc - // -2 singles automatic naming of push column - data->m_graph->pushValuesToLayer(source_type,source_layer,dest_type,dest_layer,source_col,dest_col,push_type,false); - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////// - -IShapeMap *IGraphFile::importMap(const char *filename, const char *type, const char *newmapname) -{ - // Note: 08-APR-2010 -- still have to add DXF and CAT (all to get automatic analysis working) - - IShapeMap *shapemap = NULL; - - MetaGraph *graph = ((IGraphOrganizer *)m_data)->m_graph; - - string type_str = string(type); - - if (!(type_str.compare("MIF") == 0 || type_str.compare("TXT") == 0 || type_str.compare("CSV") == 0)) { - return NULL; - } - - if (type_str.compare("TXT") == 0 || type_str.compare("CSV") == 0) - { - // these can be x,y points or x1,y1,x2,y2 lines - // first line should be labels, creates a datamap - ifstream file(filename); - - if (!file) { - return NULL; - } - else { - int mapref = graph->importTxt( file, pstring(newmapname), (type_str.compare("CSV")==0) ); - - if (mapref != -1) { - // note, at this stage in development, you CANNOT go from the mapref directly here as the getIShapeMap has both shape graphs and data maps mixed together - ShapeMap& basemap = graph->m_data_maps.getMap(mapref); - shapemap = ((IGraphOrganizer *)m_data)->getIShapeMap(&basemap); - } - } - } - else if (type_str.compare("MIF") == 0) { - - pstring miffilename = pstring(filename) + ".mif"; - pstring midfilename = pstring(filename) + ".mid"; - - ifstream miffile( miffilename.c_str() ); - ifstream midfile( midfilename.c_str() ); - - if (miffile && midfile) { - int mapref = graph->m_data_maps.addMap(pstring(newmapname),ShapeMap::DATAMAP); - - ShapeMap& mifmap = graph->m_data_maps.getMap(mapref); - - int ok = mifmap.loadMifMap(miffile,midfile); - if (ok == MINFO_OK || ok == MINFO_MULTIPLE) { // multiple is just a warning - // note, at this stage in development, you CANNOT go from the mapref directly here as the getIShapeMap has both shape graphs and data maps mixed together - shapemap = ((IGraphOrganizer *)m_data)->getIShapeMap(&mifmap); - } - else { // error: undo! - graph->m_data_maps.removeMap(mapref); - } - } - } - - return shapemap; -} - -IShapeMap *IGraphFile::makeAxialMapFromBaseMap(IComm *comm, IShapeMap *basemap, const char *newmapname) -{ - IShapeMap *retvar = NULL; - - bool created_comm = false; - if (comm == NULL) { - comm = getIComm(); - if (comm == NULL || comm->isValid()) { - return NULL; - } - created_comm = true; - } - - retvar = ((IGraphOrganizer *)m_data)->makeAxialMapFromBaseMap(comm, basemap, newmapname); - - if (created_comm) { - delete comm; - } - - return retvar; -} - - -IShapeMap *IGraphFile::makeSegmentMapFromAxialMap(IComm *comm, IShapeMap *axialmap, const char *newmapname, double stubremoval) -{ - IShapeMap *retvar = NULL; - - bool created_comm = false; - if (comm == NULL) { - comm = getIComm(); - if (comm == NULL || comm->isValid()) { - return NULL; - } - created_comm = true; - } - - retvar = ((IGraphOrganizer *)m_data)->makeSegmentMapFromAxialMap(comm, axialmap, newmapname, stubremoval); - - if (created_comm) { - delete comm; - } - - return retvar; -} - - -///////////////////////////////////////////////////////////////////////////////////// - -// m_data for a IComm should be a "Communicator *" - -IComm::IComm() -{ - m_data = NULL; -} - -// n.b., may be problematic if not an ICommunicator -IComm::~IComm() -{ - // check that this is a DLL interface created Communicator before deleting it - if (m_data != NULL && ((Communicator *)m_data)->GetDeleteFlag()) { - delete ((ICommunicator *) m_data); - m_data = NULL; - } - // note: front-end supplied Communicators will be deleted by the front-end -} - -void IComm::setData(void *data) -{ - m_data = data; -} - -void *IComm::getData() -{ - return m_data; -} - -bool IComm::isValid() -{ - return (m_data != NULL); -} - -IComm *getIComm() -{ - ICommunicator *comm = new ICommunicator(); - IComm *icomm = new IComm(); - icomm->setData(comm); - return icomm; -} - -void IComm::close() -{ - // check that this is a DLL interface created Communicator before deleting it - if (m_data != NULL && ((Communicator *)m_data)->GetDeleteFlag()) { - delete ((ICommunicator *) m_data); - m_data = NULL; - } - // note: front-end supplied Communicators will IGNORE this instruction -} - -void IComm::cancelProcess() -{ - ((ICommunicator *)m_data)->Cancel(); -} - -int IComm::getNumSteps() -{ - return ((ICommunicator *)m_data)->num_steps; -} - -int IComm::getCurrentStep() -{ - return ((ICommunicator *)m_data)->step; -} - -int IComm::getNumRecords() -{ - return ((ICommunicator *)m_data)->num_records; -} - -int IComm::getCurrentRecord() -{ - return ((ICommunicator *)m_data)->record; -} - -bool IComm::isProcessCancelled() -{ - return (m_data == NULL) ? false : (((Communicator *)m_data)->IsCancelled()); -} - -void IComm::setNumSteps(int steps) -{ - if (m_data != NULL) { - ((Communicator *)m_data)->CommPostMessage( Communicator::NUM_STEPS, steps ); - } -} - -void IComm::setCurrentStep(int step) -{ - if (m_data != NULL) { - ((Communicator *)m_data)->CommPostMessage( Communicator::CURRENT_STEP, step ); - } -} - -void IComm::setNumRecords(int records) -{ - if (m_data != NULL) { - ((Communicator *)m_data)->CommPostMessage( Communicator::NUM_RECORDS, records ); - } -} - -void IComm::setCurrentRecord(int record) -{ - if (m_data != NULL) { - ((Communicator *)m_data)->CommPostMessage( Communicator::CURRENT_RECORD, record ); - } -} - -////////////////////////////////////////////////////////////////////////////////// - -// m_data for a IVGAMap should be a "PointMap *" - -IVGAMap::IVGAMap() -{ - m_data = NULL; - - m_cursor_point = -1; - m_cursor_selected_point = -1; -} - -IVGAMap::~IVGAMap() -{ -} - -void IVGAMap::setData(void *data) -{ - m_data = data; -} - -int IVGAMap::getPointCount() -{ - return ((PointMap *)m_data)->getPointCount(); -} - -int IVGAMap::getFirstPoint() -{ - PointMap& pd = *(PointMap *)m_data; - PixelRef cur(0,0); - while (cur.y < pd.getRows() && !pd.getPoint(cur).filled()) { - cur.x += 1; - if (cur.x == pd.getCols()) { - cur.x = 0; - cur.y += 1; - } - } - if (cur.y == pd.getRows()) { - m_cursor_point = -1; - return -1; - } - m_cursor_point = (int)cur; - return m_cursor_point; -} - -int IVGAMap::getNextPoint() -{ - PointMap& pd = *(PointMap *)m_data; - PixelRef cur(m_cursor_point); - do { - cur.x += 1; - if (cur.x == pd.getCols()) { - cur.x = 0; - cur.y += 1; - } - } while (cur.y < pd.getRows() && !pd.getPoint(cur).filled()); - if (cur.y == pd.getRows()) { - m_cursor_point = -1; - return -1; - } - m_cursor_point = (int)cur; - return m_cursor_point; -} - -int IVGAMap::getSelectedPointCount() -{ - return ((PointMap *)m_data)->getSelCount(); -} - -int IVGAMap::getFirstSelectedPoint() -{ - if (((PointMap *)m_data)->getSelSet().size()) { - m_cursor_selected_point = 0; - return ((PointMap *)m_data)->getSelSet()[m_cursor_selected_point]; - } - m_cursor_selected_point = -1; - return m_cursor_selected_point; -} - -int IVGAMap::getNextSelectedPoint() -{ - m_cursor_selected_point++; - if (m_cursor_selected_point < (int)((PointMap *)m_data)->getSelSet().size()) { - return ((PointMap *)m_data)->getSelSet()[m_cursor_selected_point]; - } - m_cursor_selected_point = -1; - return m_cursor_selected_point; -} - -DPoint IVGAMap::getLocation(int id) -{ - if (id == -1) { - return DPoint(); - } - Point2f p = ((PointMap *)m_data)->depixelate(id); - return DPoint(p.x,p.y); -} - -void IVGAMap::clearSelection() -{ - ((PointMap *)m_data)->clearSel(); -} - -void IVGAMap::selectPoint(int id, bool replace) // replace defaults to false -{ - pvecint selset; - selset.push_back(id); - ((PointMap *)m_data)->setCurSel(selset,replace); // note: defaults to add to current selection -} - -int IVGAMap::getNode(DPoint& point) -{ - // n.b., "false" returns unconstrained point: must check if inside bounds or not using includes - PixelRef pix = ((PointMap *)m_data)->pixelate(Point2f(point.x,point.y), false); - if (!((PointMap *)m_data)->includes(pix)) { - return -1; - } - return int(pix); -} - -bool IVGAMap::isEmptyNode(int id) -{ - if (id == -1) { - return false; - } - return ((PointMap *)m_data)->getPoint(id).empty(); -} - -bool IVGAMap::isGraphNode(int id) -{ - if (id == -1) { - return false; - } - return ((PointMap *)m_data)->getPoint(id).filled(); -} - -bool IVGAMap::isBoundaryNode(int id) -{ - if (id == -1) { - return false; - } - return ((PointMap *)m_data)->getPoint(id).edge(); -} - -void IVGAMap::setMergePoint(int id, int merge_id) -{ - if (id == -1) { - return; - } - PixelRef pix; - if (merge_id == -1) { - pix = id; - } - else { - pix = PixelRef(merge_id); - } - // you cannot just set the merge point, as this is associated with a merge line - // so this piece of code sets up the merge for you properly: - ((PointMap *)m_data)->mergePixels(id,pix); -} - -// if the point is merged with another point, let the user know what it is -int IVGAMap::getMergePoint(int id) -{ - if (id == -1) { - return -1; - } - PixelRef pix = ((PointMap *)m_data)->getPoint(id).getMergePixel(); - if (pix == NoPixel) { - return -1; - } - return int(pix); -} - -// arbitrary data that the user might want to associate with a point -void IVGAMap::setUserData(int id, void *data) -{ - if (id == -1) { - return; - } - ((PointMap *)m_data)->getPoint(id).setUserData(data); -} - -// arbitrary data that the user might want to associate with a point -void *IVGAMap::getUserData(int id) -{ - if (id == -1) { - return NULL; - } - return ((PointMap *)m_data)->getPoint(id).getUserData(); -} - -// the longest line of sight length for bin (0-31) (use -1 for longest line of sight in any direction) -// type 0: standard longest line of site, type 1: longest occluded edge -double IVGAMap::getLoSLength(int id, int bin, int type) -{ - PointMap& pd = *(PointMap *)m_data; - if (id == -1 || !pd.getPoint(id).filled()) { - return -1.0; - } - else if (bin == -1) { - // note, just goes through all of them to find the longest! - double maxdist = -1.0; - for (int i = 0; i < 32; i++) { - double thisdist = (type == 0) ? pd.getPoint(id).getNode().bindistance(bin) : - pd.getPoint(id).getNode().occdistance(bin); - if (thisdist > maxdist) { - maxdist = thisdist; - } - } - return maxdist; - } - else if (type == 0) { - return pd.getPoint(id).getNode().bindistance(bin); - } - else { - return pd.getPoint(id).getNode().occdistance(bin); - } -} - -int IVGAMap::getConnectedPointCount(int id, int b) -{ - PointMap& pd = *(PointMap *)m_data; - if (id == -1 || !pd.getPoint(id).filled()) { - return 0; - } - if (b == -1) { - return pd.getPoint(id).getNode().count(); - } - else { - return pd.getPoint(id).getNode().bincount(b); - } -} - -int IVGAMap::getFirstConnectedPoint(int id, int b) -{ - PointMap& pd = *(PointMap *)m_data; - if (id == -1 || !pd.getPoint(id).filled()) { - return -1; - } - Node& node = pd.getPoint(id).getNode(); - if (b == -1) { - if (node.count() == 0) { - return -1; - } - else { - node.first(); - return node.cursor(); - } - } - else { - if (node.bincount(b) == 0) { - return -1; - } - else { - node.bin(b).first(); - return node.bin(b).cursor(); - } - } -} - -int IVGAMap::getNextConnectedPoint(int id, int b) -{ - PointMap& pd = *(PointMap *)m_data; - if (id == -1 || !pd.getPoint(id).filled()) { - return -1; - } - Node& node = pd.getPoint(id).getNode(); - if (b == -1) { - node.next(); - if (node.is_tail()) { - return -1; - } - else { - return node.cursor(); - } - } - else { - node.bin(b).next(); - if (node.bin(b).is_tail()) { - return -1; - } - else { - return node.bin(b).cursor(); - } - } -} - -char IVGAMap::getGridConnections(int id) -{ - // note, doesn't matter if this point is not filled -- it just has - // zero grid connections - if (id == -1) { - return -1; - } - return ((PointMap *)m_data)->getPoint(id).getGridConnections(); -} - -double IVGAMap::getGridSpacing() -{ - return ((PointMap *)m_data)->getSpacing(); - -} - -const char *IVGAMap::getDisplayedAttributeColumn() -{ - PointMap& pd = *(PointMap *)m_data; - return pd.getAttributeTable().getColumnName(pd.getDisplayedAttribute()).c_str(); -} - -void IVGAMap::setDisplayedAttributeColumn(const char *attribute) -{ - if (strcmp(attribute,"Ref Number") == 0) { - ((PointMap *)m_data)->setDisplayedAttribute(-1); - } - else { - int col = ((PointMap *)m_data)->getAttributeTable().getColumnIndex(pstring(attribute)); - if (col != -1) { - ((PointMap *)m_data)->setDisplayedAttribute(col); - } - } -} - -void IVGAMap::analysePointDepth(IComm *comm, int method) -{ - PointMap& pd = *(PointMap *)m_data; - - bool created_comm = false; - if (comm == NULL) { - comm = getIComm(); - if (comm == NULL || comm->isValid()) { - return; - } - created_comm = true; - } - - switch (method) { - case IVGA_STEP: - pd.analyseVisualPointDepth((Communicator *)(comm->getData())); - break; - case IVGA_METRIC: - pd.analyseMetricPointDepth((Communicator *)(comm->getData())); - break; - case IVGA_ANGULAR: - pd.analyseAngularPointDepth((Communicator *)(comm->getData())); - break; - } - - if (created_comm) { - delete comm; - } -} - -////////////////////////////////////////////////////////////////////////////////// - -// m_data for a IShapeMap should be a "ShapeMap *" - -// remind programmers that cursors are invalidated by add / remove shape - -IShapeMap::IShapeMap() -{ - m_data = NULL; - - m_cursor_shape = -1; - m_cursor_selected_shape = -1; -} - -IShapeMap::~IShapeMap() -{ -} - -void IShapeMap::setData(void *data) -{ - m_data = data; -} - -// Basic info about the shape map - -const char *IShapeMap::getMapName() -{ - return ((ShapeMap *)m_data)->getName().c_str(); -} - -// basic info about the map type -bool IShapeMap::isAxialMap() -{ - return ((ShapeMap *)m_data)->isAxialMap(); -} -bool IShapeMap::isSegmentMap() -{ - return ((ShapeMap *)m_data)->isSegmentMap(); -} -bool IShapeMap::isDataMap() -{ - return (((ShapeMap *)m_data)->getMapType() == ShapeMap::DATAMAP); -} -bool IShapeMap::isDrawingMap() -{ - return (((ShapeMap *)m_data)->getMapType() == ShapeMap::DRAWINGMAP); -} -int IShapeMap::getMapType() -{ - int actual_type = ((ShapeMap *)m_data)->getMapType(); - int return_type = 0; - // at the moment there are fewer map types in idepthmap.h than in shapemap.h - switch (actual_type) { - case ShapeMap::DRAWINGMAP: - return_type = IShapeMap::IDRAWINGMAP; - break; - case ShapeMap::DATAMAP: - return_type = IShapeMap::IDATAMAP; - break; - case ShapeMap::CONVEXMAP: - return_type = IShapeMap::ICONVEXMAP; - break; - case ShapeMap::AXIALMAP: case ShapeMap::ALLLINEMAP: - return_type = IShapeMap::IAXIALMAP; - break; - case ShapeMap::SEGMENTMAP: - return_type = IShapeMap::ISEGMENTMAP; - break; - case ShapeMap::PESHMAP: case ShapeMap::POINTMAP: - return_type = IShapeMap::ISHAPEMAP; - break; - default: - return_type = 0; - break; - }; - return return_type; -} - -// iterator for all shapes (uses m_cursor_shape) -int IShapeMap::getShapeCount() -{ - return ((ShapeMap *)m_data)->getShapeCount(); -} - -int IShapeMap::getFirstShape() -{ - ShapeMap& axmap = *((ShapeMap *)m_data); - - m_cursor_shape = 0; - - if (m_cursor_shape >= (int)axmap.getShapeCount()) { - m_cursor_shape = -1; - } - - return m_cursor_shape; -} - -int IShapeMap::getNextShape() -{ - ShapeMap& axmap = *((ShapeMap *)m_data); - - m_cursor_shape++; - - if (m_cursor_shape >= (int)axmap.getShapeCount()) { - m_cursor_shape = -1; - } - - return m_cursor_shape; -} - -/// iterator for selected shapes in the Depthmap UI (uses m_cursor_selected_shape) -int IShapeMap::getSelectedShapeCount() -{ - return ((ShapeMap *)m_data)->getSelCount(); -} - -int IShapeMap::getFirstSelectedShape() -{ - ShapeMap& axmap = *((ShapeMap *)m_data); - if (axmap.getSelCount() > 0) { - m_cursor_selected_shape = 0; - return axmap.getSelSet().at(0); - } - else { - m_cursor_selected_shape = -1; - return -1; - } -} - -int IShapeMap::getNextSelectedShape() -{ - ShapeMap& axmap = *((ShapeMap *)m_data); - if (axmap.isSelected() && m_cursor_selected_shape < (int)axmap.getSelCount() - 1) { - m_cursor_selected_shape++; - return axmap.getSelSet().at(m_cursor_selected_shape); - } - else { - m_cursor_selected_shape = -1; - return -1; - } -} - -///////////////////////////////////////////////////////////////////////////// - -// -void IShapeMap::clearSelection() -{ - ((ShapeMap *)m_data)->clearSel(); -} - -void IShapeMap::selectShape(int id, bool replace) // replace defaults to false -{ - pvecint temp; - temp.push_back(id); - ((ShapeMap *)m_data)->setCurSelDirect(temp, !replace ); // <- default: add to existing selection -} - -int IShapeMap::selectShapesWithinRadius(DPoint& point, double dist) -{ - ShapeMap& map = *((ShapeMap *)m_data); - pvecint shapes; - int ret = map.withinRadius( Point2f(point.x,point.y), dist, shapes ); - map.setCurSelDirect(shapes,true); // <- note, add to existing selection - return ret; -} - -///////////////////////////////////////////////////////////////////////////// - -// iterator for connections -int IShapeMap::getConnectedShapeCount(int id, int dir) -{ - const Connector& axline = ((ShapeMap *)m_data)->getConnections().at(id); - int linecount = 0; - switch (dir) { - case CONN_ALL: - if (((ShapeMap *)m_data)->isSegmentMap()) { - linecount = axline.count(Connector::SEG_CONN_ALL); - } - else { - linecount = axline.count(Connector::CONN_ALL); - } - break; - case CONN_FW: - linecount = axline.count(Connector::SEG_CONN_FW); - break; - case CONN_BK: - linecount = axline.count(Connector::SEG_CONN_BK); - break; - } - return linecount; -} - -int IShapeMap::getFirstConnectedShape(int id, int dir) -{ - const Connector& axline = ((ShapeMap *)m_data)->getConnections().at(id); - int retvar = -1; - axline.first(); - switch (dir) { - case CONN_ALL: - if (((ShapeMap *)m_data)->isSegmentMap()) { - retvar = axline.cursor(Connector::SEG_CONN_ALL); - } - else { - retvar = axline.cursor(Connector::CONN_ALL); - } - break; - case CONN_FW: - retvar = axline.cursor(Connector::SEG_CONN_FW); - break; - case CONN_BK: - retvar = axline.cursor(Connector::SEG_CONN_BK); - break; - } - return retvar; -} - -int IShapeMap::getNextConnectedShape(int id, int dir) -{ - const Connector& axline = ((ShapeMap *)m_data)->getConnections().at(id); - int retvar = -1; - axline.next(); - switch (dir) { - case CONN_ALL: - if ( ((ShapeMap *)m_data)->isSegmentMap()) { - retvar = axline.cursor(Connector::SEG_CONN_ALL); - } - else { - retvar = axline.cursor(Connector::CONN_ALL); - } - break; - case CONN_FW: - retvar = axline.cursor(Connector::SEG_CONN_FW); - break; - case CONN_BK: - retvar = axline.cursor(Connector::SEG_CONN_BK); - break; - } - return retvar; -} - -int IShapeMap::getConnectionDirection(int id, int dir) -{ - const Connector& axline = ((ShapeMap *)m_data)->getConnections().at(id); - int retvar = -1; - if ( ((ShapeMap *)m_data)->isSegmentMap()) { - switch (dir) { - case CONN_ALL: - retvar = (axline.direction(Connector::SEG_CONN_ALL) == 1) ? CONN_FW : CONN_BK; - break; - case CONN_FW: - retvar = (axline.direction(Connector::SEG_CONN_FW) == 1) ? CONN_FW : CONN_BK; - break; - case CONN_BK: - retvar = (axline.direction(Connector::SEG_CONN_BK) == 1) ? CONN_FW : CONN_BK; - break; - } - } - return retvar; -} - -double IShapeMap::getConnectionWeight(int id, int dir) -{ - const Connector& axline = ((ShapeMap *)m_data)->getConnections().at(id); - double retvar = 0.0; - if ( ((ShapeMap *)m_data)->isSegmentMap()) { - switch (dir) { - case CONN_ALL: - retvar = axline.weight(Connector::SEG_CONN_ALL); - break; - case CONN_FW: - retvar = axline.weight(Connector::SEG_CONN_FW); - break; - case CONN_BK: - retvar = axline.weight(Connector::SEG_CONN_BK); - break; - } - } - return retvar; -} - -// test shape is a point and test shape is a line (also need others) -bool IShapeMap::isPointShape(int id) -{ - return ((ShapeMap *)m_data)->getAllShapes().at(id).isPoint(); -} -bool IShapeMap::isLineShape(int id) -{ - return ((ShapeMap *)m_data)->getAllShapes().at(id).isLine(); -} -bool IShapeMap::isPolyLineShape(int id) -{ - return ((ShapeMap *)m_data)->getAllShapes().at(id).isPolyLine(); -} -bool IShapeMap::isPolygonShape(int id) -{ - return ((ShapeMap *)m_data)->getAllShapes().at(id).isPolygon(); -} - -// the physical point coordinates (test it's a line first) -DPoint IShapeMap::getPointCoords(int id) -{ - // note, using rowid - ShapeMap& axmap = *((ShapeMap *)m_data); - const Point2f& pt = axmap.getAllShapes().at(id).getPoint(); - return DPoint(pt.x,pt.y); -} - -// the physical line coordinates (test it's a line first) -DLine IShapeMap::getLineCoords(int id) -{ - // note, using rowid - ShapeMap& axmap = *((ShapeMap *)m_data); - const Line& linein = axmap.getAllShapes().at(id).getLine(); - return DLine(DPoint(linein.ax(),linein.ay()),DPoint(linein.bx(),linein.by())); -} - -// for polylines and polygons, use a pair of functions: -int IShapeMap::getVertexCount(int id) -{ - return ((ShapeMap *)m_data)->getAllShapes().at(id).size(); -} - -DPoint IShapeMap::getVertex(int id, int v) -{ - Point2f pt = ((ShapeMap *)m_data)->getAllShapes().at(id).at(v); - return DPoint(pt.x,pt.y); -} - -//////////////////////////////////////////////////////////////////////// - -int IShapeMap::getShape(DPoint& point) -{ - return ((ShapeMap *)m_data)->getClosestOpenGeom(Point2f(point.x,point.y)); -} - -// Get the displayed attribute column -const char *IShapeMap::getDisplayedAttributeColumn() -{ - ShapeMap& map = *((ShapeMap *)m_data); - return map.getAttributeTable().getColumnName(map.getDisplayedAttribute()).c_str(); -} - -// Display the attribute column -void IShapeMap::setDisplayedAttributeColumn(const char *attribute) -{ - if (strcmp(attribute,"Ref Number") == 0) { - // invalidate it, as it's almost certain the user wants to redraw the output: - ((ShapeMap *)m_data)->invalidateDisplayedAttribute(); - ((ShapeMap *)m_data)->setDisplayedAttribute(-1); - } - else { - int col = ((ShapeMap *)m_data)->getAttributeTable().getColumnIndex(pstring(attribute)); - if (col != -1) { - // invalidate it, as it's almost certain the user wants to redraw the output: - ((ShapeMap *)m_data)->invalidateDisplayedAttribute(); - ((ShapeMap *)m_data)->setDisplayedAttribute(col); - } - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////// - -// Editing axial maps - -void IShapeMap::clearMap() -{ - // zap everything apart from mapinfodata (i.e., the projection)... use with caution! - ((ShapeMap *)m_data)->clearAll(); -} - -void IShapeMap::beginShape() -{ - // first, this will interrupt cursors for selections and line retrieval - // note, do *not* clear the selection here as repeated calls to beginShape will slow to a crawl - m_cursor_shape = -1; - m_cursor_selected_shape = -1; - - ((ShapeMap *)m_data)->shapeBegin(); -} - -void IShapeMap::addVertex(DPoint& point) -{ - ((ShapeMap *)m_data)->shapeVertex(Point2f(point.x,point.y)); -} - -int IShapeMap::endShape(bool open) -{ - return ((ShapeMap *)m_data)->shapeEnd(open); -} - -void IShapeMap::commitShapes() -{ - // note, intended for more than one shape - ((ShapeMap *)m_data)->shapesCommit(); -} - -bool IShapeMap::removeShape(int id) -{ - ShapeMap& axmap = *((ShapeMap *)m_data); - - // first, this will interrupt cursors for selections and shape retrieval: - axmap.clearSel(); - m_cursor_shape = -1; - m_cursor_selected_shape = -1; - - // note: uses rowid so convert to key. - // Also note that "undoing" set to true means that it won't try to set up and undo buffer - if (id >= 0 && id < (int)axmap.getShapeCount()) { - axmap.removeShape(axmap.getAttributeTable().getRowKey(id),true); - return true; - } - - return false; -} - -bool IShapeMap::connectDirected(int from, int fromdir, int to, int todir, double conn_weight) -{ - // translate to dmap conn values: - if (fromdir == CONN_FW) { - fromdir = 1; - } - else { - fromdir = -1; - } - if (todir == CONN_FW) { - todir = 1; - } - else { - todir = -1; - } - return ((ShapeMap *)m_data)->linkShapes(from,fromdir,to,todir,(float)conn_weight); -} - -bool IShapeMap::connectUndirected(int id1, int id2) -{ - return ((ShapeMap *)m_data)->linkShapes(id1,id2,false); -} - -int IShapeMap::connectIntersected(int id) -{ - return ((ShapeMap *)m_data)->connectIntersected(id,false); -} - -void IShapeMap::makeAllConnections() -{ - ((ShapeMap *)m_data)->makeShapeConnections(); -} - -bool IShapeMap::disconnect(int id1, int id2) -{ - return ((ShapeMap *)m_data)->unlinkShapes(id1,id2,false); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// Shape map extras - -bool IShapeMap::exportMap(const char *filename, const char *type) -{ - bool retvar = false; - - string type_str = string(type); - - if (!(type_str.compare("MIF") == 0 || type_str.compare("mif") == 0)) { - return retvar; - } - - string filename_str = string(filename); - - // if extension exists already, strip it - if (filename_str.rfind(".mif") == filename_str.length() - 4 || filename_str.rfind(".MIF") == filename_str.length() - 4) { - filename_str = filename_str.substr(0,filename_str.length()-4); - } - - string miffilename = filename_str; - miffilename.append(".mif"); - string midfilename = filename_str; - midfilename.append(".mid"); - - ofstream miffile(miffilename.c_str()); - if (miffile.fail() || miffile.bad()) { - return retvar; - } - ofstream midfile(midfilename.c_str()); - if (midfile.fail() || midfile.bad()) { - return retvar; - } - - retvar = ((ShapeMap *)m_data)->outputMifMap(miffile, midfile); - - return retvar; -} - -int IShapeMap::analyseSegments(IComm *comm, size_t radius_count, float *radius_list, const char *weighting_column, const char *weighting_column2, const char* routeweight_column, bool interactive) -{ - ShapeGraph& map = *((ShapeGraph *)m_data); - - if (!map.isSegmentMap()) { - return 0; - } - - Options options; - options.tulip_bins = 1024; - options.choice = true; - options.weighted_measure_col = -1; - options.radius_type = Options::RADIUS_METRIC; - for (size_t i = 0; i < radius_count; i++) { - options.radius_list.push_back(radius_list[i]); - } - if (radius_count == 0) { - // default: radius n - options.radius_list.push_back(-1.0f); - } - - bool created_comm = false; - if (comm == NULL) { - comm = getIComm(); - if (comm == NULL || comm->isValid()) { - return false; - } - created_comm = true; - } - - pstring weighting_column_str; - if (weighting_column != NULL) { - weighting_column_str = weighting_column; - } - else { - weighting_column_str = "Segment Length"; - } - options.weighted_measure_col = map.getAttributeTable().getColumnIndex(weighting_column_str); - //EFEF - pstring weighting_column_str2; - if (weighting_column2 != NULL) { - weighting_column_str2 = weighting_column2; - } - else { - weighting_column_str2 = ""; - } - options.weighted_measure_col2 = map.getAttributeTable().getColumnIndex(weighting_column_str2); - //routeweight - pstring routeweight_column_str; - if (routeweight_column != NULL) { - routeweight_column_str = routeweight_column; - } - else { - routeweight_column_str = ""; - } - options.routeweight_col = map.getAttributeTable().getColumnIndex(routeweight_column_str); - //EFEF - - int count = 0; - - try { - // note: non-interactive sets selection_only to true and interactive to false (for multi-processor environments) - count = map.analyseTulip((Communicator *)(comm->getData()), options.tulip_bins, options.choice, options.radius_type, options.radius_list, options.weighted_measure_col, options.weighted_measure_col2, options.routeweight_col, !interactive, interactive); - } - catch (Communicator::CancelledException) - { - // this is only used in interactive mode (in non-interactive, it will not throw the exception, simply return count of the number of records it processed) - count = 0; - } - - if (created_comm) { - delete comm; - } - - return count; -} - -bool IShapeMap::loadUnlinks(IShapeMap *unlinks_points_map) -{ - ((ShapeGraph *)m_data)->unlinkFromShapeMap(*((ShapeMap *)(unlinks_points_map->m_data))); - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// m_data for a IAttributes should be an "AttributeTable *" - -IAttributes::IAttributes() -{ - m_data = NULL; - m_analysis_type = -1; - // note, m_cursor_column = -1 used for ref_number column - m_cursor_column = -2; - m_cursor_row = -1; -} - -IAttributes::~IAttributes() -{ -} - -void IAttributes::setData(void *data, int analysis_type) -{ - m_data = data; - if (analysis_type & DLL_VGA_ANALYSIS) { - m_analysis_type = DLL_VGA_ANALYSIS; - } - else { - m_analysis_type = DLL_AXIAL_ANALYSIS | DLL_SEGMENT_ANALYSIS | DLL_DATA_ANALYSIS; - } -} - -int IAttributes::getAttributeColumnCount() -{ - return ((AttributeTable *)m_data)->getColumnCount(); -} - -const char *IAttributes::getFirstAttributeColumn() -{ - AttributeTable& table = *((AttributeTable *)m_data); - - m_cursor_column = -1; - - if (m_cursor_column >= table.getColumnCount()) { - m_cursor_column = -2; - return NULL; - } - - return table.getColumnName(m_cursor_column).c_str(); -} - -const char *IAttributes::getNextAttributeColumn() -{ - AttributeTable& table = *((AttributeTable *)m_data); - - m_cursor_column++; - - if (m_cursor_column >= table.getColumnCount()) { - m_cursor_column = -2; - return NULL; - } - - return table.getColumnName(m_cursor_column).c_str(); -} - -// Get the row entries from the attributes -int IAttributes::getAttributeRowCount() -{ - return ((AttributeTable *)m_data)->getRowCount(); -} - -int IAttributes::getFirstAttributeRow() -{ - AttributeTable& table = *((AttributeTable *)m_data); - m_cursor_row = 0; - if (m_cursor_row >= table.getRowCount()) { - m_cursor_row = -1; - return -1; - } - if (m_analysis_type != DLL_VGA_ANALYSIS) { - return m_cursor_row; // anything but vga - } - else { - return table.getRowKey(m_cursor_row); // vga only - } -} - -int IAttributes::getNextAttributeRow() -{ - AttributeTable& table = *((AttributeTable *)m_data); - m_cursor_row++; - if (m_cursor_row >= table.getRowCount()) { - m_cursor_row = -1; - return -1; - } - if (m_analysis_type != DLL_VGA_ANALYSIS) { - return m_cursor_row; // anything but vga - } - else { - return table.getRowKey(m_cursor_row); // vga only - } -} - -///////////////////////////////////////////////////////////////////////// - -bool IAttributes::insertAttributeColumn(const char *attribute) -{ - if (strcmp(attribute,"Ref Number") != 0) { - AttributeTable *table = (AttributeTable *)m_data; - int n = table->getColumnIndex(pstring(attribute)); - if (n == -1 || !table->isColumnLocked(n)) { - table->insertColumn(pstring(attribute)); - return true; - } - } - return false; -} - -bool IAttributes::deleteAttributeColumn(const char *attribute) -{ - AttributeTable *table = (AttributeTable *)m_data; - int n = table->getColumnIndex(pstring(attribute)); - if (n != -1 && !table->isColumnLocked(n)) { - table->removeColumn(n); - if (n >= table->getDisplayColumn()) { - // there is a problem here: the associated geometry layer will be out of step when it comes to display - // this is corrected in "getDisplayedAttribute" (untidy, but works) - table->setDisplayColumn(n-1,true); - } - return true; - } - return false; -} - -bool IAttributes::renameAttributeColumn(const char *oldname, const char *newname) -{ - AttributeTable *table = (AttributeTable *)m_data; - int n = table->getColumnIndex(pstring(oldname)); - if (n != -1 && !table->isColumnLocked(n)) { - table->renameColumn(n,newname); - return true; - } - return false; -} - -bool IAttributes::isValidAttributeColumn(const char *attribute) -{ - return ((AttributeTable *)m_data)->isValidColumn(pstring(attribute)); -} - -bool IAttributes::isLockedAttributeColumn(const char *attribute) -{ - AttributeTable *table = (AttributeTable *)m_data; - int n = table->getColumnIndex(pstring(attribute)); - if (n != -1 && !table->isColumnLocked(n)) { - return table->isColumnLocked(n); - } - // n.b., this should really throw an exception: - return false; -} - -// get an attribute from the attribute table for the current point: -float IAttributes::getAttribute(int id, const char *attribute) -{ - AttributeTable& table = *((AttributeTable *)m_data); - int index = (m_analysis_type != DLL_VGA_ANALYSIS) ? id : table.getRowid(id); // vga needs to look up rowid, all others use rowid directly - if (index == -1) { - return -1.0f; - } - return table.getValue(index,pstring(attribute)); -} - -// set an attribute in the attribute table for the current point: -void IAttributes::setAttribute(int id, const char *attribute, float value) -{ - AttributeTable& table = *((AttributeTable *)m_data); - int index = (m_analysis_type != DLL_VGA_ANALYSIS) ? id : table.getRowid(id); // vga needs to look up rowid, all others use rowid directly - if (index == -1) { - return; - } - // nb., changeValue modifies tot value (but not reduce min/max) - table.changeValue(index,pstring(attribute),value); -} - -// set an attribute in the attribute table for the current point: -void IAttributes::incrAttribute(int id, const char *attribute) -{ - AttributeTable& table = *((AttributeTable *)m_data); - int index = (m_analysis_type != DLL_VGA_ANALYSIS) ? id : table.getRowid(id); // vga needs to look up rowid, all others use rowid directly - if (index == -1) { - return; - } - // nb., changeValue modifies tot value (but not reduce min/max) - table.incrValue(index,pstring(attribute)); -} - -///////////////////////////////////////////////////////////////////////// - -bool IAttributes::importTable(const char *filename, bool merge) -{ - ifstream stream(filename); - if (!stream) { - return false; - } - return ((AttributeTable *)m_data)->importTable(stream, merge); -} - -bool IAttributes::exportTable(const char *filename, bool updated_only) -{ - ofstream stream(filename); - if (!stream) { - return false; - } - return ((AttributeTable *)m_data)->exportTable(stream, updated_only); -} - - diff --git a/salalib/idepthmap.h b/salalib/idepthmap.h deleted file mode 100644 index 5621e889..00000000 --- a/salalib/idepthmap.h +++ /dev/null @@ -1,637 +0,0 @@ -#ifndef __IDEPTHMAP_H__ -#define __IDEPTHMAP_H__ - -/////////////////////////////////////////////////////////////////////////////////////// - -// File: idepthmap.h -// Author: Alasdair Turner -// Copyright (C) 2007-2010 University College London - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// This defines interface for a DLL module library used in the Depthmap application -// THIRD PARTY DEVELOPERS: DO NOT MODIFY THIS FILE - -// It's a little complicated to look at, but it doesn't actually *do* that much - -// Firstly, it has miscellaneous structs to help the interface: -// struct DPoint; -// struct DLine; - -// Secondly, it defines your interface to Depthmap: -// class IComm; (to communicate the state of your analysis back to Depthmap) -// class IVGAMap; (for VGA analysis) -// class IShapeMap; (for axial, segment and data analysis) -// class IAttributes; (your interface to attribute values, whether or not -// the graph is a visibility graph or any other sort of graph) -// class IGraphFile; (for analysis of more than one map) -// -// (Note, despite the separate attribute interface, if you wish to display a certain -// attribute you must use the "setDisplayedAttribute" function within the relevant -// graph interface, i.e., through IVGAMap or IShapeMap) - -// Thirdly, it defines function prototypes for three functions you implement: -// -// char *getModuleName(); Return the name of your module (which will be added to the tools menu) -// char *getAnalysisName(int analysis); Return the name of an individual analysis within the module (which will be added as a menu item to your module) -// int getAnalysisType(int analysis); Return the type of analysis according to menu option. -// -// getAnalysisType must have one of -// DLL_NO_ANALYSIS, DLL_VGA_ANALYSIS, DLL_AXIAL_ANALYSIS, DLL_SEGMENT_ANALYSIS, DLL_DATA_ANALYSIS, DLL_ATTRIBUTE_ANALYSIS or DLL_GRAPH_FILE_ANALYSIS set, -// -// bool preprocess(int analysis); // Optional, for setting up -// -// Write the an appropriate function for your analysis type: -// -// bool processVGA(int analysis, IComm *, IVGAMap *, IAttributes *); // For DLL_VGA_ANALYSIS -// bool processShape(int analysis, IComm *, IShapeMap *, IAttributes *); // For DLL_AXIAL_ANALYSIS, DLL_SEGMENT_ANALYSIS or DLL_ATTRIBUTE_ANALYSIS -// bool processAttributes(int analysis, IComm *, IAttributes *); // For DLL_ATTRIBUTE_ANALYSIS -// bool processGraphFile(int analysis, IComm *, IGraphFile *); // For DLL_GRAPH_FILE_ANALYSIS -// -// void postprocess(int analysis); // Optional, for any tidying up -// -// You MUST supply getModuleName, getAnalysisType, getAnalysisName -// -// If the analysisType function specifies anything other than DLL_NO_ANALYSIS, then -// at least one of processVGA, processShape, processAttributes or processGraphFile must also be defined -// (as appropriate to the analysis type selected) -// -// The functions preprocess and postprocess are optional -// -// Note that DLL_NO_ANALYSIS calls preprocess only: -// For example, use this for to set module options or to display an about box -// - -// Do not alter this version number, it is the minimum -// compatible version of Depthmap for your DLL -#define DLL_DEPTHMAP_VERSION 10.04 - -#include -// Windows math.h does not define M_PI -#define DLL_PI 3.1415926535897932384626433832795 - -// Modified by Dream -#if defined(_WIN32) - -#ifdef _DEPTHMAP - // This is the version for the Depthmap app - #define DepthmapClass __declspec(dllexport) -#else - // This is the version for your module - #define DepthmapClass __declspec(dllimport) - #define DllProc __declspec(dllexport) -#endif - -#else - #define DepthmapClass - #define DllProc -#endif - -// this is a helper struct (with some basic functionality) -// this is not exported as DLLs do not support operator overrides -struct DepthmapClass DPoint -{ - double x; - double y; - DPoint() - { x = 0.0; y = 0.0; } - DPoint(double p, double q) - { x = p; y = q; } -}; - -// this is a helper struct -struct DepthmapClass DLine -{ - DPoint a; - DPoint b; - DLine() - { ; } - DLine(const DPoint& p, const DPoint& q) - { a = p; b = q; } -}; - -// send communications to and from the app: -// typically, set your number of records, then each iteration set the current record, -// check isProcessCancelled -- if so, please tidy up and return false from process function -class DepthmapClass IComm -{ -public: - IComm(); - virtual ~IComm(); - bool isProcessCancelled(); - void setNumSteps(int steps); - void setCurrentStep(int step); - void setNumRecords(int records); - void setCurrentRecord(int record); - // - bool isValid(); -public: - // IComm messages: specify the callback function below if you want to use these - enum { ICOMM_NUM_STEPS, ICOMM_CURRENT_STEP, ICOMM_NUM_RECORDS, ICOMM_CURRENT_RECORD }; -public: - // These are intended to be used through SalaDLL rather than standard Depthmap - void cancelProcess(); - int getNumSteps(); - int getCurrentStep(); - int getNumRecords(); - int getCurrentRecord(); - // - // Do NOT close the IComm unless you know what you are doing: - void close(); -private: - // INTERNAL TO DEPTHMAP - // the data that is transferred to your app: - // do not change this variable - void *m_data; -public: - // INTERNAL TO DEPTHMAP - // Depthmap calls these functions to interface the data - // do not call these functions - void setData(void *data); - void *getData(); -}; - -// avoid using this in your own Depthmap DLLs (it is designed for the sala.dll redistributable) -// instead, use the IComm passed to you via the processing functions -DepthmapClass IComm *getIComm(); - -// this class forms your interface to Depthmap VGA functionality: -class DepthmapClass IVGAMap -{ -// your public interface: -public: - IVGAMap(); - virtual ~IVGAMap(); -public: - enum {IVGA_STEP, IVGA_METRIC, IVGA_ANGULAR}; -protected: - // POINT INTERFACE - // this is the main iterator, it is used for all getPoint... functions - int m_cursor_point; - // secondary iterator for selected points - int m_cursor_selected_point; -public: - // if you know the id, you can move the cursor to this point: - void setCursorPoint(int id) - { m_cursor_point = id; } - // - // iterator for all points (uses m_cursor_point) - int getPointCount(); - int getFirstPoint(); - int getNextPoint(); - // - // iterator for selected points in the Depthmap UI (uses m_cursor_selected_point) - int getSelectedPointCount(); - int getFirstSelectedPoint(); - int getNextSelectedPoint(); - // - // clear selection: straight forward I hope - void clearSelection(); - // must know the id to get this (if replace is "true" then any existing current selection will be cleared) - void selectPoint(int id, bool replace = false); - // - // some basic info for the current point: - // - // the physical location of the point - DPoint getLocation(int id); - // getting the point for the physical location (returns -1 if it does not correspond to a node) - // (note, it may not have attribute data available: also check isGraphNode) - int getNode(DPoint& point); - // is the node simply empty? (i.e., no graph information) - bool isEmptyNode(int id); - // does the node have VGA / attribute information available for it? - bool isGraphNode(int id); - // is the node on the edge of the graph - bool isBoundaryNode(int id); - // merge two points together (use id and -1 as parameters to unmerge points) - void setMergePoint(int id, int merge_id); - // which point (if any) is the node conecptually merged with (returns -1 if not merged) - int getMergePoint(int id); - // assign arbitrary data to the point - void setUserData(int id, void *data); - // retrieve arbitrary data from the point - void *getUserData(int id); - // the longest line of sight length for bin (0-31) (use -1 for longest line of sight in any direction) - double getLoSLength(int id, int bin = -1, int type = 0); // type 0: standard LoS, type 1: longest occluded dist in this direction - // - // iterator for points connected to a node (set bin to -1 to get all points or bin in range 0-31) - // note, these functions use internal cursors within Depthmap and not available to us - int getConnectedPointCount(int id, int bin = -1); - int getFirstConnectedPoint(int id, int bin = -1); - int getNextConnectedPoint(int id, int bin = -1); - // - // straight forward grid connections -- returns direction of connections - // bitwise or-ed together if there is an accessible grid location in that direction - enum { CONNECT_E = 0x01, CONNECT_NE = 0x02, CONNECT_N = 0x04, CONNECT_NW = 0x08, - CONNECT_W = 0x10, CONNECT_SW = 0x20, CONNECT_S = 0x40, CONNECT_SE = 0x80 }; - char getGridConnections(int id); - double getGridSpacing(); - // - // Get the currently displayed attribute column - const char *getDisplayedAttributeColumn(); - // Display the attribute column - // (note: do this last! -- if you do it half way through, you will confuse colour scheme) - void setDisplayedAttributeColumn(const char *attribute); - // - // method should be one of IVGA_STEP, IVGA_METRIC or IVGA_ANGULAR - void analysePointDepth(IComm *comm, int method); - // -private: - // INTERNAL TO DEPTHMAP - // the data that is transferred to your app: - // do not change this variable - void *m_data; -public: - // INTERNAL TO DEPTHMAP - // Depthmap calls this function to give the interface the data - // do not call this function - void setData(void *data); -}; - -// this class forms your interface to Depthmap Axial, Segment, Drawing and Data functionality -// IMPORTANT: Note that not all functions work with all sorts of graph -class DepthmapClass IShapeMap -{ -// your public interface: -public: - IShapeMap(); - virtual ~IShapeMap(); -protected: - // SHAPE INTERFACE - // this is the main iterator, it is used for all getShape... functions - int m_cursor_shape; - // secondary iterator for selected shape - int m_cursor_selected_shape; -public: - // IDrawingMap is for drawing without attributes - // IDataMap is for map with attributes - // IAxialMap is designed for axial line maps only - // ISegmentMap is designed for segment maps only - // IConvexMap is designed for maps with polygons only and manually added connections - // IShapeMap is designed for a graph with generic shapes intersecting - enum { IDRAWINGMAP = 0x01, IDATAMAP = 0x02, ICONVEXMAP = 0x08, IAXIALMAP = 0x20, ISEGMENTMAP = 0x40, ISHAPEMAP = 0x80 }; - // some basic information about the map: - const char *getMapName(); - // map type for some usually encountered types - bool isAxialMap(); - bool isSegmentMap(); - bool isDataMap(); - bool isDrawingMap(); - // for further control, get the map type explicitly - int getMapType(); - // is it currently displayed - bool isVisible(); - // - // if you know the id, you can move the cursor to this shape: - void setCursorShape(int id) - { m_cursor_shape = id; } - // - // iterator for all shapes (uses m_cursor_shape) - int getShapeCount(); - int getFirstShape(); - int getNextShape(); - // - // iterator for selected shapes in the Depthmap UI (uses m_cursor_selected_shape) - int getSelectedShapeCount(); - int getFirstSelectedShape(); - int getNextSelectedShape(); - // - // clear selection: straight forward I hope - void clearSelection(); - // must know the id to get this (if replace is "true" then any existing current selection will be cleared) - void selectShape(int id, bool replace = false); - // I'm not sure how useful this function will be, but you might want to - // find shapes within a radius of a point: - int selectShapesWithinRadius(DPoint& point, double dist); - // selection to layer converts the current selection to a layer within your map: - void makeLayerFromSelection(const char *layer_name); - // - // iterator for connections -- note that in segment maps you - // will have 'forward' and 'back' connections at each end of the line - // a data map can still call these functions, but will not return any results - // note, these functions use internal cursors within Depthmap and not available to us - enum { CONN_ALL, CONN_FW, CONN_BK }; - int getConnectedShapeCount(int id, int dir = CONN_ALL); - int getFirstConnectedShape(int id, int dir = CONN_ALL); - int getNextConnectedShape(int id, int dir = CONN_ALL); - // note that getConnectionWeight and getConnectionDirection get the connection from the - // current position of the connected line cursor, - int getConnectionDirection(int id, int dir = CONN_ALL); - double getConnectionWeight(int id, int dir = CONN_ALL); - // - // used to determine type of shape: - bool isPointShape(int id); - bool isLineShape(int id); - bool isPolyLineShape(int id); - bool isPolygonShape(int id); - // the physical point coordinates - // (note, you should check it's a point first, otherwise this will return the centroid of the shape - DPoint getPointCoords(int id); - // the physical line coordinates - // (note, you should check it's a line first, otherwise this will return the bounding box of the shape - DLine getLineCoords(int id); - // for polylines and polygons, use a pair of functions: - int getVertexCount(int id); - DPoint getVertex(int id, int v); - // - // getting the shape id from a physical location (returns -1 if it does not correspond to a shape) - // note: uses a selection algorithm to find a shape close to the point - int getShape(DPoint& point); - // Get the currently displayed attribute - const char *getDisplayedAttributeColumn(); - // Display the attribute column - // (note: do this last! -- if you do it half way through, you will confuse colour scheme) - void setDisplayedAttributeColumn(const char *attribute); - // - ////////////////////////////////////////////////////////////////////////////// - // EDITING THE MAP (from Dmap version 8) - // Before you start you may want to clear everything: WARNING!, this deletes absolutely everything in your map! - void clearMap(); - // Note that you *MUST* call commitShapes() after adding shapes - // 1) Adding / removing shapes - // Adding a shape works very much like OpenGL: - // Start with beginShape then call vertex for each vertex, before calling endShape - // endShape returns the id of the new shape. - // The shapes do not have to be lines! - // Note that links are not made automatically for overlapping geometry: - // you must use connectDirected, connectUndirected, or connectIntersected - void beginShape(); - void addVertex(DPoint& point); - // set the 'open' parameter to true if you want to create a point, line or polyline, otherwise, for a closed polygon, set to false - int endShape(bool open); - // after adding geometry, you must commitShapes -- - // you can finish adding all the geometry you want (e.g., load a file of shapes) before calling commitShapes, - // but intersection testing and screen draw rely on commitShapes being called - void commitShapes(); - // removeShape straight forward (also removes all links associated with this shape), returns true if shape is removed successfully - // (note, no need to call commit) - bool removeShape(int id); - // - // For axial / segment (and other types of graph), you can add connections: - // 2) Adding / removing connections - // Use connectUndirected to add a single link with all graph types except segment - // -- returns true if connection is made or weight modified, note: uses links / unlinks table - bool connectUndirected(int id1, int id2); - // Use connectDirected with segment graphs *only* - // Note that despite the "fromdir" and "todir" (CONN_FW or CONN_BK) this only ever connects from the "from" node to the "to" node - // e.g.., a connection back from the from node to the to node would use CONN_BK for direction - bool connectDirected(int from, int fromdir, int to, int todir, double conn_weight); - // connectIntersected makes undirected (two way) connections from the shape - // to all existing shapes it intersects or touches: returns the number of connections made - int connectIntersected(int id); - // makeAllConnections *clears* everything (including all existing attributes, links, unlinks) before connecting intersecting shapes: - void makeAllConnections(); - // disconnect removes connections between the shapes if the connections exist: - // returns true if the shapes were previously connected, false if they were not previously connected - bool disconnect(int id1, int id2); - // -public: - // This calls the standard Depthmap analyseSegments (technically, Tulip 1024 analysis) - // if interactive is false, then analyseSegments will only analyse the current selection (if a selection has been made) - // if weighting_column is null, then segment length will be used for the weighting - // returns the number of segments analysed - int analyseSegments(IComm *comm, size_t radius_count, float *radius_array, const char *weighting_column, const char *weighting_column2, const char *routeweight_column, bool interactive); - // Export the map. Currently only supports MapInfo MIF/MID combination. Type MUST be "MIF" (in capitals) - bool exportMap(const char *filename, const char *type); - // Load unlinks for an axial map relies on you having an IShapeMap with a set of unlink points in it - bool loadUnlinks(IShapeMap *unlink_points_map); - // - ////////////////////////////////////////////////////////////////////////////////////// -private: - // INTERNAL TO DEPTHMAP - // the data that is transferred to your app: - // do not change this variable - void *m_data; -public: - // INTERNAL TO DEPTHMAP - // Depthmap calls this function to give the interface the data - // do not call this function - void setData(void *data); -}; - -// IAttributes -// this class forms your interface to attributes, it can be -// used with any analysis, just use the id code of the -// relevant data type (point, line or segment) to access the -// attribute for it -class DepthmapClass IAttributes -{ -protected: - int m_cursor_column; - int m_cursor_row; -public: - IAttributes(); - ~IAttributes(); - // Get a list of attributes - int getAttributeColumnCount(); - const char *getFirstAttributeColumn(); - const char *getNextAttributeColumn(); - // Get the row entries from the attributes - int getAttributeRowCount(); - int getFirstAttributeRow(); - int getNextAttributeRow(); - // Either insert an attribute, or, if the column exists, clear it: (you cannot clear the Ref Number column or a locked column) - bool insertAttributeColumn(const char *attribute); - // Delete an attribute column (you cannot delete the Ref Number column or a locked column) - bool deleteAttributeColumn(const char *attribute); - // Rename an attribute column (you cannot rename the Ref Number column or a locked column) - bool renameAttributeColumn(const char *oldname, const char *newname); - // Check that an attribute is valid - bool isValidAttributeColumn(const char *attribute); - // Check to see if the attribute is locked (e.g., Connectivity on an axial map) - bool isLockedAttributeColumn(const char *attribute); - // get an attribute from the attribute table for a point or line: - float getAttribute(int row, const char *attribute); - // set an attribute in the attribute table for a point or line: - void setAttribute(int row, const char *attribute, float value); - // increment an attribute in the attribute table for a point or line: - void incrAttribute(int row, const char *attribute); - // helpers: import and export of tables (as tab delimited text files) - // import: merge adds columns together - bool importTable(const char *filename, bool merge); - // note, columns are flagged internally in Depthmap after internal processes - bool exportTable(const char *filename, bool updated_only); -private: - // INTERNAL TO DEPTHMAP - // the data that is transferred to your app: - // do not change this variable - void *m_data; - // new for 708: attribute table records the analysis type - // this is required because the sort of id used differs when using PointMaps (a "pixel" id) to all other maps - int m_analysis_type; -public: - // INTERNAL TO DEPTHMAP - // Depthmap calls this function to give the interface the data - // do not call this function - void setData(void *data, int analysis_type); -}; - -// From DMap version 8 you can also access the graph file directly -// This should free you up to write inter-map analyses - -class DepthmapClass IGraphFile -{ -public: - IGraphFile(); - virtual ~IGraphFile(); -public: - // VGA straight forward (note: no insert as yet) - int getVGAMapCount(); - IVGAMap *getFirstVGAMap(); - IVGAMap *getNextVGAMap(); - // Shape maps: used for segment, axial, data and drawing maps - int getShapeMapCount(); - IShapeMap *getFirstShapeMap(); - IShapeMap *getNextShapeMap(); - IShapeMap *insertShapeMap(const char *name, int type); // for type, see IShapeMap types above -public: - // retrieve the attribute table for either vga or shape layer interfaces: - IAttributes *getAttributes(IVGAMap *ivga); - IAttributes *getAttributes(IShapeMap *ishape); - // get the view order: 0 is topmost, then 1, and so on, to bottom most. -1 is not displayed - int getViewOrder(IVGAMap *ivga); - int getViewOrder(IShapeMap *ishape); - // - // Push values between maps (values are transferred between overlapping geometry) - // Push type suggests what to do if more than one object is overlapping - enum { IPUSH_MAX, IPUSH_MIN, IPUSH_AVG, IPUSH_TOT }; - // set dest_attribute to NULL to get an automatically assigned output column name - bool pushValuesToMap(IShapeMap *source, IShapeMap *dest, const char *source_attribute, const char *dest_attribute, int push_type); - bool pushValuesToMap(IVGAMap *source, IShapeMap *dest, const char *source_attribute, const char *dest_attribute, int push_type); - bool pushValuesToMap(IShapeMap *source, IVGAMap *dest, const char *source_attribute, const char *dest_attribute, int push_type); -public: - // These allow extra control for interface to standard Depthmap functions - // Please use with caution when writing your own interfaces -- these are intended for sala.dll redistributables rather than Depthmap processing - // - // Import a map from a CAT, DXF or MIF / MID combination - // Note: type must be in capitals: e.g., "MIF" for MIF / MID - // Currently, CAT and DXF return NULL regardless of success or failure - // (as they create drawing maps which are currently unsupported through the IShapeMap interface - IShapeMap *importMap(const char *filename, const char *type, const char *newmapname); - // - // make an axial map from a data map or a drawing map - IShapeMap *makeAxialMapFromBaseMap(IComm *comm, IShapeMap *basemap, const char *newmapname); - // make a segment map from an axial map (cuts segments at axial-axial intersections) - IShapeMap *makeSegmentMapFromAxialMap(IComm *comm, IShapeMap *axialmap, const char *newmapname, double stubremoval); // n.b. converts an axial map - // - bool save(const char *filename); - // - friend DepthmapClass IGraphFile *newGraphFile(); - friend DepthmapClass IGraphFile *openGraphFile(const char *filename); - // -private: - // INTERNAL TO DEPTHMAP - // the data that is transferred to your app: - // do not change this variable - void *m_data; -public: - // INTERNAL TO DEPTHMAP - // Depthmap calls this function to give the interface the data - // do not call this function - void setData(void *data); -}; - -// You can even open your own graph files or create new ones -// use with caution in your own interfaces -DepthmapClass IGraphFile *newGraphFile(); -DepthmapClass IGraphFile *openGraphFile(const char *filename); -DepthmapClass void closeGraphFile(IGraphFile *& file); // use this to close and tidy up a graph file created with "new" or "open" - -// functions which Depthmap will load - -enum {DLL_NO_ANALYSIS = 0x01, - DLL_VGA_ANALYSIS = 0x02, - DLL_AXIAL_ANALYSIS = 0x04, - DLL_SEGMENT_ANALYSIS = 0x08, - DLL_DATA_ANALYSIS = 0x10, - DLL_ATTRIBUTE_ANALYSIS = 0x20, - DLL_ANALYSIS_TYPE = 0x3f, // note this deliberately doesn't include DLL_GRAPH_FILE_ANALYSIS - DLL_GRAPH_FILE_ANALYSIS = 0x40 }; - -// Depthmap will load your functions with these function specs: -typedef char *(*FUNC_GETMODULENAME)(); -typedef int (*FUNC_GETANALYSISTYPE)(int analysis); -typedef char *(*FUNC_GETANALYSISNAME)(int analysis); -typedef bool (*FUNC_PREPROCESS)(int analysis); -typedef bool (*FUNC_PROCESSVGA)(int analysis, IComm *, IVGAMap *, IAttributes *); -typedef bool (*FUNC_PROCESSSHAPE)(int analysis, IComm *, IShapeMap *, IAttributes *); -typedef bool (*FUNC_PROCESSATTRIBUTES)(int analysis, IComm *, IAttributes *); -typedef bool (*FUNC_PROCESSGRAPHFILE)(int analysis, IComm *, IGraphFile *); -typedef void (*FUNC_POSTPROCESS)(int analysis); -typedef float (*FUNC_GETMODULEVERSION)(); - -#ifndef _DEPTHMAP - // getModuleName - // use this function to return the name of your module -- you MUST write this function - // (which will be added to the tools menu when you import the analysis / Depthmap starts up) - extern "C" {DllProc char *getModuleName();} - // getAnalysisType - // use this function to return what type of analysis your module performs: - // it must be one of DLL_NO_ANALYSIS, DLL_VGA_ANALYSIS, DLL_AXIAL_ANALYSIS, DLL_SEGMENT_ANALYSIS or DLL_DATA_ANALYSIS - extern "C" {DllProc int getAnalysisType(int analysis);} - // getAnalysisName - // use this function to name up to 8 different analyses within a module - // you MUST supply at least one analysis name - // Depthmap will call with i = 0,1,2,3... etc. - // Return NULL when there are no more analyses - extern "C" {DllProc char *getAnalysisName(int analysis);} - // preprocess - // in preprocess, you might open a dialog box and allow the user to enter options - // parameter "analysis" corresponds to analyses named by getAnalysisName, - // if there are no named analyses, the parameter is set to -1 - // return true for Depthmap to run process, or false to stop without processing - extern "C" {DllProc bool preprocess(int analysis);} - // process (processVGA and processShape) - // in process, you do the analysis your module performs, this will be run in a - // separate thread, when finished, Depthmap will redraw and update attribute tables - // parameters analysis corresponds to analyses named by getAnalysisName, - // if there are no named analyses, this is set to -1 - // IComm * allows you to tell the front end how far you are through your analysis - // please also check the isCancelled() function frequently to see if the user wants to stop analysis - // processVGA - // IVGAMap * gives you access to the graph itself -- see above for details - // return true for success, false for failure - extern "C" {DllProc bool processVGA(int analysis, IComm *, IVGAMap *, IAttributes *);} - // processShape - // (note process shape is used for *all of* segment analysis, axial analysis and data analysis) - // IShapeMap * gives you access to the graph itself -- see above for details - // return true for success, false for failure - extern "C" {DllProc bool processShape(int analysis, IComm *, IShapeMap *, IAttributes *);} - // processAttributes - // for certain functions you may not care what sort of graph is shown, you may simply - // want to change the attributes: use this function to do so - extern "C" {DllProc bool processAttributes(int analysis, IComm *, IAttributes *);} - // processGraphFile - // for certain functions you may need access to more than one layer - // this function allows you access to the top level graph file - extern "C" {DllProc bool processGraphFile(int analysis, IComm *, IGraphFile *);} - // postprocess - // in postprocess, you might want to open a dialog box to give the user a summary of - // what happened during the analysis - // parameter analysis corresponds to analyses named by getAnalysisName, - // if there are no named analyses, this is set to -1 - extern "C" {DllProc void postprocess(int analysis);} - // - // OTHER INTERNAL METHODS - // do not alter this function: - extern "C" {DllProc float getModuleVersion(); } - // this appears to work, even though it's expecting an extern function: - extern "C" float getModuleVersion(); -#endif - -inline float getModuleVersion() -{ return (float)DLL_DEPTHMAP_VERSION; } - - -#endif diff --git a/salalib/idepthmapx.cpp b/salalib/idepthmapx.cpp deleted file mode 100644 index 85f68ec3..00000000 --- a/salalib/idepthmapx.cpp +++ /dev/null @@ -1,415 +0,0 @@ -// sala - a component of the depthmapX - spatial network analysis platform -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - - - -// this includes helpers for idepthmap - -#include - -#include -#include -#include - -#include -#include - -////////////////////////////////////////////////////////////////////// - -IGraphOrganizer::IGraphOrganizer() -{ - m_graph = NULL; - m_delete_flag = false; - m_vga_map_cursor = -1; - m_shape_map_cursor = -1; -} - -IGraphOrganizer::~IGraphOrganizer() -{ - if (m_delete_flag) { - delete m_graph; - } -} - -void IGraphOrganizer::setDeleteFlag() -{ - m_delete_flag = true; -} - -IVGAMap *IGraphOrganizer::getFirstIVGAMap() -{ - m_vga_map_cursor = 0; - IVGAMap *ret = getIVGAMap(m_vga_map_cursor); - if (ret == NULL) { - m_vga_map_cursor = -1; - } - return ret; -} - -IVGAMap *IGraphOrganizer::getNextIVGAMap() -{ - m_vga_map_cursor++; - IVGAMap *ret = getIVGAMap(m_vga_map_cursor); - if (ret == NULL) { - m_vga_map_cursor = -1; - } - return ret; -} - -IVGAMap *IGraphOrganizer::getIVGAMap(PointMap *map) -{ - if (map == NULL) { - return NULL; - } - size_t n = m_vga_maps.searchindex(map); - if (n == paftl::npos) { - n = m_vga_maps.add(map,IVGAMap(),paftl::ADD_HERE); - m_vga_maps[n].setData((void *)map); - m_ivga_maps.add(&(m_vga_maps[n]),map); // also reverse lookup - } - return &(m_vga_maps[n]); -} - -// INTERNAL ONLY -- others use cursor version or pointer version above -IVGAMap *IGraphOrganizer::getIVGAMap(int i) -{ - IVGAMap *p_ivga = NULL; - if (i >= 0 && size_t(i) < m_graph->PointMaps::size()) { - p_ivga = getIVGAMap(&(m_graph->PointMaps::at(i))); - } - return p_ivga; -} - -IShapeMap *IGraphOrganizer::getFirstIShapeMap() -{ - m_shape_map_cursor = 0; - IShapeMap *ret = getIShapeMap(m_shape_map_cursor); - if (ret == NULL) { - m_shape_map_cursor = -1; - } - return ret; -} - -IShapeMap *IGraphOrganizer::getNextIShapeMap() -{ - m_shape_map_cursor++; - IShapeMap *ret = getIShapeMap(m_shape_map_cursor); - if (ret == NULL) { - m_vga_map_cursor = -1; - } - return ret; -} - -IShapeMap *IGraphOrganizer::getIShapeMap(ShapeMap *map) -{ - if (map == NULL) { - return NULL; - } - int n = m_shape_maps.searchindex(map); - if (n == -1) { - n = m_shape_maps.add(map,IShapeMap(),paftl::ADD_HERE); - m_shape_maps[n].setData((void *)map); - m_ishape_maps.add(&(m_shape_maps[n]),map); // also reverse lookup - } - return &(m_shape_maps[n]); -} - - -// INTERNAL ONLY -- others use cursor version above or by pointer version above -IShapeMap *IGraphOrganizer::getIShapeMap(int i) -{ - IShapeMap *p_layer = NULL; - int shape_graphs = m_graph->getShapeGraphs().getMapCount(); - int data_maps = m_graph->getDataMaps().getMapCount(); - if (i >= 0 && i < shape_graphs) { - p_layer = getIShapeMap(&(m_graph->getShapeGraphs().getMap(i))); - } - else if (i >= shape_graphs && i < shape_graphs + data_maps) { - p_layer = getIShapeMap(&(m_graph->getDataMaps().getMap(i-shape_graphs))); - } - return p_layer; -} - -// PROTECTED: only use this internally in IGraphFile * -int IGraphOrganizer::getMapRef(IShapeMap *map) -{ - size_t n = m_ishape_maps.searchindex(map); - if (n == paftl::npos) { - return -1; - } - ShapeMap *basemap = m_ishape_maps[n]; - // - if (!map->isDataMap()) { - // look for it... - for (size_t i = 0; i < m_graph->m_shape_graphs.getMapCount(); i++) { - if (&(m_graph->m_shape_graphs.getMap(i)) == basemap) { - return i; - } - } - } - else { - // look for it... - for (size_t i = 0; i < m_graph->m_data_maps.getMapCount(); i++) { - if (&(m_graph->m_data_maps.getMap(i)) == basemap) { - return i; - } - } - } - return -1; -} - -// PROTECTED: only use this internally in IGraphFile * -int IGraphOrganizer::getMapRef(IVGAMap *map) -{ - size_t n = m_ivga_maps.searchindex(map); - if (n == paftl::npos) { - return -1; - } - PointMap *basemap = m_ivga_maps[n]; - // - // look for it... - for (size_t i = 0; i < m_graph->PointMaps::size(); i++) { - if (&(m_graph->PointMaps::at(i)) == basemap) { - return i; - } - } - return -1; -} - -//////////////////////////////////////////////////////////////// - -// these three are tough as they all require adding maps into the lookup tables - -IShapeMap *IGraphOrganizer::addShapeMap(const char *name, int type) -{ - ShapeMap *p_map = NULL; - IShapeMap *p_imap = NULL; - - if (type == IShapeMap::IDATAMAP) { - int mapref = m_graph->addShapeMap(name); - p_map = &(m_graph->getDataMaps().getMap(mapref)); - } - else { - // I'm assuming here that the new map type is already checked and allowable... - int mapref = m_graph->addShapeGraph(name,type); - p_map = &(m_graph->getShapeGraphs().getMap(mapref)); - } - - if (p_map) { - p_imap = getIShapeMap(p_map); - - // don't know why, but it looks like we need to do this here: - QtRegion r = m_graph->getBoundingBox(); - if (r.isNull()) { - r = QtRegion(Point2f(-50.0,-50.0),Point2f(50.0,50.0)); - } - p_map->init(0,r); - p_map->setEditable(true); - } - - return p_imap; -} - -IShapeMap *IGraphOrganizer::makeAxialMapFromBaseMap(IComm *comm, IShapeMap *basemap, const char *newmapname) -{ - IShapeMap *newmap = NULL; - - size_t n = m_ishape_maps.searchindex(basemap); - if (n == paftl::npos) { - return NULL; - } - ShapeMap& truebasemap = *(m_ishape_maps[n]); - - bool copydata = true; - - try { - int mapref = m_graph->getShapeGraphs().convertDataToAxial((Communicator *)(comm->getData()), newmapname, truebasemap, copydata); - ShapeGraph *p_map = &(m_graph->getShapeGraphs().getMap(mapref)); - newmap = getIShapeMap(p_map); - } - catch (Communicator::CancelledException) - { - newmap = NULL; - } - - return newmap; -} - - -IShapeMap *IGraphOrganizer::makeSegmentMapFromAxialMap(IComm *comm, IShapeMap *axialmap, const char *newmapname, double stubremoval) -{ - IShapeMap *newmap = NULL; - int mapref = -1; - - bool keeporiginal = true; - bool copydata = true; - - if (!axialmap->isAxialMap()) { - return NULL; - } - - // set the displayed map to the axial map (I know, it's all a bit UI focused...) - int basemapref = getMapRef(axialmap); - if (basemapref == -1) { - return NULL; - } - m_graph->m_shape_graphs.setDisplayedMapRef( basemapref ); - - try { - mapref = m_graph->m_shape_graphs.convertAxialToSegment((Communicator *)(comm->getData()), newmapname, keeporiginal, copydata, stubremoval); - ShapeGraph *p_map = &(m_graph->getShapeGraphs().getMap(mapref)); - newmap = getIShapeMap(p_map); - } - catch (Communicator::CancelledException) - { - newmap = NULL; - } - - return newmap; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -AttributeTable *IGraphOrganizer::getAttributeTable(IVGAMap *ivga) -{ - AttributeTable *p_table = NULL; - for (size_t i = 0; i < m_vga_maps.size(); i++) { - if (&(m_vga_maps.value(i)) == ivga) { - PointMap *p_map = m_vga_maps.key(i); - p_table = &(p_map->getAttributeTable()); - break; - } - } - return p_table; -} - -AttributeTable *IGraphOrganizer::getAttributeTable(IShapeMap *ishape) -{ - AttributeTable *p_table = NULL; - for (size_t i = 0; i < m_shape_maps.size(); i++) { - if (&(m_shape_maps.value(i)) == ishape) { - ShapeMap *p_map = m_shape_maps.key(i); - p_table = &(p_map->getAttributeTable()); - break; - } - } - return p_table; -} - -///////////////////////////////////////////////////////////////////////////////////////// - - -IAttributes *IGraphOrganizer::getIAttributes(AttributeTable *p_table, int analysis_type) -{ - IAttributes *p_attr = NULL; - size_t n = m_attribute_tables.searchindex(p_table); - if (n == paftl::npos) { - n = m_attribute_tables.add(p_table,IAttributes(),paftl::ADD_HERE); - m_attribute_tables[n].setData((void *)p_table, analysis_type); - } - p_attr = &(m_attribute_tables[n]); - return p_attr; -} - -IAttributes *IGraphOrganizer::getIAttributes(IVGAMap *ivga) -{ - IAttributes *p_attr = NULL; - for (size_t i = 0; i < m_vga_maps.size(); i++) { - if (&(m_vga_maps.value(i)) == ivga) { - PointMap *p_map = m_vga_maps.key(i); - AttributeTable *p_table = &(p_map->getAttributeTable()); - p_attr = getIAttributes(p_table, DLL_VGA_ANALYSIS); - break; - } - } - return p_attr; -} - -IAttributes *IGraphOrganizer::getIAttributes(IShapeMap *ishape) -{ - IAttributes *p_attr = NULL; - for (size_t i = 0; i < m_shape_maps.size(); i++) { - if (&(m_shape_maps.value(i)) == ishape) { - ShapeMap *p_map = m_shape_maps.key(i); - AttributeTable *p_table = &(p_map->getAttributeTable()); - p_attr = getIAttributes(p_table, DLL_AXIAL_ANALYSIS | DLL_SEGMENT_ANALYSIS); - break; - } - } - return p_attr; -} - -///////////////////////////////////////////////////// - -int IGraphOrganizer::getViewOrder(IVGAMap *ivga) -{ - int order = -1; - int view = m_graph->getViewClass() & (MetaGraph::VIEWVGA | MetaGraph::VIEWBACKVGA); - if (view != 0) { - size_t n = m_ivga_maps.searchindex(ivga); - if (n == paftl::npos) { - return -1; - } - else if (m_ivga_maps[n] == &(m_graph->getDisplayedPointMap())) { - if (view == MetaGraph::VIEWVGA) { - order = 0; - } - else { - order = 1; - } - } - } - return order; -} -int IGraphOrganizer::getViewOrder(IShapeMap *ishape) -{ - int order = -1; - if (!ishape->isDataMap()) { // assume everything else is a graph - int view = m_graph->getViewClass() & (MetaGraph::VIEWAXIAL | MetaGraph::VIEWBACKAXIAL); - if (view != 0) { - size_t n = m_ishape_maps.searchindex(ishape); - if (n == paftl::npos) { - return -1; - } - else if (m_ishape_maps[n] == &(m_graph->getDisplayedShapeGraph())) { - if (view == MetaGraph::VIEWAXIAL) { - order = 0; - } - else { - order = 1; - } - } - } - } - else { - int view = m_graph->getViewClass() & (MetaGraph::VIEWDATA | MetaGraph::VIEWBACKDATA); - if (view != 0) { - size_t n = m_ishape_maps.searchindex(ishape); - if (n == paftl::npos) { - return -1; - } - else if (m_ishape_maps[n] == &(m_graph->getDisplayedDataMap())) { - if (view == MetaGraph::VIEWDATA) { - order = 0; - } - else { - order = 1; - } - } - } - } - return order; -} diff --git a/salalib/idepthmapx.h b/salalib/idepthmapx.h deleted file mode 100644 index 72e6231e..00000000 --- a/salalib/idepthmapx.h +++ /dev/null @@ -1,94 +0,0 @@ -// sala - a component of the depthmapX - spatial network analysis platform -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - - -#ifndef __IDEPTHMAPX_H__ -#define __IDEPTHMAPX_H__ - -/////////////////////////////////////////////////////////////////////////////////////// -// Extra functionality specifically for the depthmapX DLL interface -// Helper for IGraphFile - -class IGraphOrganizer { - friend class IGraphFile; -protected: - MetaGraph *m_graph; -private: - // You MUST use pqmap here! - // It is necessary so the IVGAMaps and IShapeMaps do not get reallocated, and that - // both IVGAMap* and IShapeMap* remain valid after adding new maps - pqmap m_vga_maps; - pqmap m_shape_maps; - pqmap m_attribute_tables; - // in addition to look up that way, we also need to look up the other way, because IShapeMap and IVGAMap won't allow us to get the data back! - pqmap m_ivga_maps; - pqmap m_ishape_maps; - // -protected: - bool m_delete_flag; - int m_vga_map_cursor; - int m_shape_map_cursor; -public: - IGraphOrganizer(); - virtual ~IGraphOrganizer(); - void setDeleteFlag(); - // -public: - // - IShapeMap *addShapeMap(const char *name, int type); - IShapeMap *makeAxialMapFromBaseMap(IComm *comm, IShapeMap *basemap, const char *newmapname); - IShapeMap *makeSegmentMapFromAxialMap(IComm *comm, IShapeMap *axialmap, const char *newmapname, double stubremoval); - // - int getIVGAMapCount() const - { return m_graph->PointMaps::size(); } - IVGAMap *getFirstIVGAMap(); - IVGAMap *getNextIVGAMap(); - // - // note shape graphs and data maps are chained together - int getIShapeMapCount() const - { return m_graph->getShapeGraphs().getMapCount() + m_graph->getDataMaps().getMapCount(); } - IShapeMap *getFirstIShapeMap(); - IShapeMap *getNextIShapeMap(); - // - IAttributes *getIAttributes(AttributeTable *p_table, int analysis_type); - IAttributes *getIAttributes(IVGAMap *ivga); - IAttributes *getIAttributes(IShapeMap *ishape); - // - int getViewOrder(IVGAMap *ivga); - int getViewOrder(IShapeMap *ishape); - // - IVGAMap *getIVGAMap(PointMap *); - IShapeMap *getIShapeMap(ShapeMap *); - // -// PointMap *getPointMap(IVGAMap *); -// ShapeMap *getShapeMap(IShapeMap *); - // -protected: - // protected as the return is mutable -- much better for everyone else to use the fixed IShapeMap pointers - int getMapRef(IShapeMap *map); - int getMapRef(IVGAMap *map); - // - // Note: shape graphs and data maps are chain together! Do not forget! - IShapeMap *getIShapeMap(int n); - IVGAMap *getIVGAMap(int n); - // - // I am not sure if I really need this, but it certainly helps when writing - // "pushValues" in IGraphFile - AttributeTable *getAttributeTable(IShapeMap *map); - AttributeTable *getAttributeTable(IVGAMap *map); -}; - -#endif diff --git a/salalib/importtypedefs.h b/salalib/importtypedefs.h new file mode 100644 index 00000000..32f0330d --- /dev/null +++ b/salalib/importtypedefs.h @@ -0,0 +1,42 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "genlib/p2dpoly.h" +#include +#include + +namespace depthmapX { + typedef std::vector ColumnData; + typedef std::map Table; + + class Polyline : public QtRegion + { + public: + std::vector m_vertices; + bool m_closed = false; + Polyline(std::vector vertices, bool closed) : m_vertices(vertices), m_closed(closed) { + } + }; + + enum ImportType { + DRAWINGMAP, DATAMAP + }; + + enum ImportFileType { + CSV, TSV, DXF + }; +} diff --git a/salalib/importutils.cpp b/salalib/importutils.cpp new file mode 100644 index 00000000..606fb9b9 --- /dev/null +++ b/salalib/importutils.cpp @@ -0,0 +1,474 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "importutils.h" + +#include "genlib/stringutils.h" + +#include + +namespace depthmapX { + + const int DXFCIRCLERES = 36; + + bool importFile(MetaGraph &mgraph, std::istream &stream, Communicator *communicator, std::string name, + ImportType mapType, ImportFileType fileType) { + + // This function is still too fiddly but at least it shows the common interface for + // drawing and data maps and how different file types may be parsed to be imported + // into them + + int state = MetaGraph::NONE; + int viewClass = MetaGraph::NONE; + + switch (mapType) { + case DRAWINGMAP: { + state = MetaGraph::LINEDATA; + viewClass = MetaGraph::SHOWSHAPETOP; + break; + } + case DATAMAP: { + state = MetaGraph::DATAMAPS; + viewClass = MetaGraph::SHOWSHAPETOP; + break; + } + } + + int oldstate = mgraph.getState(); + mgraph.setState(oldstate & ~state); + + // Currently the drawing shapemaps are understood as two-level trees (file -> layers) + // while the data shapemaps are flat. Therefore, for the moment, when we load dxfs as + // drawing shapemaps then we let the filename be the parent and the layers the children. + // For text files (csv, tsv) we create an artificial parent with the relevant name + // Drawing shapemaps also carry region data that needs to be initialised and their parents + // updated when they are created. + // Ideally datamaps and drawingmaps should be more similar. + + if (mapType == DRAWINGMAP) { + mgraph.m_drawingFiles.emplace_back(name); + } + + bool parsed = false; + + switch (fileType) { + case CSV: { + ShapeMap &shapeMap = mgraph.createNewShapeMap(mapType, name); + int newMapIdx = mgraph.getMapRef(mgraph.getDataMaps(), shapeMap.getName()); + parsed = importTxt(shapeMap, stream, ','); + + if (!parsed) { + mgraph.deleteShapeMap(mapType, shapeMap); + break; + } + if (mapType == DRAWINGMAP) { + mgraph.updateParentRegions(shapeMap); + } else if (mapType == DATAMAP) { + mgraph.setDisplayedDataMapRef(newMapIdx); + } + break; + } + case TSV: { + ShapeMap &shapeMap = mgraph.createNewShapeMap(mapType, name); + int newMapIdx = mgraph.getMapRef(mgraph.getDataMaps(), shapeMap.getName()); + parsed = importTxt(shapeMap, stream, '\t'); + + if (!parsed) { + mgraph.deleteShapeMap(mapType, shapeMap); + break; + } + if (mapType == DRAWINGMAP) { + mgraph.updateParentRegions(shapeMap); + } else if (mapType == DATAMAP) { + mgraph.setDisplayedDataMapRef(newMapIdx); + } + break; + } + case DXF: { + + DxfParser dp; + + if (communicator) { + dp = DxfParser(communicator); + + try { + *communicator >> dp; + } catch (Communicator::CancelledException) { + return 0; + } catch (std::logic_error &) { + return -1; + } + + if (communicator->IsCancelled()) { + return 0; + } + } else { + dp.open(stream); + } + + for (auto &layer : dp.getLayers()) { + + const DxfLayer &dxfLayer = layer.second; + + if (dxfLayer.empty()) { + continue; + } + + ShapeMap &shapeMap = mgraph.createNewShapeMap(mapType, layer.first); + parsed = importDxfLayer(dxfLayer, shapeMap); + + if (!parsed) { + mgraph.deleteShapeMap(mapType, shapeMap); + break; + } + if (mapType == DRAWINGMAP) { + mgraph.updateParentRegions(shapeMap); + } + } + break; + } + } + + if (parsed) { + mgraph.setState(mgraph.getState() | state); + mgraph.setViewClass(viewClass); + return true; + } else { + mgraph.setState(oldstate); + return false; + } + } + + bool importTxt(ShapeMap &shapeMap, std::istream &stream, char delimiter = '\t') { + Table table = csvToTable(stream, delimiter); + std::vector columns; + int xcol = -1, ycol = -1, x1col = -1, y1col = -1, x2col = -1, y2col = -1, refcol = -1; + for (auto const &column : table) { + if (column.first == "x" || column.first == "easting") + xcol = columns.size(); + else if (column.first == "y" || column.first == "northing") + ycol = columns.size(); + else if (column.first == "x1") + x1col = columns.size(); + else if (column.first == "x2") + x2col = columns.size(); + else if (column.first == "y1") + y1col = columns.size(); + else if (column.first == "y2") + y2col = columns.size(); + else if (column.first == "Ref") + refcol = columns.size(); + columns.push_back(column.first); + } + + if (xcol != -1 && ycol != -1 && refcol != -1) { + std::map points = + extractPointsWithRefs(table[columns[xcol]], table[columns[ycol]], table[columns[refcol]]); + table.erase(table.find(columns[xcol])); + table.erase(table.find(columns[ycol])); + table.erase(table.find(columns[refcol])); + + QtRegion region; + + for (auto &point : points) { + if (region.atZero()) { + region = point.second; + } else { + region = runion(region, point.second); + } + } + + shapeMap.init(points.size(), region); + shapeMap.importPointsWithRefs(points, table); + + } else if (xcol != -1 && ycol != -1) { + std::vector points = extractPoints(table[columns[xcol]], table[columns[ycol]]); + table.erase(table.find(columns[xcol])); + table.erase(table.find(columns[ycol])); + + QtRegion region; + + for (auto &point : points) { + if (region.atZero()) { + region = point; + } else { + region = runion(region, point); + } + } + + shapeMap.init(points.size(), region); + shapeMap.importPoints(points, table); + + } else if (x1col != -1 && y1col != -1 && x2col != -1 && y2col != -1 && refcol != -1) { + std::map lines = + extractLinesWithRef(table[columns[x1col]], table[columns[y1col]], table[columns[x2col]], + table[columns[y2col]], table[columns[refcol]]); + table.erase(table.find(columns[x1col])); + table.erase(table.find(columns[y1col])); + table.erase(table.find(columns[x2col])); + table.erase(table.find(columns[y2col])); + table.erase(table.find(columns[refcol])); + + QtRegion region; + + for (auto &line : lines) { + if (region.atZero()) { + region = line.second; + } else { + region = runion(region, line.second); + } + } + + shapeMap.init(lines.size(), region); + shapeMap.importLinesWithRefs(lines, table); + } else if (x1col != -1 && y1col != -1 && x2col != -1 && y2col != -1) { + std::vector lines = extractLines(table[columns[x1col]], table[columns[y1col]], table[columns[x2col]], + table[columns[y2col]]); + table.erase(table.find(columns[x1col])); + table.erase(table.find(columns[y1col])); + table.erase(table.find(columns[x2col])); + table.erase(table.find(columns[y2col])); + + QtRegion region; + + for (auto &line : lines) { + if (region.atZero()) { + region = line; + } else { + region = runion(region, line); + } + } + + shapeMap.init(lines.size(), region); + shapeMap.importLines(lines, table); + } + return true; + } + + Table csvToTable(std::istream &stream, char delimiter = '\t') { + + Table table; + std::vector columns; + + std::string inputline; + std::getline(stream, inputline); + + // check for a matching delimited header line... + auto strings = dXstring::split(inputline, delimiter); + if (strings.size() < 2) { + // throw exception + return table; + } + + for (auto &columnName : strings) { + if (!columnName.empty()) { + dXstring::ltrim(columnName, '\"'); + dXstring::rtrim(columnName, '\"'); + } + table.insert(std::make_pair(columnName, std::vector())); + columns.push_back(columnName); + } + + while (!stream.eof()) { + std::getline(stream, inputline); + if (!inputline.empty()) { + auto strings = dXstring::split(inputline, delimiter); + if (strings.size() != columns.size()) { + std::stringstream message; + message << "Cells in line " << inputline << "not the same number as the columns" << std::flush; + throw RuntimeException(message.str().c_str()); + } + if (!strings.size()) { + continue; + } + for (size_t i = 0; i < strings.size(); i++) { + table[columns[i]].push_back(strings[i]); + } + } + } + return table; + } + + std::vector extractLines(ColumnData &x1col, ColumnData &y1col, ColumnData &x2col, ColumnData &y2col) { + std::vector lines; + for (size_t i = 0; i < x1col.size(); i++) { + double x1 = stod(x1col[i]); + double y1 = stod(y1col[i]); + double x2 = stod(x2col[i]); + double y2 = stod(y2col[i]); + lines.push_back(Line(Point2f(x1, y1), Point2f(x2, y2))); + } + return lines; + } + + std::map extractLinesWithRef(ColumnData &x1col, ColumnData &y1col, ColumnData &x2col, ColumnData &y2col, + ColumnData &refcol) { + std::map lines; + for (size_t i = 0; i < x1col.size(); i++) { + double x1 = stod(x1col[i]); + double y1 = stod(y1col[i]); + double x2 = stod(x2col[i]); + double y2 = stod(y2col[i]); + int ref = stoi(refcol[i]); + lines.insert(std::make_pair(ref, Line(Point2f(x1, y1), Point2f(x2, y2)))); + } + return lines; + } + std::vector extractPoints(ColumnData &x, ColumnData &y) { + std::vector points; + for (size_t i = 0; i < x.size(); i++) { + points.push_back(Point2f(stod(x[i]), stod(y[i]))); + } + return points; + } + std::map extractPointsWithRefs(ColumnData &x, ColumnData &y, ColumnData &ref) { + std::map points; + for (size_t i = 0; i < x.size(); i++) { + points.insert(std::make_pair(stoi(ref[i]), Point2f(stod(x[i]), stod(y[i])))); + } + return points; + } + + bool importDxfLayer(const DxfLayer &dxfLayer, ShapeMap &shapeMap) { + std::vector points; + std::vector lines; + std::vector polylines; + + for (size_t jp = 0; jp < dxfLayer.numPoints(); jp++) { + const DxfVertex &dxf_point = dxfLayer.getPoint(jp); + points.push_back(Point2f(dxf_point.x, dxf_point.y)); + } + + for (size_t j = 0; j < dxfLayer.numLines(); j++) { + const DxfLine &dxf_line = dxfLayer.getLine(j); + Line line = Line(Point2f(dxf_line.getStart().x, dxf_line.getStart().y), + Point2f(dxf_line.getEnd().x, dxf_line.getEnd().y)); + lines.push_back(line); + } + + for (size_t k = 0; k < dxfLayer.numPolyLines(); k++) { + const DxfPolyLine &poly = dxfLayer.getPolyLine(k); + std::vector vertices; + for (size_t m = 0; m < poly.numVertices(); m++) { + DxfVertex v = poly.getVertex(m); + vertices.push_back(Point2f(v.x, v.y)); + } + polylines.push_back( + depthmapX::Polyline(vertices, (poly.getAttributes() & DxfPolyLine::CLOSED) == DxfPolyLine::CLOSED)); + } + + for (size_t l = 0; l < dxfLayer.numSplines(); l++) { + const DxfSpline &poly = dxfLayer.getSpline(l); + std::vector vertices; + for (size_t m = 0; m < poly.numVertices(); m++) { + DxfVertex v = poly.getVertex(m); + vertices.push_back(Point2f(v.x, v.y)); + } + polylines.push_back( + depthmapX::Polyline(vertices, (poly.getAttributes() & DxfPolyLine::CLOSED) == DxfPolyLine::CLOSED)); + } + + for (size_t n = 0; n < dxfLayer.numArcs(); n++) { + const DxfArc &circ = dxfLayer.getArc(n); + std::vector vertices; + size_t segments = circ.numSegments(DXFCIRCLERES); + if (segments > 1) { + for (size_t m = 0; m <= segments; m++) { + DxfVertex v = circ.getVertex(m, segments); + vertices.push_back(Point2f(v.x, v.y)); + } + } + polylines.push_back(depthmapX::Polyline(vertices, false)); + } + + for (size_t n = 0; n < dxfLayer.numEllipses(); n++) { + const DxfEllipse &ellipse = dxfLayer.getEllipse(n); + std::vector vertices; + size_t segments = ellipse.numSegments(DXFCIRCLERES); + if (segments > 1) { + for (size_t m = 0; m <= segments; m++) { + DxfVertex v = ellipse.getVertex(m, segments); + vertices.push_back(Point2f(v.x, v.y)); + } + } + polylines.push_back(depthmapX::Polyline(vertices, false)); + } + + for (size_t nc = 0; nc < dxfLayer.numCircles(); nc++) { + const DxfCircle &circ = dxfLayer.getCircle(nc); + std::vector vertices; + for (int m = 0; m < DXFCIRCLERES; m++) { + DxfVertex v = circ.getVertex(m, DXFCIRCLERES); + vertices.push_back(Point2f(v.x, v.y)); + } + polylines.push_back(depthmapX::Polyline(vertices, true)); + } + DxfVertex layerMin = dxfLayer.getExtMin(); + DxfVertex layerMax = dxfLayer.getExtMax(); + + QtRegion region = QtRegion(Point2f(layerMin.x, layerMin.y), Point2f(layerMax.x, layerMax.y)); + + shapeMap.init(points.size() + lines.size() + polylines.size(), region); + // parameters could be passed in the Table here such as the layer/block/colour/linetype etc. + shapeMap.importPoints(points, Table()); + shapeMap.importLines(lines, Table()); + shapeMap.importPolylines(polylines, Table()); + return true; + } + + bool importAttributes(AttributeTable &attributes, std::istream &stream, char delimiter = '\t') { + Table table = csvToTable(stream, delimiter); + std::vector outColumns; + int refcol = -1; + for (auto const &column : table) { + if (column.first == "Ref") + refcol = outColumns.size(); + else + outColumns.push_back(column.first); + } + if(table.size() == 0) { + throw RuntimeException("No usable data found in file"); + } + if(refcol == -1) { + throw RuntimeException("The \"Ref\" column is reqired"); + } + if(outColumns.size() < 1) { + throw RuntimeException("No data found to join"); + } + std::vector inRows; + for(const auto& refInFile: table["Ref"]) { + int ref = std::stoi(refInFile); + auto iter = attributes.find(AttributeKey(ref)); + if(iter == attributes.end()) { + std::stringstream message; + message << "Key " << ref << "not found in attribute table" << std::flush; + throw RuntimeException(message.str().c_str()); + } + inRows.push_back(&(iter->getRow())); + } + + // Up until this point we have not touched the attribute table + // so no need for corrective measures yet + + for(const std::string& column: outColumns) { + int colIdx = attributes.insertOrResetColumn(column); + auto outRowIter = table[column].begin(); + for(auto inRowIter = inRows.begin(); inRowIter != inRows.end(); inRowIter++, outRowIter++) { + (*inRowIter)->setValue(colIdx, std::stof(*outRowIter)); + } + } + return true; + } +} // namespace depthmapX diff --git a/salalib/importutils.h b/salalib/importutils.h new file mode 100644 index 00000000..39dbc6ea --- /dev/null +++ b/salalib/importutils.h @@ -0,0 +1,36 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/importtypedefs.h" +#include "salalib/mgraph.h" +#include "salalib/parsers/dxfp.h" +#include +#include + +namespace depthmapX { + bool importFile(MetaGraph &mgraph, std::istream &stream, Communicator *communicator, std::string name, + ImportType mapType, ImportFileType fileType); + bool importTxt(ShapeMap &shapeMap, std::istream &stream, char delimiter); + depthmapX::Table csvToTable(std::istream &stream, char delimiter); + std::vector extractLines(ColumnData &x1col, ColumnData &y1col, ColumnData &x2col, ColumnData &y2col); + std::map extractLinesWithRef(ColumnData &x1col, ColumnData &y1col, ColumnData &x2col, ColumnData &y2col, + ColumnData &refcol); + std::vector extractPoints(ColumnData &x, ColumnData &y); + std::map extractPointsWithRefs(ColumnData &x, ColumnData &y, ColumnData &ref); + bool importDxfLayer(const DxfLayer &dxfLayer, ShapeMap &shapeMap); + bool importAttributes(AttributeTable &attributes, std::istream &stream, char delimiter); +} // namespace depthmapX diff --git a/salalib/isegment.h b/salalib/isegment.h new file mode 100644 index 00000000..f38cde66 --- /dev/null +++ b/salalib/isegment.h @@ -0,0 +1,67 @@ +// Copyright (C) 2018 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +// Interface to handle different kinds of VGA analysis + +#include "salalib/axialmap.h" +#include "salalib/options.h" + +#include "genlib/comm.h" + +#include + +class ISegment +{ +public: + virtual std::string getAnalysisName() const = 0; + virtual bool run(Communicator *comm, ShapeGraph &map, bool simple_version) = 0; + virtual ~ISegment(){} + + // Axial map helper: convert a radius for angular analysis + + static std::string makeFloatRadiusText(double radius) + { + std::string radius_text; + if (radius > 100.0) { + radius_text = dXstring::formatString(radius,"%.f"); + } + else if (radius < 0.1) { + radius_text = dXstring::formatString(radius,"%.4f"); + } + else { + radius_text = dXstring::formatString(radius,"%.2f"); + } + return radius_text; + } + + static std::string makeRadiusText(int radius_type, double radius) + { + std::string radius_text; + if (radius != -1) { + if (radius_type == Options::RADIUS_STEPS) { + radius_text = std::string(" R") + dXstring::formatString(int(radius),"%d") + " step"; + } + else if (radius_type == Options::RADIUS_METRIC) { + radius_text = std::string(" R") + makeFloatRadiusText(radius) + " metric"; + } + else { // radius angular + radius_text = std::string(" R") + makeFloatRadiusText(radius); + } + } + return radius_text; + } +}; diff --git a/salalib/isovist.cpp b/salalib/isovist.cpp index 2e7caa51..02408cb8 100644 --- a/salalib/isovist.cpp +++ b/salalib/isovist.cpp @@ -15,14 +15,11 @@ // along with this program. If not, see . +#include "salalib/isovist.h" + #include #include #include -#include - -#include // purely for the version info --- as phased out should replace - -#include "isovist.h" /////////////////////////////////////////////////////////////////////// @@ -34,7 +31,7 @@ void Isovist::makeit(BSPNode *root, const Point2f& p, const QtRegion& region, double startangle, double endangle) { // region is used to give an idea of scale, so isovists can be linked when there is floating point error - double tolerance = __max(region.width(),region.height()) * 1e-9; + double tolerance = std::max(region.width(),region.height()) * 1e-9; m_centre = p; m_blocks.clear(); @@ -52,12 +49,12 @@ void Isovist::makeit(BSPNode *root, const Point2f& p, const QtRegion& region, do bool parity = false; if (startangle > endangle) { - m_gaps.push_back(IsoSeg(0.0,endangle)); - m_gaps.push_back(IsoSeg(startangle,2.0*M_PI)); + m_gaps.insert(IsoSeg(0.0,endangle)); + m_gaps.insert(IsoSeg(startangle,2.0*M_PI)); } else { parity = true; - m_gaps.push_back(IsoSeg(startangle,endangle)); + m_gaps.insert(IsoSeg(startangle,endangle)); } make(root); @@ -69,30 +66,33 @@ void Isovist::makeit(BSPNode *root, const Point2f& p, const QtRegion& region, do m_occlusion_points.clear(); bool markedcentre = false; - for (size_t i = 0; i < m_blocks.size(); i++) { - if (!complete && !markedcentre && !parity && m_blocks[i].startangle == startangle) { + auto prev = m_blocks.begin(); + auto curr = m_blocks.begin(); + for (;curr != m_blocks.end(); ++curr){ + if (!complete && !markedcentre && !parity && curr->startangle == startangle) { // centre m_poly.push_back(p); // perimeter! occlusivity! markedcentre = true; } - if (i != 0 && !approxeq(m_blocks[i-1].endpoint, m_blocks[i].startpoint, tolerance)) { - m_poly.push_back(m_blocks[i].startpoint); + if (curr != m_blocks.begin() && !approxeq(prev->endpoint, curr->startpoint, tolerance)) { + m_poly.push_back(curr->startpoint); // record perimeter information: - double occluded = dist(m_blocks[i-1].endpoint,m_blocks[i].startpoint); + double occluded = dist(prev->endpoint,curr->startpoint); m_perimeter += occluded; m_occluded_perimeter += occluded; // record the near *point* for use in agent analysis // (as the point will not move between isovists, so can record *which* occlusion this is, and spot novel ones) - if (dist(m_blocks[i-1].endpoint,m_centre) < dist(m_blocks[i].startpoint,m_centre)) { - m_occlusion_points.push_back(PointDist(m_blocks[i-1].endpoint,occluded)); + if (dist(prev->endpoint,m_centre) < dist(curr->startpoint,m_centre)) { + m_occlusion_points.push_back(PointDist(prev->endpoint,occluded)); } else { - m_occlusion_points.push_back(PointDist(m_blocks[i].startpoint,occluded)); + m_occlusion_points.push_back(PointDist(curr->startpoint,occluded)); } } - m_poly.push_back(m_blocks[i].endpoint); - m_perimeter += dist(m_blocks[i].startpoint,m_blocks[i].endpoint); + m_poly.push_back(curr->endpoint); + m_perimeter += dist(curr->startpoint,curr->endpoint); + prev = curr; } // for some reason to do with ordering, if parity is true, the centre point must be last not first if (!complete && parity) { @@ -100,20 +100,20 @@ void Isovist::makeit(BSPNode *root, const Point2f& p, const QtRegion& region, do m_poly.push_back(p); // perimeter! occlusivity! } - if (m_blocks.size() && !approxeq(m_blocks.tail().endpoint, m_blocks.head().startpoint, tolerance)) { - m_poly.push_back(m_blocks.head().startpoint); + if (m_blocks.size() && !approxeq(m_blocks.rbegin()->endpoint, m_blocks.begin()->startpoint, tolerance)) { + m_poly.push_back(m_blocks.begin()->startpoint); // record perimeter information: - double occluded = dist(m_blocks.tail().endpoint,m_blocks.head().startpoint); + double occluded = dist(m_blocks.rbegin()->endpoint,m_blocks.begin()->startpoint); m_perimeter += occluded; m_occluded_perimeter += occluded; // record the near *point* for use in agent analysis // (as the point will not move between isovists, so can record *which* occlusion this is, and spot novel ones) if (occluded > 1.5) { - if (dist(m_blocks.tail().endpoint,m_centre) < dist(m_blocks.head().startpoint,m_centre)) { - m_occlusion_points.push_back(PointDist(m_blocks.tail().endpoint,occluded)); + if (dist(m_blocks.rbegin()->endpoint,m_centre) < dist(m_blocks.begin()->startpoint,m_centre)) { + m_occlusion_points.push_back(PointDist(m_blocks.rbegin()->endpoint,occluded)); } else { - m_occlusion_points.push_back(PointDist(m_blocks.head().startpoint,occluded)); + m_occlusion_points.push_back(PointDist(m_blocks.begin()->startpoint,occluded)); } } } @@ -125,18 +125,18 @@ int Isovist::getClosestLine(BSPNode *root, const Point2f& p) m_blocks.clear(); m_gaps.clear(); - m_gaps.push_back(IsoSeg(0.0,2.0*M_PI)); + m_gaps.insert(IsoSeg(0.0,2.0*M_PI)); make(root); int mintag = -1; double mindist = 0.0; - for (size_t i = 0; i < m_blocks.size(); i++) { - Line l(m_blocks[i].startpoint, m_blocks[i].endpoint); + for (auto& block: m_blocks) { + Line l(block.startpoint, block.endpoint); if (mintag == -1 || dist(p,l) < mindist) { mindist = dist(p,l); - mintag = m_blocks[i].tag; + mintag = block.tag; } } @@ -148,18 +148,18 @@ void Isovist::make(BSPNode *here) if (m_gaps.size()) { int which = here->classify(m_centre); if (which == BSPNode::BSPLEFT) { - if (here->left) - make(here->left); - drawnode(here->line,here->m_tag); - if (here->right) - make(here->right); + if (here->m_left.get()) + make(here->m_left.get()); + drawnode(here->getLine(),here->getTag()); + if (here->m_right) + make(here->m_right.get()); } else { - if (here->right) - make(here->right); - drawnode(here->line,here->m_tag); - if (here->left) - make(here->left); + if (here->m_right.get()) + make(here->m_right.get()); + drawnode(here->getLine(),here->getTag()); + if (here->m_left) + make(here->m_left.get()); } } } @@ -194,61 +194,80 @@ void Isovist::drawnode(const Line& li, int tag) addBlock(li,tag,angle2,angle1); } } - // - for (size_t i = m_gaps.size() - 1; i != paftl::npos; i--) { - if (m_gaps[i].tagdelete) { - m_gaps.remove_at(i); - } + // + for (auto it = m_gaps.begin(); it != m_gaps.end(); ) { + if (it->tagdelete) { + it = m_gaps.erase(it); + } + else { + ++it; + } } } void Isovist::addBlock(const Line& li, int tag, double startangle, double endangle) { - int gap = 0; + auto gap = m_gaps.begin(); bool finished = false; while (!finished) { - while (gap < (int)m_gaps.size() && m_gaps[gap].endangle < startangle) { + while (gap != m_gaps.end() && gap->endangle < startangle) { gap++; } - if (gap < (int)m_gaps.size() && m_gaps[gap].startangle < endangle + 1e-9) { + if (gap != m_gaps.end() && gap->startangle < endangle + 1e-9) { double a,b; - if (m_gaps[gap].startangle > startangle - 1e-9) { - a = m_gaps[gap].startangle; - if (m_gaps[gap].endangle < endangle + 1e-9) { - b = m_gaps[gap].endangle; - m_gaps[gap].tagdelete = true; + if (gap->startangle > startangle - 1e-9) { + a = gap->startangle; + if (gap->endangle < endangle + 1e-9) { + b = gap->endangle; + gap->tagdelete = true; } else { b = endangle; - m_gaps[gap].startangle = endangle; + IsoSeg isoseg = *gap; + isoseg.startangle = endangle; + auto hint = gap; + hint++; + m_gaps.erase(gap); + gap = m_gaps.insert(hint, isoseg); } } else { a = startangle; - if (m_gaps[gap].endangle < endangle + 1e-9) { - b = m_gaps[gap].endangle; - m_gaps[gap].endangle = startangle; + if (gap->endangle < endangle + 1e-9) { + b = gap->endangle; + IsoSeg isoseg = *gap; + isoseg.endangle = startangle; + auto hint = gap; + hint++; + m_gaps.erase(gap); + gap = m_gaps.insert(hint, isoseg); } else { b = endangle; - m_gaps.add(IsoSeg(endangle, m_gaps[gap].endangle, m_gaps[gap].quadrant)); - m_gaps[gap].endangle = startangle; + m_gaps.insert(IsoSeg(endangle, gap->endangle, gap->quadrant)); + IsoSeg isoseg = *gap; + isoseg.endangle = startangle; + auto hint = gap; + hint++; + m_gaps.erase(gap); + gap = m_gaps.insert(hint, isoseg); gap++; // advance past gap just added } } Point2f pa = intersection_point(li,Line(m_centre,m_centre+pointfromangle(a))); Point2f pb = intersection_point(li,Line(m_centre,m_centre+pointfromangle(b))); - m_blocks.add(IsoSeg(a,b,pa,pb,tag)); + m_blocks.insert(IsoSeg(a,b,pa,pb,tag)); } else { finished = true; } + if(gap == m_gaps.end()) break; gap++; } } -void Isovist::setData(AttributeTable& table, int row, bool simple_version) +void Isovist::setData(AttributeTable& table, AttributeRow& row, bool simple_version) { // the area / centre of gravity calculation is a duplicate of the SalaPolygon version, // included here for general information about the isovist @@ -286,58 +305,31 @@ void Isovist::setData(AttributeTable& table, int row, bool simple_version) driftvec.normalise(); double driftang = driftvec.angle(); // - int col = table.getOrInsertColumnIndex("Isovist Area"); - if (col == -1) { - col = table.insertColumn("Isovist Area"); - } - table.setValue(row,col,(float)area); - + int col = table.getOrInsertColumn("Isovist Area"); + row.setValue(col, float(area)); - // dX simple version test // TV -//#define _COMPILE_dX_SIMPLE_VERSION -#ifndef _COMPILE_dX_SIMPLE_VERSION if(!simple_version) { - col = table.getColumnIndex("Isovist Compactness"); - if (col == -1) { - col = table.insertColumn("Isovist Compactness"); - } - table.setValue(row,col, (float)(4.0 * M_PI * area / (m_perimeter*m_perimeter))); + col = table.getOrInsertColumn("Isovist Compactness"); + row.setValue(col, float(4.0 * M_PI * area / (m_perimeter*m_perimeter))); - col = table.getColumnIndex("Isovist Drift Angle"); - if (col == -1) { - col = table.insertColumn("Isovist Drift Angle"); - } - table.setValue(row,col,(float)(180.0*driftang/M_PI)); + col = table.getOrInsertColumn("Isovist Drift Angle"); + row.setValue(col, float(180.0*driftang/M_PI)); - col = table.getColumnIndex("Isovist Drift Magnitude"); - if (col == -1) { - col = table.insertColumn("Isovist Drift Magnitude"); - } - table.setValue(row,col,(float)driftmag); - col = table.getColumnIndex("Isovist Min Radial"); - if (col == -1) { - col = table.insertColumn("Isovist Min Radial"); - } - table.setValue(row,col,(float)m_min_radial); - col = table.getColumnIndex("Isovist Max Radial"); - if (col == -1) { - col = table.insertColumn("Isovist Max Radial"); - } - table.setValue(row,col,(float)m_max_radial); + col = table.getOrInsertColumn("Isovist Drift Magnitude"); + row.setValue(col, float(driftmag)); - col = table.getColumnIndex("Isovist Occlusivity"); - if (col == -1) { - col = table.insertColumn("Isovist Occlusivity"); - } - table.setValue(row,col,(float)m_occluded_perimeter); + col = table.getOrInsertColumn("Isovist Min Radial"); + row.setValue(col, float(m_min_radial)); - col = table.getColumnIndex("Isovist Perimeter"); - if (col == -1) { - col = table.insertColumn("Isovist Perimeter"); - } - table.setValue(row,col,(float)m_perimeter); + col = table.getOrInsertColumn("Isovist Max Radial"); + row.setValue(col, float(m_max_radial)); + + col = table.getOrInsertColumn("Isovist Occlusivity"); + row.setValue(col, float(m_occluded_perimeter)); + + col = table.getOrInsertColumn("Isovist Perimeter"); + row.setValue(col, float(m_perimeter)); } -#endif } diff --git a/salalib/isovist.h b/salalib/isovist.h index f2ba48f5..37f31a35 100644 --- a/salalib/isovist.h +++ b/salalib/isovist.h @@ -18,14 +18,18 @@ // isovist.h -#ifndef __ISOVIST_H__ -#define __ISOVIST_H__ +#pragma once + +#include "salalib/attributetable.h" + +#include "genlib/bsptree.h" +#include // this is very much like sparksieve: struct IsoSeg { - bool tagdelete; + mutable bool tagdelete; double startangle; double endangle; Point2f startpoint; @@ -60,27 +64,25 @@ class Isovist { protected: Point2f m_centre; - pqvector m_blocks; - pqvector m_gaps; - pvecpoint m_poly; - prefvec m_occlusion_points; + std::set m_blocks; + std::set m_gaps; + std::vector m_poly; + std::vector m_occlusion_points; double m_perimeter; double m_occluded_perimeter; double m_max_radial; double m_min_radial; public: Isovist() {;} - const pvecpoint& getPolygon() const { return m_poly; } - const prefvec& getOcclusionPoints() const { return m_occlusion_points; } + const std::vector& getPolygon() const { return m_poly; } + const std::vector& getOcclusionPoints() const { return m_occlusion_points; } const Point2f& getCentre() const { return m_centre; } // void makeit(BSPNode *root, const Point2f& p, const QtRegion& region, double startangle = 0.0, double endangle = 0.0); void make(BSPNode *here); void drawnode(const Line& li, int tag); void addBlock(const Line& li, int tag, double startangle, double endangle); - void setData(AttributeTable& table, int row, bool simple_version); + void setData(AttributeTable &table, AttributeRow &row, bool simple_version); // int getClosestLine(BSPNode *root, const Point2f& p); }; - -#endif diff --git a/salalib/isovistdef.h b/salalib/isovistdef.h new file mode 100644 index 00000000..a4fd1d07 --- /dev/null +++ b/salalib/isovistdef.h @@ -0,0 +1,60 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "genlib/p2dpoly.h" + +class IsovistDefinition +{ +public: + IsovistDefinition( double x, double y, double angle, double viewAngle ) : mLocation(x, y), mAngle(angle), mViewAngle(viewAngle) + { + if ( viewAngle >= 2 * M_PI) + { + mAngle = 0.0; + mViewAngle = 0.0; + } + } + + IsovistDefinition(double x, double y) : mLocation(x,y), mAngle(0), mViewAngle(0) + {} + + const Point2f &getLocation() const { return mLocation;} + double getAngle() const { return mAngle; } + double getViewAngle() const { return mViewAngle; } + double getLeftAngle() const { + double leftAngle = mAngle - 0.5 * mViewAngle; + if (leftAngle < 0 ) + { + leftAngle += 2 * M_PI; + } + return leftAngle; + } + + double getRightAngle() const{ + double rightAngle = mAngle + 0.5 * mViewAngle; + if (rightAngle > 2 * M_PI) + { + rightAngle -= 2 * M_PI; + } + return rightAngle; + } + +private: + Point2f mLocation; + double mAngle; + double mViewAngle; +}; diff --git a/salalib/ivga.h b/salalib/ivga.h new file mode 100644 index 00000000..858adeaa --- /dev/null +++ b/salalib/ivga.h @@ -0,0 +1,32 @@ +// Copyright (C) 2018 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +// Interface to handle different kinds of VGA analysis + +#include "salalib/mgraph.h" +#include "salalib/pointdata.h" + +#include "genlib/comm.h" + +#include + +class IVGA { + public: + virtual std::string getAnalysisName() const = 0; + virtual bool run(Communicator *comm, PointMap &map, bool simple_version) = 0; + virtual ~IVGA() {} +}; diff --git a/salalib/layermanager.h b/salalib/layermanager.h new file mode 100644 index 00000000..fd00af0a --- /dev/null +++ b/salalib/layermanager.h @@ -0,0 +1,92 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once +#include +#include +#include + + +class LayerManager +{ +public: + typedef int64_t KeyType; + virtual size_t addLayer(const std::string &layerName) = 0; + virtual const std::string& getLayerName(size_t index) const = 0; + virtual size_t getLayerIndex(const std::string &layerName) const = 0; + virtual void setLayerVisible( size_t layerIndex, bool visible = true ) = 0; + virtual bool isLayerVisible( size_t layerIndex ) const = 0; + virtual size_t getNumLayers() const = 0; + + virtual KeyType getKey(size_t layerIndex) const = 0; + virtual bool isVisible( const KeyType &key ) const = 0; + + virtual void read(std::istream& stream) = 0; + virtual void write(std::ostream& stream) const = 0; + + virtual ~LayerManager(){} + +public: + class OutOfLayersException : depthmapX::BaseException + { + public: + OutOfLayersException() + {} + OutOfLayersException(const std::string &message) : depthmapX::BaseException(message.c_str()) + { + } + }; + + class DuplicateKeyException : depthmapX::BaseException + { + public: + DuplicateKeyException() + {} + DuplicateKeyException(const std::string &message) : depthmapX::BaseException(message.c_str()) + { + } + }; + +}; + +class LayerAware +{ +public: + virtual void setLayerKey( const LayerManager::KeyType & key) + { + m_layerKey = key; + } + + virtual const LayerManager::KeyType& getLayerKey() const + { + return m_layerKey; + } + + virtual ~LayerAware(){} + +protected: + LayerManager::KeyType m_layerKey; +}; + + +inline bool isObjectVisible(const LayerManager& manager, const LayerAware& object ) +{ + return manager.isVisible(object.getLayerKey()); +} + +inline void addLayerToObject(LayerAware& object, const LayerManager::KeyType& layerKey) +{ + object.setLayerKey(object.getLayerKey() | layerKey); +} diff --git a/salalib/layermanagerimpl.cpp b/salalib/layermanagerimpl.cpp new file mode 100644 index 00000000..3d1e2a68 --- /dev/null +++ b/salalib/layermanagerimpl.cpp @@ -0,0 +1,185 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "layermanagerimpl.h" +#include + +LayerManagerImpl::LayerManagerImpl() : m_visibleLayers(1) +{ + m_layers.push_back("Everything"); + m_layerLookup["Everything"] = 0; +} + +size_t LayerManagerImpl::addLayer(const std::string &layerName) +{ + size_t newLayerIndex = m_layers.size(); + if (newLayerIndex > 63) + { + throw OutOfLayersException(); + } + auto result = m_layerLookup.insert(std::make_pair(layerName, newLayerIndex)); + if (!result.second) + { + throw DuplicateKeyException(std::string("Trying to insert duplicate key: ") + layerName); + } + m_layers.push_back(layerName); + return newLayerIndex; +} + +const std::string& LayerManagerImpl::getLayerName(size_t index) const +{ + checkIndex(index); + return m_layers[index]; +} + +size_t LayerManagerImpl::getLayerIndex(const std::string &layerName) const +{ + auto iter = m_layerLookup.find(layerName); + if ( iter == m_layerLookup.end()) + { + throw std::out_of_range("Unknown layer name"); + } + return iter->second; +} + +void LayerManagerImpl::setLayerVisible(size_t layerIndex, bool visible) +{ + checkIndex(layerIndex); + if (layerIndex == 0) + { + // this it the everything layer - if switching on just show everything, else switch everything off + m_visibleLayers = visible ? 1 : 0; + return; + } + int64_t layerValue = ((KeyType)1) << layerIndex; + + // if visible, switch on this layer and switch everything layer off, else just switch off this layer + if (visible) + { + m_visibleLayers = (m_visibleLayers | layerValue) & (~0x1); + } + else + { + m_visibleLayers &= (~layerValue); + } +} + +bool LayerManagerImpl::isLayerVisible(size_t layerIndex) const +{ + checkIndex(layerIndex); + return isVisible(getKey(layerIndex)); +} + +bool LayerManagerImpl::isVisible(const KeyType &key) const +{ + return (m_visibleLayers & key) != 0; +} + +void LayerManagerImpl::read(std::istream &stream) +{ + m_layerLookup.clear(); + m_layers.clear(); + KeyType dummy; + stream.read((char *)&dummy, sizeof(dummy)); + stream.read((char *)&m_visibleLayers, sizeof(m_visibleLayers)); + int count; + stream.read((char *)&count, sizeof(int)); + for( int i = 0; i < count; ++i) + { + stream.read((char *)&dummy, sizeof(dummy)); + m_layers.push_back(dXstring::readString(stream)); + m_layerLookup[m_layers.back()] = i; + } +} + +void LayerManagerImpl::write(std::ostream &stream) const +{ + // KeyType availableLayers = 0; + // for (size_t i = m_layers.size(); i < 64; ++i) + // { + // availableLayers |= ((KeyType)1) << i; + // } + + // TODO: (PK) While the above seems to me like the sane solution and potentially + // what the intention was in the original implementation, the one in the old + // attributes table seems to be messed up because of its starting value. + // Therefore, for temporary binary compatibility at least until the new + // attributes table is in place the original solution is used here as found + // in AttributeTable::selectionToLayer(): + + int64_t availableLayers = 0xffffffff << (32 + 0xfffffffe); + // should have been: + // int64_t availableLayers = (int64_t(0xffffffff) << 32) + 0xfffffffe; + + for (size_t i = 1; i < 64 & i < m_layers.size(); ++i) { + int loc = 1; + while (loc < 64 && ((availableLayers>>loc) & 0x1) == 0) { + loc++; + } + if (loc == 64) { + // too many layers -- maximum 64 + throw OutOfLayersException(); + } + int64_t newlayer = 0x1 << loc; + // now layer has been found, eliminate from available layers + // and add a lookup for the name + availableLayers = (availableLayers & (~newlayer)); + } + + + stream.write((const char *)&availableLayers, sizeof(KeyType)); + stream.write((const char *)&m_visibleLayers, sizeof(KeyType)); + int size_as_int = (int)m_layers.size(); + stream.write((const char *)&size_as_int, sizeof(int)); + + availableLayers = 0xffffffff << (32 + 0xfffffffe); + int64_t newlayer = 0x1; + stream.write((const char *)&newlayer, sizeof(KeyType)); + dXstring::writeString(stream, m_layers[0]); + for ( size_t i = 1; i < m_layers.size(); ++i) + { + // again keeping binary comatibility +// KeyType key = ((KeyType)1) << i; +// stream.write((const char *)&key, sizeof(KeyType)); +// dXstring::writeString(stream,m_layers[i]); + + int loc = 1; + while (loc < 64 && ((availableLayers>>loc) & 0x1) == 0) { + loc++; + } + if (loc == 64) { + // too many layers -- maximum 64 + throw OutOfLayersException(); + } + newlayer = 0x1 << loc; + stream.write((const char *)&newlayer, sizeof(KeyType)); + dXstring::writeString(stream, m_layers[i]); + } +} + + +LayerManager::KeyType LayerManagerImpl::getKey(size_t layerIndex) const +{ + return ((int64_t)1) << layerIndex; +} + +void LayerManagerImpl::checkIndex(size_t index) const +{ + if(index >= m_layers.size()) + { + throw std::out_of_range("Invalid layer index"); + } +} + diff --git a/salalib/layermanagerimpl.h b/salalib/layermanagerimpl.h new file mode 100644 index 00000000..666a0924 --- /dev/null +++ b/salalib/layermanagerimpl.h @@ -0,0 +1,51 @@ +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once +#include "layermanager.h" +#include +#include + +class LayerManagerImpl : public LayerManager +{ + + + // LayerManager interface +public: + LayerManagerImpl(); + virtual size_t addLayer(const std::string &layerName); + virtual const std::string& getLayerName(size_t index) const; + virtual size_t getLayerIndex(const std::string &layerName) const; + virtual void setLayerVisible(size_t layerIndex, bool visible); + virtual bool isLayerVisible(size_t layerIndex) const; + virtual size_t getNumLayers() const {return m_layers.size();} + + virtual KeyType getKey(size_t layerIndex) const; + virtual bool isVisible(const KeyType &key) const; + + virtual void read(std::istream& stream); + virtual void write(std::ostream& stream ) const; + +private: + void checkIndex(size_t index) const; + +private: + int64_t m_visibleLayers; + std::vector m_layers; + std::map m_layerLookup; + + +}; + diff --git a/salalib/linkutils.cpp b/salalib/linkutils.cpp new file mode 100644 index 00000000..34235597 --- /dev/null +++ b/salalib/linkutils.cpp @@ -0,0 +1,115 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "linkutils.h" +#include + +namespace depthmapX { + std::vector pixelateMergeLines(const std::vector& mergeLines, PointMap& currentMap) + { + std::vector mergePixelPairs; + + std::vector::const_iterator iter = mergeLines.begin(), end = + mergeLines.end(); + for ( ; iter != end; ++iter ) + { + const Line & mergeLine = *iter; + const PixelRef & a = currentMap.pixelate(mergeLine.start(), false); + const PixelRef & b = currentMap.pixelate(mergeLine.end(), false); + + mergePixelPairs.push_back(PixelRefPair(a, b)); + } + return mergePixelPairs; + } + + void mergePixelPairs(const std::vector& links, PointMap& currentMap) { + + // check if any link pixel already exists on the map + std::vector::const_iterator iter = links.begin(), end = + links.end(); + for ( ; iter != end; ++iter ) + { + const PixelRefPair link = *iter; + + // check in limits: + if (!currentMap.includes(link.a) || !currentMap.getPoint(link.a).filled() + || !currentMap.includes(link.b) || !currentMap.getPoint(link.b).filled()) + { + std::stringstream message; + message << "Line ends not both on painted analysis space (index: " + << (iter - links.begin() + 1) + << ")" << std::flush; + throw depthmapX::InvalidLinkException(message.str().c_str()); + } + + // check if we were given coordinates that fall on a previously + // merged cell, in which case the newest given will replace the + // oldest and effectively delete the whole link + if(currentMap.isPixelMerged(link.a) + || currentMap.isPixelMerged(link.b)) + { + // one of the cells is already on the map + std::stringstream message; + message << "Link pixel found that is already linked on the map (index: " + << (iter - links.begin() + 1) + << ")" + << std::flush; + throw depthmapX::InvalidLinkException(message.str().c_str()); + } + + // also check if given links have overlapping pixels: + std::vector::const_iterator prevIter = links.begin(); + for ( ; prevIter != iter; ++prevIter ) + { + const PixelRefPair prevLink = *prevIter; + + // PixelRefPair internal == operator only checks a with a and b with b + // but we also need to check the inverse + if(link.a == prevLink.a + || link.b == prevLink.b + || link.a == prevLink.b + || link.b == prevLink.a) + { + // one of the cells has already been seen. + std::stringstream message; + message << "Overlapping link found (index: " + << (iter - links.begin() + 1) + << ")" << std::flush; + throw depthmapX::InvalidLinkException(message.str().c_str()); + } + } + } + std::for_each(links.begin(), links.end(), + [&](const PixelRefPair &pair)->void{ currentMap.mergePixels(pair.a,pair.b); }); + } + + std::vector getMergedPixelsAsLines(PointMap& currentMap) + { + std::vector mergedPixelsAsLines; + std::vector> mergedPixelPairs = currentMap.getMergedPixelPairs(); + + std::vector>::const_iterator iter = mergedPixelPairs.begin(), end = + mergedPixelPairs.end(); + for ( ; iter != end; ++iter ) + { + std::pair pixelPair = *iter; + mergedPixelsAsLines.push_back(SimpleLine( + currentMap.depixelate(pixelPair.first), + currentMap.depixelate(pixelPair.second) + )); + } + return mergedPixelsAsLines; + } +} diff --git a/salalib/linkutils.h b/salalib/linkutils.h new file mode 100644 index 00000000..d0534d3b --- /dev/null +++ b/salalib/linkutils.h @@ -0,0 +1,33 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "mgraph.h" +#include "genlib/exceptions.h" +#include + +namespace depthmapX { + + class InvalidLinkException : public depthmapX::BaseException + { + public: + InvalidLinkException(std::string message) : depthmapX::BaseException(message) + {} + }; + std::vector pixelateMergeLines(const std::vector& mergeLines, PointMap& currentMap); + void mergePixelPairs(const std::vector &links, PointMap& currentMap); + std::vector getMergedPixelsAsLines(PointMap& currentMap); +} diff --git a/salalib/mapconverter.cpp b/salalib/mapconverter.cpp new file mode 100644 index 00000000..fd4c7c36 --- /dev/null +++ b/salalib/mapconverter.cpp @@ -0,0 +1,538 @@ +#include "salalib/mapconverter.h" +#include "salalib/tidylines.h" + +#include "genlib/exceptions.h" + +#include + +// convert line layers to an axial map + +std::unique_ptr MapConverter::convertDrawingToAxial(Communicator *comm, const std::string& name, + const std::vector &drawingFiles) +{ + if (comm) { + comm->CommPostMessage( Communicator::NUM_STEPS, 2 ); + comm->CommPostMessage( Communicator::CURRENT_STEP, 1 ); + } + + QtRegion region; + std::map lines; // map required for tidy lines, otherwise acts like vector + std::map layers; // this is used to say which layer it originated from + + bool recordlayer = false; + + // add all visible layers to the set of polygon lines... + int count = 0; + for (const auto& pixelGroup: drawingFiles) { + int j = 0; + for (const auto& pixel: pixelGroup.m_spacePixels) { + if (pixel.isShown()) { + if (region.atZero()) { + region = pixel.getRegion(); + } + else { + region = runion(region, pixel.getRegion()); + } + std::vector newLines = pixel.getAllShapesAsLines(); + for (const auto& line: newLines) { + lines.insert(std::make_pair(count, Line(line.start(), line.end()))); + layers.insert(std::make_pair(count,j)); + count ++; + } + pixel.setShow(false); + } + if (j > 0) { + recordlayer = true; + } + j++; + } + } + if (count == 0) { + // TODO: write a better error message + throw depthmapX::RuntimeException("Failed to convert lines"); + } + + // quick tidy removes very short and duplicate lines, but does not merge overlapping lines + TidyLines tidier; + tidier.quicktidy(lines, region); + if (lines.size() == 0) { + throw depthmapX::RuntimeException("No lines found after removing short and duplicates"); + } + + if (comm) { + comm->CommPostMessage( Communicator::CURRENT_STEP, 2 ); + } + + // create map layer... + // we can stop here for all line axial map! + std::unique_ptr usermap(new ShapeGraph(name,ShapeMap::AXIALMAP)); + + usermap->init(int(lines.size()),region); // used to be double density + std::map layerAttributes; + usermap->initialiseAttributesAxial(); + int layerCol = -1; + if (recordlayer) { + layerCol = usermap->getAttributeTable().getOrInsertColumn("Drawing Layer"); + } + for (auto & line: lines) { + if (recordlayer) + { + layerAttributes[layerCol] = float(layers.find(line.first)->second); + } + usermap->makeLineShape(line.second, false, false, layerAttributes ); + } + + usermap->makeConnections(); + + return usermap; +} + +// create axial map directly from data maps +// note that actually should be able to merge this code with the line layers, now both use similar code + +std::unique_ptr MapConverter::convertDataToAxial(Communicator *comm, const std::string& name, + ShapeMap& shapemap, bool copydata) +{ + if (comm) { + comm->CommPostMessage( Communicator::NUM_STEPS, 2 ); + comm->CommPostMessage( Communicator::CURRENT_STEP, 1 ); + } + + // add all visible layers to the set of polygon lines... + + std::map lines; + std::map keys; + + //m_region = shapemap.getRegion(); + QtRegion region = shapemap.getRegion(); + + // add all visible layers to the set of polygon lines... + + int count = 0; + for (auto shape: shapemap.getAllShapes()) { + int key = shape.first; + + std::vector shapeLines = shape.second.getAsLines(); + for(Line line: shapeLines) { + lines.insert(std::make_pair(count,line)); + keys.insert(std::make_pair(count,key)); + count++; + } + } + if (lines.size() == 0) { + throw depthmapX::RuntimeException("No lines found in data map"); + } + + // quick tidy removes very short and duplicate lines, but does not merge overlapping lines + TidyLines tidier; + tidier.quicktidy(lines, region); + if (lines.size() == 0) { + throw depthmapX::RuntimeException("No lines found after removing short and duplicates"); + } + + if (comm) { + comm->CommPostMessage( Communicator::CURRENT_STEP, 2 ); + } + + // create map layer... + // we can stop here for all line axial map! + std::unique_ptr usermap(new ShapeGraph(name,ShapeMap::AXIALMAP)); + + usermap->init(int(lines.size()),region); // used to be double density + usermap->initialiseAttributesAxial(); + + usermap->getAttributeTable().insertOrResetColumn("Data Map Ref"); + + std::map extraAttr; + std::map inOutColumns; + if (copydata) { + AttributeTable& input = shapemap.getAttributeTable(); + AttributeTable& output = usermap->getAttributeTable(); + + // TODO: Compatibility. The columns are sorted in the old implementation so + // they are also passed sorted in the conversion: + + std::vector indices(input.getNumColumns()); + std::iota(indices.begin(), indices.end(), static_cast(0)); + + std::sort(indices.begin(), indices.end(), + [&](size_t a, size_t b) { + return input.getColumnName(a) < input.getColumnName(b); + }); + + std::vector newColumns; + for (size_t i = 0; i < indices.size(); i++) { + int idx = indices[i]; + std::string colname = input.getColumnName(idx); + for (size_t k = 1; output.hasColumn(colname); k++){ + colname = dXstring::formatString(int(k), input.getColumnName(idx) + " %d"); + } + newColumns.push_back(colname); + output.insertOrResetColumn(colname); + } + for (size_t i = 0; i < indices.size(); i++) { + inOutColumns[indices[i]] = output.getOrInsertColumn(newColumns[i]); + } + } + + int dataMapShapeRefCol = usermap->getAttributeTable().getOrInsertColumn("Data Map Ref"); + + AttributeTable& input = shapemap.getAttributeTable(); + auto keyIter = keys.begin(); + for (auto& line: lines) { + if (copydata){ + auto& row = input.getRow(AttributeKey(keyIter->second)); + for (auto inOutColumn: inOutColumns){ + extraAttr[inOutColumn.second] = row.getValue(inOutColumn.first); + } + } + extraAttr[dataMapShapeRefCol] = keyIter->second; + usermap->makeLineShape(line.second, false, false, extraAttr); + ++keyIter; + } + + // n.b. make connections also initialises attributes + + usermap->makeConnections(); + + // if we are inheriting from a mapinfo map, pass on the coordsys and bounds: + if (shapemap.hasMapInfoData()) { + usermap->copyMapInfoBaseData(shapemap); + } + + return usermap; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +// yet more conversions, this time polygons to shape elements + +std::unique_ptr MapConverter::convertDrawingToConvex(Communicator *, const std::string& name, + const std::vector &drawingFiles) +{ + std::unique_ptr usermap(new ShapeGraph(name,ShapeMap::CONVEXMAP)); + int conn_col = usermap->getAttributeTable().insertOrResetLockedColumn("Connectivity"); + + size_t count = 0; + + for (const auto& pixelGroup: drawingFiles) { + for (const auto& pixel: pixelGroup.m_spacePixels) { + if (pixel.isShown()) { + auto refShapes = pixel.getAllShapes(); + for (const auto& refShape: refShapes) { + const SalaShape& shape = refShape.second; + if (shape.isPolygon()) { + int newShapeRef = usermap->makeShape(shape); + usermap->getConnections().push_back( Connector() ); + usermap->getAttributeTable().getRow(AttributeKey(newShapeRef)).setValue(conn_col,0); + count++; + } + } + } + } + } + if (count == 0) { + throw depthmapX::RuntimeException("No polygons found in drawing"); + } + + for (const auto& pixelGroup: drawingFiles) { + for (const auto& pixel: pixelGroup.m_spacePixels) { + pixel.setShow(false); + } + } + + return usermap; +} + +std::unique_ptr MapConverter::convertDataToConvex(Communicator *, const std::string& name, + ShapeMap& shapemap, bool copydata) +{ + std::unique_ptr usermap(new ShapeGraph(name,ShapeMap::CONVEXMAP)); + int conn_col = usermap->getAttributeTable().insertOrResetLockedColumn("Connectivity"); + + std::vector lookup; + auto refShapes = shapemap.getAllShapes(); + std::map extraAttr; + std::vector attrCols; + AttributeTable& input = shapemap.getAttributeTable(); + if (copydata) { + AttributeTable& output = usermap->getAttributeTable(); + for (size_t i = 0; i < input.getNumColumns(); i++) { + std::string colname = input.getColumnName(i); + for (int k = 1; static_cast(output.getColumnIndex(colname)) != -1; k++){ + colname = dXstring::formatString(k,input.getColumnName(i) + " %d"); + } + attrCols.push_back(output.insertOrResetColumn(colname)); + } + } + + for (auto refShape: refShapes) { + if ( copydata ){ + for ( size_t i = 0; i < input.getNumColumns(); ++i ){ + extraAttr[attrCols[size_t(i)]] = input.getRow(AttributeKey(refShape.first)).getValue(i); + } + } + SalaShape& shape = refShape.second; + if (shape.isPolygon()) { + int n = usermap->makeShape(shape, -1, extraAttr); + usermap->getConnections().push_back( Connector() ); + usermap->getAttributeTable().getRow(AttributeKey(n)).setValue(conn_col,0); + } + } + if (usermap->getShapeCount() == 0) { + throw depthmapX::RuntimeException("No polygons found in data map"); + } + + return usermap; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +// create segment map directly from line layers + +std::unique_ptr MapConverter::convertDrawingToSegment(Communicator *comm, const std::string& name, + const std::vector &drawingFiles) +{ + if (comm) { + comm->CommPostMessage( Communicator::NUM_STEPS, 2 ); + comm->CommPostMessage( Communicator::CURRENT_STEP, 1 ); + } + + std::map lines; + std::map layers; // this is used to say which layer it originated from + bool recordlayer = false; + + QtRegion region; + + // add all visible layers to the set of polygon lines... + int count = 0; + for (const auto& pixelGroup: drawingFiles) { + int j = 0; + for (const auto& pixel: pixelGroup.m_spacePixels) { + if (pixel.isShown()) { + if (region.atZero()) { + region = pixel.getRegion(); + } + else { + region = runion(region, pixel.getRegion()); + } + std::vector newLines = pixel.getAllShapesAsLines(); + for (const auto& line: newLines) { + lines.insert(std::make_pair(count, Line(line.start(), line.end()))); + layers.insert(std::make_pair(count,j)); + count++; + } + pixel.setShow(false); + } + if (j > 0) { + recordlayer = true; + } + j++; + } + } + if (count == 0) { + throw depthmapX::RuntimeException("No lines found in drawing"); + } + + // quick tidy removes very short and duplicate lines, but does not merge overlapping lines + TidyLines tidier; + tidier.quicktidy(lines, region); + if (lines.size() == 0) { + throw depthmapX::RuntimeException("No lines found after removing short and duplicates"); + } + + if (comm) { + comm->CommPostMessage( Communicator::CURRENT_STEP, 2 ); + } + + // create map layer... + // we can stop here for all line axial map! + std::unique_ptr usermap(new ShapeGraph(name,ShapeMap::SEGMENTMAP)); + + usermap->init(int(lines.size()),region); + std::map layerAttributes; + usermap->initialiseAttributesSegment(); + int layerCol = -1; + if (recordlayer) { + layerCol = usermap->getAttributeTable().insertOrResetColumn("Drawing Layer"); + } + for (auto & line: lines) { + if (recordlayer) + { + layerAttributes[layerCol] = float(layers.find(line.first)->second); + } + usermap->makeLineShape(line.second, false, false, layerAttributes); + } + + // make it! + usermap->makeNewSegMap(); + + return usermap; +} + +// create segment map directly from data maps (ultimately, this will replace the line layers version) + +std::unique_ptr MapConverter::convertDataToSegment(Communicator *comm, const std::string& name, + ShapeMap& shapemap, bool copydata) +{ + if (comm) { + comm->CommPostMessage( Communicator::NUM_STEPS, 2 ); + comm->CommPostMessage( Communicator::CURRENT_STEP, 1 ); + } + + std::map lines; + std::map keys; + + // no longer requires m_region + //m_region = shapemap.getRegion(); + QtRegion region = shapemap.getRegion(); + + // add all visible layers to the set of polygon lines... + + int count = 0; + for (auto shape: shapemap.getAllShapes()) { + int key = shape.first; + std::vector shapeLines = shape.second.getAsLines(); + for(Line line: shapeLines) { + lines.insert(std::make_pair(count,line)); + keys.insert(std::make_pair(count,key)); + count++; + } + } + if (lines.size() == 0) { + throw depthmapX::RuntimeException("No lines found in data map"); + } + + // quick tidy removes very short and duplicate lines, but does not merge overlapping lines + TidyLines tidier; + tidier.quicktidy(lines, region); + + if (lines.size() == 0) { + throw depthmapX::RuntimeException("No lines found after removing short and duplicates"); + } + + if (comm) { + comm->CommPostMessage( Communicator::CURRENT_STEP, 2 ); + } + + // create map layer... + // note, I may need to reuse this: + std::unique_ptr usermap(new ShapeGraph(name,ShapeMap::SEGMENTMAP)); + + // if we are inheriting from a mapinfo map, pass on the coordsys and bounds: + if (shapemap.hasMapInfoData()) { + usermap->copyMapInfoBaseData(shapemap); + } + + usermap->init(int(lines.size()),region); + usermap->initialiseAttributesSegment(); + + usermap->getAttributeTable().insertOrResetColumn("Data Map Ref"); + + std::map extraAttr; + std::map inOutColumns; + if (copydata) { + AttributeTable& input = shapemap.getAttributeTable(); + AttributeTable& output = usermap->getAttributeTable(); + + // TODO: Compatibility. The columns are sorted in the old implementation so + // they are also passed sorted in the conversion: + + std::vector indices(input.getNumColumns()); + std::iota(indices.begin(), indices.end(), static_cast(0)); + + std::sort(indices.begin(), indices.end(), + [&](size_t a, size_t b) { + return input.getColumnName(a) < input.getColumnName(b); + }); + + std::vector newColumns; + for (size_t i = 0; i < indices.size(); i++) { + int idx = indices[i]; + std::string colname = input.getColumnName(idx); + for (size_t k = 1; output.hasColumn(colname); k++){ + colname = dXstring::formatString(int(k), input.getColumnName(idx) + " %d"); + } + newColumns.push_back(colname); + output.insertOrResetColumn(colname); + } + for (size_t i = 0; i < indices.size(); i++) { + inOutColumns[indices[i]] = output.getOrInsertColumn(newColumns[i]); + } + } + + int dataMapShapeRefCol = usermap->getAttributeTable().getOrInsertColumn("Data Map Ref"); + + AttributeTable& input = shapemap.getAttributeTable(); + auto keyIter = keys.begin(); + for (auto& line: lines) { + if (copydata){ + auto& row = input.getRow(AttributeKey(keyIter->second)); + for (auto inOutColumn: inOutColumns){ + extraAttr[inOutColumn.second] = row.getValue(inOutColumn.first); + } + } + extraAttr[dataMapShapeRefCol] = keyIter->second; + usermap->makeLineShape(line.second, false, false, extraAttr); + ++keyIter; + } + + // start to be a little bit more efficient about memory now we are hitting the limits + // from time to time: + if (!copydata) { + lines.clear(); + } + + // make it! + usermap->makeNewSegMap(); + + return usermap; +} + +// stubremoval is fraction of overhanging line length before axial "stub" is removed +std::unique_ptr MapConverter::convertAxialToSegment(Communicator *, ShapeGraph& axialMap, + const std::string& name, bool keeporiginal, + bool copydata, double stubremoval) +{ + std::vector lines; + std::vector connectionset; + + axialMap.makeSegmentMap(lines, connectionset, stubremoval); + + // destroy unnecessary parts of axial map as quickly as possible in order not to overload memory + if (!keeporiginal) { + axialMap.getAllShapes().clear(); + axialMap.getConnections().clear(); + } + + // create map layer... + std::unique_ptr segmap(new ShapeGraph(name,ShapeMap::SEGMENTMAP)); + + segmap->init(int(lines.size()),axialMap.getRegion()); + segmap->initialiseAttributesSegment(); + + for (size_t k = 0; k < lines.size(); k++) { + segmap->makeLineShape(lines[k]); + } + + // clear data as soon as we do not need it: + lines.clear(); + + // if we are inheriting from a mapinfo map, pass on the coordsys and bounds: + if (axialMap.hasMapInfoData()) { + segmap->copyMapInfoBaseData(axialMap); + } + + + segmap->makeSegmentConnections(connectionset); + + if (copydata) { + segmap->pushAxialValues(axialMap); + } + // destroy unnecessary parts of axial map as quickly as possible in order not to overload memory + if (!keeporiginal) { + axialMap.getAttributeTable().clear(); + } + + return segmap; +} diff --git a/salalib/mapconverter.h b/salalib/mapconverter.h new file mode 100644 index 00000000..17cb311b --- /dev/null +++ b/salalib/mapconverter.h @@ -0,0 +1,26 @@ +#pragma once + +#include "salalib/axialmap.h" +#include "salalib/shapemap.h" +#include "salalib/spacepixfile.h" +#include "genlib/comm.h" + +namespace MapConverter { + +std::unique_ptr convertDrawingToAxial(Communicator *comm, const std::string& name, + const std::vector &drawingFiles); +std::unique_ptr convertDataToAxial(Communicator *comm, const std::string& name, + ShapeMap& shapemap, bool copydata = false); +std::unique_ptr convertDrawingToConvex(Communicator *, const std::string& name, + const std::vector &drawingFiles); +std::unique_ptr convertDataToConvex(Communicator *, const std::string& name, + ShapeMap& shapemap, bool copydata = false); +std::unique_ptr convertDrawingToSegment(Communicator *comm, const std::string& name, + const std::vector &drawingFiles); +std::unique_ptr convertDataToSegment(Communicator *comm, const std::string& name, + ShapeMap& shapemap, bool copydata = false); +std::unique_ptr convertAxialToSegment(Communicator *, ShapeGraph& axialMap, + const std::string& name, bool keeporiginal = true, + bool pushvalues = false, double stubremoval = 0.0); + +} diff --git a/salalib/mgraph.cpp b/salalib/mgraph.cpp index 967acc2e..4d55929c 100644 --- a/salalib/mgraph.cpp +++ b/salalib/mgraph.cpp @@ -18,40 +18,56 @@ // The meta graph -#include -#include -#include -#include -#include -#include -#include - -#include "isovist.h" -#include "ntfp.h" -#include "tigerp.h" -#include "gmlmap.h" -#include - -// shouldn't really include this -- required for node in PushValuesToLayer -#include - -// Quick mod - TV -#pragma warning (disable: 4800) - -/////////////////////////////////////////////////////////////////////////////////// - -MetaGraph::MetaGraph() +#include "salalib/alllinemap.h" +#include "salalib/mapconverter.h" +#include "salalib/isovist.h" +#include "salalib/mgraph.h" + +#include "salalib/importutils.h" +#include "salalib/parsers/ntfp.h" +#include "salalib/parsers/tigerp.h" +#include "salalib/parsers/dxfp.h" + +#include "salalib/segmmodules/segmangular.h" +#include "salalib/segmmodules/segmtulip.h" +#include "salalib/segmmodules/segmtulipdepth.h" +#include "salalib/segmmodules/segmmetric.h" +#include "salalib/segmmodules/segmmetricpd.h" +#include "salalib/segmmodules/segmtopological.h" +#include "salalib/segmmodules/segmtopologicalpd.h" +#include "salalib/axialmodules/axialintegration.h" +#include "salalib/axialmodules/axialstepdepth.h" +#include "salalib/vgamodules/vgaisovist.h" +#include "salalib/vgamodules/vgavisualglobal.h" +#include "salalib/vgamodules/vgavisualglobaldepth.h" +#include "salalib/vgamodules/vgavisuallocal.h" +#include "salalib/vgamodules/vgametric.h" +#include "salalib/vgamodules/vgametricdepth.h" +#include "salalib/vgamodules/vgaangular.h" +#include "salalib/vgamodules/vgaangulardepth.h" +#include "salalib/vgamodules/vgathroughvision.h" +#include "salalib/agents/agenthelpers.h" + +#include "mgraph440/mgraph.h" + +#include "genlib/pafmath.h" +#include "genlib/p2dpoly.h" +#include "genlib/comm.h" + +#include "math.h" +#include "time.h" + +#include +#include + + +MetaGraph::MetaGraph(std::string name) { + m_name = name; m_state = 0; - m_lock = NULL; m_view_class = VIEWNONE; m_file_version = -1; // <- if unsaved, file version is -1 - // Standard layers no longer added: the gates layer will be initialised with the first push to layer, - // or when made from axial lines. - - m_attr_conv_table = NULL; - // whether or not showing text / grid saved with file: m_showtext = false; m_showgrid = false; @@ -72,12 +88,12 @@ MetaGraph::~MetaGraph() QtRegion MetaGraph::getBoundingBox() const { - QtRegion bounds = SuperSpacePixel::getRegion(); - if (bounds.isNull() && ((getState() & MetaGraph::SHAPEGRAPHS) == MetaGraph::SHAPEGRAPHS)) { - bounds = m_shape_graphs.getBoundingBox(); + QtRegion bounds = m_region; + if (bounds.atZero() && ((getState() & MetaGraph::SHAPEGRAPHS) == MetaGraph::SHAPEGRAPHS)) { + bounds = getDisplayedShapeGraph().getRegion(); } - if (bounds.isNull() && ((getState() & MetaGraph::DATAMAPS) == MetaGraph::DATAMAPS)) { - bounds = m_data_maps.getBoundingBox(); + if (bounds.atZero() && ((getState() & MetaGraph::DATAMAPS) == MetaGraph::DATAMAPS)) { + bounds = getDisplayedDataMap().getRegion(); } return bounds; } @@ -194,40 +210,19 @@ double MetaGraph::getLocationValue(const Point2f& point) val = getDisplayedPointMap().getLocationValue(point); } else if (viewingProcessedLines()) { - val = m_shape_graphs.getDisplayedMap().getLocationValue(point); + val = getDisplayedShapeGraph().getLocationValue(point); } else if (viewingProcessedShapes()) { - val = m_data_maps.getDisplayedMap().getLocationValue(point); + val = getDisplayedDataMap().getLocationValue(point); } return val; } -void MetaGraph::copyLineData(const SuperSpacePixel& meta) -{ - m_state &= ~LINEDATA; - - *(SuperSpacePixel *)this = meta; - - PointMaps::setSpacePixel( (SuperSpacePixel *) this ); // <- also helpfully gives PointMap the space pixel - - m_state |= LINEDATA; -} - -void MetaGraph::copyPointMap(const PointMap& meta) -{ - m_state &= ~POINTMAPS; - - *(PointMap *)this = meta; - - m_state |= POINTMAPS; -} - bool MetaGraph::setGrid( double spacing, const Point2f& offset ) { m_state &= ~POINTMAPS; - getDisplayedPointMap().setSpacePixel( (SuperSpacePixel *) this ); getDisplayedPointMap().setGrid( spacing, offset ); m_state |= POINTMAPS; @@ -260,28 +255,9 @@ bool MetaGraph::makePoints( const Point2f& p, int fill_type , Communicator *comm return true; } -bool MetaGraph::undoPoints() -{ - bool b_return = getDisplayedPointMap().undoPoints(); -/* - if (PointMap::m_point_count == 0) { - m_state &= ~POINTS; - } - else { - m_state |= POINTS; - } -*/ - return b_return; -} - bool MetaGraph::clearPoints() { bool b_return = getDisplayedPointMap().clearPoints(); -/* - if (PointMap::m_point_count == 0) { - m_state &= ~POINTS; - } -*/ return b_return; } @@ -290,48 +266,59 @@ bool MetaGraph::makeGraph( Communicator *communicator, int algorithm, double max // this is essentially a version tag, and remains for historical reasons: m_state |= ANGULARGRAPH; - bool retvar = false; + bool graphMade = false; try { // algorithm is now used for boundary graph option (as a simple boolean) - retvar = getDisplayedPointMap().sparkGraph2(communicator, (algorithm != 0), maxdist); + graphMade = getDisplayedPointMap().sparkGraph2(communicator, (algorithm != 0), maxdist); } catch (Communicator::CancelledException) { - retvar = false; + graphMade = false; } - if (retvar) { + if (graphMade) { + setViewClass(SHOWVGATOP); + } + + return graphMade; +} + +bool MetaGraph::unmakeGraph(bool removeLinks) +{ + bool graphUnmade = getDisplayedPointMap().unmake(removeLinks); + + if (graphUnmade) { setViewClass(SHOWVGATOP); } - return retvar; + return graphUnmade; } bool MetaGraph::analyseGraph( Communicator *communicator, Options options , bool simple_version ) // <- options copied to keep thread safe { - bool retvar = false; + bool analysisCompleted = false; if (options.point_depth_selection) { - if (m_view_class & VIEWVGA && !PointMaps::getDisplayedPointMap().isSelected()) { + if (m_view_class & VIEWVGA && !getDisplayedPointMap().isSelected()) { return false; } - else if (m_view_class & VIEWAXIAL && !m_shape_graphs.getDisplayedMap().isSelected()) { + else if (m_view_class & VIEWAXIAL && !getDisplayedShapeGraph().isSelected()) { return false; } } try { - retvar = true; + analysisCompleted = true; if (options.point_depth_selection == 1) { if (m_view_class & VIEWVGA) { - PointMaps::getDisplayedPointMap().analyseVisualPointDepth( communicator ); + analysisCompleted = VGAVisualGlobalDepth().run(communicator, getDisplayedPointMap(), false); } else if (m_view_class & VIEWAXIAL) { - if (!m_shape_graphs.getDisplayedMap().isSegmentMap()) { - m_shape_graphs.getDisplayedMap().stepdepth( communicator ); + if (!getDisplayedShapeGraph().isSegmentMap()) { + analysisCompleted = AxialStepDepth().run(communicator, getDisplayedShapeGraph(), false); } else { - m_shape_graphs.getDisplayedMap().angularstepdepth( communicator ); + analysisCompleted = SegmentTulipDepth().run(communicator, getDisplayedShapeGraph(), false); } } // REPLACES: @@ -339,46 +326,52 @@ bool MetaGraph::analyseGraph( Communicator *communicator, Options options , bool } else if (options.point_depth_selection == 2) { if (m_view_class & VIEWVGA) { - PointMaps::getDisplayedPointMap().analyseMetricPointDepth( communicator ); + analysisCompleted = VGAMetricDepth().run(communicator, getDisplayedPointMap(), false); } - else if (m_view_class & VIEWAXIAL && m_shape_graphs.getDisplayedMap().isSegmentMap()) { - m_shape_graphs.getDisplayedMap().analyseTopoMetPD( communicator, 1 ); // 1 is metric step depth + else if (m_view_class & VIEWAXIAL && getDisplayedShapeGraph().isSegmentMap()) { + analysisCompleted = SegmentMetricPD().run(communicator, getDisplayedShapeGraph(), false); } } else if (options.point_depth_selection == 3) { - PointMaps::getDisplayedPointMap().analyseAngularPointDepth( communicator ); + analysisCompleted = VGAAngularDepth().run(communicator, getDisplayedPointMap(), false); } else if (options.point_depth_selection == 4) { if (m_view_class & VIEWVGA) { - PointMaps::getDisplayedPointMap().binDisplay( communicator ); + getDisplayedPointMap().binDisplay( communicator ); } - else if (m_view_class & VIEWAXIAL && m_shape_graphs.getDisplayedMap().isSegmentMap()) { - m_shape_graphs.getDisplayedMap().analyseTopoMetPD( communicator, 0 ); // 0 is topological step depth + else if (m_view_class & VIEWAXIAL && getDisplayedShapeGraph().isSegmentMap()) { + analysisCompleted = SegmentTopologicalPD().run(communicator, getDisplayedShapeGraph(), false); } } else if (options.output_type == Options::OUTPUT_ISOVIST) { - PointMaps::getDisplayedPointMap().analyseIsovist( communicator, *this, simple_version ); + analysisCompleted = VGAIsovist().run(communicator, getDisplayedPointMap(), simple_version); } else if (options.output_type == Options::OUTPUT_VISUAL) { - PointMaps::getDisplayedPointMap().analyseVisual( communicator, options, simple_version ); - // REPLACES: - // Graph::calculate_depth_matrix( communicator, options, output_graph ); + bool localResult = true; + bool globalResult = true; + if (options.local) { + localResult = VGAVisualLocal(options.gates_only).run(communicator, getDisplayedPointMap(), simple_version); + } + if (options.global) { + globalResult = VGAVisualGlobal(options.radius, options.gates_only).run(communicator, getDisplayedPointMap(), simple_version); + } + analysisCompleted = globalResult & localResult; } else if (options.output_type == Options::OUTPUT_METRIC) { - PointMaps::getDisplayedPointMap().analyseMetric( communicator, options ); + analysisCompleted = VGAMetric(options.radius, options.gates_only).run(communicator, getDisplayedPointMap(), simple_version); } else if (options.output_type == Options::OUTPUT_ANGULAR) { - PointMaps::getDisplayedPointMap().analyseAngular( communicator, options ); + analysisCompleted = VGAAngular(options.radius, options.gates_only).run(communicator, getDisplayedPointMap(), simple_version); } else if (options.output_type == Options::OUTPUT_THRU_VISION) { - retvar = analyseThruVision( communicator, options.gatelayer ); + analysisCompleted = VGAThroughVision().run(communicator, getDisplayedPointMap(), simple_version); } } catch (Communicator::CancelledException) { - retvar = false; + analysisCompleted = false; } - return retvar; + return analysisCompleted; } ////////////////////////////////////////////////////////////////// @@ -422,45 +415,45 @@ bool MetaGraph::makeShape(const Line& line) return (map.makeLineShape(line,true) != -1); } -bool MetaGraph::polyBegin(const Line& line) +int MetaGraph::polyBegin(const Line& line) { if (!isEditableMap()) { - return false; + return -1; } ShapeMap& map = getEditableMap(); - return (map.polyBegin(line) != -1); + return map.polyBegin(line); } -bool MetaGraph::polyAppend(const Point2f& point) +bool MetaGraph::polyAppend(int shape_ref, const Point2f& point) { if (!isEditableMap()) { return false; } ShapeMap& map = getEditableMap(); - return map.polyAppend(point); + return map.polyAppend(shape_ref, point); } -bool MetaGraph::polyClose() +bool MetaGraph::polyClose(int shape_ref) { if (!isEditableMap()) { return false; } ShapeMap& map = getEditableMap(); - return map.polyClose(); + return map.polyClose(shape_ref); } -bool MetaGraph::polyCancel() +bool MetaGraph::polyCancel(int shape_ref) { if (!isEditableMap()) { return false; } ShapeMap& map = getEditableMap(); - return map.polyCancel(); + return map.polyCancel(shape_ref); } bool MetaGraph::moveSelShape(const Line& line) { - bool retvar = false; + bool shapeMoved = false; if (m_view_class & VIEWAXIAL) { ShapeGraph& map = getDisplayedShapeGraph(); if (!map.isEditable()) { @@ -469,10 +462,9 @@ bool MetaGraph::moveSelShape(const Line& line) if (map.getSelCount() > 1) { return false; } - // note, selection sets currently store rowids not uids, but moveShape sensibly works off uid: - int rowid = map.getSelSet()[0]; - retvar = map.moveShape(map.getIndex(rowid),line); - if (retvar) { + int rowid = *map.getSelSet().begin(); + shapeMoved = map.moveShape(rowid,line); + if (shapeMoved) { map.clearSel(); } } @@ -484,14 +476,13 @@ bool MetaGraph::moveSelShape(const Line& line) if (map.getSelCount() > 1) { return false; } - // note, selection sets currently store rowids not uids, but moveShape sensibly works off uid: - int rowid = map.getSelSet()[0]; - retvar = map.moveShape(map.getIndex(rowid),line); - if (retvar) { + int rowid = *map.getSelSet().begin(); + shapeMoved = map.moveShape(rowid, line); + if (shapeMoved) { map.clearSel(); } } - return retvar; + return shapeMoved; } ////////////////////////////////////////////////////////////////// @@ -499,36 +490,38 @@ bool MetaGraph::moveSelShape(const Line& line) // returns 0: fail, 1: made isovist, 2: made isovist and added new shapemap layer int MetaGraph::makeIsovist(Communicator *communicator, const Point2f& p, double startangle, double endangle, bool simple_version) { - int retvar = 0; + int isovistMade = 0; // first make isovist Isovist iso; if (makeBSPtree(communicator)) { - retvar = 1; - iso.makeit(m_bsp_root,p,SuperSpacePixel::m_region, startangle, endangle); - int shapelayer = m_data_maps.getMapRef("Isovists"); + isovistMade = 1; + iso.makeit(m_bsp_root, p, m_region, startangle, endangle); + int shapelayer = getMapRef(m_dataMaps, "Isovists"); if (shapelayer == -1) { - shapelayer = m_data_maps.addMap("Isovists",ShapeMap::DATAMAP); + m_dataMaps.emplace_back("Isovists",ShapeMap::DATAMAP); + setDisplayedDataMapRef(m_dataMaps.size() - 1); + shapelayer = m_dataMaps.size() - 1; m_state |= DATAMAPS; - retvar = 2; + isovistMade = 2; } - ShapeMap& map = m_data_maps.getMap(shapelayer); + ShapeMap& map = m_dataMaps[shapelayer]; // false: closed polygon, true: isovist int polyref = map.makePolyShape(iso.getPolygon(),false); - map.getAllShapes().search(polyref).setCentroid(p); + map.getAllShapes()[polyref].setCentroid(p); map.overrideDisplayedAttribute(-2); map.setDisplayedAttribute(-1); setViewClass(SHOWSHAPETOP); AttributeTable& table = map.getAttributeTable(); - int row = table.getRowid(polyref); + AttributeRow& row = table.getRow(AttributeKey(polyref)); iso.setData(table,row, simple_version); } - return retvar; + return isovistMade; } -static pair startendangle( Point2f vec, double fov) +static std::pair startendangle( Point2f vec, double fov) { - pair angles; + std::pair angles; // n.b. you must normalise this before getting the angle! vec.normalise(); angles.first = vec.angle() - fov / 2.0; @@ -543,7 +536,7 @@ static pair startendangle( Point2f vec, double fov) // returns 0: fail, 1: made isovist, 2: made isovist and added new shapemap layer int MetaGraph::makeIsovistPath(Communicator *communicator, double fov, bool simple_version) { - int retvar = 0; + int pathMade = 0; // must be showing a suitable map -- that is, one which may have polylines or lines ShapeMap *map = NULL, *isovists = NULL; @@ -566,25 +559,27 @@ int MetaGraph::makeIsovistPath(Communicator *communicator, double fov, bool simp bool first = true; if (makeBSPtree(communicator)) { - pvecint& selset = map->getSelSet(); - pqmap& shapes = map->getAllShapes(); - for (size_t i = 0; i < selset.size(); i++) { - SalaShape& path = shapes.value(selset[i]); + std::set selset = map->getSelSet(); + std::map& shapes = map->getAllShapes(); + for (auto& shapeRef: selset) { + const SalaShape& path = shapes.at(shapeRef); if (path.isLine() || path.isPolyLine()) { if (first) { - retvar = 1; - isovistmapref = m_data_maps.getMapRef("Isovists"); + pathMade = 1; + isovistmapref = getMapRef(m_dataMaps, "Isovists"); if (isovistmapref == -1) { - isovistmapref = m_data_maps.addMap("Isovists",ShapeMap::DATAMAP); - retvar = 2; + m_dataMaps.emplace_back("Isovists",ShapeMap::DATAMAP); + isovistmapref = m_dataMaps.size() - 1; + setDisplayedDataMapRef(isovistmapref); + pathMade = 2; } - isovists = &(m_data_maps.getMap(isovistmapref)); + isovists = &(m_dataMaps[isovistmapref]); first = false; } // now make an isovist: Isovist iso; // - pair angles; + std::pair angles; angles.first = 0.0; angles.second = 0.0; // @@ -594,26 +589,26 @@ int MetaGraph::makeIsovistPath(Communicator *communicator, double fov, bool simp if (fov < 2.0 * M_PI) { angles = startendangle(vec, fov); } - iso.makeit(m_bsp_root,start,SuperSpacePixel::m_region, angles.first, angles.second); + iso.makeit(m_bsp_root, start, m_region, angles.first, angles.second); int polyref = isovists->makePolyShape(iso.getPolygon(),false); - isovists->getAllShapes().search(polyref).setCentroid(start); + isovists->getAllShapes()[polyref].setCentroid(start); AttributeTable& table = isovists->getAttributeTable(); - int row = table.getRowid(polyref); + AttributeRow& row = table.getRow(AttributeKey(polyref)); iso.setData(table,row, simple_version); } else { - for (size_t i = 0; i < path.size() - 1; i++) { - Line li = Line(path[i],path[i+1]); + for (size_t i = 0; i < path.m_points.size() - 1; i++) { + Line li = Line(path.m_points[i],path.m_points[i+1]); Point2f start = li.t_start(); Point2f vec = li.vector(); if (fov < 2.0 * M_PI) { angles = startendangle(vec, fov); } - iso.makeit(m_bsp_root,start,SuperSpacePixel::m_region, angles.first, angles.second); + iso.makeit(m_bsp_root, start, m_region, angles.first, angles.second); int polyref = isovists->makePolyShape(iso.getPolygon(),false); - isovists->getAllShapes().search(polyref).setCentroid(start); + isovists->getAllShapes().find(polyref)->second.setCentroid(start); AttributeTable& table = isovists->getAttributeTable(); - int row = table.getRowid(polyref); + AttributeRow& row = table.getRow(AttributeKey(polyref)); iso.setData(table,row, simple_version); } } @@ -622,17 +617,17 @@ int MetaGraph::makeIsovistPath(Communicator *communicator, double fov, bool simp if (isovists) { isovists->overrideDisplayedAttribute(-2); isovists->setDisplayedAttribute(-1); - m_data_maps.setDisplayedMapRef(isovistmapref); + setDisplayedDataMapRef(isovistmapref); } } - return retvar; + return pathMade; } // this version uses your own isovist (and assumes no communicator required for BSP tree bool MetaGraph::makeIsovist(const Point2f& p, Isovist& iso) { if (makeBSPtree()) { - iso.makeit(m_bsp_root,p,SuperSpacePixel::m_region); + iso.makeit(m_bsp_root, p, m_region); return true; } return false; @@ -644,29 +639,24 @@ bool MetaGraph::makeBSPtree(Communicator *communicator) return true; } - prefvec partitionlines; - for (size_t i = 0; i < SuperSpacePixel::size(); i++) { - for (size_t j = 0; j < SuperSpacePixel::at(i).size(); j++) { + std::vector partitionlines; + for (const auto& pixelGroup: m_drawingFiles) { + for (const auto& pixel: pixelGroup.m_spacePixels) { // chooses the first editable layer it can find: - if (SuperSpacePixel::at(i).at(j).isShown()) { - for (size_t k = 0; k < SuperSpacePixel::at(i).at(j).getAllShapes().size(); k++) { - SalaShape& shape = SuperSpacePixel::at(i).at(j).getAllShapes().at(k); - // I'm not sure what the tagging was meant for any more, - // tagging at the moment tags the *polygon* it was original attached to - // must check it is not a zero length line: - if (shape.isLine() && shape.getLine().length() > 0.0) { - partitionlines.push_back(TaggedLine(shape.getLine(),k)); - } - else if (shape.isPolyLine() || shape.isPolygon()) { - for (size_t n = 0; n < shape.size() - 1; n++) { - if (shape[n] != shape[n+1]) { - partitionlines.push_back(TaggedLine(Line(shape[n],shape[n+1]),k)); + if (pixel.isShown()) { + auto refShapes = pixel.getAllShapes(); + int k = -1; + for (const auto& refShape: refShapes) { + k++; + std::vector newLines = refShape.second.getAsLines(); + // I'm not sure what the tagging was meant for any more, + // tagging at the moment tags the *polygon* it was original attached to + // must check it is not a zero length line: + for(const Line& line: newLines) { + if(line.length() > 0.0) { + partitionlines.push_back(TaggedLine(line,k)); } - } - if (shape.isPolygon() && shape.head() != shape.tail()) { - partitionlines.push_back(TaggedLine(Line(shape.tail(),shape.head()),k)); - } - } + } } } } @@ -682,17 +672,12 @@ bool MetaGraph::makeBSPtree(Communicator *communicator) } m_bsp_root = new BSPNode(); - // Quick mod - TV -#if defined(_WIN32) - __time64_t atime = 0; -#else time_t atime = 0; -#endif communicator->CommPostMessage( Communicator::NUM_RECORDS, partitionlines.size() ); qtimer( atime, 0 ); try { - m_bsp_root->make(communicator,atime,partitionlines,NULL); + BSPTree::make(communicator,atime,partitionlines,m_bsp_root); m_bsp_tree = true; } catch (Communicator::CancelledException) { @@ -710,47 +695,56 @@ bool MetaGraph::makeBSPtree(Communicator *communicator) ////////////////////////////////////////////////////////////////// -int MetaGraph::addShapeGraph(const pstring& name, int type) +int MetaGraph::addShapeGraph(std::unique_ptr& shapeGraph) { + m_shapeGraphs.push_back(std::move(shapeGraph)); + int mapref= int(m_shapeGraphs.size() - 1); + setDisplayedShapeGraphRef(mapref); + m_state |= SHAPEGRAPHS; + setViewClass(SHOWAXIALTOP); + return mapref; +} + +int MetaGraph::addShapeGraph(const std::string& name, int type) { - int mapref= m_shape_graphs.addMap(name,type); - m_state |= SHAPEGRAPHS; - setViewClass(SHOWAXIALTOP); - // add a couple of default columns: - AttributeTable& table = m_shape_graphs.getMap(mapref).getAttributeTable(); - table.insertLockedColumn("Connectivity"); - if ((type & ShapeMap::LINEMAP) != 0) { - table.insertLockedColumn("Line Length"); - } - return mapref; + std::unique_ptr shapeGraph(new ShapeGraph(name, type)); + int mapref = addShapeGraph(shapeGraph); + // add a couple of default columns: + AttributeTable& table = m_shapeGraphs[size_t(mapref)]->getAttributeTable(); + int connIdx = table.insertOrResetLockedColumn("Connectivity"); + if ((type & ShapeMap::LINEMAP) != 0) { + table.insertOrResetLockedColumn("Line Length"); + } + m_shapeGraphs[mapref]->setDisplayedAttribute(connIdx); + return mapref; } -int MetaGraph::addShapeMap(const pstring& name) +int MetaGraph::addShapeMap(const std::string& name) { - int ref = m_data_maps.addMap(name,ShapeMap::DATAMAP); + m_dataMaps.emplace_back(name,ShapeMap::DATAMAP); m_state |= DATAMAPS; setViewClass(SHOWSHAPETOP); - return ref; + return m_dataMaps.size() - 1; } void MetaGraph::removeDisplayedMap() { int ref = getDisplayedMapRef(); switch (m_view_class & VIEWFRONT) { case VIEWVGA: - PointMaps::removeMap(ref); - if (PointMaps::size() == 0) { + removePointMap(ref); + if (m_pointMaps.empty()) { setViewClass(SHOWHIDEVGA); m_state &= ~POINTMAPS; } break; case VIEWAXIAL: - m_shape_graphs.removeMap(ref); - if (m_shape_graphs.getMapCount() == 0) { + removeShapeGraph(ref); + if (m_shapeGraphs.empty()) { setViewClass(SHOWHIDEAXIAL); m_state &= ~SHAPEGRAPHS; } break; case VIEWDATA: - m_data_maps.removeMap(ref); - if (m_data_maps.getMapCount() == 0) { + removeDataMap(ref); + if (m_dataMaps.empty()) { setViewClass(SHOWHIDESHAPE); m_state &= ~DATAMAPS; } @@ -762,58 +756,61 @@ void MetaGraph::removeDisplayedMap() ////////////////////////////////////////////////////////////////// -bool MetaGraph::convertDrawingToAxial(Communicator *comm, pstring layer_name) +bool MetaGraph::convertDrawingToAxial(Communicator *comm, std::string layer_name) { int oldstate = m_state; m_state &= ~SHAPEGRAPHS; - bool retvar = false; + bool converted = true; try { - int mapref = m_shape_graphs.convertDrawingToAxial( comm, layer_name, (SuperSpacePixel&) *this ); - if (mapref != -1) { - retvar = true; - } + auto shapeGraph = MapConverter::convertDrawingToAxial( comm, layer_name, m_drawingFiles ); + int mapref = addShapeGraph(shapeGraph); + setDisplayedShapeGraphRef(mapref); } catch (Communicator::CancelledException) { - retvar = false; + converted = false; } m_state |= oldstate; - if (retvar) { + if (converted) { m_state |= SHAPEGRAPHS; setViewClass(SHOWAXIALTOP); } - return retvar; + return converted; } -bool MetaGraph::convertDataToAxial(Communicator *comm, pstring layer_name, bool keeporiginal, bool pushvalues) +bool MetaGraph::convertDataToAxial(Communicator *comm, std::string layer_name, bool keeporiginal, bool pushvalues) { int oldstate = m_state; m_state &= ~SHAPEGRAPHS; - bool retvar = false; + bool converted = true; try { - int mapref = m_shape_graphs.convertDataToAxial( comm, layer_name, m_data_maps.getDisplayedMap(), pushvalues ); - if (mapref != -1) { - retvar = true; - } + auto shapeGraph = MapConverter::convertDataToAxial( comm, layer_name, getDisplayedDataMap(), pushvalues ); + addShapeGraph(shapeGraph); + + m_shapeGraphs.back()->overrideDisplayedAttribute(-2); // <- override if it's already showing + m_shapeGraphs.back()->setDisplayedAttribute( + m_shapeGraphs.back()->getAttributeTable().getColumnIndex("Connectivity") ); + + setDisplayedShapeGraphRef(int(m_shapeGraphs.size() - 1)); } catch (Communicator::CancelledException) { - retvar = false; + converted = false; } m_state |= oldstate; - if (retvar) { + if (converted) { if (!keeporiginal) { - m_data_maps.removeMap( m_data_maps.getDisplayedMapRef() ); - if (m_data_maps.getMapCount() == 0) { + removeDataMap( getDisplayedDataMapRef() ); + if (m_dataMaps.empty()) { setViewClass(SHOWHIDESHAPE); m_state &= ~DATAMAPS; } @@ -822,40 +819,47 @@ bool MetaGraph::convertDataToAxial(Communicator *comm, pstring layer_name, bool setViewClass(SHOWAXIALTOP); } - return retvar; + return converted; } // typeflag: -1 convert drawing to convex, 0 or 1, convert data to convex (1 is pushvalues) -bool MetaGraph::convertToConvex(Communicator *comm, pstring layer_name, bool keeporiginal, int typeflag) +bool MetaGraph::convertToConvex(Communicator *comm, std::string layer_name, bool keeporiginal, int shapeMapType, bool copydata) { int oldstate = m_state; m_state &= ~SHAPEGRAPHS; // and convex maps... - bool retvar = false; + bool converted = false; try { - int mapref; - if (typeflag == -1) { - mapref = m_shape_graphs.convertDrawingToConvex( comm, layer_name, (SuperSpacePixel&) *this ); + int mapref = -1; + if (shapeMapType == ShapeMap::DRAWINGMAP) { + auto shapeGraph = MapConverter::convertDrawingToConvex( comm, layer_name, m_drawingFiles ); + mapref = addShapeGraph(shapeGraph); } - else { - mapref = m_shape_graphs.convertDataToConvex( comm, layer_name, m_data_maps.getDisplayedMap(), (typeflag != 0) ); + else if (shapeMapType == ShapeMap::DATAMAP) { + auto shapeGraph = MapConverter::convertDataToConvex( comm, layer_name, getDisplayedDataMap(), copydata ); + mapref = addShapeGraph(shapeGraph); } + + m_shapeGraphs.back()->overrideDisplayedAttribute( -2 ); // <- override if it's already showing + m_shapeGraphs.back()->setDisplayedAttribute( -1 ); + setDisplayedShapeGraphRef(int(m_shapeGraphs.size() - 1)); + if (mapref != -1) { - retvar = true; + converted = true; } } catch (Communicator::CancelledException) { - retvar = false; + converted = false; } m_state |= oldstate; - if (retvar) { - if (typeflag != -1 && !keeporiginal) { - m_data_maps.removeMap( m_data_maps.getDisplayedMapRef() ); - if (m_data_maps.getMapCount() == 0) { + if (converted) { + if (shapeMapType != ShapeMap::DRAWINGMAP && !keeporiginal) { + removeDataMap( getDisplayedDataMapRef() ); + if (m_dataMaps.empty()) { setViewClass(SHOWHIDESHAPE); m_state &= ~DATAMAPS; } @@ -864,61 +868,63 @@ bool MetaGraph::convertToConvex(Communicator *comm, pstring layer_name, bool kee setViewClass(SHOWAXIALTOP); } - return retvar; + return converted; } -bool MetaGraph::convertDrawingToSegment(Communicator *comm, pstring layer_name) +bool MetaGraph::convertDrawingToSegment(Communicator *comm, std::string layer_name) { int oldstate = m_state; m_state &= ~SHAPEGRAPHS; - bool retvar = false; + bool converted = true; try { - int mapref = m_shape_graphs.convertDrawingToSegment( comm, layer_name, (SuperSpacePixel&) *this ); - if (mapref != -1) { - retvar = true; - } + auto shapeGraph = MapConverter::convertDrawingToSegment( comm, layer_name, m_drawingFiles ); + addShapeGraph(shapeGraph); + + setDisplayedShapeGraphRef(int(m_shapeGraphs.size() - 1)); } catch (Communicator::CancelledException) { - retvar = false; + converted = false; } m_state |= oldstate; - if (retvar) { + if (converted) { m_state |= SHAPEGRAPHS; setViewClass(SHOWAXIALTOP); } - return retvar; + return converted; } -bool MetaGraph::convertDataToSegment(Communicator *comm, pstring layer_name, bool keeporiginal, bool pushvalues) +bool MetaGraph::convertDataToSegment(Communicator *comm, std::string layer_name, bool keeporiginal, bool pushvalues) { int oldstate = m_state; m_state &= ~SHAPEGRAPHS; - bool retvar = false; + bool converted = true; try { - int mapref = m_shape_graphs.convertDataToSegment( comm, layer_name, m_data_maps.getDisplayedMap(), pushvalues ); - if (mapref != -1) { - retvar = true; - } + auto shapeGraph = MapConverter::convertDataToSegment( comm, layer_name, getDisplayedDataMap(), pushvalues ); + addShapeGraph(shapeGraph); + + m_shapeGraphs.back()->overrideDisplayedAttribute( -2 ); // <- override if it's already showing + m_shapeGraphs.back()->setDisplayedAttribute( -1 ); + setDisplayedShapeGraphRef(int(m_shapeGraphs.size() - 1)); } catch (Communicator::CancelledException) { - retvar = false; + converted = false; } m_state |= oldstate; - if (retvar) { + if (converted) { if (!keeporiginal) { - m_data_maps.removeMap( m_data_maps.getDisplayedMapRef() ); - if (m_data_maps.getMapCount() == 0) { + removeDataMap( getDisplayedDataMapRef() ); + if (m_dataMaps.empty()) { setViewClass(SHOWHIDESHAPE); m_state &= ~DATAMAPS; } @@ -927,43 +933,47 @@ bool MetaGraph::convertDataToSegment(Communicator *comm, pstring layer_name, boo setViewClass(SHOWAXIALTOP); } - return retvar; + return converted; } // note: type flag says whether this is graph to data map or drawing to data map -bool MetaGraph::convertToData(Communicator *comm, pstring layer_name, bool keeporiginal, int typeflag) +bool MetaGraph::convertToData(Communicator *, std::string layer_name, bool keeporiginal, int shapeMapType, bool copydata) { int oldstate = m_state; m_state &= ~DATAMAPS; - bool retvar = false; + bool converted = false; try { // This should be much easier than before, // simply move the shapes from the drawing layer // note however that more than one layer might be combined: // create map layer... - int destmapref = m_data_maps.addMap(layer_name,ShapeMap::DATAMAP); - ShapeMap& destmap = m_data_maps.getMap(destmapref); + m_dataMaps.emplace_back(layer_name,ShapeMap::DATAMAP); + int destmapref = m_dataMaps.size() - 1; + ShapeMap& destmap = m_dataMaps.back(); AttributeTable& table = destmap.getAttributeTable(); int count = 0; // // drawing to data - if (typeflag == -1) { + if (shapeMapType == ShapeMap::DRAWINGMAP) { int layercol = destmap.addAttribute("Drawing Layer"); // add all visible layers to the set of map: - for (size_t i = 0; i < SuperSpacePixel::size(); i++) { - for (size_t j = 0; j < SuperSpacePixel::at(i).size(); j++) { - if (SuperSpacePixel::at(i).at(j).isShown()) { - for (size_t k = 0; k < SuperSpacePixel::at(i).at(j).getAllShapes().size(); k++) { - int key = destmap.makeShape(SuperSpacePixel::at(i).at(j).getAllShapes().at(k)); - table.setValue(table.getRowid(key),layercol,float(j+1)); + for (const auto& pixelGroup: m_drawingFiles) { + int j = 0; + for (const auto& pixel: pixelGroup.m_spacePixels) { + if (pixel.isShown()) { + auto refShapes = pixel.getAllShapes(); + for (const auto& refShape: refShapes) { + int key = destmap.makeShape(refShape.second); + table.getRow(AttributeKey(key)).setValue(layercol,float(j+1)); count++; } - SuperSpacePixel::at(i).at(j).setShow(false); + pixel.setShow(false); } + j++; } } } @@ -972,33 +982,33 @@ bool MetaGraph::convertToData(Communicator *comm, pstring layer_name, bool keepo ShapeGraph& sourcemap = getDisplayedShapeGraph(); count = sourcemap.getShapeCount(); // take viewed graph and push all geometry to it (since it is *all* geometry, pushing is easy) - int copyflag = (typeflag == 0) ? (ShapeMap::COPY_GEOMETRY) : (ShapeMap::COPY_GEOMETRY | ShapeMap::COPY_ATTRIBUTES); + int copyflag = copydata ? (ShapeMap::COPY_GEOMETRY | ShapeMap::COPY_ATTRIBUTES) : (ShapeMap::COPY_GEOMETRY); destmap.copy(sourcemap, copyflag); } // if (count == 0) { // if no objects converted then a crash is caused, so remove it: - m_data_maps.removeMap(destmapref); - retvar = false; + removeDataMap(destmapref); + converted = false; } else { // we can stop here! -- remember to set up display: - m_data_maps.setDisplayedMapRef(destmapref); + setDisplayedDataMapRef(destmapref); destmap.invalidateDisplayedAttribute(); destmap.setDisplayedAttribute(-1); - retvar = true; + converted = true; } } catch (Communicator::CancelledException) { - retvar = false; + converted = false; } m_state |= oldstate; - if (retvar) { - if (typeflag != -1 && !keeporiginal) { - m_shape_graphs.removeMap( m_shape_graphs.getDisplayedMapRef() ); - if (m_shape_graphs.getMapCount() == 0) { + if (converted) { + if (shapeMapType != ShapeMap::DRAWINGMAP && !keeporiginal) { + removeShapeGraph( getDisplayedShapeGraphRef() ); + if (m_shapeGraphs.empty()) { setViewClass(SHOWHIDEAXIAL); m_state &= ~SHAPEGRAPHS; } @@ -1007,12 +1017,12 @@ bool MetaGraph::convertToData(Communicator *comm, pstring layer_name, bool keepo setViewClass(SHOWSHAPETOP); } - return retvar; + return converted; } -bool MetaGraph::convertToDrawing(Communicator *comm, pstring layer_name, int typeflag) +bool MetaGraph::convertToDrawing(Communicator *, std::string layer_name, bool fromDisplayedDataMap) { - bool retvar = false; + bool converted = false; int oldstate = m_state; @@ -1020,7 +1030,7 @@ bool MetaGraph::convertToDrawing(Communicator *comm, pstring layer_name, int typ try { const ShapeMap *sourcemap; - if (typeflag == 0) { + if (fromDisplayedDataMap) { sourcemap = &(getDisplayedDataMap()); } else { @@ -1029,198 +1039,167 @@ bool MetaGraph::convertToDrawing(Communicator *comm, pstring layer_name, int typ // if (sourcemap->getShapeCount() != 0) { // this is very simple: create a new drawing layer, and add the data... - int group = -1; - for (size_t i = 0; i < SuperSpacePixel::size(); i++) { - if (SuperSpacePixel::at(i).getName() == "Converted Maps") { - group = i; + auto group = m_drawingFiles.begin(); + for (; group != m_drawingFiles.end(); ++group) { + if (group->getName() == "Converted Maps") { + break; } } - if (group == -1) { - SuperSpacePixel::push_back(pstring("Converted Maps")); - group = SuperSpacePixel::size() - 1; + if (group == m_drawingFiles.end()) { + m_drawingFiles.emplace_back(std::string("Converted Maps")); + group = std::prev(m_drawingFiles.end()); } - SuperSpacePixel::at(group).push_back(ShapeMap(layer_name)); - SuperSpacePixel::at(group).tail().copy(*sourcemap, ShapeMap::COPY_GEOMETRY); + group->m_spacePixels.emplace_back(layer_name); + group->m_spacePixels.back().copy(*sourcemap, ShapeMap::COPY_GEOMETRY); // // dummy set still required: - SuperSpacePixel::at(group).tail().invalidateDisplayedAttribute(); - SuperSpacePixel::at(group).tail().setDisplayedAttribute(-1); + group->m_spacePixels.back().invalidateDisplayedAttribute(); + group->m_spacePixels.back().setDisplayedAttribute(-1); // - // two levels of merge region: - if (SuperSpacePixel::at(group).size() == 1) { - SuperSpacePixel::at(group).m_region = sourcemap->getRegion(); + // three levels of merge region: + if (group->m_spacePixels.size() == 1) { + group->m_region = group->m_spacePixels.back().getRegion(); } else { - SuperSpacePixel::at(group).m_region = runion(SuperSpacePixel::at(group).m_region, sourcemap->getRegion()); + group->m_region = runion(group->m_region, group->m_spacePixels.back().getRegion()); } - if (SuperSpacePixel::size() == 1) { - SuperSpacePixel::m_region = SuperSpacePixel::at(group).m_region; + if (m_drawingFiles.size() == 1) { + m_region = group->m_region; } else { - SuperSpacePixel::m_region = runion(SuperSpacePixel::m_region, SuperSpacePixel::at(group).m_region); + m_region = runion(m_region, group->m_region); } // - retvar = true; + converted = true; } - retvar = true; + converted = true; } catch (Communicator::CancelledException) { - retvar = false; + converted = false; } m_state |= oldstate; - if (retvar) { + if (converted) { m_state |= LINEDATA; } - return retvar; + return converted; } -bool MetaGraph::convertPointsToShape() +bool MetaGraph::convertAxialToSegment(Communicator *comm, std::string layer_name, bool keeporiginal, bool pushvalues, double stubremoval) { - bool retvar = false; int oldstate = m_state; - m_state &= ~DATAMAPS; - - if (m_data_maps.getMapCount() == 0) { - m_data_maps.addMap(pstring("Gates"),ShapeMap::DATAMAP); - } - - if (m_data_maps.getDisplayedMap().makeShapeFromPointSet(getDisplayedPointMap()) != -1) { - getDisplayedPointMap().clearSel(); - // override the displayed attribute and redisplay: - m_data_maps.getDisplayedMap().overrideDisplayedAttribute(-2); - m_data_maps.getDisplayedMap().setDisplayedAttribute(-1); - // set up a specifc view class to show both layers: - m_view_class = VIEWVGA | VIEWBACKDATA; - m_state |= DATAMAPS; - retvar = true; - } - else if (!oldstate) { - m_data_maps.removeMap(0); - } - - m_state |= oldstate; - - return retvar; -} + m_state &= ~SHAPEGRAPHS; -/* -bool MetaGraph::convertBoundaryGraph( Communicator *communicator ) -{ - m_state &= ~SHAPEGRAPHS; // Clear axial map data flag (stops accidental redraw during reload) + bool converted = true; - bool retvar = false; + int orig_ref = getDisplayedShapeGraphRef(); try { - retvar = m_shape_graphs.convertBoundaryGraph( communicator, (PointMap&) *this ); - } - catch (Communicator::CancelledException) { - retvar = false; - } - - if (retvar) { - m_state |= SHAPEGRAPHS; - setViewClass(SHOWAXIALTOP); - } - - return retvar; -} -*/ - -bool MetaGraph::convertAxialToSegment(Communicator *comm, pstring layer_name, bool keeporiginal, bool pushvalues, double stubremoval) -{ - int oldstate = m_state; + if (orig_ref == -1) { + return false; + } - m_state &= ~SHAPEGRAPHS; - - bool retvar = false; + auto shapeGraph = MapConverter::convertAxialToSegment(comm, getDisplayedShapeGraph(), + layer_name, keeporiginal, + pushvalues, stubremoval); + addShapeGraph(shapeGraph); - int orig_ref = m_shape_graphs.getDisplayedMapRef(); + m_shapeGraphs.back()->overrideDisplayedAttribute(-2); // <- override if it's already showing + m_shapeGraphs.back()->setDisplayedAttribute( + m_shapeGraphs.back()->getAttributeTable().getColumnIndex("Connectivity") ); - try { - int mapref = m_shape_graphs.convertAxialToSegment( comm, layer_name, keeporiginal, pushvalues, stubremoval); - if (mapref != -1) { - retvar = true; - } + setDisplayedShapeGraphRef(int(m_shapeGraphs.size() - 1)); } catch (Communicator::CancelledException) { - retvar = false; + converted = false; } m_state |= oldstate; - if (retvar) { + if (converted) { if (!keeporiginal) { - m_shape_graphs.removeMap(orig_ref); + removeShapeGraph(orig_ref); } m_state |= SHAPEGRAPHS; setViewClass(SHOWAXIALTOP); } - return retvar; + return converted; } -int MetaGraph::loadMifMap(Communicator *comm, istream& miffile, istream& midfile) +int MetaGraph::loadMifMap(Communicator *comm, std::istream& miffile, std::istream& midfile) { int oldstate = m_state; m_state &= ~DATAMAPS; - int retvar = -1; + int mapLoaded = -1; try { // create map layer... - int mifmapref = m_data_maps.addMap(comm->GetMBInfileName(),ShapeMap::DATAMAP); - ShapeMap& mifmap = m_data_maps.getMap(mifmapref); - retvar = mifmap.loadMifMap(miffile, midfile); - if (retvar == MINFO_OK || retvar == MINFO_MULTIPLE) { // multiple is just a warning + m_dataMaps.emplace_back(comm->GetMBInfileName(),ShapeMap::DATAMAP); + int mifmapref = m_dataMaps.size() - 1; + ShapeMap& mifmap = m_dataMaps.back(); + mapLoaded = mifmap.loadMifMap(miffile, midfile); + if (mapLoaded == MINFO_OK || mapLoaded == MINFO_MULTIPLE) { // multiple is just a warning // display an attribute: mifmap.overrideDisplayedAttribute(-2); mifmap.setDisplayedAttribute(-1); - m_data_maps.setDisplayedMapRef(mifmapref); + setDisplayedDataMapRef(mifmapref); } else { // error: undo! - m_data_maps.removeMap(mifmapref); + removeDataMap(mifmapref); } } catch (Communicator::CancelledException) { - retvar = -1; + mapLoaded = -1; } m_state = oldstate; - if (retvar == MINFO_OK || retvar == MINFO_MULTIPLE) { // MINFO_MULTIPLE is simply a warning + if (mapLoaded == MINFO_OK || mapLoaded == MINFO_MULTIPLE) { // MINFO_MULTIPLE is simply a warning m_state |= DATAMAPS; setViewClass(SHOWSHAPETOP); } - return retvar; + return mapLoaded; } bool MetaGraph::makeAllLineMap( Communicator *communicator, const Point2f& seed ) { int oldstate = m_state; - m_state &= ~SHAPEGRAPHS; // Clear axial map data flag (stops accidental redraw during reload) + m_state &= ~SHAPEGRAPHS; // Clear axial map data flag (stops accidental redraw during reload) + m_view_class &= ~VIEWAXIAL; // Also clear the view_class flag - bool retvar = false; + bool mapMade = true; try { - retvar = m_shape_graphs.makeAllLineMap( communicator, (SuperSpacePixel&) *this, seed ); + // this is an index to look up the all line map, used by UI to determine if can make fewest line map + // note: it is not saved for historical reasons + if (m_all_line_map != -1) { + removeShapeGraph(m_all_line_map); + m_all_line_map = -1; + } + + m_shapeGraphs.push_back(std::unique_ptr(new AllLineMap(communicator, m_drawingFiles, seed))); + + m_all_line_map = int(m_shapeGraphs.size() - 1); + setDisplayedShapeGraphRef(m_all_line_map); } catch (Communicator::CancelledException) { - retvar = false; + mapMade = false; } m_state = oldstate; - if (retvar) { + if (mapMade) { m_state |= SHAPEGRAPHS; setViewClass(SHOWAXIALTOP); } - return retvar; + return mapMade; } @@ -1229,163 +1208,186 @@ bool MetaGraph::makeFewestLineMap( Communicator *communicator, int replace ) int oldstate= m_state; m_state &= ~SHAPEGRAPHS; // Clear axial map data flag (stops accidental redraw during reload) - bool retvar = false; + bool mapMade = true; try { - retvar = m_shape_graphs.makeFewestLineMap(communicator, (replace != 0)); + // no all line map + if (m_all_line_map == -1) { + return false; + } + + AllLineMap* alllinemap = dynamic_cast(m_shapeGraphs[size_t(m_all_line_map)].get()); + + if(alllinemap == nullptr) { + throw depthmapX::RuntimeException("Failed to cast from ShapeGraph to AllLineMap"); + } + + // waiting for C++17... + std::unique_ptr fewestlinemap_subsets, fewestlinemap_minimal; + std::tie(fewestlinemap_subsets, fewestlinemap_minimal) = alllinemap->extractFewestLineMaps(communicator); + + if (replace != 0) { + int index = -1; + + for(size_t i = 0; i < m_shapeGraphs.size(); i++) { + if(m_shapeGraphs[i]->getName() == "Fewest-Line Map (Subsets)" || + m_shapeGraphs[i]->getName() == "Fewest Line Map (Subsets)") { + index = int(i); + } + } + + if(index != -1) { + removeShapeGraph(index); + } + + for(size_t i = 0; i < m_shapeGraphs.size(); i++) { + if(m_shapeGraphs[i]->getName() == "Fewest-Line Map (Subsets)" || + m_shapeGraphs[i]->getName() == "Fewest Line Map (Subsets)") { + index = int(i); + } + } + + if(index != -1) { + removeShapeGraph(index); + } + } + addShapeGraph(fewestlinemap_subsets); + addShapeGraph(fewestlinemap_minimal); + + setDisplayedShapeGraphRef(int(m_shapeGraphs.size() - 2)); + } catch (Communicator::CancelledException) { - retvar = false; + mapMade = false; } m_state = oldstate; - if (retvar) { + if (mapMade) { m_state |= SHAPEGRAPHS; // note: should originally have at least one axial map setViewClass(SHOWAXIALTOP); } - return retvar; + return mapMade; } -bool MetaGraph::analyseAxial( Communicator *communicator, Options options, bool simple_version ) // options copied to keep thread safe +bool MetaGraph::analyseAxial( Communicator *communicator, Options options, bool ) // options copied to keep thread safe { m_state &= ~SHAPEGRAPHS; // Clear axial map data flag (stops accidental redraw during reload) - bool retvar = false; + bool analysisCompleted = false; try { - pvecint radius; - for (size_t i = 0; i < options.radius_list.size(); i++) { - radius.push_back( (int) options.radius_list[i] ); - } - retvar = m_shape_graphs.getDisplayedMap().integrate( communicator, radius, options.choice, options.local, options.fulloutput, options.weighted_measure_col, simple_version ); + analysisCompleted = AxialIntegration(options.radius_set, options.weighted_measure_col, options.choice, options.fulloutput, + options.local) + .run(communicator, getDisplayedShapeGraph(), false); } catch (Communicator::CancelledException) { - retvar = false; + analysisCompleted = false; } m_state |= SHAPEGRAPHS; - return retvar; + return analysisCompleted; } -bool MetaGraph::analyseSegments( Communicator *communicator, Options options ) // <- options copied to keep thread safe +bool MetaGraph::analyseSegmentsTulip( Communicator *communicator, Options options ) // <- options copied to keep thread safe { - m_state &= ~SHAPEGRAPHS; // Clear axial map data flag (stops accidental redraw during reload) + m_state &= ~SHAPEGRAPHS; // Clear axial map data flag (stops accidental redraw during reload) - bool retvar = false; + bool analysisCompleted = false; try { - if (options.tulip_bins == 0) { - retvar = m_shape_graphs.getDisplayedMap().analyseAngular(communicator, options.radius_list); - } - else { - retvar = m_shape_graphs.getDisplayedMap().analyseTulip(communicator, options.tulip_bins, options.choice, - options.radius_type, options.radius_list, options.weighted_measure_col); - } - } + analysisCompleted = SegmentTulip(options.radius_set, options.sel_only, options.tulip_bins, options.weighted_measure_col, + options.radius_type, options.choice) + .run(communicator, getDisplayedShapeGraph(), false); + } catch (Communicator::CancelledException) { - retvar = false; + analysisCompleted = false; } m_state |= SHAPEGRAPHS; - return retvar; + return analysisCompleted; } -bool MetaGraph::analyseTopoMet( Communicator *communicator, Options options ) // <- options copied to keep thread safe +bool MetaGraph::analyseSegmentsAngular( Communicator *communicator, Options options ) // <- options copied to keep thread safe { - m_state &= ~SHAPEGRAPHS; // Clear axial map data flag (stops accidental redraw during reload) + m_state &= ~SHAPEGRAPHS; // Clear axial map data flag (stops accidental redraw during reload) - bool retvar = false; + bool analysisCompleted = false; try { - // note: "output_type" reused for analysis type (either 0 = topological or 1 = metric) - retvar = m_shape_graphs.getDisplayedMap().analyseTopoMet(communicator, options.output_type, options.radius, options.sel_only); - } + analysisCompleted = SegmentAngular(options.radius_set).run(communicator, getDisplayedShapeGraph(), false); + } catch (Communicator::CancelledException) { - retvar = false; + analysisCompleted = false; } m_state |= SHAPEGRAPHS; - return retvar; + return analysisCompleted; } - -bool MetaGraph::analyseAngular( Communicator *communicator, bool analyse_in_memory ) +bool MetaGraph::analyseTopoMetMultipleRadii( Communicator *communicator, Options options ) // <- options copied to keep thread safe { - bool retvar = false; - /* - Graph::m_nodes.openread(); + m_state &= ~SHAPEGRAPHS; // Clear axial map data flag (stops accidental redraw during reload) + + bool analysisCompleted = true; - if (analyse_in_memory) { - Graph::m_nodes.loadmem(); - } try { - retvar = Graph::angular_analysis( communicator ); - } - catch (Communicator::CancelledException) { - retvar = false; + // note: "output_type" reused for analysis type (either 0 = topological or 1 = metric) + for(size_t r = 0; r < options.radius_set.size(); r++) { + if(options.output_type == 0) { + if(!SegmentTopological(options.radius, options.sel_only).run(communicator, getDisplayedShapeGraph(), false)) + analysisCompleted = false; + } else { + if(!SegmentMetric(options.radius, options.sel_only).run(communicator, getDisplayedShapeGraph(), false)) + analysisCompleted = false; + } + } } - if (analyse_in_memory) { - Graph::m_nodes.unloadmem(); + catch (Communicator::CancelledException) { + analysisCompleted = false; } - Graph::m_nodes.close(); - - if (retvar) { - setDisplayAttribute( AttrHeader::MEDIAN_ANGLE ); - } + m_state |= SHAPEGRAPHS; - m_state |= AXIALLINES; - */ - return retvar; + return analysisCompleted; } -bool MetaGraph::makeAxialLines( Communicator *communicator, bool analyse_in_memory ) +bool MetaGraph::analyseTopoMet( Communicator *communicator, Options options ) // <- options copied to keep thread safe { - bool retvar = false; - - /* - m_state &= ~AXIALLINES; // Clear axial line data flag (stops accidental redraw during reload) + m_state &= ~SHAPEGRAPHS; // Clear axial map data flag (stops accidental redraw during reload) - Graph::m_nodes.openread(); + bool analysisCompleted = false; - if (analyse_in_memory) { - Graph::m_nodes.loadmem(); - } try { - retvar = AxialLines::makeAxialLines( (Graph&) *this, (PointMap&) *this ); + // note: "output_type" reused for analysis type (either 0 = topological or 1 = metric) + if(options.output_type == 0) { + analysisCompleted = SegmentTopological(options.radius, options.sel_only).run(communicator, getDisplayedShapeGraph(), false); + } else { + analysisCompleted = SegmentMetric(options.radius, options.sel_only).run(communicator, getDisplayedShapeGraph(), false); + } } catch (Communicator::CancelledException) { - retvar = false; - } - if (analyse_in_memory) { - Graph::m_nodes.unloadmem(); + analysisCompleted = false; } - Graph::m_nodes.close(); + m_state |= SHAPEGRAPHS; - if (retvar) - m_state |= AXIALLINES; - */ - return retvar; + return analysisCompleted; } -const int DXFCIRCLERES = 36; - int MetaGraph::loadLineData( Communicator *communicator, int load_type ) { + if (load_type & DXF) { + // separate the stream and the communicator, allowing non-file streams read + return depthmapX::importFile(*this, *communicator, communicator, communicator->GetMBInfileName(), depthmapX::ImportType::DRAWINGMAP, depthmapX::ImportFileType::DXF); + } + m_state &= ~LINEDATA; // Clear line data flag (stops accidental redraw during reload) -/* - if (m_state & POINTS) { - PointMap::s_bl = NoPixel; // <- force coming clear to clear *all* points - PointMap::clearPoints(); // If points exist, clear them - m_state &= ~POINTS; // ...and clear the flag - } -*/ + // if bsp tree exists if (m_bsp_root) { delete m_bsp_root; @@ -1394,21 +1396,12 @@ int MetaGraph::loadLineData( Communicator *communicator, int load_type ) m_bsp_tree = false; if (load_type & REPLACE) { - SuperSpacePixel::clear(); + m_drawingFiles.clear(); } - SuperSpacePixel::push_back(communicator->GetMBInfileName()); - - if (load_type & DXF) { - - // separate the stream and the communicator, allowing non-file streams read - int error = loadDxf(*communicator, communicator); + m_drawingFiles.emplace_back(communicator->GetMBInfileName()); - if (error != 1) { - return error; - } - } - else if (load_type & CAT) { + if (load_type & CAT) { // separate the stream and the communicator, allowing non-file streams read int error = loadCat(*communicator, communicator); if (error != 1) { @@ -1430,44 +1423,47 @@ int MetaGraph::loadLineData( Communicator *communicator, int load_type ) map.open(communicator->GetFileSet(), communicator); } catch (Communicator::CancelledException) { - SuperSpacePixel::pop_back(); + m_drawingFiles.pop_back(); return 0; } - catch (pexception) { - SuperSpacePixel::pop_back(); + catch (std::invalid_argument&) { + m_drawingFiles.pop_back(); + return -1; + } + catch (std::out_of_range&) { + m_drawingFiles.pop_back(); return -1; } if (communicator->IsCancelled()) { - SuperSpacePixel::pop_back(); + m_drawingFiles.pop_back(); return 0; } - SuperSpacePixel::tail().m_region = map.getRegion();; - - for (size_t i = 0; i < map.size(); i++) { + m_drawingFiles.back().m_region = map.getRegion();; - SuperSpacePixel::tail().push_back(ShapeMap(map[i].getName())); - SuperSpacePixel::tail().at(i).init(map[i].getLineCount(), map.getRegion()); + for (auto layer: map.layers) { - for (size_t j = 0; j < map[i].size(); j++) { + m_drawingFiles.back().m_spacePixels.emplace_back(layer.getName()); + m_drawingFiles.back().m_spacePixels.back().init(layer.getLineCount(), map.getRegion()); - for (size_t k = 0; k < map[i][j].size(); k++) { - - SuperSpacePixel::tail().at(i).makeLineShape( map[i][j][k] ); + for (auto geometry: layer.geometries) { + for (auto& line: geometry.lines) { + m_drawingFiles.back().m_spacePixels.back().makeLineShape( line ); } } - SuperSpacePixel::tail().at(i).setDisplayedAttribute(-2); - SuperSpacePixel::tail().at(i).setDisplayedAttribute(-1); + // TODO: Investigate why setDisplayedAttribute needs to be set to -2 first + m_drawingFiles.back().m_spacePixels.back().setDisplayedAttribute(-2); + m_drawingFiles.back().m_spacePixels.back().setDisplayedAttribute(-1); } } - if (SuperSpacePixel::size() == 1) { - SuperSpacePixel::m_region = SuperSpacePixel::tail().m_region; + if (m_drawingFiles.size() == 1) { + m_region = m_drawingFiles.back().m_region; } else { - SuperSpacePixel::m_region = runion(SuperSpacePixel::m_region, SuperSpacePixel::tail().m_region); + m_region = runion(m_region, m_drawingFiles.back().m_region); } m_state |= LINEDATA; @@ -1475,132 +1471,38 @@ int MetaGraph::loadLineData( Communicator *communicator, int load_type ) return 1; } -int MetaGraph::loadDxf( istream& stream, Communicator *communicator) -{ - DxfParser dp; - - if (communicator) { - dp = DxfParser( communicator ); - - try { - *communicator >> dp; - } - catch (Communicator::CancelledException) { - SuperSpacePixel::pop_back(); - return 0; - } - catch (pexception) { - SuperSpacePixel::pop_back(); - return -1; - } - - if (communicator->IsCancelled()) { - SuperSpacePixel::pop_back(); - return 0; - } - } - else { - dp.open(stream); - } - - SuperSpacePixel::tail().m_region = QtRegion(dp.getExtMin(), dp.getExtMax()); - - int i = 0; - - for (int layerref = 0; layerref < dp.numLayers(); layerref++) { - - const DxfLayer& dxf_layer = dp.getLayerNum( layerref ); - - if (dxf_layer.empty()) { - continue; - } - - SuperSpacePixel::tail().push_back(ShapeMap(dxf_layer.getName())); - // note the circle lines are not counted in the total number of lines, as we have to specify number of segments - SuperSpacePixel::tail().at(i).init(dxf_layer.numTotalPoints() + dxf_layer.numTotalLines() + dxf_layer.numArcs() * DXFCIRCLERES + dxf_layer.numCircles() * DXFCIRCLERES, QtRegion(Point2f(dxf_layer.getExtMin()),Point2f(dxf_layer.getExtMax())) ); - - for (int jp = 0; jp < dxf_layer.numPoints(); jp++) { - - const DxfVertex& dxf_point = dxf_layer.getPoint( jp ); - Point2f point = Point2f(dxf_point); - SuperSpacePixel::tail().at(i).makePointShape( point ); - - } - - for (int j = 0; j < dxf_layer.numLines(); j++) { - - const DxfLine& dxf_line = dxf_layer.getLine( j ); - Line line = Line( Point2f(dxf_line.getStart()), Point2f(dxf_line.getEnd()) ); - SuperSpacePixel::tail().at(i).makeLineShape( line ); +// From: Alasdair Turner (2004) - Depthmap 4: a researcher's handbook (p. 6): +// [..] CAT, which stands for Chiron and Alasdair Transfer Format [..] - } - for (int k = 0; k < dxf_layer.numPolyLines(); k++) { - - const DxfPolyLine& poly = dxf_layer.getPolyLine( k ); - pvecpoint points; - for (int m = 0; m < poly.numVertices(); m++) { - points.push_back(poly.getVertex(m)); - } - SuperSpacePixel::tail().at(i).makePolyShape( points, (poly.getAttributes() & DxfPolyLine::CLOSED) != DxfPolyLine::CLOSED ); - } - for (int l = 0; l < dxf_layer.numSplines(); l++) { - - const DxfSpline& poly = dxf_layer.getSpline( l ); - - pvecpoint points; - for (int m = 0; m < poly.numVertices(); m++) { - points.push_back(poly.getVertex(m)); - } - SuperSpacePixel::tail().at(i).makePolyShape( points, (poly.getAttributes() & DxfPolyLine::CLOSED) != DxfPolyLine::CLOSED ); - - } - // needs fixing to use appropriate poly type: - for (int n = 0; n < dxf_layer.numArcs(); n++) { - - const DxfArc& circ = dxf_layer.getArc( n ); - int segments = circ.numSegments(DXFCIRCLERES); - if (segments > 1) { - for (int m = 0; m < segments; m++) { - // note, loops on DXFCIRCLERES (e.g. 36) to 0 - Line line = Line( Point2f(circ.getVertex(m,DXFCIRCLERES)), Point2f(circ.getVertex(m+1,DXFCIRCLERES)) ); - SuperSpacePixel::tail().at(i).makeLineShape( line ); +void MetaGraph::writeMapShapesAsCat(ShapeMap& map, std::ostream &stream) { + stream << "CAT" << std::endl; + for (auto refShape: map.getAllShapes()) { + SalaShape& shape = refShape.second; + if(shape.isPolyLine() || shape.isPolygon()) { + stream << "Begin " << (shape.isPolyLine() ? "Polyline" : "Polygon") << std::endl; + for (Point2f p: shape.m_points) { + stream << p.x << " " << p.y << std::endl; } - } - } - for (int nc = 0; nc < dxf_layer.numCircles(); nc++) { - - const DxfCircle& circ = dxf_layer.getCircle( nc ); - pvecpoint points; - for (int m = 0; m < DXFCIRCLERES; m++) { - points.push_back(circ.getVertex(m,DXFCIRCLERES)); - } - SuperSpacePixel::tail().at(i).makePolyShape( points, false ); - } - - SuperSpacePixel::tail().at(i).setDisplayedAttribute(-2); - SuperSpacePixel::tail().at(i).setDisplayedAttribute(-1); - - i++; - } - - return 1; + stream << "End " << (shape.isPolyLine() ? "Polyline" : "Polygon") << std::endl; + } else if(shape.isLine()) { + stream << "Begin Polyline" << std::endl; + stream << shape.getLine().ax() << " " << shape.getLine().ay() << std::endl; + stream << shape.getLine().bx() << " " << shape.getLine().by() << std::endl; + stream << "End Polyline" << std::endl; + } + } } -int MetaGraph::loadCat( istream& stream, Communicator *communicator ) +int MetaGraph::loadCat( std::istream& stream, Communicator *communicator ) { if (communicator) { long size = communicator->GetInfileSize(); communicator->CommPostMessage( Communicator::NUM_RECORDS, size ); } - // Quick mod - TV -#if defined(_WIN32) - __time64_t a_time = 0; -#else - time_t a_time = 0; -#endif + time_t atime = 0; - qtimer( a_time, 0 ); + qtimer( atime, 0 ); long size = 0; int numlines = 0; @@ -1611,23 +1513,24 @@ int MetaGraph::loadCat( istream& stream, Communicator *communicator ) while (!stream.eof()) { - pstring inputline; + std::string inputline; stream >> inputline; if (inputline.length() > 1 && inputline[0] != '#') { if (!parsing) { - if (inputline.makelower() == "begin polygon") { + if (dXstring::toLower(inputline) == "begin polygon") { parsing = 1; } - else if (inputline.makelower() == "begin polyline") { + else if (dXstring::toLower(inputline) == "begin polyline") { parsing = 2; } } - else if (inputline.makelower().substr(0,3) == "end") { + else if (dXstring::toLower(inputline).substr(0,3) == "end") { parsing = 0; } else { - current_point.x = inputline.ltrim().splice(' ').c_double(); - current_point.y = inputline.ltrim().c_double(); + auto tokens = dXstring::split(inputline, ' ', true); + current_point.x = stod(tokens[0]); + current_point.y = stod(tokens[1]); numlines++; if (first) { min_point = current_point; @@ -1651,53 +1554,54 @@ int MetaGraph::loadCat( istream& stream, Communicator *communicator ) } } } - SuperSpacePixel::tail().m_region = QtRegion(min_point, max_point); - SuperSpacePixel::tail().push_back(ShapeMap()); - SuperSpacePixel::tail().tail().init( numlines, QtRegion(min_point, max_point) ); + m_drawingFiles.back().m_region = QtRegion(min_point, max_point); + m_drawingFiles.back().m_spacePixels.emplace_back(); + m_drawingFiles.back().m_spacePixels.back().init( numlines, QtRegion(min_point, max_point) ); // in MSVC 6, ios::eof remains set and it needs to be cleared. // in MSVC 8 it's even worse: it won't even seekg until eof flag has been cleared stream.clear(); - stream.seekg(0, ios::beg); + stream.seekg(0, std::ios::beg); parsing = 0; first = true; - pvecpoint points; + std::vector points; while (!stream.eof()) { - pstring inputline; + std::string inputline; stream >> inputline; if (inputline.length() > 1 && inputline[0] != '#') { if (!parsing) { - if (inputline.makelower() == "begin polygon") { + if (dXstring::toLower(inputline) == "begin polygon") { parsing = 1; first = true; } - else if (inputline.makelower() == "begin polyline") { + else if (dXstring::toLower(inputline) == "begin polyline") { parsing = 2; first = true; } } - else if (inputline.makelower().substr(0,3) == "end") { + else if (dXstring::toLower(inputline).substr(0,3) == "end") { if (points.size() > 2) { if (parsing == 1) { // polygon - SuperSpacePixel::tail().tail().makePolyShape(points, false); + m_drawingFiles.back().m_spacePixels.back().makePolyShape(points, false); } else { // polyline - SuperSpacePixel::tail().tail().makePolyShape(points, true); + m_drawingFiles.back().m_spacePixels.back().makePolyShape(points, true); } } else if (points.size() == 2) { - SuperSpacePixel::tail().tail().makeLineShape(Line(points[0],points[1])); + m_drawingFiles.back().m_spacePixels.back().makeLineShape(Line(points[0],points[1])); } points.clear(); parsing = 0; } else { - current_point.x = inputline.ltrim().splice(' ').c_double(); - current_point.y = inputline.ltrim().c_double(); + auto tokens = dXstring::split(inputline, ' ', true); + current_point.x = stod(tokens[0]); + current_point.y = stod(tokens[1]); points.push_back(current_point); } } @@ -1705,7 +1609,7 @@ int MetaGraph::loadCat( istream& stream, Communicator *communicator ) size += inputline.length() + 1; if (communicator) { - if (qtimer( a_time, 500 )) { + if (qtimer( atime, 500 )) { if (communicator->IsCancelled()) { throw Communicator::CancelledException(); } @@ -1714,18 +1618,13 @@ int MetaGraph::loadCat( istream& stream, Communicator *communicator ) } } - SuperSpacePixel::tail().tail().setDisplayedAttribute(-2); - SuperSpacePixel::tail().tail().setDisplayedAttribute(-1); + m_drawingFiles.back().m_spacePixels.back().setDisplayedAttribute(-2); + m_drawingFiles.back().m_spacePixels.back().setDisplayedAttribute(-1); return 1; } -// Quick mod - TV -#if defined(_WIN32) -int MetaGraph::loadRT1(const pqvector& fileset, Communicator *communicator) -#else -int MetaGraph::loadRT1(const pqvector& fileset, Communicator *communicator) -#endif +int MetaGraph::loadRT1(const std::vector& fileset, Communicator *communicator) { TigerMap map; @@ -1733,375 +1632,158 @@ int MetaGraph::loadRT1(const pqvector& fileset, Communicator *communicat map.parse( fileset, communicator ); } catch (Communicator::CancelledException) { - SuperSpacePixel::pop_back(); + m_drawingFiles.pop_back(); return 0; } - catch (pexception) { - SuperSpacePixel::pop_back(); + catch (std::invalid_argument&) { + m_drawingFiles.pop_back(); + return -1; + } + catch (std::out_of_range&) { + m_drawingFiles.pop_back(); return -1; } if (communicator->IsCancelled()) { - SuperSpacePixel::pop_back(); + m_drawingFiles.pop_back(); return 0; } - SuperSpacePixel::tail().m_region = QtRegion(map.getBottomLeft(), map.getTopRight()); + m_drawingFiles.back().m_region = QtRegion(map.getBottomLeft(), map.getTopRight()); // for each category - for (size_t i = 0; i < map.size(); i++) { - - SuperSpacePixel::tail().push_back(ShapeMap(map.key(i))); - SuperSpacePixel::tail().at(i).init(map.value(i).size(), map.getRegion() ); + for (auto val: map.m_categories) { + ShapeMap shapeMap = ShapeMap(val.first); + shapeMap.init(val.second.chains.size(), map.getRegion() ); // for each chains in category: - for (size_t j = 0; j < map.value(i).size(); j++) { + for (size_t j = 0; j < val.second.chains.size(); j++) { // for each node pair in each category - for (size_t k = 0; k < map.value(i).at(j).size(); k++) { - SuperSpacePixel::tail().at(i).makeLineShape( map.value(i).at(j).at(k) ); + for (size_t k = 0; k < val.second.chains[j].lines.size(); k++) { + shapeMap.makeLineShape( val.second.chains[j].lines[k] ); } } - SuperSpacePixel::tail().at(i).setDisplayedAttribute(-2); - SuperSpacePixel::tail().at(i).setDisplayedAttribute(-1); + shapeMap.setDisplayedAttribute(-2); + shapeMap.setDisplayedAttribute(-1); + m_drawingFiles.back().m_spacePixels.emplace_back(std::move(shapeMap)); } return 1; } +ShapeMap &MetaGraph::createNewShapeMap(depthmapX::ImportType mapType, std::string name) { + + if (mapType == depthmapX::ImportType::DATAMAP) { + m_dataMaps.emplace_back(name, ShapeMap::DATAMAP); + m_dataMaps.back().setDisplayedAttribute(0); + return m_dataMaps.back(); + } + // depthmapX::ImportType::DRAWINGMAP + m_drawingFiles.back().m_spacePixels.emplace_back(name); + return m_drawingFiles.back().m_spacePixels.back(); +} + +void MetaGraph::deleteShapeMap(depthmapX::ImportType mapType, ShapeMap &shapeMap) { + + switch(mapType) { + case depthmapX::ImportType::DRAWINGMAP: { + // go through the files to find if the layer is in one of them + // if it is, remove it and if the remaining file is empty then + // remove that too + auto pixelGroup = m_drawingFiles.begin(); + for (; pixelGroup != m_drawingFiles.begin(); ++pixelGroup) { + auto mapToRemove = pixelGroup->m_spacePixels.end(); + auto pixel = pixelGroup->m_spacePixels.begin(); + for (; pixel != pixelGroup->m_spacePixels.end(); ++pixel) { + if(&(*pixel) == &shapeMap) { + mapToRemove = pixel; + break; + } + } + if(mapToRemove != pixelGroup->m_spacePixels.end()) { + pixelGroup->m_spacePixels.erase(mapToRemove); + if(pixelGroup->m_spacePixels.size() == 0) { + m_drawingFiles.erase(pixelGroup); + } + break; + } + } + } + case depthmapX::ImportType::DATAMAP: { + for(size_t i = 0; i < m_dataMaps.size(); i++) { + if(&m_dataMaps[i] == &shapeMap) { + m_dataMaps.erase(m_dataMaps.begin() + i); + break; + } + } + } + } +} +void MetaGraph::updateParentRegions(ShapeMap &shapeMap) { + if(m_drawingFiles.back().m_region.atZero()) { + m_drawingFiles.back().m_region = shapeMap.getRegion(); + } else { + m_drawingFiles.back().m_region = runion(m_drawingFiles.back().m_region, shapeMap.getRegion()); + } + if(m_region.atZero()) { + m_region = m_drawingFiles.back().m_region; + } else { + m_region = runion(m_region, m_drawingFiles.back().m_region); + } +} -/* -// DEPRECATED +// the tidy(ish) version: still needs to be at top level and switch between layers -void MetaGraph::fastGraph( istream& stream, double spacing ) +bool MetaGraph::pushValuesToLayer(int desttype, int destlayer, int push_func, bool count_col) { - // does the lot -- assumes a bounding polygon, - // and tries to find a location outside all other polygons to populate grid - prefvec polygons; + int sourcetype = m_view_class; + int sourcelayer = getDisplayedMapRef(); + int col_in = getDisplayedAttribute(); + // no col_out specified + int col_out = -2; - // any name for the file will do... - SuperSpacePixel::push_back(SpacePixelFile("salad")); - - // load the data from the file - loadCat( stream, NULL, &polygons ); + // temporarily turn off everything to prevent redraw during sensitive time: + int oldstate = m_state; + m_state &= ~(DATAMAPS | AXIALLINES | POINTMAPS); - // organise the data from the file - for (int i = 0; i < SuperSpacePixel::tail().size(); i++) { - SuperSpacePixel::tail().at(i).sortPixelLines(); - } - if (SuperSpacePixel::size() == 1) { - SuperSpacePixel::m_region = SuperSpacePixel::tail().m_region; - } - else { - SuperSpacePixel::m_region = runion(SuperSpacePixel::m_region, SuperSpacePixel::tail().m_region); - } + bool valuesPushed = pushValuesToLayer(sourcetype, sourcelayer, desttype, destlayer, col_in, + col_out, push_func, count_col); - m_state |= LINEDATA; + m_state = oldstate; - setGrid( spacing ); + return valuesPushed; +} - // this is a silly way to do this, but there you go, randomly choose points until you get one - // that hits empty space... - srand(time(NULL)); - int testhits, count = 0; - PixelRef testpixel; - Point2f testpoint; - do { - count++; - testhits = 0; - testpixel = PixelRef( rand() % PointMap::getCols(), rand() % PointMap::getRows() ); - testpoint = PointMap::depixelate(testpixel); - for (int i = 0; i < polygons.size(); i++) { - try { - if (polygons[i].contains(testpoint)) { - testhits++; - } - } - catch (int) { - // polygons throw if on edge: - // break from this loop and continue do-while loop: - testhits = 0; - break; - } - } - } while (testhits != 1 && count < (PointMap::getCols() * PointMap::getRows()) ); +// helper - if (testhits != 1) { - return; // give up, you must have tried just about every location by now... +void pushValue(double& val, int& count, double thisval, int push_func) +{ + if (thisval != -1) { + switch (push_func) { + case MetaGraph::PUSH_FUNC_MAX: + if (val == -1 || thisval > val) + val = thisval; + break; + case MetaGraph::PUSH_FUNC_MIN: + if (val == -1 || thisval < val) + val = thisval; + break; + case MetaGraph::PUSH_FUNC_AVG: + case MetaGraph::PUSH_FUNC_TOT: + if (val == -1.0) + val = thisval; + else + val += thisval; + break; + } + count++; } +} - PointMap::makePoints(testpoint, Point::FILLED); - - m_state |= POINTS; - - PointMap::sparkGraph2(NULL, 0); - - m_state |= GRAPH | ANGULARGRAPH; - - setViewClass(SHOWVGATOP); - - // Testing: - // write("dummy.graph"); -} -*/ - -bool MetaGraph::importCat(istream& filecontents) -{ - // any name for the file will do... - SuperSpacePixel::push_back(SpacePixelFile("salad")); - - // load the data from the file - if (!loadCat( filecontents, NULL )) { - return false; - } - - if (SuperSpacePixel::size() == 1) { - SuperSpacePixel::m_region = SuperSpacePixel::tail().m_region; - } - else { - SuperSpacePixel::m_region = runion(SuperSpacePixel::m_region, SuperSpacePixel::tail().m_region); - } - - m_state |= LINEDATA; - - return true; -} - -bool MetaGraph::importDxf(istream& filecontents) -{ - // any name for the file will do... - SuperSpacePixel::push_back(SpacePixelFile("salad")); - - // load the data from the file - if (!loadDxf( filecontents, NULL )) { - return false; - } - - if (SuperSpacePixel::size() == 1) { - SuperSpacePixel::m_region = SuperSpacePixel::tail().m_region; - } - else { - SuperSpacePixel::m_region = runion(SuperSpacePixel::m_region, SuperSpacePixel::tail().m_region); - } - - m_state |= LINEDATA; - - return true; -} - -// a second does the lot, especially for evolutionary graphs -// essentially, hand the ecoevograph a new meta graph each time... -// it'll do everything for you - -void MetaGraph::fastGraph( const Point2f& seed, double spacing ) -{ - setGrid( spacing ); - - PointMaps::getDisplayedPointMap().makePoints(seed, 0); // 0 = not semifilled - - m_state |= POINTMAPS; - - PointMaps::getDisplayedPointMap().sparkGraph2(NULL, 0, -1.0); - - // historical tag - essentially stamps version, so kept: - m_state |= ANGULARGRAPH; - - setViewClass(SHOWVGATOP); - - // Testing: - // write("dummy.graph"); -} - -int MetaGraph::importTxt( istream& stream, const pstring& name, bool csv ) -{ - int oldstate = m_state; - - m_state &= ~DATAMAPS; - - int x = m_data_maps.addMap(name,ShapeMap::DATAMAP); - - if (!m_data_maps.getDisplayedMap().importTxt( stream, csv )) { - m_data_maps.removeMap(x); - m_state = oldstate; - return -1; - } - - m_state |= DATAMAPS; - setViewClass(SHOWSHAPETOP); - - return x; -} - -/////////////////////////////////////////////////////////////////////////////// - -// New layer interaction code - -int MetaGraph::convertDataLayersToShapeMap(DataLayers& datalayers, PointMap& pointmap) -{ - int retvar = 1; - // check for existence of data: - pmap conversion_lookup; - size_t i; - for (i = 0; i < size_t(datalayers.getLayerCount()); i++) { - if (datalayers[i].getObjectCount()) { - int x = m_data_maps.addMap(datalayers[i].getLayerName(),ShapeMap::DATAMAP); - conversion_lookup.add(i,x); - } - } - // nothing to convert: - if (!conversion_lookup.size()) { - return 0; - } - - for (i = 0; i < conversion_lookup.size(); i++) { - ShapeMap& shapemap = m_data_maps.getMap(conversion_lookup.value(i)); - int layer_ref = datalayers.getLayerRef(conversion_lookup.key(i)); - pvecint *shape_pixel_lists = new pvecint [datalayers[i].getObjectCount()]; - int j; - for (j = 0; j < pointmap.getAttributeTable().getRowCount(); j++) { - PixelRef pix = pointmap.getAttributeTable().getRowKey(j); - int z = pointmap.getPoint(pix).getDataObject(layer_ref); - if (z != -1) { - shape_pixel_lists[z].push_back(pix); - } - } - // add shapes: - pvecint row_lookup; - for (j = 0; j < datalayers[i].getObjectCount(); j++) { - for (size_t k = 0; k < shape_pixel_lists[j].size(); k++) { - pointmap.overrideSelPixel(shape_pixel_lists[j][k]); - } - row_lookup.push_back(shapemap.makeShapeFromPointSet(pointmap)); - pointmap.clearSel(); - } - delete [] shape_pixel_lists; - // now add attributes: - AttributeTable& table = shapemap.getAttributeTable(); - // add columns, note, we'll have to add and then have lookups because not necessarily in alphabetical order: - for (j = 0; j < datalayers[i].getColumnCount(); j++) { - table.insertColumn(datalayers[i].getColumnTitle(j)); - } - pvecint column_lookup; - for (j = 0; j < datalayers[i].getColumnCount(); j++) { - column_lookup.push_back(table.getColumnIndex(datalayers[i].getColumnTitle(j))); - } - - // now we can add the data for this horrible matrix: - for (j = 0; j < datalayers[i].getObjectCount(); j++) { - for (int k = 0; k < datalayers[i].getColumnCount(); k++) { - if (row_lookup[j] != -1) { - int row = table.getRowid(row_lookup[j]); // row lookup should equal j since this is a new shape map, but for safety looked up - table.setValue(row,column_lookup[k],float(datalayers[i][j][k])); - } - else { - // conversion error occurred: - retvar = -1; - } - } - } - - // set the displayed attribute ready for first draw: - shapemap.overrideDisplayedAttribute(-2); - shapemap.setDisplayedAttribute(-1); - } - // the horror is over: - return retvar; -} - -// similar (but much, much easier than above -- relies on order of index order of -// axial lines being the same as as the created poly index order and both attribute -// tables -- should be since the map is in indexed order, as is its attribute table) - -// DEPRECATED: only need to switch map type flag - -void MetaGraph::convertShapeGraphToShapeMap(const ShapeGraph& axialmap) -{ - int x = m_data_maps.addMap("Axial Gates",ShapeMap::DATAMAP); - ShapeMap& shapemap = m_data_maps.getMap(x); - - // use the dangermouse all polygon grabber: - const pqmap& polys = axialmap.getAllShapes(); - shapemap.init(axialmap.getShapeCount(),axialmap.getRegion()); - size_t i; - for (i = 0; i < axialmap.getShapeCount(); i++) { - if (polys[i].isLine()) { // it ought to be since we're starting with an axial map! - shapemap.makeLineShape(polys[i].getLine()); - } - } - - // now convert attributes and we're done! - const AttributeTable& table_in = axialmap.getAttributeTable(); - AttributeTable& table_out = shapemap.getAttributeTable(); - - for (i = 0; i < size_t(table_in.getColumnCount()); i++) { - table_out.insertColumn(table_in.getColumnName(i)); - } - - int counter = 0; - for (i = 0; i < size_t(table_in.getRowCount()); i++) { - if (polys[i].isLine()) { // check needs to be maintained so indices match - for (int j = 0; j < table_in.getColumnCount(); j++) { - table_out.setValue(counter,j,table_in.getValue(i,j)); - } - counter++; // in case 'i' skips over a few non-line objects - } - } - - shapemap.overrideDisplayedAttribute(-2); - shapemap.setDisplayedAttribute(-1); -} - - -// the tidy(ish) version: still needs to be at top level and switch between layers - -bool MetaGraph::pushValuesToLayer(int desttype, int destlayer, int push_func, bool count_col) -{ - int sourcetype = m_view_class; - int sourcelayer = getDisplayedMapRef(); - int col_in = getDisplayedAttribute(); - // no col_out specified - int col_out = -2; - - // temporarily turn off everything to prevent redraw during sensitive time: - int oldstate = m_state; - m_state &= ~(DATAMAPS | AXIALLINES | POINTMAPS); - - bool retvar = pushValuesToLayer(sourcetype,sourcelayer,desttype,destlayer,col_in,col_out,push_func,count_col); - - m_state = oldstate; - - return retvar; -} - -// helper - -void pushValue(double& val, int& count, double thisval, int push_func) -{ - if (thisval != -1) { - switch (push_func) { - case MetaGraph::PUSH_FUNC_MAX: - if (val == -1 || thisval > val) - val = thisval; - break; - case MetaGraph::PUSH_FUNC_MIN: - if (val == -1 || thisval < val) - val = thisval; - break; - case MetaGraph::PUSH_FUNC_AVG: - case MetaGraph::PUSH_FUNC_TOT: - if (val == -1.0) - val = thisval; - else - val += thisval; - break; - } - count++; - } -} - -// the full ubercontrol version: +// the full ubercontrol version: bool MetaGraph::pushValuesToLayer(int sourcetype, int sourcelayer, int desttype, int destlayer, int col_in, int col_out, int push_func, bool count_col) { @@ -2109,89 +1791,112 @@ bool MetaGraph::pushValuesToLayer(int sourcetype, int sourcelayer, int desttype, AttributeTable& table_out = getAttributeTable(desttype, destlayer); if (col_out == -2) { - pstring name = table_in.getColumnName(col_in); - if ((table_out.isValidColumn(name) && table_out.isColumnLocked(table_out.getColumnIndex(name))) || name == "Object Count") { - name = pstring("Copied ") + name; + std::string name = table_in.getColumnName(col_in); + if ((table_out.hasColumn(name) && table_out.getColumn(table_out.getColumnIndex(name)).isLocked()) || name == "Object Count") { + name = std::string("Copied ") + name; } - col_out = table_out.insertColumn(name); + col_out = table_out.insertOrResetColumn(name); } int col_count = -1; if (count_col) { - col_count = table_out.insertColumn(pstring("Object Count")); + col_count = table_out.insertOrResetColumn("Object Count"); if (col_count <= col_out) { col_out++; } } if (sourcetype & VIEWDATA) { - pvecint gatelist; - for (int i = 0; i < table_out.getRowCount(); i++) { - if (!table_out.isVisible(i)) { - continue; - } - gatelist.clear(); + + for (auto iter_out = table_out.begin(); iter_out != table_out.end(); iter_out++) { + int key_out = iter_out->getKey().value; + std::vector gatelist; if (desttype == VIEWVGA) { - m_data_maps.getMap(sourcelayer).pointInPolyList(PointMaps::at(destlayer).getPoint(table_out.getRowKey(i)).m_location,gatelist); + if (!isObjectVisible(m_pointMaps[destlayer].m_layers, iter_out->getRow())) { + continue; + } + gatelist = m_dataMaps[sourcelayer].pointInPolyList(m_pointMaps[destlayer].getPoint(key_out).m_location); } else if (desttype == VIEWAXIAL) { - m_data_maps.getMap(sourcelayer).shapeInPolyList(m_shape_graphs.getMap(destlayer).getAllShapes().search(table_out.getRowKey(i)),gatelist); + if (!isObjectVisible(m_shapeGraphs[destlayer]->getLayers(), iter_out->getRow())) { + continue; + } + auto shapeMap = m_shapeGraphs[destlayer]->getAllShapes(); + gatelist = m_dataMaps[sourcelayer].shapeInPolyList(shapeMap[key_out]); } else if (desttype == VIEWDATA) { if (sourcelayer == destlayer) { // error: pushing to same map return false; } - m_data_maps.getMap(sourcelayer).shapeInPolyList(m_data_maps.getMap(destlayer).getAllShapes().search(table_out.getRowKey(i)),gatelist); + if (!isObjectVisible(m_dataMaps[destlayer].getLayers(), iter_out->getRow())) { + continue; + } + auto dataMap = m_dataMaps[destlayer].getAllShapes(); + gatelist = m_dataMaps[sourcelayer].shapeInPolyList(dataMap[key_out]); } double val = -1.0; int count = 0; - for (size_t j = 0; j < gatelist.size(); j++) { - if (table_in.isVisible(gatelist[j])) { - double thisval = table_in.getValue(gatelist[j],col_in); + for (int gate: gatelist) { + AttributeRow &row_in = + m_dataMaps[sourcelayer].getAttributeRowFromShapeIndex(gate); + + if (isObjectVisible(m_dataMaps[sourcelayer].getLayers(), row_in)) { + double thisval = row_in.getValue(col_in); pushValue(val,count,thisval,push_func); } } if (push_func == PUSH_FUNC_AVG && val != -1.0) { val /= double(count); } - table_out.setValue(i,col_out,float(val)); + iter_out->getRow().setValue(col_out,float(val)); if (count_col) { - table_out.setValue(i,col_count,float(count)); + iter_out->getRow().setValue(col_count,float(count)); } } } else { // prepare a temporary value table to store counts and values - double *vals = new double [table_out.getRowCount()]; - int *counts = new int [table_out.getRowCount()]; + std::vector vals(table_out.getNumRows()); + std::vector counts(table_out.getNumRows()); - int i; - for (i = 0; i < table_out.getRowCount(); i++) { + for (size_t i = 0; i < table_out.getNumRows(); i++) { counts[i] = 0; // count set to zero for all vals[i] = -1; } - pvecint gatelist; if (sourcetype & VIEWVGA) { - for (int i = 0; i < table_in.getRowCount(); i++) { - if (!table_in.isVisible(i)) { + for (auto iter_in = table_in.begin(); iter_in != table_in.end(); iter_in++) { + int pix_in = iter_in->getKey().value; + if (!isObjectVisible(m_pointMaps[sourcelayer].getLayers(), iter_in->getRow())) { continue; } - gatelist.clear(); + std::vector gatelist; if (desttype == VIEWDATA) { - m_data_maps.getMap(destlayer).pointInPolyList(PointMaps::at(sourcelayer).getPoint(table_in.getRowKey(i)).m_location,gatelist); - } - else if (desttype == VIEWAXIAL) { + gatelist = m_dataMaps[size_t(destlayer)].pointInPolyList(m_pointMaps[size_t(sourcelayer)].getPoint(pix_in).m_location); + double thisval = iter_in->getRow().getValue(col_in); + for (int gate: gatelist) { + AttributeRow &row_out = + m_dataMaps[destlayer].getAttributeRowFromShapeIndex(gate); + if (isObjectVisible(m_dataMaps[destlayer].getLayers(), row_out)) { + double& val = vals[gate]; + int& count = counts[gate]; + pushValue(val,count,thisval,push_func); + } + } + } else if (desttype == VIEWAXIAL) { // note, "axial" could be convex map, and hence this would be a valid operation - m_shape_graphs.getMap(destlayer).pointInPolyList(PointMaps::at(sourcelayer).getPoint(table_in.getRowKey(i)).m_location,gatelist); - } - double thisval = table_in.getValue(i,col_in); - for (size_t j = 0; j < gatelist.size(); j++) { - if (table_out.isVisible(gatelist[j])) { - double& val = vals[gatelist[j]]; - int& count = counts[gatelist[j]]; - pushValue(val,count,thisval,push_func); + gatelist = m_shapeGraphs[size_t(destlayer)]->pointInPolyList(m_pointMaps[size_t(sourcelayer)].getPoint(pix_in).m_location); + double thisval = iter_in->getRow().getValue(col_in); + for (int gate: gatelist) { + int key_out = m_shapeGraphs[destlayer]->getShapeRefFromIndex(gate)->first; + AttributeRow &row_out = + table_out.getRow(AttributeKey(key_out)); + if (isObjectVisible(m_shapeGraphs[destlayer]->getLayers(), row_out)) { + double& val = vals[gate]; + int& count = counts[gate]; + pushValue(val,count,thisval,push_func); + } } } } @@ -2201,126 +1906,78 @@ bool MetaGraph::pushValuesToLayer(int sourcetype, int sourcelayer, int desttype, // perform axial -> gate map in this direction // however, "Axial" to VGA, likely to have more points than "axial" shapes, should probably be performed using the first // algorithm - for (int i = 0; i < table_in.getRowCount(); i++) { - if (!table_in.isVisible(i)) { + for (auto iter_in = table_in.begin(); iter_in != table_in.end(); iter_in++) { + int key_in = iter_in->getKey().value; + if (!isObjectVisible(m_shapeGraphs[size_t(sourcelayer)]->getLayers(),iter_in->getRow())) { continue; } - gatelist.clear(); + std::vector gatelist; if (desttype == VIEWDATA) { - m_data_maps.getMap(destlayer).shapeInPolyList(m_shape_graphs.getMap(sourcelayer).getAllShapes().search(table_in.getRowKey(i)),gatelist); + auto dataMap = m_shapeGraphs[size_t(sourcelayer)]->getAllShapes(); + gatelist = m_dataMaps[size_t(destlayer)].shapeInPolyList(dataMap[key_in]); + double thisval = iter_in->getRow().getValue(col_in); + for (int gate: gatelist) { + int key_out = m_dataMaps[destlayer].getShapeRefFromIndex(gate)->first; + AttributeRow &row_out = + table_out.getRow(AttributeKey(key_out)); + if (isObjectVisible(m_dataMaps[size_t(destlayer)].getLayers(), row_out)) { + double& val = vals[gate]; + int& count = counts[gate]; + pushValue(val,count,thisval,push_func); + } + } } else if (desttype == VIEWAXIAL) { - m_shape_graphs.getMap(destlayer).shapeInPolyList(m_shape_graphs.getMap(sourcelayer).getAllShapes().search(table_in.getRowKey(i)),gatelist); - } - double thisval = table_in.getValue(i,col_in); - for (size_t j = 0; j < gatelist.size(); j++) { - if (table_out.isVisible(gatelist[j])) { - double& val = vals[gatelist[j]]; - int& count = counts[gatelist[j]]; - pushValue(val,count,thisval,push_func); + auto shapeMap = m_shapeGraphs[size_t(sourcelayer)]->getAllShapes(); + gatelist = m_shapeGraphs[size_t(destlayer)]->shapeInPolyList(shapeMap[key_in]); + double thisval = iter_in->getRow().getValue(col_in); + for (int gate: gatelist) { + int key_out = m_shapeGraphs[destlayer]->getShapeRefFromIndex(gate)->first; + AttributeRow &row_out = table_out.getRow(AttributeKey(key_out)); + if (isObjectVisible(m_shapeGraphs[destlayer]->getLayers(), row_out)) { + double& val = vals[gate]; + int& count = counts[gate]; + pushValue(val,count,thisval,push_func); + } } } } } + int i = -1; + for (auto iter = table_out.begin(); iter != table_out.end(); iter++) { + i++; - for (i = 0; i < table_out.getRowCount(); i++) { - if (!table_out.isVisible(i)) { + if (!isObjectVisible(m_shapeGraphs[destlayer]->getLayers(), iter->getRow())) { continue; } if (push_func == PUSH_FUNC_AVG && vals[i] != -1.0) { vals[i] /= double(counts[i]); } - table_out.setValue(i,col_out,float(vals[i])); + iter->getRow().setValue(col_out,float(vals[i])); if (count_col) { - table_out.setValue(i,col_count,float(counts[i])); + iter->getRow().setValue(col_count,float(counts[i])); } } - - delete [] vals; - delete [] counts; } // display new data in the relevant layer if (desttype == VIEWVGA) { - PointMaps::at(destlayer).overrideDisplayedAttribute(-2); - PointMaps::at(destlayer).setDisplayedAttribute(col_out); + m_pointMaps[destlayer].overrideDisplayedAttribute(-2); + m_pointMaps[destlayer].setDisplayedAttribute(col_out); } else if (desttype == VIEWAXIAL) { - m_shape_graphs.getMap(destlayer).overrideDisplayedAttribute(-2); - m_shape_graphs.getMap(destlayer).setDisplayedAttribute(col_out); + m_shapeGraphs[destlayer]->overrideDisplayedAttribute(-2); + m_shapeGraphs[destlayer]->setDisplayedAttribute(col_out); } else if (desttype == VIEWDATA) { - m_data_maps.getMap(destlayer).overrideDisplayedAttribute(-2); - m_data_maps.getMap(destlayer).setDisplayedAttribute(col_out); + m_dataMaps[destlayer].overrideDisplayedAttribute(-2); + m_dataMaps[destlayer].setDisplayedAttribute(col_out); } return true; } -// DEPRECATED CODE: REPLACED WITH THE FUNCTION ABOVE -// Replaced 21-Aug-05 - -/* -if (m_view_class & VIEWAXIAL) { - return m_shape_graphs.pushValuesToLayer(); -} - -// note: only pushes to gates... -DataLayer& layer = (DataLayer&) getLayer(DataLayers::GATES); - -int attr = PointMaps::getDisplayedPointMap().getDisplayedAttribute(); -const AttributeTable& table = PointMaps::getDisplayedPointMap().getAttributeTable(); - -// give the layer col a nice name! -int col = layer.addColumn( table.getColumnName(attr) ); - -// I think this is the only way to store how many points are in the object: -int *objpointcounts = new int [layer.getObjectCount()]; -for (int h = 0; h < layer.getObjectCount(); h++) { - objpointcounts[h] = 0; -} - -// just doing here for now: -PointMap& map = PointMaps::getDisplayedPointMap(); -for (int i = 0; i < map.m_cols; i++) { - for (int j = 0; j < map.m_rows; j++) { - if ( map.m_points[i][j].getState() & Point::FILLED ) { - int obj = map.m_points[i][j].getDataObject( getCurrentLayerRef() ); - if (obj != -1) { - if (average_over_isovist) { - // doesn't include self for now... - double val = 0.0; - Node& n = map.m_points[i][j].getNode(); - n.first(); - while (!n.is_tail()) - { - val += table.getValue(table.getRowIndex(n.cursor()),attr); - } - layer[obj][col] += val / map.m_points[i][j].getNode().count(); - } - else { - layer[obj][col] += table.getValue(table.getRowIndex(PixelRef(i,j)),attr); - } - objpointcounts[obj] += 1; - } - } - } -} - -for (int k = 0; k < layer.getObjectCount(); k++) -{ - layer[k][col] /= double(objpointcounts[k]); -} - -delete [] objpointcounts; - -// finally, tell layers that we'd like to view this next time: -layer.setDisplayColumn(col+1); // (+1 for ref number) -*/ - -/////////////////////////////////////////////////////////////////////////////////// - // Agent functionality: some of it still kept here with the metagraph // (to allow push value to layer and back again) @@ -2330,20 +1987,35 @@ void MetaGraph::runAgentEngine(Communicator *comm) if (m_agent_engine.m_gatelayer != -1) { // switch the reference numbers from the gates layer to the vga layer - int colgates = table.insertColumn(g_col_gate); + int colgates = table.insertOrResetColumn(g_col_gate); pushValuesToLayer(VIEWDATA,m_agent_engine.m_gatelayer, VIEWVGA,getDisplayedPointMapRef(), -1,colgates,PUSH_FUNC_TOT); - table.insertColumn(g_col_gate_counts); + table.insertOrResetColumn(g_col_gate_counts); } + m_agent_engine.run(comm, &(getDisplayedPointMap()) ); + if(m_agent_engine.m_record_trails) { + std::string mapName = "Agent Trails"; + int count = 1; + while(std::find_if(std::begin(m_dataMaps), std::end(m_dataMaps), + [&] (ShapeMap const& m) {return m.getName() == mapName; }) != m_dataMaps.end()) { + mapName = "Agent Trails " + std::to_string(count); + count++; + } + m_dataMaps.emplace_back(mapName); + m_agent_engine.insertTrailsInMap(m_dataMaps.back()); + + m_state |= DATAMAPS; + } + if (m_agent_engine.m_gatelayer != -1) { // switch column counts from vga layer to gates layer... int colcounts = table.getColumnIndex(g_col_gate_counts); - AttributeTable& tableout = m_data_maps.getMap(m_agent_engine.m_gatelayer).getAttributeTable(); - int targetcol = tableout.insertColumn("Agent Counts"); + AttributeTable& tableout = m_dataMaps[m_agent_engine.m_gatelayer].getAttributeTable(); + int targetcol = tableout.insertOrResetColumn("Agent Counts"); pushValuesToLayer(VIEWVGA,getDisplayedPointMapRef(), VIEWDATA,m_agent_engine.m_gatelayer, colcounts,targetcol,PUSH_FUNC_TOT); @@ -2355,16 +2027,16 @@ void MetaGraph::runAgentEngine(Communicator *comm) } // Thru vision - +// TODO: Undocumented functionality bool MetaGraph::analyseThruVision(Communicator *comm, int gatelayer) { - bool retvar = false; + bool analysisCompleted = false; AttributeTable& table = getDisplayedPointMap().getAttributeTable(); // always have temporary gate counting layers -- makes it easier to code - int colgates = table.insertColumn(g_col_gate); - int colcounts = table.insertColumn(g_col_gate_counts); + int colgates = table.insertOrResetColumn(g_col_gate); + int colcounts = table.insertOrResetColumn(g_col_gate_counts); if (gatelayer != -1) { // switch the reference numbers from the gates layer to the vga layer @@ -2374,19 +2046,19 @@ bool MetaGraph::analyseThruVision(Communicator *comm, int gatelayer) } try { - retvar = getDisplayedPointMap().analyseThruVision(comm); + analysisCompleted = VGAThroughVision().run(comm, getDisplayedPointMap(), false); } catch (Communicator::CancelledException) { - retvar = false; + analysisCompleted = false; } // note after the analysis, the column order might have changed... retrieve: colgates = table.getColumnIndex(g_col_gate); colcounts = table.getColumnIndex(g_col_gate_counts); - if (retvar && gatelayer != -1) { - AttributeTable& tableout = m_data_maps.getMap(gatelayer).getAttributeTable(); - int targetcol = tableout.insertColumn("Thru Vision Counts"); + if (analysisCompleted && gatelayer != -1) { + AttributeTable& tableout = m_dataMaps[gatelayer].getAttributeTable(); + int targetcol = tableout.insertOrResetColumn("Thru Vision Counts"); pushValuesToLayer(VIEWVGA,getDisplayedPointMapRef(), VIEWDATA,gatelayer, colcounts,targetcol,PUSH_FUNC_TOT); @@ -2396,7 +2068,7 @@ bool MetaGraph::analyseThruVision(Communicator *comm, int gatelayer) table.removeColumn(colcounts); table.removeColumn(colgates); - return retvar; + return analysisCompleted; } /////////////////////////////////////////////////////////////////////////////////// @@ -2406,13 +2078,13 @@ int MetaGraph::getDisplayedMapRef() const int ref = -1; switch (m_view_class & VIEWFRONT) { case VIEWVGA: - ref = PointMaps::getDisplayedPointMapRef(); + ref = getDisplayedPointMapRef(); break; case VIEWAXIAL: - ref = m_shape_graphs.getDisplayedMapRef(); + ref = getDisplayedShapeGraphRef(); break; case VIEWDATA: - ref = m_data_maps.getDisplayedMapRef(); + ref = getDisplayedDataMapRef(); break; } return ref; @@ -2423,16 +2095,39 @@ int MetaGraph::getDisplayedMapRef() const int MetaGraph::getDisplayedMapType() { - int type = ShapeMap::EMPTYMAP; switch (m_view_class & VIEWFRONT) { + case VIEWVGA: + return ShapeMap::POINTMAP; case VIEWAXIAL: - type = m_shape_graphs.getDisplayedMap().getMapType(); - break; + return getDisplayedShapeGraph().getMapType(); case VIEWDATA: - type = m_data_maps.getDisplayedMap().getMapType(); - break; + return getDisplayedDataMap().getMapType(); + } + return ShapeMap::EMPTYMAP; +} + +AttributeTable& MetaGraph::getDisplayedMapAttributes() +{ + switch (m_view_class & VIEWFRONT) { + case VIEWVGA: + return getDisplayedPointMap().getAttributeTable(); + case VIEWAXIAL: + return getDisplayedShapeGraph().getAttributeTable(); + case VIEWDATA: + return getDisplayedDataMap().getAttributeTable(); } - return type; + throw depthmapX::RuntimeException("No map displayed to get attribute table from"); +} + +bool MetaGraph::hasVisibleDrawingLayers() { + if(!m_drawingFiles.empty()) { + for (const auto& pixelGroup: m_drawingFiles) { + for (const auto& pixel: pixelGroup.m_spacePixels) { + if (pixel.isShown()) return true; + } + } + } + return false; } // note: 0 is not at all editable, 1 is editable off and 2 is editable on @@ -2450,9 +2145,9 @@ int MetaGraph::isEditable() const break; case VIEWAXIAL: { - int type = m_shape_graphs.getDisplayedMap().getMapType(); + int type = getDisplayedShapeGraph().getMapType(); if (type != ShapeMap::SEGMENTMAP && type != ShapeMap::ALLLINEMAP) { - editable = m_shape_graphs.getDisplayedMap().isEditable() ? EDITABLE_ON : EDITABLE_OFF; + editable = getDisplayedShapeGraph().isEditable() ? EDITABLE_ON : EDITABLE_OFF; } else { editable = NOT_EDITABLE; @@ -2460,7 +2155,7 @@ int MetaGraph::isEditable() const } break; case VIEWDATA: - editable = m_data_maps.getDisplayedMap().isEditable() ? EDITABLE_ON : EDITABLE_OFF; + editable = getDisplayedDataMap().isEditable() ? EDITABLE_ON : EDITABLE_OFF; break; } return editable; @@ -2474,10 +2169,10 @@ bool MetaGraph::canUndo() const canundo = getDisplayedPointMap().canUndo(); break; case VIEWAXIAL: - canundo = m_shape_graphs.getDisplayedMap().canUndo(); + canundo = getDisplayedShapeGraph().canUndo(); break; case VIEWDATA: - canundo = m_data_maps.getDisplayedMap().canUndo(); + canundo = getDisplayedDataMap().canUndo(); break; } return canundo; @@ -2490,17 +2185,17 @@ void MetaGraph::undo() getDisplayedPointMap().undoPoints(); break; case VIEWAXIAL: - m_shape_graphs.getDisplayedMap().undo(); + getDisplayedShapeGraph().undo(); break; case VIEWDATA: - m_data_maps.getDisplayedMap().undo(); + getDisplayedDataMap().undo(); break; } } // Moving to global ways of doing things: -int MetaGraph::addAttribute(const pstring& name) +int MetaGraph::addAttribute(const std::string& name) { int col; switch (m_view_class & VIEWFRONT) { @@ -2508,10 +2203,10 @@ int MetaGraph::addAttribute(const pstring& name) col = getDisplayedPointMap().addAttribute(name); break; case VIEWAXIAL: - col = m_shape_graphs.getDisplayedMap().addAttribute(name); + col = getDisplayedShapeGraph().addAttribute(name); break; case VIEWDATA: - col = m_data_maps.getDisplayedMap().addAttribute(name); + col = getDisplayedDataMap().addAttribute(name); break; } return col; @@ -2524,17 +2219,17 @@ void MetaGraph::removeAttribute(int col) getDisplayedPointMap().removeAttribute(col); break; case VIEWAXIAL: - m_shape_graphs.getDisplayedMap().removeAttribute(col); + getDisplayedShapeGraph().removeAttribute(col); break; case VIEWDATA: - m_data_maps.getDisplayedMap().removeAttribute(col); + getDisplayedDataMap().removeAttribute(col); break; } } bool MetaGraph::isAttributeLocked(int col) { - return getAttributeTable(m_view_class).isColumnLocked(col); + return getAttributeTable(m_view_class).getColumn(col).isLocked(); } int MetaGraph::getDisplayedAttribute() const @@ -2545,10 +2240,10 @@ int MetaGraph::getDisplayedAttribute() const col = getDisplayedPointMap().getDisplayedAttribute(); break; case VIEWAXIAL: - col = m_shape_graphs.getDisplayedMap().getDisplayedAttribute(); + col = getDisplayedShapeGraph().getDisplayedAttribute(); break; case VIEWDATA: - col = m_data_maps.getDisplayedMap().getDisplayedAttribute(); + col = getDisplayedDataMap().getDisplayedAttribute(); break; } return col; @@ -2563,12 +2258,12 @@ void MetaGraph::setDisplayedAttribute(int col) getDisplayedPointMap().setDisplayedAttribute(col); break; case VIEWAXIAL: - m_shape_graphs.getDisplayedMap().overrideDisplayedAttribute(-2); - m_shape_graphs.getDisplayedMap().setDisplayedAttribute(col); + getDisplayedShapeGraph().overrideDisplayedAttribute(-2); + getDisplayedShapeGraph().setDisplayedAttribute(col); break; case VIEWDATA: - m_data_maps.getDisplayedMap().overrideDisplayedAttribute(-2); - m_data_maps.getDisplayedMap().setDisplayedAttribute(col); + getDisplayedDataMap().overrideDisplayedAttribute(-2); + getDisplayedDataMap().setDisplayedAttribute(col); break; } } @@ -2583,13 +2278,13 @@ AttributeTable& MetaGraph::getAttributeTable(int type, int layer) } switch (type & VIEWFRONT) { case VIEWVGA: - tab = (layer == -1) ? &(getDisplayedPointMap().getAttributeTable()) : &(PointMaps::at(layer).getAttributeTable()); + tab = (layer == -1) ? &(getDisplayedPointMap().getAttributeTable()) : &(m_pointMaps[layer].getAttributeTable()); break; case VIEWAXIAL: - tab = (layer == -1) ? &(m_shape_graphs.getDisplayedMap().getAttributeTable()) : &(m_shape_graphs.getMap(layer).getAttributeTable()); + tab = (layer == -1) ? &(getDisplayedShapeGraph().getAttributeTable()) : &(m_shapeGraphs[layer]->getAttributeTable()); break; case VIEWDATA: - tab = (layer == -1) ? &(m_data_maps.getDisplayedMap().getAttributeTable()) : &(m_data_maps.getMap(layer).getAttributeTable()); + tab = (layer == -1) ? &(getDisplayedDataMap().getAttributeTable()) : &(m_dataMaps[layer].getAttributeTable()); break; } return *tab; @@ -2603,110 +2298,114 @@ const AttributeTable& MetaGraph::getAttributeTable(int type, int layer) const } switch (type) { case VIEWVGA: - tab = layer == -1 ? &(getDisplayedPointMap().getAttributeTable()) : &(PointMaps::at(layer).getAttributeTable()); + tab = layer == -1 ? &(getDisplayedPointMap().getAttributeTable()) : &(m_pointMaps[layer].getAttributeTable()); break; case VIEWAXIAL: - tab = layer == -1 ? &(m_shape_graphs.getDisplayedMap().getAttributeTable()) : &(m_shape_graphs.getMap(layer).getAttributeTable()); + tab = layer == -1 ? &(getDisplayedShapeGraph().getAttributeTable()) : &(m_shapeGraphs[layer]->getAttributeTable()); break; case VIEWDATA: - tab = layer == -1 ? &(m_data_maps.getDisplayedMap().getAttributeTable()) : &(m_data_maps.getMap(layer).getAttributeTable()); + tab = layer == -1 ? &(getDisplayedDataMap().getAttributeTable()) : &(m_dataMaps[layer].getAttributeTable()); break; } return *tab; } - -/////////////////////////////////////////////////////////////////////////////////// - -/* -// These two functions are no longer supported - -// for editing spacespixel lines post build - -// *before* using these functions you need to make at least one layer -// *editable* (e.g., getLineLayer(0,0).setEditable(true)) -// *after* using these functions you need to rebuild the graph -// (use dynamicSparkGraph2) - -int MetaGraph::addLineDynamic(const Line& l) -{ - LineKey linekey = -1; - - // this is only used once the graph is built - if (!getDisplayedPointMap().isProcessed()) { - return linekey; - } - - PointMaps::getDisplayedPointMap().blockLines(); - - for (int i = 0; i < getLineFileCount(); i++) { - for (int j = 0; j < getLineLayerCount(i); j++) { - // chooses the first editable layer it can find: - if (SuperSpacePixel::at(i).at(j).isEditable()) { - SpacePixel& spacepix = SuperSpacePixel::at(i).at(j); - linekey.file = i; - linekey.layer = j; - linekey.lineref = spacepix.addLineDynamic(l); - } - } +LayerManagerImpl &MetaGraph::getLayers(int type, int layer) { + LayerManagerImpl *tab = NULL; + if (type == -1) { + type = m_view_class; + } + switch (type & VIEWFRONT) { + case VIEWVGA: + tab = (layer == -1) ? &(getDisplayedPointMap().getLayers()) : &(m_pointMaps[layer].getLayers()); + break; + case VIEWAXIAL: + tab = (layer == -1) ? &(getDisplayedShapeGraph().getLayers()) : &(m_shapeGraphs[layer]->getLayers()); + break; + case VIEWDATA: + tab = (layer == -1) ? &(getDisplayedDataMap().getLayers()) : &(m_dataMaps[layer].getLayers()); + break; + } + return *tab; +} + +const LayerManagerImpl &MetaGraph::getLayers(int type, int layer) const { + const LayerManagerImpl *tab = NULL; + if (type == -1) { + type = m_view_class & VIEWFRONT; + } + switch (type) { + case VIEWVGA: + tab = layer == -1 ? &(getDisplayedPointMap().getLayers()) : &(m_pointMaps[layer].getLayers()); + break; + case VIEWAXIAL: + tab = layer == -1 ? &(getDisplayedShapeGraph().getLayers()) : &(m_shapeGraphs[layer]->getLayers()); + break; + case VIEWDATA: + tab = layer == -1 ? &(getDisplayedDataMap().getLayers()) : &(m_dataMaps[layer].getLayers()); + break; + } + return *tab; +} + +AttributeTableHandle& MetaGraph::getAttributeTableHandle(int type, int layer) +{ + AttributeTableHandle *tab = NULL; + if (type == -1) { + type = m_view_class; } - - if (linekey != -1) { - // update the pointdata... nb. The graph isn't affected until you rebuild graph - // (as you might be playing with more than one line at a time it seems sensible to - // wait until you're ready to go with all of them) - PointMaps::getDisplayedPointMap().addLineDynamic(linekey,l); + switch (type & VIEWFRONT) { + case VIEWVGA: + tab = (layer == -1) ? &(getDisplayedPointMap().getAttributeTableHandle()) : &(m_pointMaps[layer].getAttributeTableHandle()); + break; + case VIEWAXIAL: + tab = (layer == -1) ? &(getDisplayedShapeGraph().getAttributeTableHandle()) : &(m_shapeGraphs[layer]->getAttributeTableHandle()); + break; + case VIEWDATA: + tab = (layer == -1) ? &(getDisplayedDataMap().getAttributeTableHandle()) : &(m_dataMaps[layer].getAttributeTableHandle()); + break; } - - return linekey; + return *tab; } -bool MetaGraph::removeLineDynamic(LineKey linekey) +const AttributeTableHandle& MetaGraph::getAttributeTableHandle(int type, int layer) const { - bool retvar = false; - - // this is only used once the graph is built - if (!getDisplayedPointMap().isProcessed()) { - return retvar; + const AttributeTableHandle *tab = NULL; + if (type == -1) { + type = m_view_class & VIEWFRONT; } - - // first *before adding or removing the line* ensure existing lines are blocked - PointMaps::getDisplayedPointMap().blockLines(); - - if (linekey != -1) { // <- this will be typical value when unset - SpacePixel& spacepix = SuperSpacePixel::at(linekey.file).at(linekey.layer); - Line line; - retvar = spacepix.removeLineDynamic(linekey.lineref,line); - - if (retvar) { - // update the pointdata... nb. The graph isn't affected until you rebuild graph - // (as you might be playing with more than one line at a time it seems sensible to - // wait until you're ready to go with all of them) - // Note: the line itself is used to find the affected pixels - PointMaps::getDisplayedPointMap().removeLineDynamic(linekey,line); - } + switch (type) { + case VIEWVGA: + tab = layer == -1 ? &(getDisplayedPointMap().getAttributeTableHandle()) : &(m_pointMaps[layer].getAttributeTableHandle()); + break; + case VIEWAXIAL: + tab = layer == -1 ? &(getDisplayedShapeGraph().getAttributeTableHandle()) : &(m_shapeGraphs[layer]->getAttributeTableHandle()); + break; + case VIEWDATA: + tab = layer == -1 ? &(getDisplayedDataMap().getAttributeTableHandle()) : &(m_dataMaps[layer].getAttributeTableHandle()); + break; } - - return retvar; + return *tab; } -*/ -/////////////////////////////////////////////////////////////////////////////// -void MetaGraph::loadGraphAgent() +int MetaGraph::readFromFile( const std::string& filename ) { -// Graph::m_nodes.openread(); -// Graph::m_nodes.loadmem(); -} -void MetaGraph::unloadGraphAgent() -{ -// Graph::m_nodes.unloadmem(); -// Graph::m_nodes.close(); -} + if (filename.empty()) { + return NOT_A_GRAPH; + } -/////////////////////////////////////////////////////////////////////////////// + #ifdef _WIN32 + std::ifstream stream( filename.c_str(), std::ios::binary | std::ios::in ); + #else + std::ifstream stream( filename.c_str(), std::ios::in ); + #endif + int result = readFromStream(stream, filename); + stream.close(); + return result; +} -int MetaGraph::read( const pstring& filename ) +int MetaGraph::readFromStream( std::istream &stream, const std::string& filename ) { m_state = 0; // <- clear the state out @@ -2717,48 +2416,37 @@ int MetaGraph::read( const pstring& filename ) } m_bsp_tree = false; - if (filename.empty()) { - return NOT_A_GRAPH; - } - -#ifdef _WIN32 - ifstream stream( filename.c_str(), ios::binary | ios::in ); -#else - ifstream stream( filename.c_str(), ios::in ); -#endif - char header[3]; stream.read( header, 3 ); if (stream.fail() || header[0] != 'g' || header[1] != 'r' || header[2] != 'f') { - stream.close(); return NOT_A_GRAPH; } int version; stream.read( (char *) &version, sizeof( version ) ); m_file_version = version; // <- recorded for easy debugging if (version > METAGRAPH_VERSION) { - stream.close(); return NEWER_VERSION; } - if (version == VERSION_VIEW_CLASS_ADDED) { - stream.close(); - return DEPRECATED_VERSION; // trial version no longer supported + if (version < METAGRAPH_VERSION) { + std::unique_ptr mgraph(new mgraph440::MetaGraph); + auto result = mgraph->read(filename); + if ( result != mgraph440::MetaGraph::OK) + { + return DAMAGED_FILE; + } + std::stringstream tempstream; + mgraph->writeToStream(tempstream, METAGRAPH_VERSION, 0); + + return readFromStream(tempstream, filename); } // have to use temporary state here as redraw attempt may come too early: int temp_state = 0; - if (version >= VERSION_STATE_RECORDED) { - stream.read( (char *) &temp_state, sizeof( temp_state ) ); - } - - if (version >= VERSION_VIEW_CLASS_ADDED) { - stream.read( (char *) &m_view_class, sizeof(m_view_class) ); - } - - if (version >= VERSION_STORE_GRIDTEXTINFO) { - stream.read( (char *) &m_showgrid, sizeof(m_showgrid) ); - stream.read( (char *) &m_showtext, sizeof(m_showtext) ); - } + int temp_view_class = 0; + stream.read( (char *) &temp_state, sizeof( temp_state ) ); + stream.read( (char *) &temp_view_class, sizeof(temp_view_class) ); + stream.read( (char *) &m_showgrid, sizeof(m_showgrid) ); + stream.read( (char *) &m_showtext, sizeof(m_showtext) ); // type codes: x --- properties // v --- virtual graph (from versions below 70) @@ -2767,15 +2455,26 @@ int MetaGraph::read( const pstring& filename ) // p --- point data // d --- data summary layers - bool conversion_required = false; - char type; stream.read( &type, 1 ); + if (type == 'd') { + // contains deprecated datalayers. Read through mgraph440 which will + // convert them into shapemaps + std::unique_ptr mgraph(new mgraph440::MetaGraph); + auto result = mgraph->read(filename); + if ( result != mgraph440::MetaGraph::OK) + { + return DAMAGED_FILE; + } + std::stringstream tempstream; + mgraph->writeToStream(tempstream, METAGRAPH_VERSION, 0); + + return readFromStream(tempstream, filename); + } if (type == 'x') { - FileProperties::read(stream,version); + FileProperties::read(stream); if (stream.eof()) { // erk... this shouldn't happen - stream.close(); return DAMAGED_FILE; } else if (!stream.eof()) { @@ -2785,11 +2484,13 @@ int MetaGraph::read( const pstring& filename ) else { FileProperties::setProperties("","","",""); } + if (stream.eof()) { + // file is still ok, just empty + return OK; + } if (type == 'v') { - conversion_required = true; - - skipVirtualMem(stream,version); + skipVirtualMem(stream); // and set our filename: // Graph::m_nodes.setFilename( filename ); @@ -2799,7 +2500,6 @@ int MetaGraph::read( const pstring& filename ) if (stream.eof()) { // erk... this shouldn't happen - stream.close(); return DAMAGED_FILE; } else if (!stream.eof()) { @@ -2807,59 +2507,37 @@ int MetaGraph::read( const pstring& filename ) } } if (type == 'l') { - try { - SuperSpacePixel::read( stream, version ); - temp_state |= LINEDATA; - if (!stream.eof()) { - stream.read( &type, 1 ); - } + m_name = dXstring::readString(stream); + stream.read( (char *) &m_region, sizeof(m_region) ); + int count; + stream.read( (char *) &count, sizeof(count) ); + for (int i = 0; i < count; i++) { + m_drawingFiles.emplace_back(); + m_drawingFiles.back().read(stream); + } + + if (m_name.empty()) { + m_name = ""; + } + temp_state |= LINEDATA; + if (!stream.eof()) { + stream.read( &type, 1 ); } - catch (pexception) { + if (!stream.eof() && !stream.good()) { // erk... this shouldn't happen - stream.close(); return DAMAGED_FILE; } } if (type == 'p') { - if (version < VERSION_NGRAPH_INTROD) { - // This hasn't been coded yet - stream.close(); - return DEPRECATED_VERSION; - } - if (version < VERSION_POINT_MAPS) { - PointMaps::push_back(PointMap()); - if (temp_state & 0x0001) { // 0x0001 was "GRAPH" - PointMaps::tail().m_processed = true; - temp_state &= ~0x0001; - } - if (temp_state & 0x0080) { // 0x0080 was "BOUNDARYGRAPH" - PointMaps::tail().m_boundarygraph = true; - temp_state &= ~0x0080; - } - PointMaps::tail().read( stream, version ); - setDisplayedPointMapRef(0); - } - else { - PointMaps::read( stream, version ); - } - PointMaps::setSpacePixel( (SuperSpacePixel *) this ); + readPointMaps( stream ); temp_state |= POINTMAPS; if (!stream.eof()) { stream.read( &type, 1 ); } } if (type == 'g') { - // Note the older version stored its attributes in a different location... - // ...well, actually, now it's been rearranged, pretty similar to the original... - // hasn't been coded yet, though (see above) - if (version < VERSION_NGRAPH_INTROD) { - if (!convertAttributes( stream, version )) { - stream.close(); - return DAMAGED_FILE; - } - } // record on state of actual point map: - PointMaps::tail().m_processed = true; + m_pointMaps.back().m_processed = true; if (!stream.eof()) { stream.read( &type, 1 ); @@ -2871,99 +2549,29 @@ int MetaGraph::read( const pstring& filename ) stream.read( &type, 1 ); } } - if (type == 'd') { - // data layers are deprecated: data layers have been replaced by shape maps - // so: first read data layers: - DataLayers dl; - dl.read( stream, version ); - // now replace with shape maps, but only if layer exists: - temp_state &= ~DATAMAPS; - // converter requires a point map to work on: - if (PointMaps::size()) { - // returns 0 if there are actually no objects in the shapemaps to convert, - int conv_ok = convertDataLayersToShapeMap(dl,getDisplayedPointMap()); - if (conv_ok == 1) { - // read objects in: - temp_state |= DATAMAPS; - } - else if (conv_ok == -1) { - // read objects in, but had trouble converting them: - temp_state |= DATAMAPS; - temp_state |= WARN_CONVERTED; - } - } - if (!stream.eof()) { - stream.read( &type, 1 ); - } - } if (type == 'x') { - m_shape_graphs.read( stream, version ); + readShapeGraphs(stream); temp_state |= SHAPEGRAPHS; - /* - // THIS CODE IS NO LONGER REQUIRED AS AXIAL MAPS *ARE* SHAPE MAPS -- can just be switched to shape map layer - if (version < VERSION_SHAPE_MAPS && m_shape_graphs.m_gate_map != -1) { - // check for a gate map: - convertShapeGraphToShapeMap(m_shape_graphs.at(m_shape_graphs.m_gate_map)); - // delete the gate map: - m_shape_graphs.remove_at(m_shape_graphs.m_gate_map); - if (m_shape_graphs.m_displayed_map >= m_shape_graphs.m_gate_map) { - int map = m_shape_graphs.m_displayed_map; - m_shape_graphs.m_displayed_map = -1; // <- have to do this as setDisplayedShapeGraph clearSels a map that may not exist anymore - setDisplayedShapeGraph(map-1); - } - m_shape_graphs.m_gate_map = -1; - if (m_shape_graphs.size() == 0) { - temp_state &= ~SHAPEGRAPHS; - } - // assume objects read in okay: - temp_state |= DATAMAPS; - } - */ if (!stream.eof()) { stream.read( &type, 1 ); } } if (type == 's') { - m_data_maps.read( stream, version ); + readDataMaps(stream); temp_state |= DATAMAPS; if (!stream.eof()) { stream.read( &type, 1 ); } } - - stream.close(); - m_state = temp_state; - - if (version < VERSION_VIEW_CLASS_ADDED) { - if (m_state & POINTMAPS) { - m_view_class = VIEWVGA; - } - else { - m_view_class = VIEWNONE; - } - } - - // Note, below version 70, the graph data must be reread: - if (version < VERSION_NGRAPH_INTROD && conversion_required) { - // reopen the stream and convert - stream.open(filename.c_str(), ios::binary | ios::in ); - int ok = convertVirtualMem(stream, version); - stream.close(); - return ok; - } - - if (version == VERSION_EXTRA_POINT_DATA_INTROD || version == VERSION_NGRAPH_INTROD || version == VERSION_SEGMENT_MAPS) { - m_state |= BUGGY; - return WARN_BUGGY_VERSION; - } + m_view_class = temp_view_class; return OK; } -int MetaGraph::write( const pstring& filename, int version, bool currentlayer ) +int MetaGraph::write( const std::string& filename, int version, bool currentlayer ) { - ofstream stream; + std::ofstream stream; int oldstate = m_state; m_state = 0; // <- temporarily clear out state, avoids any potential read / write errors @@ -2971,7 +2579,7 @@ int MetaGraph::write( const pstring& filename, int version, bool currentlayer ) char type; // As of MetaGraph version 70 the disk caching has been removed - stream.open( filename.c_str(), ios::binary | ios::out | ios::trunc ); + stream.open( filename.c_str(), std::ios::binary | std::ios::out | std::ios::trunc ); if (stream.fail()) { if (stream.rdbuf()->is_open()) { stream.close(); @@ -3014,39 +2622,47 @@ int MetaGraph::write( const pstring& filename, int version, bool currentlayer ) if (m_view_class & MetaGraph::VIEWVGA) { type = 'p'; stream.write(&type, 1); - PointMaps::write( stream, version, true ); + writePointMaps( stream, true ); } else if (m_view_class & MetaGraph::VIEWAXIAL) { type = 'x'; stream.write(&type, 1); - m_shape_graphs.write( stream, version, true ); + writeShapeGraphs( stream, true ); } else if (m_view_class & MetaGraph::VIEWDATA) { type = 's'; stream.write(&type, 1); - m_data_maps.write( stream, version, true ); + writeDataMaps( stream, true ); } } else { if (oldstate & LINEDATA) { type = 'l'; stream.write(&type, 1); - SuperSpacePixel::write( stream, version ); + dXstring::writeString(stream, m_name); + stream.write( (char *) &m_region, sizeof(m_region) ); + + // Quick mod - TV + int count = m_drawingFiles.size(); + stream.write( (char *) &count, sizeof(count) ); + for (auto& spacePixel: m_drawingFiles) { + spacePixel.write(stream); + } } if (oldstate & POINTMAPS) { type = 'p'; stream.write(&type, 1); - PointMaps::write( stream, version ); + writePointMaps( stream ); } if (oldstate & SHAPEGRAPHS) { type = 'x'; stream.write(&type, 1); - m_shape_graphs.write( stream, version ); + writeShapeGraphs( stream ); } if (oldstate & DATAMAPS) { type = 's'; stream.write(&type, 1); - m_data_maps.write( stream, version ); + writeDataMaps( stream ); } } @@ -3056,154 +2672,287 @@ int MetaGraph::write( const pstring& filename, int version, bool currentlayer ) return OK; } -int MetaGraph::convertAttributes( ifstream& stream, int version ) -{ - int ret = 1; - // This is adapted from original ArVertexList code: +std::streampos MetaGraph::skipVirtualMem(std::istream& stream) +{ + // it's graph virtual memory: skip it + int nodes = -1; + stream.read( (char *) &nodes, sizeof(nodes) ); - int attr_count, which_attributes; - stream.read( (char *) &which_attributes, sizeof(int) ); - stream.read( (char *) &attr_count, sizeof(int) ); + nodes *= 2; - int size; - stream.read( (char *) &size, sizeof(int) ); - - if (m_attr_conv_table) - delete m_attr_conv_table; - m_attr_conv_table = new pqvector; - pqvector& attrs = *m_attr_conv_table; - - size_t i; - for (i = 0; i < size_t(size); i++) { - AttrBody attr(-1, g_attr_header); - attr.read(stream, attr_count); // <- only write in saved attributes - if (attr.ref != -1) { - attrs.add( attr ); - } + for (int i = 0; i < nodes; i++) { + int connections; + stream.read( (char *) &connections, sizeof(connections) ); + stream.seekg( stream.tellg() + std::streamoff(connections * sizeof(connections)) ); } + return (stream.tellg()); +} - for (size_t ii = 0; ii < attrs.size(); ii++) { - // Check these are numbered 0 to n, and set the pos to be used later: - if (attrs[ii].ref != ii) { - ret = 0; - break; - } - attrs[ii].pos = -1; - } +std::vector MetaGraph::getVisibleDrawingLines() { - if (ret == 0) { - delete m_attr_conv_table; - m_attr_conv_table = NULL; - return 0; - } + std::vector lines; - for (i = 0; i < PointMaps::size(); i++) { - PointMap& map = PointMaps::at(i); - for (int j = 0; j < map.m_cols; j++) { - for (int k = 0; k < map.m_rows; k++) { - // Note: block used to be the noderef - if (map.m_points[j][k].filled() && map.m_points[j][k].m_block != -1) { - AttrBody test(-1,g_attr_header); - test.ref = map.m_points[j][k].m_block; - size_t pos = attrs.searchindex(test); - if (pos != paftl::npos) { - map.m_points[j][k].setAttributes(attrs[pos]); - attrs[pos].pos = (int) PixelRef(j,k); // <- note this can be used to convert the virtual mem quickly - } - else { - // oops - ret = 0; - } + for (const auto& pixelGroup: m_drawingFiles) { + for (const auto& pixel: pixelGroup.m_spacePixels) { + if (pixel.isShown()) { + const std::vector &newLines = pixel.getAllShapesAsLines(); + lines.insert(std::end(lines), std::begin(newLines), std::end(newLines)); } + } + } + return lines; +} + +int MetaGraph::addNewPointMap(const std::string& name) +{ + std::string myname = name; + int counter = 1; + bool duplicate = true; + while (duplicate) { + duplicate = false; + for (auto& pointMap: m_pointMaps) { + if (pointMap.getName() == myname) { + duplicate = true; + myname = dXstring::formatString(counter++,name + " %d"); + break; } } } - return ret; + m_pointMaps.push_back(PointMap(m_region, m_drawingFiles, myname)); + m_displayed_pointmap = m_pointMaps.size() - 1; + return m_pointMaps.size() - 1; } -#include // for conversion - -int MetaGraph::convertVirtualMem( ifstream& stream, int version ) +bool MetaGraph::readPointMaps(std::istream& stream) { - if (!m_attr_conv_table) { - return 0; + stream.read((char *) &m_displayed_pointmap, sizeof(m_displayed_pointmap)); + int count; + stream.read((char *) &count, sizeof(count)); + for (int i = 0; i < count; i++) { + m_pointMaps.push_back(PointMap(m_region, m_drawingFiles)); + m_pointMaps.back().read( stream ); } - if (~m_state & ANGULARGRAPH) { - // can't convert non-angular graphs: - if (m_attr_conv_table) - delete m_attr_conv_table; - m_attr_conv_table = NULL; - return DEPRECATED_VERSION; - } - - // The attr conv table can help us quickly convert: - pqvector& attrs = *m_attr_conv_table; - - pvecint nodes; - pvecint bins; - - PixelRefList bins_b[32]; - static float far_bin_dists[32]; - for (int ii = 0; ii < 32; ii++) { - far_bin_dists[ii] = 0.0f; - } - - char header[3]; - stream.read( header, 3 ); // 'grf' - stream.read( (char *) &version, sizeof( version ) ); // version - char type; - stream.read( (char *) &type, sizeof( type ) ); // 'v' - - int size; - stream.read( (char *) &size, sizeof( size ) ); - - PointMap& map = PointMaps::tail(); - for (int i = 0; i < size; i++) { - nodes.read(stream); - bins.read(stream); - if (attrs[i].pos != -1) { - PixelRef curs = (PixelRef) attrs[i].pos; - - for (int j = 0; j < 32; j++) { - for (int k = loword(bins[j]); k < hiword(bins[j]); k++) { - int next = attrs[nodes[k]].pos; - if (next != -1) { - bins_b[j].push_back( (PixelRef) next ); - } - } - } + return true; +} - Point& pt = map.getPoint( curs ); - pt.m_node = new Node; - pt.m_node->make( curs, bins_b, far_bin_dists, 0x00FF ); +bool MetaGraph::writePointMaps(std::ofstream& stream, bool displayedmaponly) +{ + if (!displayedmaponly) { + stream.write((char *) &m_displayed_pointmap, sizeof(m_displayed_pointmap)); + int count = m_pointMaps.size(); + stream.write((char *) &count, sizeof(count)); + for (auto& pointmap: m_pointMaps) { + pointmap.write( stream ); } - nodes.clear(); - bins.clear(); } + else { + int dummy; + // displayed map is 0: + dummy = 0; + stream.write((char *) &dummy, sizeof(dummy)); + // count is 1 + dummy = 1; + stream.write((char *) &dummy, sizeof(dummy)); + // + m_pointMaps[m_displayed_pointmap].write(stream); + } + return true; +} - delete m_attr_conv_table; - m_attr_conv_table = NULL; +bool MetaGraph::readDataMaps(std::istream& stream ) +{ + m_dataMaps.clear(); // empty existing data + // n.b. -- do not change to size_t as will cause 32-bit to 64-bit conversion problems + unsigned int displayed_map; + stream.read((char *)&displayed_map,sizeof(displayed_map)); + m_displayed_datamap = size_t(displayed_map); + // read maps + // n.b. -- do not change to size_t as will cause 32-bit to 64-bit conversion problems + unsigned int count = 0; + stream.read((char *) &count, sizeof(count)); - return WARN_CONVERTED; + for (size_t j = 0; j < size_t(count); j++) { + m_dataMaps.emplace_back(); + m_dataMaps.back().read(stream); + } + return true; } -streampos MetaGraph::skipVirtualMem(ifstream& stream, int version) +bool MetaGraph::writeDataMaps( std::ofstream& stream, bool displayedmaponly ) { - // it's graph virtual memory: skip it - int nodes = -1; - stream.read( (char *) &nodes, sizeof(nodes) ); + if (!displayedmaponly) { + // n.b. -- do not change to size_t as will cause 32-bit to 64-bit conversion problems + unsigned int displayed_map = (unsigned int)(m_displayed_datamap); + stream.write((char *)&displayed_map,sizeof(displayed_map)); + // write maps + // n.b. -- do not change to size_t as will cause 32-bit to 64-bit conversion problems + unsigned int count = (unsigned int) m_dataMaps.size(); + stream.write((char *) &count, sizeof(count)); + for (size_t j = 0; j < count; j++) { + m_dataMaps[j].write(stream); + } + } + else { + unsigned int dummy; + // displayed map is 0 + dummy = 0; + stream.write((char *)&dummy,sizeof(dummy)); + // count is 1 + dummy = 1; + stream.write((char *)&dummy,sizeof(dummy)); + // write map: + m_dataMaps[m_displayed_datamap].write(stream); + } + return true; +} - // in angular version, have to skip two pvectors for each node: - if (version >= 30) - nodes *= 2; - for (int i = 0; i < nodes; i++) { - int connections; - stream.read( (char *) &connections, sizeof(connections) ); - // This relies on the pvecint storage... hope it don't change! - stream.seekg( stream.tellg() + streamoff(connections * sizeof(connections)) ); +bool MetaGraph::readShapeGraphs(std::istream& stream) +{ + m_shapeGraphs.clear(); // empty existing data + // n.b. -- do not change to size_t as will cause 32-bit to 64-bit conversion problems + unsigned int displayed_map; + stream.read((char *)&displayed_map,sizeof(displayed_map)); + setDisplayedShapeGraphRef(int(displayed_map)); + // read maps + // n.b. -- do not change to size_t as will cause 32-bit to 64-bit conversion problems + unsigned int count = 0; + stream.read((char *) &count, sizeof(count)); + + for (size_t j = 0; j < size_t(count); j++) { + m_shapeGraphs.push_back(std::unique_ptr(new ShapeGraph())); + + // P.K. Hairy solution given that we don't know the type/name of the shapegraph + // before we actually read it: mark the beginning of the shapegraph in the stream + // and if it's found to be an AllLineMap then just roll the stream back and read + // from the mark again + + long mark = stream.tellg(); + m_shapeGraphs.back()->read(stream); + std::string name = m_shapeGraphs.back()->getName(); + + if(name == "All-Line Map" || + name == "All Line Map") { + m_shapeGraphs.pop_back(); + m_shapeGraphs.push_back(std::unique_ptr(new AllLineMap())); + stream.seekg(mark); + m_shapeGraphs.back()->read(stream); + } + } + + // P.K: ideally this should be read together with the + // all-line map, but the way the graph file is structured + // this is not possible + // TODO: Fix on next graph file update + + bool foundAllLineMap = false; + for(size_t i = 0; i < m_shapeGraphs.size(); i++) { + ShapeGraph* shapeGraph = m_shapeGraphs[i].get(); + if(shapeGraph->getName() == "All-Line Map" || + shapeGraph->getName() == "All Line Map") { + foundAllLineMap = true; + AllLineMap* alllinemap = dynamic_cast(shapeGraph); + if(alllinemap == nullptr) { + throw depthmapX::RuntimeException("Failed to cast from ShapeGraph to AllLineMap"); + } + // these are additional essentially for all line axial maps + // should probably be kept *with* the all line axial map... + alllinemap->m_poly_connections.clear(); + dXreadwrite::readIntoVector(stream, alllinemap->m_poly_connections); + alllinemap->m_radial_lines.clear(); + dXreadwrite::readIntoVector(stream, alllinemap->m_radial_lines); + + // this is an index to look up the all line map, used by UI to determine if can make fewest line map + // note: it is not saved for historical reasons + // will get confused by more than one all line map + m_all_line_map = int(i); + + // there is currently only one: + break; + } + } + if(!foundAllLineMap) { + // P.K. This is just a dummy read to cover cases where there is no All-Line Map + // The below is taken from pmemvec::read + + // READ / WRITE USES 32-bit LENGTHS (number of elements) + // n.b., do not change this to size_t as it will cause 32-bit to 64-bit conversion problems + unsigned int length; + stream.read( (char *) &length, sizeof(unsigned int) ); + stream.read( (char *) &length, sizeof(unsigned int) ); + } + return true; +} + +bool MetaGraph::writeShapeGraphs( std::ofstream& stream, bool displayedmaponly ) +{ + if (!displayedmaponly) { + // n.b. -- do not change to size_t as will cause 32-bit to 64-bit conversion problems + unsigned int displayed_map = (unsigned int)(getDisplayedShapeGraphRef()); + stream.write((char *)&displayed_map,sizeof(displayed_map)); + // write maps + // n.b. -- do not change to size_t as will cause 32-bit to 64-bit conversion problems + unsigned int count = (unsigned int) m_shapeGraphs.size(); + stream.write((char *) &count, sizeof(count)); + for (size_t j = 0; j < count; j++) { + m_shapeGraphs[j]->write(stream); + } + } + else { + unsigned int dummy; + // displayed map is 0 + dummy = 0; + stream.write((char *)&dummy,sizeof(dummy)); + // count is 1 + dummy = 1; + stream.write((char *)&dummy,sizeof(dummy)); + // write map: + m_shapeGraphs[getDisplayedShapeGraphRef()]->write(stream); + } + + if(m_all_line_map == -1) { + std::vector temp_poly_connections; + std::vector temp_radial_lines; + + dXreadwrite::writeVector(stream, temp_poly_connections); + dXreadwrite::writeVector(stream, temp_radial_lines); + } else { + AllLineMap* alllinemap = dynamic_cast(m_shapeGraphs[size_t(m_all_line_map)].get()); + + if(alllinemap == nullptr) { + throw depthmapX::RuntimeException("Failed to cast from ShapeGraph to AllLineMap"); + } + + dXreadwrite::writeVector(stream, alllinemap->m_poly_connections); + dXreadwrite::writeVector(stream, alllinemap->m_radial_lines); + } + return true; +} + +void MetaGraph::makeViewportShapes( const QtRegion& viewport ) const +{ + m_current_layer = -1; + size_t i = m_drawingFiles.size() - 1; + for (auto iter = m_drawingFiles.rbegin(); iter != m_drawingFiles.rend(); iter++) { + if (iter->isShown()) { + m_current_layer = (int) i; + iter->makeViewportShapes( (viewport.atZero() ? m_region : viewport) ); + } + i--; + } +} + +bool MetaGraph::findNextShape(bool& nextlayer) const +{ + if (m_current_layer == -1) + return false; + while (!m_drawingFiles[m_current_layer].findNextShape(nextlayer)) { + while (++m_current_layer < (int)m_drawingFiles.size() && !m_drawingFiles[m_current_layer].isShown()); + if (m_current_layer == static_cast(m_drawingFiles.size())) { + m_current_layer = -1; + return false; + } } - return (stream.tellg()); + return true; } - diff --git a/salalib/mgraph.h b/salalib/mgraph.h index 32a6595e..5eadc874 100644 --- a/salalib/mgraph.h +++ b/salalib/mgraph.h @@ -15,162 +15,31 @@ // along with this program. If not, see . -#ifndef __MGRAPH_H__ -#define __MGRAPH_H__ +#pragma once // Interface: the meta graph loads and holds all sorts of arbitrary data... -// Current metagraph version -const int METAGRAPH_VERSION = 440; +#include "salalib/mgraph_consts.h" +#include "salalib/displayparams.h" +#include "salalib/fileproperties.h" +#include "salalib/importtypedefs.h" -// Human readable(ish) metagraph version changes +// still call paftl: +#include "salalib/connector.h" +#include "salalib/spacepix.h" +#include "salalib/agents/agentengine.h" // for agent engine interface -const int VERSION_ALWAYS_RECORD_BINDISTANCES = 440; +// still need paftl: +#include "salalib/shapemap.h" +#include "salalib/pointdata.h" +#include "salalib/axialmap.h" -// 17-Aug-2010 Version stamp for Depthmap 10.08.00 -const int VERSION_100800 = 430; -// 12-Jul-2010 Version stamp for Depthmap 10.07.00 -const int VERSION_100700 = 430; +#include "genlib/p2dpoly.h" -// 12-Jul-2010 Occlusion distances for agent control test -const int VERSION_OCCDISTANCES = 430; - -// 07-Feb-2010 Axial lines no longer self-connect -const int VERSION_NO_SELF_CONNECTION = 420; - -// 31-Jan-2009 Maps have sublayers -const int VERSION_MAP_LAYERS = 410; -// -// 390 and 400 used only for testing -// -// 31-Jan-2009 this is simply a version stamp for Depthmap 8.14.00 and 8.15.00 -// The idea is that I should start writing code that saves in version 380 format -// as a benchmark "save for older version" -const int VERSION_81500 = 380; -const int VERSION_81400 = 380; -// -// 20-Apr-2008 The shape map name lookup could have been corrupted. In addition it's not that useful (never much to sort through, unique layer names not necessary) -const int VERSION_NO_SHAPEMAP_NAME_LOOKUP = 380; -// 15-Mar-2008 -const int VERSION_SHAPE_AREA_PERIMETER = 370; -const int VERSION_FORGET_COLUMN_CREATOR = 370; -// 04-Oct-2007 -const int VERSION_MAP_TYPES = 360; -// 20-Sep-2007 -const int VERSION_STORE_COLUMN_CREATOR = 350; -const int VERSION_ATTRIBUTE_LOCKING = 350; -// version 340 unused -// 08-Jun-2007: Store all drawing layers as shape maps rather than spacepixels (continued) -const int VERSION_DRAWING_SHAPES_B = 330; -// 27-Nov-2006: Store all drawing layers as shape maps rather than spacepixels -const int VERSION_DRAWING_SHAPES = 320; -// 27-Nov-2006: Store axial maps as children of shape maps rather than spacepixels -const int VERSION_AXIAL_SHAPES = 310; -// 01-Sep-2006: Store formulae for columns -const int VERSION_STORE_FORMULA = 300; -// 14-May-2006: Occlusions with node -const int VERSION_OCCLUSIONS = 290; -// 28-Dec-2005: Polygon shapes have centroids -const int VERSION_SHAPE_CENTROIDS = 280; -// 18-Dec-2005: Mapinfo data read into shape maps instead of axial maps -const int VERSION_MAPINFO_SHAPES = 270; -// 14-Sep-2005: QtRegion bug with segment maps from imported axial maps fixed: -const int VERSION_AXIAL_REGION_FIX = 263; -// 01-Sep-2005: Now Pointmaps really ought to store their names: -const int VERSION_POINT_MAP_NAMES = 262; -// 25-Aug-2005: And an extension to shape maps to make them easier to use as lines or points -const int VERSION_EXTENDED_SHAPE_MAPS = 261; -// 23-Aug-2005: Although in test from 11-Aug-2005, useful to read the testing graphs created: -const int VERSION_SHAPE_MAPS = 260; -// 11-Aug-2005: Also, a set of PointMaps now replace a single instance of PointData -const int VERSION_POINT_MAPS = 251; -// 11-Aug-2005: Location stored with points, not depixelated on the fly -const int VERSION_POINT_LOCATIONS = 250; -// 01-Mar-2005: Quick grid connections -const int VERSION_GRID_CONNECTIONS = 240; -// 02-Dec-2004: Axial map gates -const int VERSION_GATE_MAPS = 230; -// 29-Oct-2004: Store the colour display settings with the graph data -const int VERSION_STORE_GRIDTEXTINFO = 220; -// 29-Oct-2004: Store the colour display settings with the graph data -const int VERSION_STORE_COLOR = 210; -// 16-Jun-2004: New boundary graph (now much simpler: nodes at edge of main graph) -const int VERSION_NEWBOUNDARYGRAPH = 200; -// 20-May-2004: Each segment must have forward and backward connections listed separately! -const int VERSION_SEGMENT_MAPS_FIX = 191; -// 17-May-2004: Axial maps can be either segment or axial maps. Affects ShapeGraph and AxialLine classes -const int VERSION_SEGMENT_MAPS = 190; -// 12-May-2004: Extra Mapinfo table data -const int VERSION_MAPINFO_DATA = 180; -// 06-May-2004: Explicit links and unlinks for axial lines -const int VERSION_AXIAL_LINKS = 170; -// 29-Feb-2004: Attributes table (already used for AxialLines) now used for PointData as well -const int VERSION_ATTRIBUTES_TABLE = 160; -// File compression introduced -const int VERSION_FILE_COMPRESSION = 150; -// Some minor modifications to the axial line format... won't load v.130 files -const int VERSION_REVISED_AXIAL = 140; -// View class specifies whether axial or vga currently viewed -const int VERSION_VIEW_CLASS_ADDED = 130; -// A distance stored in the bin -const int VERSION_BINDISTANCES = 120; -// A set of nodes on the boundaries of the isovist -const int VERSION_BOUNDARYGRAPH = 110; -// Dynamic lines (addable and removable) in the visibility graph -const int VERSION_DYNAMICLINES = 100; -// Line layers are coloured... -const int VERSION_LAYERCOLORS = 91; -// Blocked locations split into 4, replaces m_noderef -const int VERSION_BLOCKEDQUAD = 90; -// Space pixel groups have different space pixels for different layers (at their own resolution!) -const int VERSION_SPACEPIXELGROUPS = 80; -// The graph state is just recorded -const int VERSION_STATE_RECORDED = 72; -// The binsizes weren't included in the metagraph 70 -const int VERSION_NGRAPH_BINCOUNT = 71; -// Major, major changes to the graph format (from now on it will now be held in memory only) -const int VERSION_NGRAPH_INTROD = 70; -// Slight changes to PointData required for the actual implementation of the quick graph -const int VERSION_SPARK_GRAPH_INTROD = 61; -// Quick graph... add underlying info about lines into the pointdata structure -const int VERSION_QUICK_GRAPH_INTROD = 60; -// Layers -const int VERSION_LAYERS_CENTROID_INTROD = 51; -const int VERSION_LAYERS_INTROD = 50; -// version 41 repairs VERSION_EXTRA_POINT_DATA_INTROD bug -const int VERSION_EXTRA_POINT_DATA_INTROD = 40; -const int VERSION_BINS_INTROD = 30; - -/////////////////////////////////////////////////////////////////////////////// - -const unsigned int SALA_SELECTED_COLOR = 0x00FFFF77; -const unsigned int SALA_HIGHLIGHTED_COLOR = 0x0077FFFF; - -/////////////////////////////////////////////////////////////////////////////// - -// Parse errors for MapInfo: - -enum { MINFO_OK, MINFO_HEADER, MINFO_TABLE, MINFO_MIFPARSE, MINFO_OBJROWS, MINFO_MULTIPLE }; - -/////////////////////////////////////////////////////////////////////////////// - -#include -#include - -#include // mainly deprecated, but includes display params -#include -#include -#include - -#include -#include -#include -#include -#include // datalayers deprecated - -// for agent engine interface -#include +#include +#include +#include /////////////////////////////////////////////////////////////////////////////////// @@ -178,28 +47,47 @@ class Communicator; // A meta graph is precisely what it says it is -class MetaGraph : public SuperSpacePixel, public PointMaps, public FileProperties +class MetaGraph : public FileProperties { +private: + QtRegion m_region; // easier public for now + std::string m_name; public: + std::vector m_drawingFiles; + const QtRegion& getRegion() { return m_region; } + void setRegion(Point2f& bottomLeft, Point2f& topRight) + { m_region.bottom_left = bottomLeft; m_region.top_right = topRight; } + bool isShown() const + { for (size_t i = 0; i < m_drawingFiles.size(); i++) if (m_drawingFiles[i].isShown()) return true; return false; } + + // TODO: drawing state functions/fields that should be eventually removed + void makeViewportShapes( const QtRegion& viewport ) const; + bool findNextShape(bool& nextlayer) const; + const SalaShape& getNextShape() const + { return m_drawingFiles[m_current_layer].getNextShape(); } + mutable int m_current_layer; + enum { ADD = 0x0001, REPLACE = 0x0002, CAT = 0x0010, DXF = 0x0020, NTF = 0x0040, RT1 = 0x0080, GML = 0x0100 }; - enum { NONE = 0x0000, /* GRAPH = 0x0001, Deprecated */ POINTMAPS = 0x0002, LINEDATA = 0x0004, - FIXED = 0x0008 /* Deprecated */, ANGULARGRAPH = 0x0010, DATAMAPS = 0x0020, AXIALLINES = 0x0040, /* BOUNDARYGRAPH = 0x0080, Deprecated */ SHAPEGRAPHS = 0x0100, - PREWRITTEN = 0x1000, BUGGY = 0x8000 }; + enum { NONE = 0x0000, POINTMAPS = 0x0002, LINEDATA = 0x0004, + ANGULARGRAPH = 0x0010, DATAMAPS = 0x0020, AXIALLINES = 0x0040, SHAPEGRAPHS = 0x0100, + BUGGY = 0x8000 }; enum { NOT_EDITABLE = 0, EDITABLE_OFF = 1, EDITABLE_ON = 2 }; protected: int m_file_version; int m_state; - void *m_lock; public: // some display options now set at file level bool m_showgrid; bool m_showtext; // public: - ShapeMaps m_data_maps; - ShapeGraphs m_shape_graphs; + std::vector m_dataMaps; + + std::vector> m_shapeGraphs; + int m_displayed_shapegraph = -1; + public: - MetaGraph(); + MetaGraph(std::string name = ""); ~MetaGraph(); // int getVersion() @@ -207,56 +95,68 @@ class MetaGraph : public SuperSpacePixel, public PointMaps, public FilePropertie // note, if unsaved, m_file_version is -1 return m_file_version; } - bool setLock(void *who) - { - if (m_lock == 0) { - m_lock = who; - return true; - } - return false; - } - bool releaseLock(void *who) + + + std::vector& getPointMaps() + { return m_pointMaps; } + PointMap& getDisplayedPointMap() + { return m_pointMaps[m_displayed_pointmap]; } + const PointMap& getDisplayedPointMap() const + { return m_pointMaps[m_displayed_pointmap]; } + void setDisplayedPointMapRef(int i) + { m_displayed_pointmap = i; } + int getDisplayedPointMapRef() const + { return m_displayed_pointmap; } + void redoPointMapBlockLines() // (flags blockedlines, but also flags that you need to rebuild a bsp tree if you have one) + { for (auto& pointMap: m_pointMaps) { pointMap.m_blockedlines = false; } } + int addNewPointMap(const std::string& name = std::string("VGA Map")); + +private: + std::vector m_pointMaps; + int m_displayed_pointmap = -1; + + // helpful to know this for creating fewest line maps, although has to be reread at input + int m_all_line_map = -1; + + void removePointMap(int i) { - if (m_lock != who) { - return false; - } - m_lock = NULL; - return true; + if (m_displayed_pointmap >= i) m_displayed_pointmap--; + if(m_displayed_pointmap < 0) m_displayed_pointmap = 0; + m_pointMaps.erase(m_pointMaps.begin() + i); } - // - void copyLineData(const SuperSpacePixel& meta); - void copyPointMap(const PointMap& meta); - // + + bool readPointMaps(std::istream &stream); + bool writePointMaps(std::ofstream& stream, bool displayedmaponly = false ); + + std::recursive_mutex mLock; +public: + std::unique_lock getLock(){ + return std::unique_lock(mLock); + } + + std::unique_lock getLockDeferred(){ + return std::unique_lock(mLock, std::defer_lock_t()); + } + int getState() const { return m_state; } // use with caution: only very rarely needed outside MetaGraph itself void setState(int state) { m_state = state; } - // - // quick loaders from input streams rather than files: - bool importCat( istream& stream ); - bool importDxf( istream& stream ); - // make a graph using the supplied seed and graph spacing: - void fastGraph( const Point2f& seed, double spacing ); - // + int loadLineData( Communicator *communicator, int load_type ); - int loadCat( istream& stream, Communicator *communicator ); - int loadDxf( istream& stream, Communicator *communicator ); - // Quick mod - TV -#if defined(_WIN32) - int loadRT1(const pqvector& fileset, Communicator *communicator); -#else - int loadRT1(const pqvector& fileset, Communicator *communicator); -#endif - int importTxt( istream& stream, const pstring& layername, bool csv ); - bool undoPoints(); + void writeMapShapesAsCat(ShapeMap& map, std::ostream &stream); + int loadCat( std::istream& stream, Communicator *communicator ); + int loadRT1(const std::vector& fileset, Communicator *communicator); + ShapeMap &createNewShapeMap(depthmapX::ImportType mapType, std::string name); + void deleteShapeMap(depthmapX::ImportType mapType, ShapeMap &shapeMap); + void updateParentRegions(ShapeMap &shapeMap); bool clearPoints(); bool setGrid( double spacing, const Point2f& offset = Point2f() ); // override of PointMap bool makePoints( const Point2f& p, int semifilled, Communicator *communicator = NULL); // override of PointMap bool makeGraph( Communicator *communicator, int algorithm, double maxdist ); + bool unmakeGraph(bool removeLinks); bool analyseGraph(Communicator *communicator, Options options , bool simple_version); // <- options copied to keep thread safe - bool analyseAngular( Communicator *communicator, bool analyse_in_memory ); - bool makeAxialLines( Communicator *communicator, bool analyse_in_memory ); // // helpers for editing maps bool isEditableMap(); @@ -265,42 +165,47 @@ class MetaGraph : public SuperSpacePixel, public PointMaps, public FilePropertie bool makeShape(const Line& line); bool moveSelShape(const Line& line); // onto polys as well: - bool polyBegin(const Line& line); - bool polyAppend(const Point2f& point); - bool polyClose(); - bool polyCancel(); + int polyBegin(const Line& line); + bool polyAppend(int shape_ref, const Point2f& point); + bool polyClose(int shape_ref); + bool polyCancel(int shape_ref); // - int addShapeGraph(const pstring& name, int type); - int addShapeMap(const pstring& name); + int addShapeGraph(std::unique_ptr& shapeGraph); + int addShapeGraph(const std::string& name, int type); + int addShapeMap(const std::string& name); void removeDisplayedMap(); // // various map conversions - bool convertDrawingToAxial(Communicator *comm, pstring layer_name); // n.b., name copied for thread safety - bool convertDataToAxial(Communicator *comm, pstring layer_name, bool keeporiginal, bool pushvalues); - bool convertDrawingToSegment(Communicator *comm, pstring layer_name); - bool convertDataToSegment(Communicator *comm, pstring layer_name, bool keeporiginal, bool pushvalues); - bool convertToData(Communicator *comm, pstring layer_name, bool keeporiginal, int typeflag); // -1 signifies convert from drawing layer, else convert from data map - bool convertToDrawing(Communicator *comm, pstring layer_name, int typeflag); // 0 signifies convert from data map, else convert from graph - bool convertToConvex(Communicator *comm, pstring layer_name, bool keeporiginal, int typeflag); // -1 signifies convert from drawing layer, else convert from data map - bool convertAxialToSegment(Communicator *comm, pstring layer_name, bool keeporiginal, bool pushvalues, double stubremoval); - // note: not same categories - bool convertPointsToShape(); - //bool convertBoundaryGraph( Communicator *communicator ); - // - // some compatibility with older version horrors: - int convertDataLayersToShapeMap(DataLayers& datalayers, PointMap& pointmap); - void convertShapeGraphToShapeMap(const ShapeGraph& axialmap); - // - int loadMifMap(Communicator *comm, istream& miffile, istream& midfile); + bool convertDrawingToAxial(Communicator *comm, std::string layer_name); // n.b., name copied for thread safety + bool convertDataToAxial(Communicator *comm, std::string layer_name, bool keeporiginal, bool pushvalues); + bool convertDrawingToSegment(Communicator *comm, std::string layer_name); + bool convertDataToSegment(Communicator *comm, std::string layer_name, bool keeporiginal, bool pushvalues); + bool convertToData(Communicator *, std::string layer_name, bool keeporiginal, int shapeMapType, bool copydata); + bool convertToDrawing(Communicator *, std::string layer_name, bool fromDisplayedDataMap); + bool convertToConvex(Communicator *comm, std::string layer_name, bool keeporiginal, int shapeMapType, bool copydata); + bool convertAxialToSegment(Communicator *comm, std::string layer_name, bool keeporiginal, bool pushvalues, double stubremoval); + int loadMifMap(Communicator *comm, std::istream& miffile, std::istream& midfile); bool makeAllLineMap( Communicator *communicator, const Point2f& seed ); bool makeFewestLineMap( Communicator *communicator, int replace ); - bool analyseAxial( Communicator *communicator, Options options, bool simple_version ); // <- options copied to keep thread safe - bool analyseSegments( Communicator *communicator, Options options ); // <- options copied to keep thread safe + bool analyseAxial(Communicator *communicator, Options options, bool); // <- options copied to keep thread safe + bool analyseSegmentsTulip( Communicator *communicator, Options options ); // <- options copied to keep thread safe + bool analyseSegmentsAngular( Communicator *communicator, Options options ); // <- options copied to keep thread safe + bool analyseTopoMetMultipleRadii( Communicator *communicator, Options options ); // <- options copied to keep thread safe bool analyseTopoMet( Communicator *communicator, Options options ); // <- options copied to keep thread safe // bool hasAllLineMap() - { return m_shape_graphs.hasAllLineMap(); } - // + { return m_all_line_map != -1; } + bool hasFewestLineMaps() { + for(const auto& shapeGraph: m_shapeGraphs) { + if(shapeGraph->getName() == "Fewest-Line Map (Subsets)" || + shapeGraph->getName() == "Fewest Line Map (Subsets)" || + shapeGraph->getName() == "Fewest-Line Map (Minimal)" || + shapeGraph->getName() == "Fewest Line Map (Minimal)") { + return true; + } + } + return false; + } enum { PUSH_FUNC_MAX = 0, PUSH_FUNC_MIN = 1, PUSH_FUNC_AVG = 2, PUSH_FUNC_TOT = 3}; bool pushValuesToLayer(int desttype, int destlayer, int push_func, bool count_col = false); bool pushValuesToLayer(int sourcetype, int sourcelayer, int desttype, int destlayer, int col_in, int col_out, int push_func, bool count_col = false); @@ -311,49 +216,98 @@ class MetaGraph : public SuperSpacePixel, public PointMaps, public FilePropertie int isEditable() const; bool canUndo() const; void undo(); - // - ShapeGraph& getDisplayedShapeGraph() - { return m_shape_graphs.getDisplayedMap(); } + + size_t m_displayed_datamap = -1; ShapeMap& getDisplayedDataMap() - { return m_data_maps.getDisplayedMap(); } - ShapeGraphs& getShapeGraphs() - { return m_shape_graphs; } - ShapeMaps& getDataMaps() - { return m_data_maps; } + { return m_dataMaps[m_displayed_datamap]; } + const ShapeMap& getDisplayedDataMap() const + { return m_dataMaps[m_displayed_datamap]; } + size_t getDisplayedDataMapRef() const + { return m_displayed_datamap; } + + void removeDataMap(size_t i) + { if (m_displayed_datamap >= i) m_displayed_datamap--; m_dataMaps.erase(m_dataMaps.begin() + i); } + + void setDisplayedDataMapRef(size_t map) + { + if (static_cast(m_displayed_datamap) != -1 && m_displayed_datamap != map) + m_dataMaps[m_displayed_datamap].clearSel(); + m_displayed_datamap = map; + } + + template + size_t getMapRef(std::vector& maps, const std::string& name) const + { + // note, only finds first map with this name + for (size_t i = 0; i < maps.size(); i++) { + if (maps[i].getName() == name) + return i; + } + return -1; + } + + std::vector >& getShapeGraphs() + { return m_shapeGraphs; } + ShapeGraph& getDisplayedShapeGraph() + { return *m_shapeGraphs[m_displayed_shapegraph].get(); } + const ShapeGraph& getDisplayedShapeGraph() const + { return *m_shapeGraphs[m_displayed_shapegraph].get(); } + void setDisplayedShapeGraphRef(int map) + { + if (m_displayed_shapegraph != -1 && m_displayed_shapegraph != map) + m_shapeGraphs[size_t(m_displayed_shapegraph)]->clearSel(); + m_displayed_shapegraph = map; + } + int getDisplayedShapeGraphRef() const + { return m_displayed_shapegraph; } + + void removeShapeGraph(int i) + { + if (m_displayed_shapegraph >= i) m_displayed_shapegraph--; + if(m_displayed_shapegraph < 0) m_displayed_shapegraph = 0; + m_shapeGraphs.erase(m_shapeGraphs.begin() + i); + } + + bool readShapeGraphs(std::istream &stream); + bool writeShapeGraphs(std::ofstream& stream, bool displayedmaponly = false ); + + std::vector& getDataMaps() + { return m_dataMaps; } + + bool readDataMaps(std::istream &stream); + bool writeDataMaps(std::ofstream& stream, bool displayedmaponly = false ); + // int getDisplayedMapType(); - // + AttributeTable& getDisplayedMapAttributes(); + bool hasVisibleDrawingLayers(); QtRegion getBoundingBox() const; // int getDisplayedAttribute() const; void setDisplayedAttribute(int col); - int addAttribute(const pstring& name); + int addAttribute(const std::string& name); void removeAttribute(int col); bool isAttributeLocked(int col); AttributeTable& getAttributeTable(int type = -1, int layer = -1); const AttributeTable& getAttributeTable(int type = -1, int layer = -1) const; - // - void loadGraphAgent(); - void unloadGraphAgent(); - // + LayerManagerImpl& getLayers(int type = -1, int layer = -1); + const LayerManagerImpl& getLayers(int type = -1, int layer = -1) const; + AttributeTableHandle& getAttributeTableHandle(int type = -1, int layer = -1); + const AttributeTableHandle& getAttributeTableHandle(int type = -1, int layer = -1) const; + int getLineFileCount() const - { return (int) SuperSpacePixel::size(); } + { return (int) m_drawingFiles.size(); } // Quick mod - TV - const pstring& getLineFileName(int file) const - { return SuperSpacePixel::at(file).getName(); } + const std::string& getLineFileName(int file) const + { return m_drawingFiles[file].getName(); } int getLineLayerCount(int file) const - { return (int) SuperSpacePixel::at(file).size(); } + { return (int) m_drawingFiles[file].m_spacePixels.size(); } - // -/* SpacePixel& getLineLayer(int file, int layer) - { return SuperSpacePixel::at(file).at(layer); } - const SpacePixel& getLineLayer(int file, int layer) const - { return SuperSpacePixel::at(file).at(layer); }*/ ShapeMap& getLineLayer(int file, int layer) - { return SuperSpacePixel::at(file).at(layer); } + { return m_drawingFiles[file].m_spacePixels[layer]; } const ShapeMap& getLineLayer(int file, int layer) const - { return SuperSpacePixel::at(file).at(layer); } + { return m_drawingFiles[file].m_spacePixels[layer]; } // // Some error handling -- the idea is that you catch the error in MetaGraph, // return a generic error code and then get your front end to interrogate the @@ -363,9 +317,9 @@ class MetaGraph : public SuperSpacePixel, public PointMaps, public FilePropertie class Error { protected: - pstring error; + std::string error; public: - Error(const pstring& err = pstring()) { error = err; } + Error(const std::string& err = std::string()) { error = err; } }; protected: Error m_last_error; @@ -378,7 +332,7 @@ class MetaGraph : public SuperSpacePixel, public PointMaps, public FilePropertie public: enum { SHOWHIDEVGA = 0x0100, SHOWVGATOP = 0x0200, SHOWHIDEAXIAL = 0x0400, SHOWAXIALTOP = 0x0800, SHOWHIDESHAPE = 0x1000, SHOWSHAPETOP = 0x2000 }; enum { VIEWNONE = 0x00, VIEWVGA = 0x01, VIEWBACKVGA = 0x02, VIEWAXIAL = 0x04, VIEWBACKAXIAL = 0x08, - VIEWLINKS = 0x10, VIEWDATA = 0x20, VIEWBACKDATA = 0x40, VIEWFRONT = 0x25, VIEWBACK = 0x4a }; + VIEWDATA = 0x20, VIEWBACKDATA = 0x40, VIEWFRONT = 0x25 }; // int getViewClass() { return m_view_class; } @@ -408,23 +362,23 @@ class MetaGraph : public SuperSpacePixel, public PointMaps, public FilePropertie { if (m_view_class & VIEWVGA) return getDisplayedPointMap().isSelected(); else if (m_view_class & VIEWAXIAL) - return m_shape_graphs.getDisplayedMap().isSelected(); + return getDisplayedShapeGraph().isSelected(); else if (m_view_class & VIEWDATA) - return m_data_maps.getDisplayedMap().isSelected(); + return getDisplayedDataMap().isSelected(); else return false; } bool setCurSel( QtRegion& r, bool add = false ) // set current selection { if (m_view_class & VIEWAXIAL) - return m_shape_graphs.getDisplayedMap().setCurSel(r, add); + return getDisplayedShapeGraph().setCurSel(r, add); else if (m_view_class & VIEWDATA) - return m_data_maps.getDisplayedMap().setCurSel( r, add ); + return getDisplayedDataMap().setCurSel( r, add ); else if (m_view_class & VIEWVGA) return getDisplayedPointMap().setCurSel( r, add ); else if (m_state & POINTMAPS && !getDisplayedPointMap().isProcessed()) // this is a default select application return getDisplayedPointMap().setCurSel( r, add ); else if (m_state & DATAMAPS) // I'm not sure why this is a possibility, but it appears you might have state & DATAMAPS without VIEWDATA... - return m_data_maps.getDisplayedMap().setCurSel( r, add ); + return getDisplayedDataMap().setCurSel( r, add ); else return false; } @@ -434,9 +388,9 @@ class MetaGraph : public SuperSpacePixel, public PointMaps, public FilePropertie if (m_view_class & VIEWVGA) return getDisplayedPointMap().clearSel(); else if (m_view_class & VIEWAXIAL) - return m_shape_graphs.getDisplayedMap().clearSel(); + return getDisplayedShapeGraph().clearSel(); else if (m_view_class & VIEWDATA) - return m_data_maps.getDisplayedMap().clearSel(); + return getDisplayedDataMap().clearSel(); else return false; } @@ -445,20 +399,20 @@ class MetaGraph : public SuperSpacePixel, public PointMaps, public FilePropertie if (m_view_class & VIEWVGA) return getDisplayedPointMap().getSelCount(); else if (m_view_class & VIEWAXIAL) - return (int) m_shape_graphs.getDisplayedMap().getSelCount(); + return (int) getDisplayedShapeGraph().getSelCount(); else if (m_view_class & VIEWDATA) - return (int) m_data_maps.getDisplayedMap().getSelCount(); + return (int) getDisplayedDataMap().getSelCount(); else return 0; } float getSelAvg() { if (m_view_class & VIEWVGA) - return (float)getDisplayedPointMap().getAttributeTable().getSelAvg(); + return (float)getDisplayedPointMap().getDisplayedSelectedAvg(); else if (m_view_class & VIEWAXIAL) - return (float)m_shape_graphs.getDisplayedMap().getAttributeTable().getSelAvg(); + return (float)getDisplayedShapeGraph().getDisplayedSelectedAvg(); else if (m_view_class & VIEWDATA) - return (float)m_data_maps.getDisplayedMap().getAttributeTable().getSelAvg(); + return (float)getDisplayedDataMap().getDisplayedSelectedAvg(); else return -1.0f; } @@ -467,34 +421,34 @@ class MetaGraph : public SuperSpacePixel, public PointMaps, public FilePropertie if (m_view_class & VIEWVGA) return getDisplayedPointMap().getSelBounds(); else if (m_view_class & VIEWAXIAL) - return m_shape_graphs.getDisplayedMap().getSelBounds(); + return getDisplayedShapeGraph().getSelBounds(); else if (m_view_class & VIEWDATA) - return m_data_maps.getDisplayedMap().getSelBounds(); + return getDisplayedDataMap().getSelBounds(); else return QtRegion(); } // setSelSet expects a set of ref ids: - void setSelSet(const pvecint& selset, bool add = false) + void setSelSet(const std::vector& selset, bool add = false) { if (m_view_class & VIEWVGA && m_state & POINTMAPS) getDisplayedPointMap().setCurSel(selset,add); else if (m_view_class & VIEWAXIAL) - m_shape_graphs.getDisplayedMap().setCurSel(selset,add); + getDisplayedShapeGraph().setCurSel(selset,add); else // if (m_view_class & VIEWDATA) - m_data_maps.getDisplayedMap().setCurSel(selset,add); } - pvecint& getSelSet() + getDisplayedDataMap().setCurSel(selset,add); } + std::set& getSelSet() { if (m_view_class & VIEWVGA && m_state & POINTMAPS) return getDisplayedPointMap().getSelSet(); else if (m_view_class & VIEWAXIAL) - return m_shape_graphs.getDisplayedMap().getSelSet(); + return getDisplayedShapeGraph().getSelSet(); else // if (m_view_class & VIEWDATA) - return m_data_maps.getDisplayedMap().getSelSet(); } - const pvecint& getSelSet() const + return getDisplayedDataMap().getSelSet(); } + const std::set& getSelSet() const { if (m_view_class & VIEWVGA && m_state & POINTMAPS) return getDisplayedPointMap().getSelSet(); else if (m_view_class & VIEWAXIAL) - return m_shape_graphs.getDisplayedMap().getSelSet(); + return getDisplayedShapeGraph().getSelSet(); else // if (m_view_class & VIEWDATA) - return m_data_maps.getDisplayedMap().getSelSet(); } + return getDisplayedDataMap().getSelSet(); } // public: // no longer supported @@ -530,18 +484,11 @@ class MetaGraph : public SuperSpacePixel, public PointMaps, public FilePropertie // a few read-write returns: enum { OK, WARN_BUGGY_VERSION, WARN_CONVERTED, NOT_A_GRAPH, DAMAGED_FILE, DISK_ERROR, NEWER_VERSION, DEPRECATED_VERSION }; // likely to use communicator if too slow... - int read( const pstring& filename ); - int write( const pstring& filename, int version, bool currentlayer = false); + int readFromFile( const std::string& filename ); + int readFromStream( std::istream &stream, const std::string& filename ); + int write( const std::string& filename, int version, bool currentlayer = false); // + std::vector getVisibleDrawingLines(); protected: - pqvector *m_attr_conv_table; - int convertAttributes( ifstream& stream, int version ); - int convertVirtualMem( ifstream& stream, int version ); - // - streampos skipVirtualMem(ifstream& stream, int version); - streampos copyVirtualMem(ifstream& reader, ofstream& writer, int version); + std::streampos skipVirtualMem(std::istream &stream); }; - -/////////////////////////////////////////////////////////////////////////////// - -#endif diff --git a/salalib/mgraph_consts.h b/salalib/mgraph_consts.h new file mode 100644 index 00000000..9ce17481 --- /dev/null +++ b/salalib/mgraph_consts.h @@ -0,0 +1,37 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2017 Christian Sailer + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +// Human readable(ish) metagraph version changes + +const int VERSION_ALWAYS_RECORD_BINDISTANCES = 440; + +// Current metagraph version +const int METAGRAPH_VERSION = VERSION_ALWAYS_RECORD_BINDISTANCES; + +/////////////////////////////////////////////////////////////////////////////// + +const unsigned int SALA_SELECTED_COLOR = 0x00FFFF77; +const unsigned int SALA_HIGHLIGHTED_COLOR = 0x0077FFFF; + +/////////////////////////////////////////////////////////////////////////////// + +// Parse errors for MapInfo: + +enum { MINFO_OK, MINFO_HEADER, MINFO_TABLE, MINFO_MIFPARSE, MINFO_OBJROWS, MINFO_MULTIPLE }; + +/////////////////////////////////////////////////////////////////////////////// diff --git a/salalib/nagent.cpp b/salalib/nagent.cpp deleted file mode 100644 index 02db8f77..00000000 --- a/salalib/nagent.cpp +++ /dev/null @@ -1,1358 +0,0 @@ -// sala - a component of the depthmapX - spatial network analysis platform -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - - - -// a simple agent demonstration for Salad (now within depthmapX) -#include -#include - -#include -#include -#include - -int thisrun = 0; - -/////////////////////////////////////////////////////////////////////////////////////////////// - -static int rankselect(int popsize) -{ - int num = int( prandom() * popsize * (popsize + 1) * 0.5 ); - for (int i = 0; i < popsize; i++) { - if (num < (popsize - i)) { - return i; - } - num -= (popsize - i); - } - return 0; // <- this shouldn't happen -} - -// note: this is tested and right: higher fitness, lower rank (so population[0] is best) -int progcompare(const void *a, const void *b ) -{ - double test = (((AgentProgram *)a)->m_fitness - ((AgentProgram *)b)->m_fitness); - if (test < 0.0) { - return 1; - } - else if (test > 0.0) { - return -1; - } - return 0; -} - -// - -pvecpoint g_trails[MAX_TRAILS]; - -/////////////////////////////////////////////////////////////////////////////////////////////// - -// run one agent engine only - -AgentEngine::AgentEngine() -{ - m_timesteps = 5000; - m_gatelayer = -1; - m_record_trails = false; - m_trail_count = MAX_TRAILS; -} - -void AgentEngine::run(Communicator *comm, PointMap *pointmap) -{ - // Quick mod - TV -#if defined(_WIN32) - __time64_t atime = 0; -#else - time_t atime =0; -#endif - if (comm) { - qtimer( atime, 0 ); - comm->CommPostMessage( Communicator::NUM_RECORDS, m_timesteps ); - } - - AttributeTable& table = pointmap->getAttributeTable(); - int displaycol = table.insertColumn(g_col_total_counts); - - int output_mode = Agent::OUTPUT_COUNTS; - if (m_gatelayer != -1) { - output_mode |= Agent::OUTPUT_GATE_COUNTS; - } - - // remove any agent trails that are left from a previous run - for (int k = 0; k < MAX_TRAILS; k++) { - g_trails[k].clear(); - } - - int trail_num = -1; - if (m_record_trails) { - if (m_trail_count < 1) { - m_trail_count = 1; - } - if (m_trail_count > MAX_TRAILS) { - m_trail_count = MAX_TRAILS; - } - trail_num = 0; - } - - // remove any agents that are left from a previous run - for (size_t j = 0; j < size(); j++) { - at(j).clear(); - } - - for (int i = 0; i < m_timesteps; i++) { - - size_t j; - for (j = 0; j < size(); j++) { - int q = invcumpoisson(prandomr(),at(j).m_release_rate); - int length = at(j).size(); - int k; - for (k = 0; k < q; k++) { - at(j).push_back(Agent(&(at(j)),pointmap,output_mode)); - } - for (k = 0; k < q; k++) { - at(j).init(length+k,trail_num); - if (trail_num != -1) { - trail_num++; - // after trail count, stop recording: - if (trail_num == m_trail_count) { - trail_num = -1; - } - } - } - } - - for (j = 0; j < size(); j++) { - at(j).move(); - } - - if (comm) { - if (qtimer( atime, 500 )) { - if (comm->IsCancelled()) { - throw Communicator::CancelledException(); - } - comm->CommPostMessage( Communicator::CURRENT_RECORD, i ); - } - } - } - - // output agent trails to file: - if (m_record_trails) { - // just dump in local file... - ofstream trails("trails.cat"); - trails << "CAT" << endl; - for (int i = 0; i < m_trail_count; i++) { - trails << "Begin Polyline" << endl; - for (size_t j = 0; j < g_trails[i].size(); j++) { - trails << g_trails[i][j].x << " " << g_trails[i][j].y << endl; - } - trails << "End Polyline" << endl; - } - } - - // actually, no, do this from the - pointmap->overrideDisplayedAttribute(-2); - pointmap->setDisplayedAttribute(displaycol); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// - -AgentSet::AgentSet() -{ - m_release_rate = 0.1; - m_lifetime = 1000; -} - -void AgentSet::init(int agent, int trail_num) -{ - if (m_release_locations.size()) { - int which = pafrand() % m_release_locations.size(); - at(agent).onInit( m_release_locations[which], trail_num ); - } - else { - const PointMap& map = at(agent).getPointMap(); - PixelRef pix; - do { - pix = map.pickPixel(prandom()); - } while (!map.getPoint(pix).filled()); - at(agent).onInit(pix, trail_num); - } -} - -void AgentSet::move() -{ - // go through backwards so remove does not affect later agents - for (size_t i = size() - 1; i != paftl::npos; i--) { - at(i).onMove(); - if (at(i).getFrame() >= m_lifetime) { - remove_at(i); - } - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////// - -AgentProgram *ProgramPopulation::makeChild() -{ - int a = rankselect(POPSIZE); - int b = rankselect(POPSIZE); - while (a == b) - b = rankselect(POPSIZE); - m_population[POPSIZE - 1] = crossover(m_population[a],m_population[b]); - m_population[POPSIZE - 1].mutate(); - - return &(m_population[POPSIZE - 1]); -} - -// note: this is correct -- do not use &m_population! -void ProgramPopulation::sort() -{ - qsort(m_population,POPSIZE,sizeof(AgentProgram),progcompare); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// - -AgentProgram::AgentProgram() -{ - m_sel_type = SEL_LOS; - m_steps = 3; - m_vbin = 7; - m_destination_directed = false; - m_los_sqrd = false; -} - -/* -AgentProgram::AgentProgram() -{ - // random program for evolution: - // m_sel_type = SEL_LENGTH + (pafrand() % 4); - m_sel_type = SEL_OPTIC_FLOW2; - - // non-evolutionary standard agent program - // note m_steps defaults to 0 for use with evolutionary (reevaulate goal every step) - m_steps = 0; - // also note evolutionary does actually use bins when not following other rules: - m_vbin = (pafrand() % 7) + 1; - - // optic flow 2 - //m_vahead = (pafrand() % m_vbin); - //m_ahead_threshold = prandom() * 19.0 + 1.0; - //m_feeler_threshold = prandom() * 4.0 + 1.0; - //m_feeler_probability = prandom(); - - // rule order relies on putting rules into slots: - for (int i = 0; i < 4; i++) { - m_rule_order[i] = -1; - } - for (int j = 0; j < 4; j++) { - int choice = pafrand() % (4 - j); - for (int k = 0; k < choice + 1; k++) { - if (m_rule_order[k] != -1) { - choice++; - } - } - m_rule_order[choice] = j; - } - for (i = 0; i < 4; i++) { - m_rule_threshold[i] = prandom() * 100.0; - m_rule_probability[i] = prandom(); - } - - m_fitness = 0.0; - - m_destination_guided = false; - m_los_sqrd = false; -} -*/ - -void AgentProgram::mutate() -{ - // don't mutate program type -/* - if (pafrand() % 20 == 0) { - m_vbin = (pafrand() % 7) + 1; - } - if (pafrand() % 20 == 0) { - m_vahead = (pafrand() % m_vbin); - } - if (pafrand() % 20 == 0) { - m_ahead_threshold = prandom() * 19.0 + 1.0; - } - if (pafrand() % 20 == 0) { - m_feeler_threshold = prandom() * 4.0 + 1.0; - } - if (pafrand() % 20 == 0) { - m_feeler_probability = prandom(); - } -*/ - - // do mutate rule order occassionally: - if (pafrand() % 20 == 0) { - // rule order relies on putting rules into slots: - for (int i = 0; i < 4; i++) { - m_rule_order[i] = -1; - } - for (int j = 0; j < 4; j++) { - int choice = pafrand() % (4 - j); - for (int k = 0; k < choice + 1; k++) { - if (m_rule_order[k] != -1) { - choice++; - } - } - m_rule_order[choice] = j; - } - } - // mutate the rule threshold / probabilities - for (int i = 0; i < 4; i++) { - if (pafrand() % 20 == 0) { // 5% mutation rate - m_rule_threshold[i] = float(prandom() * 100.0); - } - if (pafrand() % 20 == 0) { // 5% mutation rate - m_rule_probability[i] = float(prandom()); - } - } - -} - -AgentProgram crossover(const AgentProgram& prog_a, const AgentProgram& prog_b) -{ - AgentProgram child; - // either one sel type or the other: - /* - if (pafrand() % 2) { - child.m_sel_type = prog_a.m_sel_type; - } - else { - child.m_sel_type = prog_b.m_sel_type; - } - */ - /* - // either one bin radius or the other - if (pafrand() % 2) - child.m_vbin = prog_a.m_vbin; - else - child.m_vbin = prog_b.m_vbin; - if (pafrand() % 2) - child.m_vahead = prog_a.m_vahead; - else - child.m_vahead = prog_b.m_vahead; - if (pafrand() % 2) - child.m_ahead_threshold = prog_a.m_ahead_threshold; - else - child.m_ahead_threshold = prog_b.m_ahead_threshold; - if (pafrand() % 2) - child.m_feeler_threshold = prog_a.m_feeler_threshold; - else - child.m_feeler_threshold = prog_b.m_feeler_threshold; - if (pafrand() % 2) - child.m_feeler_probability = prog_a.m_feeler_probability; - else - child.m_feeler_probability = prog_b.m_feeler_probability; -*/ - - // either one rule priority order or the other (don't try to mix!) - if (pafrand() % 2) { - for (int i = 0; i < 4; i++) { - child.m_rule_order[i] = prog_a.m_rule_order[i]; - } - } - else { - for (int i = 0; i < 4; i++) { - child.m_rule_order[i] = prog_b.m_rule_order[i]; - } - } - // for each rule, either one rule threshold / probability or the other: - for (int i = 0; i < 4; i++) { - if (pafrand() % 2) { - child.m_rule_threshold[i] = prog_a.m_rule_threshold[i]; - } - else { - child.m_rule_threshold[i] = prog_b.m_rule_threshold[i]; - } - if (pafrand() % 2) { - child.m_rule_probability[i] = prog_a.m_rule_probability[i]; - } - else { - child.m_rule_probability[i] = prog_b.m_rule_probability[i]; - } - } - - return child; -} - -void AgentProgram::save(const pstring& filename) -{ - // standard ascii: - ofstream file(filename.c_str()); - - file << "Destination selection: "; - switch (m_sel_type) { - case SEL_STANDARD: - file << "Standard" << endl; - break; - case SEL_LENGTH: - file << "Gibsonian Length" << endl; - break; - case SEL_OPTIC_FLOW: - file << "Gibsonian Optic Flow" << endl; - break; - case SEL_COMPARATIVE_LENGTH: - file << "Gibsonian Comparative Length" << endl; - break; - case SEL_COMPARATIVE_OPTIC_FLOW: - file << "Gibsonian Comparative Optic Flow" << endl; - break; - default: - file << "Unknown" << endl; - } - - file << "Steps: " << m_steps << endl; - file << "Bins: " << ((m_vbin == -1) ? 32 : m_vbin * 2 + 1) << endl; - /* - file << "Ahead bins: " << m_vahead * 2 + 1 << endl; - file << "Ahead threshold: " << m_ahead_threshold << endl; - file << "Feeler threshold: " << m_feeler_threshold << endl; - file << "Feeler probability: " << m_feeler_probability << endl; -*/ - file << "Rule order: " << m_rule_order[0] << " " - << m_rule_order[1] << " " - << m_rule_order[2] << " " - << m_rule_order[3] << endl; - - for (int i = 0; i < 4; i++) { - file << "Rule " << i << " (Bin -" << 1 + (i * 2) << "/+" << 1 + (i * 2) << ")" << endl; - file << "Threshold: " << m_rule_threshold[i] << endl; - file << "Turn Probability: " << m_rule_probability[i] << endl; - } - - file << "Fitness: " << m_fitness << endl; -} - -bool AgentProgram::open(const pstring& filename) -{ - // standard ascii: - ifstream file(filename.c_str()); - - pstring line; - file >> line; - if (!line.empty()) { - line.makelower(); - if (!compare(line,"destination selection:",22)) { - return false; - } - else { - pstring method = line.substr(22); - method.ltrim(); - if (!method.empty()) { - if (method == "standard") { - m_sel_type = SEL_STANDARD; - } - else if (method == "gibsonian length") { - m_sel_type = SEL_LENGTH; - } - else if (method == "gibsonian optic flow") { - m_sel_type = SEL_OPTIC_FLOW; - } - else if (method == "gibsonian comparative length") { - m_sel_type = SEL_COMPARATIVE_LENGTH; - } - else if (method == "gibsonian comparative optic flow") { - m_sel_type = SEL_COMPARATIVE_OPTIC_FLOW; - } - file >> line; - } - else { - return false; - } - } - } - else { - return false; - } - - bool foundsteps = false; - bool foundbins = false; - - if (!line.empty()) { - line.makelower(); - if (compare(line,"steps:",6)) { - pstring steps = line.substr(6); - steps.ltrim(); - m_steps = atoi(steps.c_str()); - file >> line; - foundsteps = true; - } - } - else { - return false; - } - - if (!line.empty()) { - line.makelower(); - if (compare(line,"bins:",5)) { - pstring bins = line.substr(6); - bins.ltrim(); - int binx = atoi(bins.c_str()); - if (binx = 32) { - m_vbin = -1; - } - else { - m_vbin = (atoi(bins.c_str()) - 1) / 2; - } - file >> line; - foundbins = true; - } - } - - if (m_sel_type == SEL_STANDARD) { - if (foundbins && foundsteps) { - return true; - } - else { - return false; - } - } - - if (!line.empty()) { - line.makelower(); - if (compare(line,"rule order:",11)) { - pstring ruleorder = line.substr(11); - ruleorder.ltrim(); - pvecstring orders = ruleorder.tokenize(' ', true); - if (orders.size() != 4) { - return false; - } - for (int i = 0; i < 4; i++) { - m_rule_order[i] = atoi(orders[i].c_str()); - } - file >> line; - } - else { - return false; - } - } - else { - return false; - } - for (int i = 0; i < 4; i++) { - if (!line.empty()) { - line.makelower(); - if (compare(line,"rule",4)) { - file >> line; - } - line.makelower(); - if (compare(line,"threshold:",10)) { - pstring threshold = line.substr(10); - threshold.ltrim(); - m_rule_threshold[i] = (float)atof(threshold.c_str()); - file >> line; - } - else { - return false; - } - line.makelower(); - if (compare(line,"turn probability:",17)) { - pstring prob = line.substr(17); - prob.ltrim(); - m_rule_probability[i] = (float)atof(prob.c_str()); - file >> line; - } - else { - return false; - } - } - else { - return false; - } - } - - return true; -} - -/////////////////////////////////////////////////////////////////////////////////////////////// - -Agent::Agent(AgentProgram *program, PointMap *pointmap, int output_mode) -{ - m_program = program; - m_pointmap = pointmap; - m_output_mode = output_mode; - m_trail_num = -1; -} - -void Agent::onInit(PixelRef node, int trail_num) -{ - m_node = node; - m_loc = m_pointmap->depixelate(m_node); - if (m_output_mode & OUTPUT_GATE_COUNTS) { - int index = m_pointmap->getAttributeTable().getRowid(m_node); - m_gate = (index != -1) ? (int)m_pointmap->getAttributeTable().getValue(index,g_col_gate) : -1; - } - else { - m_gate = -1; - } - m_gate_encountered = false; - m_step = 0; - m_stuck = false; - m_stopped = false; - m_frame = 0; - m_target_lock = false; - m_vector = Point2f(1,0); - - m_at_target = false; - m_at_destination = false; - - m_trail_num = trail_num; - - m_vector = onLook(true); - - m_vector.normalise(); - - m_target_pix = NoPixel; -} - -void Agent::onMove() -{ - m_at_target = false; - m_frame++; - if (m_program->m_destination_directed && dist(m_loc,m_destination) < 10.0) { - // reached final destination - onDestination(); - } - else if ((m_program->m_sel_type & AgentProgram::SEL_TARGETTED) && dist(m_loc,m_target) < m_pointmap->getSpacing()) { - // reached target (intermediate destination) - m_step = 0; - onTarget(); - m_vector = onLook(false); - } - else if (prandomr() < (1.0 / m_program->m_steps) && !m_target_lock) { // note, on average, will change 1 in steps - m_step = 0; - m_vector = onLook(false); - /* - if (m_program->m_destination_directed) { - Point2f vec2 = m_destination - m_loc; - vec2.normalise(); - if (dot(vec2,m_vector) < 0.0) { - m_vector = onLook(false); - } - } - */ - } - if (m_stuck) { - // oops... - return; - } - // now step... - PixelRef lastnode = m_node; - onStep(); - if (m_node != lastnode && m_output_mode != OUTPUT_NOTHING) { - int index = m_pointmap->getAttributeTable().getRowid(m_node); - if (index != -1) { - if (m_output_mode & OUTPUT_COUNTS) { - m_pointmap->getAttributeTable().incrValue(index, g_col_total_counts); - } - if (m_output_mode & OUTPUT_GATE_COUNTS) { - int obj = (int)m_pointmap->getAttributeTable().getValue(index, g_col_gate); - if (m_gate != obj) { - m_gate = obj; - if (m_gate != -1) { - m_pointmap->getAttributeTable().incrValue(index, g_col_gate_counts); - // actually crossed into a new gate: - m_gate_encountered = true; - } - } - } - } - } - // done. happy hamster. -} -void Agent::onDestination() -{ - m_at_destination = true; -} -void Agent::onTarget() -{ - m_occ_memory.a().clear(); - m_at_target = true; -} - -//////////////////////////////////////////////////////////////////// - -void Agent::onStep() -{ - m_stopped = false; - m_step++; - // - Point2f nextloc = m_loc + (m_pointmap->getSpacing() * m_vector); - // note: false returns unconstrained pixel: goodStep must check it is in bounds using m_pointmap->includes - PixelRef nextnode = m_pointmap->pixelate(nextloc,false); - if (nextnode != m_node) { - // quick check location is okay... - if (goodStep(nextnode)) { - m_node = nextnode; - m_loc = nextloc; - } - else { - // try other nearby nodes... - if (!diagonalStep()) { - m_stopped = true; - } - } - } - else { - m_loc = nextloc; - } - if (!m_stopped && m_trail_num != -1) { - g_trails[m_trail_num].push_back(m_loc); - } -} -bool Agent::diagonalStep() -{ - Point2f vector1 = m_vector; - vector1.rotate(M_PI / 4.0); - Point2f nextloc1 = m_loc + (m_pointmap->getSpacing() * vector1); - // note: "false" does not constrain to bounds: must be checked using m_pointmap->includes before getPoint is used - PixelRef nextnode1 = m_pointmap->pixelate(nextloc1,false); - - Point2f vector2 = m_vector; - vector2.rotate(-M_PI / 4.0); - Point2f nextloc2 = m_loc + (m_pointmap->getSpacing() * vector2); - // note: "false" does not constrain to bounds: must be checked using m_pointmap->includes before getPoint is used - int nextnode2 = m_pointmap->pixelate(nextloc2,false); - - bool good = false; - if (pafrand() % 2 == 0) { - if (goodStep(nextnode1)) { - m_node = nextnode1; - m_loc = nextloc1; - good = true; - } - else if (goodStep(nextnode2)) { - m_node = nextnode2; - m_loc = nextloc2; - good = true; - } - } - else { - if (goodStep(nextnode2)) { - m_node = nextnode2; - m_loc = nextloc2; - good = true; - } - else if (goodStep(nextnode1)) { - m_node = nextnode1; - m_loc = nextloc1; - good = true; - } - } - return good; -} -bool Agent::goodStep(PixelRef node) -{ - if (!m_pointmap->includes(node)) { - return false; - } - // n.b., you have to know how the nodes are labelled for this connectValue trick - PixelRef dir; - dir.x = node.x - m_node.x; - dir.y = node.y - m_node.y; - // now translate dir to correct CONNECT value - if (m_pointmap->getPoint(m_node).getGridConnections() & connectValue(dir)) { - return true; - } - - return false; -} - -////////////////////////////////////////////////////////////////////// - -// The various look algorithms - -Point2f Agent::onLook(bool wholeisovist) -{ - Point2f dir; - if (m_program->m_sel_type & AgentProgram::SEL_GIBSONIAN) { - dir = onGibsonianLook(wholeisovist); - } - else if ((m_program->m_sel_type & AgentProgram::SEL_OCCLUSION) == AgentProgram::SEL_OCCLUSION) { - dir = onOcclusionLook(wholeisovist, m_program->m_sel_type); - } - else { - switch (m_program->m_sel_type) { - case AgentProgram::SEL_STANDARD: - dir = onStandardLook(wholeisovist); - break; - case AgentProgram::SEL_LOS: case AgentProgram::SEL_LOS_OCC: - if (m_program->m_destination_directed) { - dir = onDirectedLoSLook(wholeisovist, m_program->m_sel_type); - } - else { - dir = onLoSLook(wholeisovist, m_program->m_sel_type); - } - break; - case AgentProgram::SEL_OPTIC_FLOW2: - dir = onGibsonianLook2(wholeisovist); - break; - } - } - if ((m_program->m_sel_type & AgentProgram::SEL_GIBSONIAN) && !m_stuck) { - // remember what the view looked like here, facing our new direction: - calcLoS(binfromvec(dir),false); - } - if ((m_program->m_sel_type & AgentProgram::SEL_GIBSONIAN2) && !m_stuck) { - calcLoS2(binfromvec(dir),false); - } - - return dir; -} - -Point2f Agent::onStandardLook(bool wholeisovist) -{ - int tarpixelate = -1; - int vbin = m_program->m_vbin; - if (wholeisovist || vbin == -1) { - vbin = 16; - } - int directionbin = 32 + binfromvec(m_vector) - vbin; - int choices = 0; - // reset for getting list, check in range: - vbin = vbin * 2 + 1; - if (vbin > 32) { - vbin = 32; - } - for (int i = 0; i < vbin; i++) { - choices += m_pointmap->getPoint(m_node).getNode().bincount( (directionbin + i) % 32 ); - } - if (choices == 0) { - if (!wholeisovist) { - return onStandardLook(true); - } - else { - m_stuck = true; - m_target = m_loc; - m_target_pix = m_node; - return Point2f(0,0); - } - } - else { - int chosen = pafrand() % choices; - Node& node = m_pointmap->getPoint(m_node).getNode(); - for (; chosen >= node.bincount( directionbin % 32 ); directionbin++) { - chosen -= node.bincount( directionbin % 32 ); - } - Bin& bin = node.bin(directionbin % 32); - bin.first(); - tarpixelate = bin.cursor(); - for (; chosen > 0; chosen--) { - bin.next(); - tarpixelate = bin.cursor(); - } - } - - m_target_pix = tarpixelate; - m_target = m_pointmap->depixelate(tarpixelate); - - return (m_target - m_loc).normalise(); -} - -Point2f Agent::onWeightedLook(bool wholeisovist) -{ - if (wholeisovist) { - // use standard targetted look instead: - return onStandardLook(true); - } - int tarpixelate = -1; - int vbin = m_program->m_vbin; - if (vbin = -1) { - vbin = 16; - } - int aheadbin = binfromvec(m_vector); - int directionbin = 32 + binfromvec(m_vector) - vbin; - prefvec weightmap; - double weight = 0.0; - // reset for getting list, check in range: - vbin = vbin * 2 + 1; - if (vbin > 32) { - vbin = 32; - } - for (int i = 0; i < vbin; i++) { - Bin& bin = m_pointmap->getPoint(m_node).getNode().bin((directionbin + i) % 32); - bin.first(); - - // Quick mod - TV -#if defined(_WIN32) - int node = bin.is_tail() ? -1 : bin.cursor(); -#else - int node = bin.is_tail() ? -1 : bin.cursor().x; -#endif - while (node != -1) { - weight += ((directionbin + i) % 32 == aheadbin) ? 5.0 : 1.0; - weightmap.push_back(wpair(weight,node)); - bin.next(); - // Quick mod - TV -#if defined(_WIN32) - node = bin.is_tail() ? -1 : bin.cursor(); -#else - node = bin.is_tail() ? -1 : bin.cursor().x; -#endif - } - } - if (weightmap.size() == 0) { - return onWeightedLook(true); - } - else { - double chosen = prandomr() * weight; - for (size_t i = 0; i < weightmap.size(); i++) { - if (chosen < weightmap[i].weight) { - tarpixelate = weightmap[i].node; - break; - } - } - } - - m_target_pix = tarpixelate; - m_target = m_pointmap->depixelate(tarpixelate); - - return (m_target - m_loc).normalise(); -} - -Point2f Agent::onOcclusionLook(bool wholeisovist, int looktype) -{ - if (AgentProgram::SEL_OCC_MEMORY) { - m_occ_memory.flip(); - m_occ_memory.a().clear(); - } - - if (wholeisovist) { - // use standard targetted look instead: - return onStandardLook(true); - } - PixelRef tarpixelate = NoPixel; - int vbin = m_program->m_vbin; - if (vbin = -1) { - vbin = 16; - } - int directionbin = 32 + binfromvec(m_vector) - vbin; - // reset for getting list, check in range: - vbin = vbin * 2 + 1; - if (vbin > 32) { - vbin = 32; - } - if (looktype == AgentProgram::SEL_OCC_ALL) { - int choices = 0; - Node& node = m_pointmap->getPoint(m_node).getNode(); - for (int i = 0; i < vbin; i++) { - if (node.m_occlusion_bins[(directionbin+i)%32].size()) { - choices += node.m_occlusion_bins[(directionbin+i)%32].size(); - } - } - if (choices == 0) { - if (!wholeisovist) { - return onStandardLook(false); - } - else { - m_stuck = true; - m_target_pix = m_node; - m_target = m_loc; - return Point2f(0,0); - } - } - else { - size_t chosen = pafrand() % choices; - for (; chosen >= node.m_occlusion_bins[ directionbin % 32 ].size(); directionbin++) { - chosen -= node.m_occlusion_bins[ directionbin % 32 ].size(); - } - tarpixelate = node.m_occlusion_bins[directionbin % 32].at(chosen); - } - } - else { - int subset = 1; - if (looktype == AgentProgram::SEL_OCC_BIN45) { - subset = 3; - } - else if (looktype == AgentProgram::SEL_OCC_BIN60) { - subset = 5; - } - prefvec weightmap; - double weight = 0.0; - Node& node = m_pointmap->getPoint(m_node).getNode(); - for (int i = 0; i < vbin; i += subset) { - PixelRef nigpix; - double fardist = -1.0; - for (int k = 0; k < subset; k++) { - for (size_t j = 0; j < node.m_occlusion_bins[(directionbin+i+k)%32].size(); j++) { - PixelRef pix = node.m_occlusion_bins[(directionbin+i+k)%32].at(j); - if (dist(pix,m_node) > fardist) { - fardist = dist(pix,m_node); - nigpix = pix; - } - } - } - if (fardist != -1.0) { - bool cont = true; - if (looktype == AgentProgram::SEL_OCC_MEMORY) { - m_occ_memory.a().add(nigpix); - // the turn chance (pafrand() % 2) may have to be modified later... - if (!m_at_target && m_occ_memory.b().searchindex(nigpix) != paftl::npos) { - cont = false; - } - } - if (cont) { - switch (looktype) { - case AgentProgram::SEL_OCC_WEIGHT_DIST: - weight += fardist; - break; - case AgentProgram::SEL_OCC_WEIGHT_ANG: - weight += (double(vbin-abs(i-vbin))); - break; - case AgentProgram::SEL_OCC_WEIGHT_DIST_ANG: - weight += fardist * (double(vbin-abs(i-vbin))); - break; - default: - weight += 1.0; - break; - } - weightmap.push_back(wpair(weight,nigpix)); - } - } - } - if (weightmap.size() == 0) { - if (!wholeisovist) { - return onStandardLook(false); - } - else { - m_stuck = true; - m_target = m_loc; - return Point2f(0,0); - } - } - else { - double chosen = prandomr() * weight; - for (size_t i = 0; i < weightmap.size(); i++) { - if (chosen < weightmap[i].weight) { - tarpixelate = weightmap[i].node; - break; - } - } - } - } - - m_target_pix = tarpixelate; - m_target = m_pointmap->depixelate(tarpixelate); - - return (m_target - m_loc).normalise(); -} - -// note: LOS look uses similar weighted choice mechanism - -Point2f Agent::onLoSLook(bool wholeisovist, int look_type) -{ - int bbin = -1; - if (m_program->m_destination_directed) { - Point2f vec2 = m_destination - m_loc; - double test = vec2.length(); - vec2.normalise(); - bbin = binfromvec(vec2); - } - int targetbin = -1; - int vbin = m_program->m_vbin; - if (wholeisovist || vbin == -1) { - vbin = 16; - } - int directionbin = 32 + binfromvec(m_vector) - vbin; - prefvec weightmap; - double weight = 0.0; - // reset for getting list, check in range: - vbin = vbin * 2 + 1; - if (vbin > 32) { - vbin = 32; - } - for (int i = 0; i < vbin; i++) { - double los = (look_type == AgentProgram::SEL_LOS) ? - m_pointmap->getPoint(m_node).getNode().bindistance( (directionbin + i) % 32 ) : - m_pointmap->getPoint(m_node).getNode().occdistance( (directionbin + i) % 32 ); - if (m_program->m_los_sqrd) { - los *= los; - } - if (m_program->m_destination_directed) { - los *= 1.0 - double(binsbetween( ((directionbin + i) % 32), bbin)) / 16.0; - } - weight += los; - weightmap.push_back(wpair(weight,(directionbin + i) % 32)); - } - if (weight == 0.0) { - if (!wholeisovist) { - return onLoSLook(true, look_type); - } - else { - // oops! - m_stuck = true; - return Point2f(0,0); - } - } - else { - double chosen = prandomr() * weight; - for (size_t i = 0; i < weightmap.size(); i++) { - if (chosen < weightmap[i].weight) { - targetbin = weightmap[i].node; - break; - } - } - } - - float angle = (float)anglefrombin2(targetbin); - - return Point2f( cosf(angle), sinf(angle) ); -} - -Point2f Agent::onDirectedLoSLook(bool wholeisovist, int look_type) -{ - int bbin = -1; - Point2f vec2 = m_destination - m_loc; - vec2.normalise(); - bbin = binfromvec(vec2); - int targetbin = -1; - int vbin = m_program->m_vbin; - if (wholeisovist || vbin == -1) { - vbin = 16; - } - int directionbin = 32 + binfromvec(vec2) - vbin; - prefvec weightmap; - double weight = 0.0; - // reset for getting list, check in range: - vbin = vbin * 2 + 1; - if (vbin > 32) { - vbin = 32; - } - for (int i = 0; i < vbin; i++) { - double los = (look_type == AgentProgram::SEL_LOS) ? - m_pointmap->getPoint(m_node).getNode().bindistance( (directionbin + i) % 32 ) : - m_pointmap->getPoint(m_node).getNode().occdistance( (directionbin + i) % 32 ); - if (m_program->m_los_sqrd) { - los *= los; - } - weight += los; - weightmap.push_back(wpair(weight,(directionbin + i) % 32)); - } - if (weight == 0.0) { - if (!wholeisovist) { - return onLoSLook(true, look_type); - } - else { - // oops! - m_stuck = true; - return Point2f(0,0); - } - } - else { - double chosen = prandomr() * weight; - for (size_t i = 0; i < weightmap.size(); i++) { - if (chosen < weightmap[i].weight) { - targetbin = weightmap[i].node; - break; - } - } - } - - float angle = (float)anglefrombin2(targetbin); - - return Point2f( cosf(angle), sinf(angle) ); -} - - -// Gibsonian agents record their last known information, -// and act according to their rules: - -Point2f Agent::onGibsonianLook(bool wholeisovist) -{ - // at start, go in any direction: - if (wholeisovist) { - return onLoSLook(true, AgentProgram::SEL_LOS); - } - // - calcLoS(binfromvec(m_vector),true); - // now, choose action according to type of agent: - int rule_choice = -1; - int dir = 0; - for (int k = 0; k < 4; k++) { - dir = onGibsonianRule(m_program->m_rule_order[k]); - if (dir != 0) { - rule_choice = m_program->m_rule_order[k]; - break; - } - } - - float angle = 0.0; - - if (rule_choice != -1) { - angle = (float)anglefrombin2((binfromvec(m_vector) + (2 * rule_choice + 1) * dir + 32) % 32); - } - - // if no rule selection made, carry on in current direction - return (rule_choice == -1) ? m_vector : Point2f( cosf(angle), sinf(angle) ); -} - -int Agent::onGibsonianRule(int rule) -{ - int option = 0; - switch (m_program->m_sel_type) { - case AgentProgram::SEL_LENGTH: - // rule_threshold from 0 to 100m - if (m_curr_los[rule + 1] > m_program->m_rule_threshold[rule]) { - option = 0x01; - } - if (m_curr_los[rule + 5] > m_program->m_rule_threshold[rule]) { - option |= 0x10; - } - break; - case AgentProgram::SEL_OPTIC_FLOW: - // rule_threshold reflects from 0x (0) to 5x (100.0) - if ((m_curr_los[rule + 1] + 1) / (m_last_los[rule + 1] + 1) > m_program->m_rule_threshold[rule] / 20.0) { - option = 0x01; - } - if ((m_curr_los[rule + 5] + 1) / (m_last_los[rule + 5] + 1) > m_program->m_rule_threshold[rule] / 20.0) { - option |= 0x10; - } - break; - case AgentProgram::SEL_COMPARATIVE_LENGTH: - // rule_threshold reflects from 0x (0) to 10x (100.0) - if ((m_curr_los[rule + 1] + 1) / (m_curr_los[0] + 1) > m_program->m_rule_threshold[rule] / 10.0) { - option = 0x01; - } - if ((m_curr_los[rule + 5] + 1) / (m_curr_los[0] + 1) > m_program->m_rule_threshold[rule] / 10.0) { - option |= 0x10; - } - break; - case AgentProgram::SEL_COMPARATIVE_OPTIC_FLOW: - // rule_threshold reflects from 0x (0) to 10x (100.0) - if ((m_curr_los[rule + 1] * m_last_los[0] + 1) / (m_last_los[rule + 1] * m_curr_los[0] + 1) > - m_program->m_rule_threshold[rule] / 10.0) { - option = 0x01; - } - if ((m_curr_los[rule + 5] * m_last_los[0] + 1) / (m_last_los[rule + 5] * m_curr_los[0] + 1) > - m_program->m_rule_threshold[rule] / 10.0) { - option |= 0x10; - } - break; - } - int dir = 0; - if (option == 0x01 && m_program->m_rule_probability[0] > prandomr()) { - dir = -1; - } - else if (option == 0x10 && m_program->m_rule_probability[0] > prandomr()) { - dir = +1; - } - else if (option == 0x11 && m_program->m_rule_probability[0] > prandomr() * prandomr()) { - // note, use random * random event as there are two ways to do this - dir = (rand() % 2) ? -1 : +1; - } - return dir; -} - -Point2f Agent::onGibsonianLook2(bool wholeisovist) -{ - // at start, go in any direction: - if (wholeisovist) { - return onLoSLook(true, AgentProgram::SEL_LOS); - } - // - calcLoS2(binfromvec(m_vector),true); - int maxbin = 0; - /* - // first action: adjust to longest line of sight - if (m_curr_los[3] > m_curr_los[0]) { - maxbin = -m_program->m_vahead; - if (m_curr_los[4] > m_curr_los[0] && (pafrand() % 2)) { - maxbin = m_program->m_vahead; - } - } - else if (m_curr_los[4] > m_curr_los[0]) { - maxbin = m_program->m_vahead; - } - */ - // second action, apply feeler rule: - char dir = 0x00; - if ((m_curr_los[1]-m_last_los[1])/m_curr_los[1] > m_program->m_feeler_threshold) { - dir |= 0x01; - } - if ((m_curr_los[2]-m_last_los[2])/m_curr_los[2] > m_program->m_feeler_threshold) { - dir |= 0x10; - } - if (dir == 0x01 && m_program->m_feeler_probability > prandomr()) { - maxbin = -m_program->m_vbin; - } - else if (dir == 0x10 && m_program->m_feeler_probability > prandomr()) { - maxbin = m_program->m_vbin; - } - else if (dir == 0x11 && m_program->m_feeler_probability > prandomr() * prandomr()) { - maxbin = (pafrand() % 2) ? m_program->m_vbin : -m_program->m_vbin; - } - // third action: detect heading for dead-end - if (maxbin == 0 && (m_curr_los[0] / m_pointmap->getSpacing() < m_program->m_ahead_threshold)) { - if (m_curr_los[1] >= m_curr_los[2]) { - maxbin = -m_program->m_vbin; - } - else { - maxbin = m_program->m_vbin; - } - } - - int bin = binfromvec(m_vector) + maxbin; - float angle = (float)anglefrombin2(bin); - - return (maxbin == 0) ? m_vector : Point2f( cosf(angle), sinf(angle) ); -} - -void Agent::calcLoS(int directionbin, bool curr) -{ - float *los; - if (curr) { - los = m_curr_los; - } - else { - los = m_last_los; - } - Node& node = m_pointmap->getPoint(m_node).getNode(); - // ahead - los[0] = node.bindistance( directionbin % 32 ); - // directions: - int count = 1; - for (int i = 1; i <= 7; i += 2) { - los[count] = node.bindistance((directionbin - i + 32) % 32); - count++; - } - for (int j = 1; j <= 7; j += 2) { - los[count] = node.bindistance((directionbin + j) % 32); - count++; - } -} - -void Agent::calcLoS2(int directionbin, bool curr) -{ - float *los; - if (curr) { - los = m_curr_los; - } - else { - los = m_last_los; - } - Node& node = m_pointmap->getPoint(m_node).getNode(); - // ahead - los[0] = node.bindistance(directionbin % 32); - // directions: - los[1] = node.bindistance( (directionbin - m_program->m_vbin + 32) % 32); - los[2] = node.bindistance( (directionbin + m_program->m_vbin) % 32); - // - los[3] = node.bindistance( (directionbin - m_program->m_vahead + 32) % 32); - los[4] = node.bindistance( (directionbin + m_program->m_vahead) % 32); -} diff --git a/salalib/nagent.h b/salalib/nagent.h deleted file mode 100644 index f632c4e7..00000000 --- a/salalib/nagent.h +++ /dev/null @@ -1,328 +0,0 @@ -// sala - a component of the depthmapX - spatial network analysis platform -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - - -// - -#ifndef __NAGENT_H__ -#define __NAGENT_H__ - -const char g_col_total_counts[] = "Gate Counts"; -const char g_col_gate_counts[] = "__Internal_Gate_Counts"; -const char g_col_gate[] = "__Internal_Gate"; - -////////////////////////////////////////////////////////////////////// - -// weighting -struct wpair -{ - double weight; - int node; - wpair(double w = 0.0, int n = -1) - { weight = w; node = n; } -}; - - -/* -// this is how pixels are referenced in depthmapX -struct Pixel -{ - // note, bit fields are stored the wrong way round: - short y : 16; - short x : 16; - Pixel() - { x = -1; y = -1; } - Pixel(int v) - { x = v >> 16; y = v & 0xffff; } - operator int () - { return (int&) *this; } -}; -*/ - -// convert an x / y difference to it's corresponding connection direction -inline char connectValue(PixelRef dir) -{ - if (dir.y > 0) { - return (Point::CONNECT_NE << (1 - dir.x)); - } - else if (dir.y < 0) { - return (Point::CONNECT_SW << (dir.x + 1)); - } - else if (dir.x == 1) { - return (char) Point::CONNECT_E; - } - else { - return (char) Point::CONNECT_W; - } -} - -/* -// some basic mathematical operators you might want -struct DPoint2 : public DPoint -{ - DPoint2() - { x = 0.0; y = 0.0; } - DPoint2(double p, double q) - { x = p; y = q; } - DPoint2(const DPoint& d) - { x = d.x; y = d.y; } - operator DPoint() { return DPoint(x,y); } - double length() { return sqrt(x * x + y * y); } - DPoint2& normalise() { double len = length(); x /= len; y /= len; return *this; } - DPoint2& scale(double s) { x *= s; y *= s; return *this; } - // normalise first before using angle / bin functions - double angle() const { return y < 0 ? 2.0 * DLL_PI - acos(x) : acos(x); } - // note the add 0.5 means angles from e.g., -1/32 to 1/32 are in bin 0 - int bin() const { return int(32.0 * (0.5 * angle() / DLL_PI) + 0.5);} - double& operator [] (int i) { return i == 0 ? x : y; } - const double operator [] (int i) const { return i == 0 ? x : y; } - friend DPoint2 operator + (const DPoint2& a, const DPoint2& b); - friend DPoint2 operator - (const DPoint2& a, const DPoint2& b); - friend double det(const DPoint2& a, const DPoint2& b); - friend double dot(const DPoint2& a, const DPoint2& b); - friend double dist(const DPoint2& a, const DPoint2& b); - friend DPoint2 operator * (double s, const DPoint2& b); - friend DPoint2 operator * (const DPoint2& a, double s); - // - DPoint2& rotate(const double theta) - { double t = x; x = x * cos(theta) - y * sin(theta); - y = y * cos(theta) + t * sin(theta); return *this; } -}; -inline DPoint2 operator + (const DPoint2& a, const DPoint2& b) -{ return DPoint2(a.x + b.x, a.y + b.y); } -inline DPoint2 operator - (const DPoint2& a, const DPoint2& b) -{ return DPoint2(a.x - b.x, a.y - b.y); } -inline double det(const DPoint2& a, const DPoint2& b) -{ return (a.x * b.y - a.y * b.x); } -inline double dot(const DPoint2& a, const DPoint2& b) -{ return (a.x * b.x + a.y * b.y); } -inline double dist(const DPoint2& a, const DPoint2& b) -{ DPoint2 c = b - a; return c.length(); } -inline DPoint2 operator * (double s, const DPoint2& b) -{ return DPoint2(s * b.x, s * b.y); } -inline DPoint2 operator * (const DPoint2& a, double s) -{ return DPoint2(s * a.x, s * a.y); } -*/ -//////////////////////////////////////////////////////////////// - -class AgentEngine; -struct AgentSet; -struct AgentProgram; -class Agent; - -const int MAX_TRAILS = 50; - -class AgentEngine : public prefvec -{ -public: // public for now for speed - int m_gatelayer; - int m_timesteps; -public: - bool m_record_trails; - int m_trail_count; -public: - AgentEngine(); - void run(Communicator *comm, PointMap *pointmap); -}; - -struct AgentProgram -{ - // comparative is comparative with current heading - enum { SEL_LOS = 0x0001, SEL_LOS_OCC = 0x0002, - SEL_TARGETTED = 0x1000, - SEL_STANDARD = 0x1001, SEL_WEIGHTED = 0x1002, - SEL_GIBSONIAN = 0x2000, - SEL_LENGTH = 0x2001, SEL_OPTIC_FLOW = 0x2002, - SEL_COMPARATIVE_LENGTH = 0x2003, SEL_COMPARATIVE_OPTIC_FLOW = 0x2004, - SEL_GIBSONIAN2 = 0x4000, - SEL_OPTIC_FLOW2 = 0x4001, - SEL_OCCLUSION = 0x9000, - SEL_OCC_ALL = 0x9001, - SEL_OCC_BIN45 = 0x9002, SEL_OCC_BIN60 = 0x9003, - SEL_OCC_STANDARD = 0x9004, - SEL_OCC_WEIGHT_DIST = 0x9005, SEL_OCC_WEIGHT_ANG = 0x9006, SEL_OCC_WEIGHT_DIST_ANG = 0x9007, - SEL_OCC_MEMORY = 0x9008 - }; - int m_sel_type; - int m_steps; - int m_vbin; - // these three variables for evolved Gibsonian agents: - int m_rule_order[4]; - float m_rule_threshold[4]; - float m_rule_probability[4]; - // these are for optic flow 2 agents - int m_vahead; // how wide your ahead vision is - float m_ahead_threshold; // will turn if neg flow greater than this threshold (set in range 1/100 to 1) - float m_feeler_threshold; // will turn if flow greater than this threshold (set in range 1 to 5) - float m_feeler_probability; // turn with this much probability if a feeler triggers - // - // simple long range destinations: - bool m_destination_directed; - bool m_los_sqrd; - // - // if it is going to evolved, then have it remember its fitness: - double m_fitness; - // - AgentProgram(); - // - // for evolution - void mutate(); - friend AgentProgram crossover(const AgentProgram& prog_a, const AgentProgram& prog_b); - // to reload later: - void save(const pstring& filename); - bool open(const pstring& filename); -}; - -struct AgentSet : public AgentProgram, public prefvec -{ - pvecint m_release_locations; - double m_release_rate; - int m_lifetime; - AgentSet(); - void move(); - void init(int agent, int trail_num = -1); -}; - -const int POPSIZE = 500; -// redo ASSAYs -- assaysize * assays (3 * 200 = 600 evaluations total) -// then take mean fitness: due to large variation in fitnesses with -// short assays such as this -const int ASSAYS = 3; -const int ASSAYSIZE = 25000; -const int GENERATIONS = 10000; -const int TIMESTEPS = 1600; - -struct ProgramPopulation -{ -public: - AgentProgram m_population[POPSIZE]; -public: - ProgramPopulation() {;} - AgentProgram *makeChild(); - void sort(); -}; - -class Agent -{ -public: - enum { OUTPUT_NOTHING = 0x00, OUTPUT_COUNTS = 0x01, OUTPUT_GATE_COUNTS = 0x02, OUTPUT_TRAILS = 0x04 }; -protected: - AgentProgram *m_program; - PointMap *m_pointmap; - // - PixelRef m_node; - int m_step; - int m_frame; - int m_gate; - bool m_stuck; - bool m_stopped; - bool m_target_lock; - bool m_gate_encountered; - bool m_at_target; - bool m_at_destination; - int m_output_mode; - Point2f m_loc; - Point2f m_target; - Point2f m_vector; - PixelRef m_target_pix; - // a long term goal: - Point2f m_destination; - // - // for recording trails: - int m_trail_num; - // - // for occlusion memory - pflipper m_occ_memory; - // - // extra memory of last observed values for Gibsonian agents: - float m_last_los[9]; - float m_curr_los[9]; -public: - Agent() - { m_program = NULL; m_pointmap = NULL; m_output_mode = OUTPUT_NOTHING; } - Agent(AgentProgram *program, PointMap *pointmap, int output_mode = OUTPUT_NOTHING); - void onInit(PixelRef node, int trail_num = -1); - void onClose(); - Point2f onLook(bool wholeisovist); - Point2f onStandardLook(bool wholeisovist); - Point2f onWeightedLook(bool wholeisovist); - Point2f onOcclusionLook(bool wholeisovist, int looktype); - Point2f onLoSLook(bool wholeisovist, int look_type); - Point2f onDirectedLoSLook(bool wholeisovist, int look_type); - Point2f onGibsonianLook(bool wholeisovist); - Point2f onGibsonianLook2(bool wholeisovist); - int onGibsonianRule(int rule); - void calcLoS(int directionbin, bool curr); - void calcLoS2(int directionbin, bool curr); - void onMove(); - void onTarget(); - void onDestination(); - void onStep(); - bool diagonalStep(); - bool goodStep(PixelRef node); - bool gateEncountered() - { return m_gate_encountered; } - const Point2f& getLoc() const - { return m_loc; } - // - const bool atTarget() const { return m_at_target; } - const bool atDestination() const { return m_at_destination; } - // - const Point2f& getLocation() const - { return m_loc; } - const Point2f& getVector() const - { return m_vector; } - const PixelRef getNode() const - { return m_node; } - const int getFrame() const - { return m_frame; } - const PointMap& getPointMap() const - { return *m_pointmap; } -}; - -// note the add 0.5 means angles from e.g., -1/32 to 1/32 are in bin 0 -inline int binfromvec(const Point2f& p) -{ return int(32.0 * (0.5 * p.angle() / M_PI) + 0.5); } - -// a random angle based on a bin direction -inline double anglefrombin2(int here) -{ - return (2.0 * M_PI) * ((double(here)-0.5)/32.0 + prandom()/32.0); -} - -inline int binsbetween(int bin1, int bin2) -{ - int b = abs(bin1 - bin2); - if (b > 16) { - b = 32 - b; - } - return b; -} - -///////////////////////////////////////////////////////////////////////////////////// - -// Playback for recorded traces - -struct Trace -{ - double starttime; - double endtime; - prefvec events; -}; - -///////////////////////////////////////////////////////////////////////////////////// - -#endif diff --git a/salalib/ngraph.cpp b/salalib/ngraph.cpp index 763d25e5..ebb9d5a7 100644 --- a/salalib/ngraph.cpp +++ b/salalib/ngraph.cpp @@ -22,8 +22,9 @@ #include #include #include +#include "genlib/containerutils.h" -void Node::make(const PixelRef pix, PixelRefList *bins, float *bin_far_dists, int q_octants) +void Node::make(const PixelRef pix, PixelRefVector *bins, float *bin_far_dists, int q_octants) { m_pixel = pix; @@ -56,16 +57,14 @@ void Node::make(const PixelRef pix, PixelRefList *bins, float *bin_far_dists, in } } -void Node::extractUnseen(PixelRefList& pixels, PointMap *pointdata, int binmark) +void Node::extractUnseen(PixelRefVector& pixels, PointMap *pointdata) { for (int i = 0; i < 32; i++) { -// if (~binmark & (1 << i)) { // <- DON'T USE THIS, IT CAUSES TOO MANY ERRORS! m_bins[i].extractUnseen(pixels, pointdata, (1 << i)); -// } } } -void Node::extractMetric(pqvector& pixels, PointMap *pointdata, const MetricTriple& curs) +void Node::extractMetric(std::set& pixels, PointMap *pointdata, const MetricTriple& curs) { //if (dist == 0.0f || concaveConnected()) { // increases effiency but is too inaccurate //if (dist == 0.0f || !fullyConnected()) { // increases effiency but can miss lines @@ -78,9 +77,9 @@ void Node::extractMetric(pqvector& pixels, PointMap *pointdata, co // based on extract metric -void Node::extractAngular(pqvector& pixels, PointMap *pointdata, const AngularTriple& curs) +void Node::extractAngular(std::set& pixels, PointMap *pointdata, const AngularTriple& curs) { - if (curs.angle == 0.0f || pointdata->getPoint(curs.pixel).blocked() || pointdata->blockedAdjacent(curs.pixel)) { + if (curs.angle == 0.0f || pointdata->getPoint(curs.pixel).blocked() || pointdata->blockedAdjacent(curs.pixel)) { for (int i = 0; i < 32; i++) { m_bins[i].extractAngular(pixels, pointdata, curs); } @@ -182,50 +181,49 @@ PixelRef Node::cursor() const return m_bins[m_curbin].cursor(); } -void Node::contents(PixelRefList& hood) const +void Node::contents(PixelRefVector& hood) const { first(); while (!is_tail()) { - hood.add(cursor()); + depthmapX::addIfNotExists(hood, cursor()); next(); } } ////////////////////////////////////////////////////////////////////////////////// -ifstream& Node::read(ifstream& stream, int version) +std::istream& Node::read(std::istream& stream) { int i; for (i = 0; i < 32; i++) { - m_bins[i].read(stream, version); + m_bins[i].read(stream); } - if (version >= VERSION_OCCLUSIONS) { - for (i = 0; i < 32; i++) { - m_occlusion_bins[i].read(stream); - } + + for (i = 0; i < 32; i++) { + dXreadwrite::readIntoVector(stream, m_occlusion_bins[i]); } + return stream; } -ofstream& Node::write(ofstream& stream, int version) +std::ostream& Node::write(std::ostream& stream) { int i; for (i = 0; i < 32; i++) { - m_bins[i].write(stream,version); + m_bins[i].write(stream); } - if (version >= VERSION_OCCLUSIONS) { - for (i = 0; i < 32; i++) { - m_occlusion_bins[i].write(stream); - } + + for (i = 0; i < 32; i++) { + dXreadwrite::writeVector(stream, m_occlusion_bins[i]); } return stream; } -ostream& operator << (ostream& stream, const Node& node) +std::ostream& operator << (std::ostream& stream, const Node& node) { for (int i = 0; i < 32; i++) { if (node.m_bins[i].count()) { - stream << " " << node.m_bins[i] << endl; + stream << " " << node.m_bins[i] << std::endl; } } return stream; @@ -233,13 +231,9 @@ ostream& operator << (ostream& stream, const Node& node) /////////////////////////////////////////////////////////////////////////////////////// -void Bin::make(const PixelRefList& pixels, char dir) +void Bin::make(const PixelRefVector& pixels, char dir) { - if (m_pixel_vecs) { - delete [] m_pixel_vecs; - m_pixel_vecs = NULL; - } - m_length = 0; + m_pixel_vecs.clear(); m_node_count = 0; if (pixels.size()) { @@ -253,58 +247,57 @@ void Bin::make(const PixelRefList& pixels, char dir) // Special, the diagonal should be pixels directly along the diagonal // Both posdiagonal and negdiagonal are positive in the x direction // Note that it is ordered anyway, so no need for anything too fancy: - if (pixels.tail().x < cur.start().x) { - cur.m_start = pixels.tail(); + if (pixels.back().x < cur.start().x) { + cur.m_start = pixels.back(); } - if (pixels.tail().x > cur.end().x) { - cur.m_end = pixels.tail(); + if (pixels.back().x > cur.end().x) { + cur.m_end = pixels.back(); } - m_length = 1; - m_pixel_vecs = new PixelVec[1]; - m_pixel_vecs[0] = cur; + m_pixel_vecs.push_back(cur); m_node_count = pixels.size(); } else { - prefvec pixel_vecs; // Reorder the pixels: if (m_dir == PixelRef::HORIZONTAL) { - pvector pixels_h; + std::set pixels_h; for (size_t i = 0; i < pixels.size(); i++) { - pixels_h.add(pixels[i]); + pixels_h.insert(PixelRefH(pixels[i])); } // this looks like a simple bubble sort - pixel_vecs.push_back(PixelVec(pixels_h[0],pixels_h[0])); - for (size_t j = 1; j < pixels_h.size(); j++) { - if (pixels_h[j-1].y != pixels_h[j].y || pixels_h[j-1].x + 1 != pixels_h[j].x) { - pixel_vecs.tail().m_end = pixels_h[j-1]; - pixel_vecs.push_back(PixelVec(pixels_h[j],pixels_h[j])); + auto curr = pixels_h.begin(); + m_pixel_vecs.push_back(PixelVec(*curr, *curr)); + ++curr; + auto prev = pixels_h.begin(); + for (;curr != pixels_h.end(); ++curr) { + if (prev->y != curr->y || prev->x + 1 != curr->x) { + m_pixel_vecs.back().m_end = *prev; + m_pixel_vecs.push_back(PixelVec(*curr, *curr)); } + prev = curr; } - pixel_vecs.tail().m_end = pixels_h.tail(); + m_pixel_vecs.back().m_end = *pixels_h.rbegin(); } if (m_dir == PixelRef::VERTICAL) { - pvector pixels_v; + std::set pixels_v; for (size_t i = 0; i < pixels.size(); i++) { - pixels_v.add(pixels[i]); + pixels_v.insert(PixelRefV(pixels[i])); } // this looks like a simple bubble sort - pixel_vecs.push_back(PixelVec(pixels_v[0],pixels_v[0])); - for (size_t j = 1; j < pixels_v.size(); j++) { - if (pixels_v[j-1].x != pixels_v[j].x || pixels_v[j-1].y + 1 != pixels_v[j].y) { - pixel_vecs.tail().m_end = pixels_v[j-1]; - pixel_vecs.push_back(PixelVec(pixels_v[j],pixels_v[j])); + auto curr = pixels_v.begin(); + m_pixel_vecs.push_back(PixelVec(*curr, *curr)); + ++curr; + auto prev = pixels_v.begin(); + for (;curr != pixels_v.end(); ++curr) { + if (prev->x != curr->x || prev->y + 1 != curr->y) { + m_pixel_vecs.back().m_end = *prev; + m_pixel_vecs.push_back(PixelVec(*curr, *curr)); } + prev = curr; } - pixel_vecs.tail().m_end = pixels_v.tail(); + m_pixel_vecs.back().m_end = *pixels_v.rbegin(); } - // Now compact the representation: - m_length = pixel_vecs.size(); - m_pixel_vecs = new PixelVec[m_length]; - for (int k = 0; k < m_length; k++) { - m_pixel_vecs[k] = pixel_vecs[k]; - } m_node_count = pixels.size(); } } @@ -312,10 +305,10 @@ void Bin::make(const PixelRefList& pixels, char dir) /////////////////////////////////////////////////////////////////////////////////////// -void Bin::extractUnseen(PixelRefList& pixels, PointMap *pointdata, int binmark) +void Bin::extractUnseen(PixelRefVector& pixels, PointMap *pointdata, int binmark) { - for (int i = 0; i < m_length; i++) { - for (PixelRef pix = m_pixel_vecs[i].start(); pix.col(m_dir) <= m_pixel_vecs[i].end().col(m_dir); ) { + for (auto pixVec: m_pixel_vecs) { + for (PixelRef pix = pixVec.start(); pix.col(m_dir) <= pixVec.end().col(m_dir); ) { Point& pt = pointdata->getPoint(pix); if (pointdata->getPoint(pix).m_misc == 0) { pixels.push_back(pix); @@ -323,9 +316,9 @@ void Bin::extractUnseen(PixelRefList& pixels, PointMap *pointdata, int binmark) } // 10.2.02 revised --- diagonal was breaking this as it was extent in diagonal or horizontal if (!(m_dir & PixelRef::DIAGONAL)) { - if (pt.m_extent.col(m_dir) >= m_pixel_vecs[i].end().col(m_dir)) + if (pt.m_extent.col(m_dir) >= pixVec.end().col(m_dir)) break; - pt.m_extent.col(m_dir) = m_pixel_vecs[i].end().col(m_dir); + pt.m_extent.col(m_dir) = pixVec.end().col(m_dir); } pix.move(m_dir); } @@ -334,17 +327,17 @@ void Bin::extractUnseen(PixelRefList& pixels, PointMap *pointdata, int binmark) /////////////////////////////////////////////////////////////////////////////////////// -void Bin::extractMetric(pqvector& pixels, PointMap *pointdata, const MetricTriple& curs) +void Bin::extractMetric(std::set& pixels, PointMap *pointdata, const MetricTriple& curs) { - for (int i = 0; i < m_length; i++) { - for (PixelRef pix = m_pixel_vecs[i].start(); pix.col(m_dir) <= m_pixel_vecs[i].end().col(m_dir); ) { + for (auto pixVec: m_pixel_vecs) { + for (PixelRef pix = pixVec.start(); pix.col(m_dir) <= pixVec.end().col(m_dir); ) { Point& pt = pointdata->getPoint(pix); if (pt.m_misc == 0 && (pt.m_dist == -1.0 || (curs.dist + dist(pix,curs.pixel) < pt.m_dist))) { pt.m_dist = curs.dist + (float) dist(pix,curs.pixel); // n.b. dmap v4.06r now sets angle in range 0 to 4 (1 = 90 degrees) pt.m_cumangle = pointdata->getPoint(curs.pixel).m_cumangle + (curs.lastpixel == NoPixel ? 0.0f : (float) (angle(pix,curs.pixel,curs.lastpixel) / (M_PI * 0.5))); - pixels.add(MetricTriple(pt.m_dist, pix, curs.pixel)); + pixels.insert(MetricTriple(pt.m_dist, pix, curs.pixel)); } pix.move(m_dir); } @@ -353,17 +346,17 @@ void Bin::extractMetric(pqvector& pixels, PointMap *pointdata, con // based on metric -void Bin::extractAngular(pqvector& pixels, PointMap *pointdata, const AngularTriple& curs) +void Bin::extractAngular(std::set& pixels, PointMap *pointdata, const AngularTriple& curs) { - for (int i = 0; i < m_length; i++) { - for (PixelRef pix = m_pixel_vecs[i].start(); pix.col(m_dir) <= m_pixel_vecs[i].end().col(m_dir); ) { + for (auto pixVec: m_pixel_vecs) { + for (PixelRef pix = pixVec.start(); pix.col(m_dir) <= pixVec.end().col(m_dir); ) { Point& pt = pointdata->getPoint(pix); if (pt.m_misc == 0) { // n.b. dmap v4.06r now sets angle in range 0 to 4 (1 = 90 degrees) float ang = (curs.lastpixel == NoPixel) ? 0.0f : (float) (angle(pix,curs.pixel,curs.lastpixel) / (M_PI * 0.5)); if (pt.m_cumangle == -1.0 || curs.angle + ang < pt.m_cumangle) { pt.m_cumangle = pointdata->getPoint(curs.pixel).m_cumangle + ang; - pixels.add(AngularTriple(pt.m_cumangle, pix, curs.pixel)); + pixels.insert(AngularTriple(pt.m_cumangle, pix, curs.pixel)); } } pix.move(m_dir); @@ -375,18 +368,18 @@ void Bin::extractAngular(pqvector& pixels, PointMap *pointdata, c bool Bin::containsPoint(const PixelRef p) const { - for (int i = 0; i < m_length; i++) { + for (auto pixVec: m_pixel_vecs) { if (m_dir & PixelRef::DIAGONAL) { // note abs is only allowed if you have pre-checked you are in the right quadrant! - if (p.x >= m_pixel_vecs[i].start().x && p.x <= m_pixel_vecs[i].end().x && - abs(p.y - m_pixel_vecs[i].start().y) == p.x - m_pixel_vecs[i].start().x) { + if (p.x >= pixVec.start().x && p.x <= pixVec.end().x && + abs(p.y - pixVec.start().y) == p.x - pixVec.start().x) { return true; } } else { - if (p.row(m_dir) == m_pixel_vecs[i].start().row(m_dir) && - p.col(m_dir) >= m_pixel_vecs[i].start().col(m_dir) && - p.col(m_dir) <= m_pixel_vecs[i].end().col(m_dir)) { + if (p.row(m_dir) == pixVec.start().row(m_dir) && + p.col(m_dir) >= pixVec.start().col(m_dir) && + p.col(m_dir) <= pixVec.end().col(m_dir)) { return true; } } @@ -396,11 +389,11 @@ bool Bin::containsPoint(const PixelRef p) const /////////////////////////////////////////////////////////////////////////////////////// -void Bin::contents(PixelRefList& hood) +void Bin::contents(PixelRefVector& hood) { first(); while (!is_tail()) { - hood.add((int) m_curpix); + depthmapX::addIfNotExists(hood, m_curpix); next(); } } @@ -408,7 +401,7 @@ void Bin::contents(PixelRefList& hood) void Bin::first() const { m_curvec = 0; - if (m_length) + if (!m_pixel_vecs.empty()) m_curpix = m_pixel_vecs[m_curvec].m_start; } @@ -416,14 +409,14 @@ void Bin::next() const { if (m_curpix.move(m_dir).col(m_dir) > m_pixel_vecs[m_curvec].end().col(m_dir)) { m_curvec++; - if (m_curvec < m_length) + if (m_curvec < static_cast(m_pixel_vecs.size())) m_curpix = m_pixel_vecs[m_curvec].m_start; } } bool Bin::is_tail() const { - return m_curvec >= m_length; + return m_curvec >= static_cast(m_pixel_vecs.size()); } PixelRef Bin::cursor() const @@ -433,107 +426,66 @@ PixelRef Bin::cursor() const /////////////////////////////////////////////////////////////////////////////////////// -ifstream& Bin::read(ifstream& stream, int version) +std::istream& Bin::read(std::istream& stream) { stream.read( (char *) &m_dir, sizeof(m_dir) ); stream.read( (char *) &m_node_count, sizeof(m_node_count) ); - if (version >= VERSION_FILE_COMPRESSION) { - if (version >= VERSION_ALWAYS_RECORD_BINDISTANCES) { - stream.read( (char *) &m_distance, sizeof(m_distance) ); - stream.read( (char *) &m_occ_distance, sizeof(m_occ_distance) ); - } - if (m_node_count) { - if (version < VERSION_ALWAYS_RECORD_BINDISTANCES) { - stream.read( (char *) &m_distance, sizeof(m_distance) ); - } - if (m_dir & PixelRef::DIAGONAL) { - m_length = 1; - m_pixel_vecs = new PixelVec [m_length]; - m_pixel_vecs[0].read(stream, version, m_dir); - } - else { - stream.read( (char *) &m_length, sizeof(m_length) ); - m_pixel_vecs = new PixelVec [m_length]; - m_pixel_vecs[0].read(stream, version, m_dir); - for (int i = 1; i < m_length; i++) { - m_pixel_vecs[i].read(stream, version, m_dir,m_pixel_vecs[i-1]); - } - } - if (version < VERSION_ALWAYS_RECORD_BINDISTANCES) { - if (version >= VERSION_OCCDISTANCES) { - stream.read( (char *) &m_occ_distance, sizeof(m_occ_distance) ); - } - else { - m_occ_distance = 0.0f; - } - } + + stream.read( (char *) &m_distance, sizeof(m_distance) ); + stream.read( (char *) &m_occ_distance, sizeof(m_occ_distance) ); + + if (m_node_count) { + if (m_dir & PixelRef::DIAGONAL) { + m_pixel_vecs = std::vector(1); + m_pixel_vecs[0].read(stream, m_dir); } else { - m_pixel_vecs = NULL; - m_length = 0; - if (version < VERSION_ALWAYS_RECORD_BINDISTANCES) { - m_distance = 0.0f; - m_occ_distance = 0.0f; + unsigned short length; + stream.read( (char *) &length, sizeof(length) ); + m_pixel_vecs = std::vector(length); + m_pixel_vecs[0].read(stream, m_dir); + for (int i = 1; i < length; i++) { + m_pixel_vecs[i].read(stream, m_dir,m_pixel_vecs[i-1]); } } } - else { - stream.read( (char *) &m_length, sizeof(m_length) ); - if (version >= VERSION_BINDISTANCES) { - stream.read( (char *) &m_distance, sizeof(m_distance) ); - } - else { - m_distance = 0.0f; - } - if (m_pixel_vecs) { - delete m_pixel_vecs; - m_pixel_vecs = NULL; - } - if (m_length) { - m_pixel_vecs = new PixelVec [m_length]; - stream.read( (char *) m_pixel_vecs, sizeof(PixelVec) * m_length); - } - } return stream; } -ofstream& Bin::write(ofstream& stream, int version) +std::ostream& Bin::write(std::ostream& stream) { stream.write( (char *) &m_dir, sizeof(m_dir) ); stream.write( (char *) &m_node_count, sizeof(m_node_count) ); - if (version >= VERSION_ALWAYS_RECORD_BINDISTANCES) { - stream.write( (char *) &m_distance, sizeof(m_distance) ); - stream.write( (char *) &m_occ_distance, sizeof(m_occ_distance) ); - } + + stream.write( (char *) &m_distance, sizeof(m_distance) ); + stream.write( (char *) &m_occ_distance, sizeof(m_occ_distance) ); + if (m_node_count) { - if (version < VERSION_ALWAYS_RECORD_BINDISTANCES) { - stream.write( (char *) &m_distance, sizeof(m_distance) ); - } + if (m_dir & PixelRef::DIAGONAL) { m_pixel_vecs[0].write(stream,m_dir); } else { - stream.write( (char *) &m_length, sizeof(m_length) ); + // TODO: Remove this limitation in the next version of the .graph format + unsigned short length = m_pixel_vecs.size(); + stream.write( (char *) &length, sizeof(length) ); m_pixel_vecs[0].write(stream,m_dir); - for (int i = 1; i < m_length; i++) { + for (int i = 1; i < length; i++) { m_pixel_vecs[i].write(stream,m_dir,m_pixel_vecs[i-1]); } } - if (version >= VERSION_OCCDISTANCES && version < VERSION_ALWAYS_RECORD_BINDISTANCES) { - stream.write( (char *) &m_occ_distance, sizeof(m_occ_distance) ); - } } return stream; } -ostream& operator << (ostream& stream, const Bin& bin) +std::ostream& operator << (std::ostream& stream, const Bin& bin) { int c = 0; - for (int i = 0; i < bin.m_length; i++) { - for (PixelRef p = bin.m_pixel_vecs[i].m_start; - p.col(bin.m_dir) <= bin.m_pixel_vecs[i].end().col(bin.m_dir); p.move(bin.m_dir)) { + for (auto pixVec: bin.m_pixel_vecs) { + for (PixelRef p = pixVec.m_start; + p.col(bin.m_dir) <= pixVec.end().col(bin.m_dir); p.move(bin.m_dir)) { if (++c % 10 == 0) { stream << "\n "; } @@ -545,7 +497,7 @@ ostream& operator << (ostream& stream, const Bin& bin) /////////////////////////////////////////////////////////////////////////////////////// -ifstream& PixelVec::read(ifstream& stream, int version, const char dir) +std::istream& PixelVec::read(std::istream& stream, const char dir) { unsigned short runlength; stream.read((char *) &m_start, sizeof(m_start)); @@ -571,7 +523,7 @@ ifstream& PixelVec::read(ifstream& stream, int version, const char dir) return stream; } -ofstream& PixelVec::write(ofstream& stream, const char dir) +std::ostream& PixelVec::write(std::ostream& stream, const char dir) { stream.write((char *) &m_start, sizeof(m_start)); unsigned short runlength; @@ -595,7 +547,7 @@ struct ShiftLength { unsigned short runlength : 12; }; -ifstream& PixelVec::read(ifstream& stream, int version, const char dir, const PixelVec& context) +std::istream& PixelVec::read(std::istream& stream, const char dir, const PixelVec& context) { short primary; ShiftLength shiftlength; @@ -619,7 +571,7 @@ ifstream& PixelVec::read(ifstream& stream, int version, const char dir, const Pi return stream; } -ofstream& PixelVec::write(ofstream& stream, const char dir, const PixelVec& context) +std::ostream& PixelVec::write(std::ostream& stream, const char dir, const PixelVec& context) { ShiftLength shiftlength; switch (dir) { diff --git a/salalib/ngraph.h b/salalib/ngraph.h index ea150f51..4070d3ce 100644 --- a/salalib/ngraph.h +++ b/salalib/ngraph.h @@ -17,12 +17,16 @@ // ngraph.h -#ifndef __NGRAPH_H__ -#define __NGRAPH_H__ +#pragma once + +#include "salalib/pixelref.h" + +#include class PointMap; struct MetricPair; struct MetricTriple; +struct AngularTriple; struct PixelVec { @@ -35,36 +39,29 @@ struct PixelVec PixelRef end() const { return m_end; } // - ifstream& read(ifstream& stream, int version, const char dir); - ifstream& read(ifstream& stream, int version, const char dir, const PixelVec& context); - ofstream& write(ofstream& stream, const char dir); - ofstream& write(ofstream& stream, const char dir, const PixelVec& context); + std::istream &read(std::istream &stream, const char dir); + std::istream &read(std::istream &stream, const char dir, const PixelVec& context); + std::ostream &write(std::ostream &stream, const char dir); + std::ostream &write(std::ostream &stream, const char dir, const PixelVec& context); }; class Bin { friend class Node; protected: - char m_dir; - unsigned short m_length; unsigned short m_node_count; float m_distance; float m_occ_distance; - PixelVec *m_pixel_vecs; public: + char m_dir; + std::vector m_pixel_vecs; Bin() - { m_dir = PixelRef::NODIR; m_length = 0; m_pixel_vecs = NULL; m_node_count = 0; m_distance = 0.0f; m_occ_distance = 0.0f; } - Bin(const Bin&) - { throw 1; } - Bin& operator = (const Bin&) - { throw 1; } - ~Bin() - { if (m_pixel_vecs) delete [] m_pixel_vecs; m_pixel_vecs = NULL; } - // - void make(const PixelRefList& pixels, char m_dir); - void extractUnseen(PixelRefList& pixels, PointMap *pointdata, int binmark); - void extractMetric(pqvector& pixels, PointMap *pointdata, const MetricTriple& curs); - void extractAngular(pqvector& pixels, PointMap *pointdata, const AngularTriple& curs); + { m_dir = PixelRef::NODIR; m_node_count = 0; m_distance = 0.0f; m_occ_distance = 0.0f; } + // + void make(const PixelRefVector& pixels, char m_dir); + void extractUnseen(PixelRefVector& pixels, PointMap *pointdata, int binmark); + void extractMetric(std::set &pixels, PointMap *pointdata, const MetricTriple& curs); + void extractAngular(std::set &pixels, PointMap *pointdata, const AngularTriple& curs); // int count() const { return m_node_count; } @@ -84,16 +81,16 @@ class Bin mutable int m_curvec; mutable PixelRef m_curpix; public: - void contents(PixelRefList& hood); + void contents(PixelRefVector& hood); void first() const; void next() const; bool is_tail() const; PixelRef cursor() const; // - ifstream& read(ifstream& stream, int version); - ofstream& write(ofstream& stream, int version); + std::istream &read(std::istream &stream); + std::ostream &write(std::ostream &stream); // - friend ostream& operator << (ostream& stream, const Bin& bin); + friend std::ostream& operator << (std::ostream& stream, const Bin& bin); }; class Node @@ -103,21 +100,13 @@ class Node Bin m_bins[32]; public: // testing some agent stuff: - pvector m_occlusion_bins[32]; + std::vector m_occlusion_bins[32]; public: - Node() - { ; } - Node(const Node&) - { throw 1; } - Node& operator = (const Node&) - { throw 1; } - ~Node() - { ; } // Note: this function clears the bins as it goes - void make(const PixelRef pix, PixelRefList *bins, float *bin_far_dists, int q_octants); - void extractUnseen(PixelRefList& pixels, PointMap *pointdata, int binmark); - void extractMetric(pqvector& pixels, PointMap *pointdata, const MetricTriple& curs); - void extractAngular(pqvector& pixels, PointMap *pointdata, const AngularTriple& curs); + void make(const PixelRef pix, PixelRefVector *bins, float *bin_far_dists, int q_octants); + void extractUnseen(PixelRefVector& pixels, PointMap *pointdata); + void extractMetric(std::set &pixels, PointMap *pointdata, const MetricTriple& curs); + void extractAngular(std::set &pixels, PointMap *pointdata, const AngularTriple& curs); bool concaveConnected(); bool fullyConnected(); // @@ -148,16 +137,16 @@ class Node // Conversion back to old fashioned schema: mutable int m_curbin; public: - void contents(PixelRefList& hood) const; + void contents(PixelRefVector& hood) const; void first() const; void next() const; bool is_tail() const; PixelRef cursor() const; // - ifstream& read(ifstream& stream, int version); - ofstream& write(ofstream& stream, int version); + std::istream &read(std::istream &stream); + std::ostream &write(std::ostream &stream); // - friend ostream& operator << (ostream& stream, const Node& node); + friend std::ostream& operator << (std::ostream& stream, const Node& node); }; // Two little helpers: @@ -198,5 +187,3 @@ inline bool operator < (const PixelRefV& a, const PixelRefV& b) { return (a.x < b.x || (a.x == b.x && a.y < b.y)); } - -#endif diff --git a/salalib/options.h b/salalib/options.h new file mode 100644 index 00000000..0ac9fad2 --- /dev/null +++ b/salalib/options.h @@ -0,0 +1,65 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include +#include + +// Options for mean depth calculations +struct Options +{ + enum output_t { OUTPUT_ISOVIST, OUTPUT_VISUAL, OUTPUT_METRIC, OUTPUT_ANGULAR, OUTPUT_THRU_VISION, OUTPUT_CLIQUE_GRAPH, + OUTPUT_KERNEL_GRAPH, OUTPUT_MATRIX_REDUCTION }; + // Output type, see above + int output_type; + // Options for the summary type: + int local; + int global; + int cliques; + // + bool choice; + // include measures that can be derived: RA, RRA and total depth + bool fulloutput; + // + enum { RADIUS_STEPS, RADIUS_METRIC, RADIUS_ANGULAR }; + int radius_type; + double radius; // <- n.b. for metric integ radius is floating point + // radius has to go up to a list (phase out radius as is) + std::set radius_set; + // + int point_depth_selection; + int tulip_bins; + bool process_in_memory; + bool sel_only; + bool gates_only; + // for pushing to a gates layer + int gatelayer; + // a column to weight measures by: + int weighted_measure_col; + int weighted_measure_col2; //EFEF + int routeweight_col; //EFEF + std::string output_file; // To save an output graph (for example) + // default values + Options() + { local = 0; global = 1; cliques = 0; + choice = false; fulloutput = false; point_depth_selection = 0; + tulip_bins = 1024; + radius = -1; radius_type = 0; + output_type = OUTPUT_ISOVIST; process_in_memory = false; gates_only = false; sel_only = false; + gatelayer = -1; + weighted_measure_col = -1;} +}; diff --git a/salalib/pafcolor.cpp b/salalib/pafcolor.cpp new file mode 100644 index 00000000..90bf34b4 --- /dev/null +++ b/salalib/pafcolor.cpp @@ -0,0 +1,250 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include // _finite support + +#include // <- sala actually includes vertex.h for us + +static unsigned int g_nicecolor[] = { + 0x003333DD, // 0 blue + 0x003388DD, // 1 + 0x0022CCDD, // 2 + 0x0022CCBB, // 3 + 0x0022DD88, // 4 + 0x0088DD22, // 5 + 0x00BBCC22, // 6 + 0x00DDCC22, // 7 + 0x00DD8833, // 8 + 0x00DD3333, // 9 red +}; + +// Test a range designed to try to keep consistent saturation and brightness of g_nicecolor, and only move hue +static unsigned int g_nicecolorhsb[] = { + 0x003333DD, // 0 blue + 0x003377DD, // 1 + 0x0033BBDD, // 2 + 0x0033DDBB, // 3 + 0x0033DD55, // 4 + 0x0055DD33, // 5 + 0x00BBDD33, // 6 + 0x00DDBB33, // 7 + 0x00DD7733, // 8 + 0x00DD3333, // 9 red +}; + +static unsigned int g_greyscale[] = { + 0x00000000, // 0 black + 0x00444444, // 1 + 0x00777777, // 2 + 0x00AAAAAA, // 3 + 0x00CCCCCC, // 4 + 0x00EEEEEE, // 5 + 0x00FFFFFF, // 6 white +}; + +static unsigned int g_bluered[] = { + 0x004575B4, // 0 blue + 0x0091BFDB, + 0x00E0F3F8, + 0x00FFFFBF, + 0x00FEE090, + 0x00FC8D59, + 0x00D73027 // 6 red +}; + +static unsigned int g_purpleorange[] = { + 0x00542788, // 0 purple + 0x00998EC3, // 1 + 0x00D8DAEB, // 2 + 0x00F7F7F7, // 3 + 0x00FEE0B6, // 4 + 0x00F1A340, // 5 + 0x00B35806 // 6 orange +}; + +// htmlByte converts a normalised number to an HTML safe byte + +unsigned char htmlByte(double colorByte) +{ + // Quick mod - TV +#if defined(_MSC_VER) + return (unsigned char((colorByte + 0.0333) * 15.0) * 0x11); +#else + return ((unsigned char)((colorByte + 0.0333) * 15.0) * 0x11); +#endif +} + +PafColor& PafColor::makeColor(double field, DisplayParams dp) +{ + // Quick mod - TV + if (field == -1.0 || std::isnan(field)) { + // -1.0 is (currently) a nan value, set alpha channel to 0 (transparent) + switch (dp.colorscale) { + case DisplayParams::MONOCHROME: + case DisplayParams::GREYSCALE: + m_color = 0x00000000; // <- monochrome and greyscale, simply hide + break; + default: + // if in colour, then show greyed out: + m_color = 0x007f7f7f; // <- grey retained for visibility on certain values + break; + } + return *this; + } + if (dp.blue > dp.red) { + field = 1.0 - field; + dp.blue = 1.0f - dp.blue; + dp.red = 1.0f - dp.red; + } + if (dp.colorscale == DisplayParams::DEPTHMAPCLASSIC) { + makeDepthmapClassic(field, dp.blue, dp.red); + } + else { + field = (field - dp.blue) / (dp.red - dp.blue); + // Quick mod - TV + if (std::isnan(field)) { + field = 0.5; + } + if (field > 1.0) { + field = 1.0; + } + else if (field < 0.0) { + field = 0.0; + } + switch(dp.colorscale) { + case DisplayParams::AXMANESQUE: + makeAxmanesque(field); + break; + case DisplayParams::HUEONLYAXMANESQUE: + makeHueOnlyAxmanesque(field); + break; + case DisplayParams::PURPLEORANGE: + makePurpleOrange(field); + break; + case DisplayParams::BLUERED: + makeBlueRed(field); + break; + case DisplayParams::GREYSCALE: + case DisplayParams::MONOCHROME: + makeGreyScale(field); + break; + } + } + return *this; +} + +// this makes an Axman-like colour range + +PafColor& PafColor::makeAxmanesque( double field ) +{ + m_color = 0xff000000 | g_nicecolor[int((field - 1e-9) * 10.0)]; + return *this; +} + +PafColor& PafColor::makeHueOnlyAxmanesque( double field ) +{ + m_color = 0xff000000 | g_nicecolorhsb[int((field - 1e-9) * 10.0)]; + return *this; +} + +// this makes a purple-orange scheme that is red-green colour-blind safe + +PafColor& PafColor::makePurpleOrange( double field ) +{ + m_color = 0xff000000 | g_purpleorange[int((field - 1e-9) * 7.0)]; + return *this; +} + +// this makes a blue-red scheme that is red-green colour-blind safe + +PafColor& PafColor::makeBlueRed( double field ) +{ + m_color = 0xff000000 | g_bluered[int((field - 1e-9) * 7.0)]; + return *this; +} + +// this makes a greyscale colour range + +PafColor& PafColor::makeGreyScale( double field ) +{ + m_color = 0xff000000 | g_greyscale[int((field - 1e-9) * 7.0)]; + return *this; +} + +// note, makeDepthmapClassic converts to a safe HTML colour + +PafColor& PafColor::makeDepthmapClassic( double field, double blue, double red ) +{ + m_color = 0xff000000; // set alpha to 255, solid colour + double green = blue + (red-blue) / 10.0; + // NB previously included colour muting: the 1.0 was originally 0.9 to mute the colours slightly + if (field >= 0.0 && field < blue) { + setr(htmlByte(0.5 * (blue - field)/blue * 1.0)); + // Quick mod - TV +#if defined(_MSC_VER) + setb(unsigned char(0xFF)); +#else + setb((unsigned char)(0xFF)); +#endif + } + else if (field >= blue && field < (green+blue)/2.0) { + // Quick mod - TV +#if defined(_MSC_VER) + setb(unsigned char(0xFF)); +#else + setb((unsigned char)(0xFF)); +#endif + setg(htmlByte((2.0*(field - blue)/(green-blue)) * 1.0)); + } + else if (field >= (green+blue)/2.0 && field < green) { + setb(htmlByte((2.0*(green - field)/(green-blue)) * 1.0)); + // Quick mod - TV +#if defined(_MSC_VER) + setg(unsigned char(0xFF)); +#else + setg((unsigned char)(0xFF)); +#endif + } + else if (field >= green && field < (green+red)/2.0 ) { + // Quick mod - TV +#if defined(_MSC_VER) + setg(unsigned char(0xFF)); +#else + setg((unsigned char)(0xFF)); +#endif + setr(htmlByte((2.0*(field - green)/(red-green)) * 1.0)); + } + else if (field >= (green+red)/2.0 && field < red) { + setg(htmlByte((2.0*(red - field)/(red-green)) * 1.0)); + // Quick mod - TV +#if defined(_MSC_VER) + setr(unsigned char(0xFF)); +#else + setr((unsigned char)(0xFF)); +#endif + } + else if (field >= red) { + // Quick mod - TV +#if defined(_MSC_VER) + setr(unsigned char(0xFF)); +#else + setr((unsigned char)(0xFF)); +#endif + setb(htmlByte(0.5 * (field - red)/(1.0 - red) * 1.0)); + } + return *this; +} diff --git a/salalib/pafcolor.h b/salalib/pafcolor.h new file mode 100644 index 00000000..4e167e25 --- /dev/null +++ b/salalib/pafcolor.h @@ -0,0 +1,94 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/displayparams.h" +#include "genlib/p2dpoly.h" + +// For my colour scheme... some parameters to pass, and my own colour class + +// Converts everything to safe HTML colours + +struct PafColor +{ + unsigned int m_color; + unsigned char redb() const + { return (unsigned char) (m_color >> 16); } + unsigned char greenb() const + { return (unsigned char) (m_color >> 8); } + unsigned char blueb() const + { return (unsigned char) (m_color); } + unsigned char alphab() const + { return (unsigned char) (m_color >> 24); } + // Quick mod - TV + void setr(unsigned char r) + { m_color &= 0xff00ffff; m_color |= (((unsigned int)r) << 16);} + // Quick mod - TV + void setg(unsigned char g) + { m_color &= 0xffff00ff; m_color |= (((unsigned int)g) << 8);} + // Quick mod - TV + void setb(unsigned char b) + { m_color &= 0xffffff00; m_color |= ((unsigned int)b);} + float redf() const + { return float(redb()) / 255.0f; } + float greenf() const + { return float(greenb()) / 255.0f; } + float bluef() const + { return float(blueb()) / 255.0f; } + PafColor() + { m_color = 0x00000000; } + PafColor(unsigned int rgb) // color in 0x00rrggbb format + { m_color = 0xff000000 | rgb; } + PafColor( double r, double g, double b, double a = 1.0 ) + { + m_color = 0x00000000 | + (((unsigned char) (a * 255.0)) << 24) | + (((unsigned char) (r * 255.0)) << 16) | + (((unsigned char) (g * 255.0)) << 8) | + (((unsigned char) (b * 255.0))); + } + + PafColor( const Point2f& vec, double a = 1.0 ) + { + m_color = 0x00000000 | + (((unsigned char) (a * 255.0)) << 24) | + (((unsigned char) (dot(vec,Point2f(1.0, 0.0)) * 255.0)) << 16) | + (((unsigned char) (dot(vec,Point2f(-0.5,0.86602540378443864676372317075294)) * 255.0)) << 8) | + (((unsigned char) (dot(vec,Point2f(-0.5,-0.86602540378443864676372317075294)) * 255.0))); + } + + operator unsigned int () + { return m_color & 0x00ffffff; } + friend bool operator == (const PafColor& a, const PafColor& b); + friend bool operator != (const PafColor& a, const PafColor& b); + PafColor& makeAxmanesque( double field); + PafColor& makeHueOnlyAxmanesque( double field); + PafColor& makePurpleOrange( double field ); + PafColor& makeBlueRed( double field ); + PafColor& makeGreyScale( double field ); + PafColor& makeMonochrome( double field ); + PafColor& makeDepthmapClassic( double field, double blue, double red ); + PafColor& makeColor(double field, DisplayParams dp); // <- note, make copy to play around with +}; +inline bool operator == (const PafColor& a, const PafColor& b) +{ + return (a.m_color == b.m_color); +} +inline bool operator != (const PafColor& a, const PafColor& b) +{ + return (a.m_color != b.m_color); +} diff --git a/salalib/parsers/CMakeLists.txt b/salalib/parsers/CMakeLists.txt new file mode 100644 index 00000000..baf6a362 --- /dev/null +++ b/salalib/parsers/CMakeLists.txt @@ -0,0 +1,11 @@ +target_sources(salalib + PRIVATE + ntfp.cpp + dxfp.cpp + mapinfodata.cpp + tigerp.cpp + PUBLIC + dxfp.h + ntfp.h + mapinfodata.h + tigerp.h) diff --git a/genlib/dxfp.cpp b/salalib/parsers/dxfp.cpp similarity index 67% rename from genlib/dxfp.cpp rename to salalib/parsers/dxfp.cpp index e7febb8d..147514b1 100644 --- a/genlib/dxfp.cpp +++ b/salalib/parsers/dxfp.cpp @@ -17,16 +17,15 @@ // parser class +#include "dxfp.h" + +#include "genlib/comm.h" // for communicator +#include "genlib/stringutils.h" #include #include -#include - -using namespace std; - -#include -#include // for communicator -#include +#include +#include static int counter = 0; @@ -66,59 +65,47 @@ const DxfVertex& DxfParser::getExtMax() const return m_region.getExtMax(); } -const DxfLayer& DxfParser::getLayerNum( const int i ) const +DxfLayer *DxfParser::getLayer( const std::string& layer_name ) // const <- removed as m_layers may be changed if DXF is poor { - return m_layers[i]; -} - -DxfLayer *DxfParser::getLayer( const pstring& layer_name ) // const <- removed as m_layers may be changed if DXF is poor -{ - static DxfLayer layer; - - layer.m_name = layer_name; - - size_t n = m_layers.searchindex( layer ); - if (n == paftl::npos) { - n = m_layers.add( layer, paftl::ADD_HERE ); + std::map::iterator layerIter = m_layers.find(layer_name); + if (layerIter == m_layers.end()) { + m_layers.insert( std::pair (layer_name, DxfLayer(layer_name))); + return &(m_layers.find(layer_name)->second); } - return &m_layers[n]; + return &(layerIter->second); } -const DxfLineType& DxfParser::getLineType( const int i ) const -{ - return m_line_types[i]; -} - -DxfLineType *DxfParser::getLineType( const pstring& line_type_name ) // const <- removed as m_layers may be changed if DXF is poor +DxfLineType *DxfParser::getLineType( const std::string& line_type_name ) // const <- removed as m_layers may be changed if DXF is poor { static DxfLineType line_type; line_type.m_name = line_type_name; - size_t n = m_line_types.searchindex( line_type ); - if (n == paftl::npos) { - n = m_line_types.add( line_type, paftl::ADD_HERE ); + std::map::iterator lineTypeIter = m_line_types.find(line_type_name); + if (lineTypeIter == m_line_types.end()) { + m_line_types.insert( std::pair (line_type_name, line_type)); + return &(m_line_types.find(line_type_name)->second); } - return &m_line_types[n]; + return &(lineTypeIter->second); } -int DxfParser::numLayers() const +size_t DxfParser::numLayers() const { return m_layers.size(); } -int DxfParser::numLineTypes() const +size_t DxfParser::numLineTypes() const { return m_line_types.size(); } /////////////////////////////////////////////////////////////////////////////// -istream& operator >> (istream& stream, DxfParser& dxfp) +std::istream& operator >> (std::istream& stream, DxfParser& dxfp) { if (dxfp.m_communicator) { - long size = dxfp.m_communicator->GetInfileSize(); + long size = static_cast(dxfp.m_communicator->GetInfileSize()); dxfp.m_communicator->CommPostMessage( Communicator::NUM_RECORDS, size ); qtimer( dxfp.m_time, 0 ); @@ -127,7 +114,7 @@ istream& operator >> (istream& stream, DxfParser& dxfp) return dxfp.open( stream ); } -istream& DxfParser::open( istream& stream ) +std::istream& DxfParser::open( std::istream& stream ) { DxfToken token; int section = UNIDENTIFIED; @@ -199,15 +186,16 @@ istream& DxfParser::open( istream& stream ) if (m_communicator->IsCancelled()) { throw Communicator::CancelledException(); } - m_communicator->CommPostMessage( Communicator::CURRENT_RECORD, m_size ); + m_communicator->CommPostMessage( Communicator::CURRENT_RECORD, static_cast(m_size) ); } } } + // Get overall bounding box from layers: - bool first = true; - for (size_t i = 0; i < m_layers.size(); i++) { - if (!m_layers[i].empty()) { - m_region.merge( m_layers[i] ); + for ( const auto& layer : m_layers ) + { + if (!layer.second.empty()) { + m_region.merge( layer.second ); } } return stream; @@ -215,7 +203,7 @@ istream& DxfParser::open( istream& stream ) /////////////////////////////////////////////////////////////////////////////// -void DxfParser::openHeader( istream& stream ) +void DxfParser::openHeader( std::istream& stream ) { DxfToken token; int subsection = UNIDENTIFIED; @@ -277,7 +265,7 @@ void DxfParser::openHeader( istream& stream ) /////////////////////////////////////////////////////////////////////////////// -void DxfParser::openTables( istream& stream ) +void DxfParser::openTables( std::istream& stream ) { DxfToken token; int subsection = UNIDENTIFIED; @@ -330,7 +318,7 @@ void DxfParser::openTables( istream& stream ) stream >> token; m_size += token.size; if ( line_type.parse( token, this ) ) { - m_line_types.add( line_type ); + m_line_types.insert( std::pair(line_type.m_name, line_type) ); if (token.data == "ENDTAB") { subsection = ZEROTOKEN; } @@ -371,7 +359,7 @@ void DxfParser::openTables( istream& stream ) /////////////////////////////////////////////////////////////////////////////// -void DxfParser::openBlocks( istream& stream ) +void DxfParser::openBlocks( std::istream& stream ) { DxfToken token; int subsection = UNIDENTIFIED; @@ -395,13 +383,13 @@ void DxfParser::openBlocks( istream& stream ) stream >> token; m_size += token.size; if ( block.parse( token, this ) ) { - int pos = m_blocks.add( block ); + m_blocks.insert( std::pair (block.m_name, block) ); if (token.data == "ENDBLK") { subsection = ZEROTOKEN; } else { // this drills down to the data for the block: - openEntities(stream, token, &m_blocks[pos] ); + openEntities(stream, token, &(m_blocks[block.m_name]) ); // only if the block ends should we move up: if (token.data == "ENDBLK") { subsection = ZEROTOKEN; @@ -424,7 +412,7 @@ void DxfParser::openBlocks( istream& stream ) if (m_communicator->IsCancelled()) { throw Communicator::CancelledException(); } - m_communicator->CommPostMessage( Communicator::CURRENT_RECORD, m_size ); + m_communicator->CommPostMessage( Communicator::CURRENT_RECORD, static_cast(m_size) ); } } } @@ -432,7 +420,7 @@ void DxfParser::openBlocks( istream& stream ) /////////////////////////////////////////////////////////////////////////////// -void DxfParser::openEntities( istream& stream, DxfToken& token, DxfBlock *block ) +void DxfParser::openEntities( std::istream& stream, DxfToken& token, DxfBlock *block ) { int subsection = UNIDENTIFIED; if (token.code == 0) { @@ -445,12 +433,13 @@ void DxfParser::openEntities( istream& stream, DxfToken& token, DxfBlock *block DxfPolyLine poly_line; DxfLwPolyLine lw_poly_line; DxfArc arc; + DxfEllipse ellipse; DxfCircle circle; DxfSpline spline; DxfInsert insert; - pstring layer_name; - pstring line_type_name; + std::string layer_name; + std::string line_type_name; while (!stream.eof() && subsection != ENDSEC) { switch (subsection) { @@ -470,6 +459,9 @@ void DxfParser::openEntities( istream& stream, DxfToken& token, DxfBlock *block else if (token.data == "ARC") { subsection = ARC; } + else if (token.data == "ELLIPSE") { + subsection = ELLIPSE; + } else if (token.data == "CIRCLE") { subsection = CIRCLE; } @@ -497,7 +489,10 @@ void DxfParser::openEntities( istream& stream, DxfToken& token, DxfBlock *block layer->m_points.push_back( point ); layer->merge(point); // <- merge bounding box layer->m_total_point_count += 1; + point.clear(); + subsection = ZEROTOKEN; } + break; case LINE: stream >> token; m_size += token.size; @@ -525,7 +520,7 @@ void DxfParser::openEntities( istream& stream, DxfToken& token, DxfBlock *block layer = poly_line.m_p_layer; } layer->m_poly_lines.push_back( poly_line ); - int line_count = (poly_line.getAttributes() & DxfPolyLine::CLOSED) ? + size_t line_count = (poly_line.getAttributes() & DxfPolyLine::CLOSED) ? poly_line.numVertices() - 2 : poly_line.numVertices() - 1; layer->merge(poly_line); // <- merge bounding box layer->m_total_line_count += line_count; @@ -544,8 +539,8 @@ void DxfParser::openEntities( istream& stream, DxfToken& token, DxfBlock *block if (layer == NULL) { layer = lw_poly_line.m_p_layer; } - layer->m_poly_lines.push_back( (const DxfPolyLine&) lw_poly_line ); - int line_count = (lw_poly_line.getAttributes() & DxfPolyLine::CLOSED) ? + layer->m_poly_lines.push_back( lw_poly_line ); + size_t line_count = (lw_poly_line.getAttributes() & DxfPolyLine::CLOSED) ? lw_poly_line.numVertices() - 2 : lw_poly_line.numVertices() - 1; layer->merge(lw_poly_line); // <- merge bounding box layer->m_total_line_count += line_count; @@ -562,12 +557,26 @@ void DxfParser::openEntities( istream& stream, DxfToken& token, DxfBlock *block if (layer == NULL) { layer = arc.m_p_layer; } - layer->m_arcs.push_back( (const DxfArc&) arc ); + layer->m_arcs.push_back( arc ); layer->merge(arc); arc.clear(); // (Now reuse) subsection = ZEROTOKEN; } break; + case ELLIPSE: + stream >> token; + m_size += token.size; + if ( ellipse.parse( token, this ) ) { + DxfLayer *layer = block; + if (layer == NULL) { + layer = ellipse.m_p_layer; + } + layer->m_ellipses.push_back( ellipse ); + layer->merge(ellipse); + ellipse.clear(); // (Now reuse) + subsection = ZEROTOKEN; + } + break; case CIRCLE: stream >> token; m_size += token.size; @@ -576,7 +585,7 @@ void DxfParser::openEntities( istream& stream, DxfToken& token, DxfBlock *block if (layer == NULL) { layer = circle.m_p_layer; } - layer->m_circles.push_back( (const DxfCircle&) circle ); + layer->m_circles.push_back( circle ); layer->merge(circle); circle.clear(); // (Now reuse) subsection = ZEROTOKEN; @@ -591,8 +600,8 @@ void DxfParser::openEntities( istream& stream, DxfToken& token, DxfBlock *block if (layer == NULL) { layer = spline.m_p_layer; } - layer->m_splines.push_back( (const DxfSpline&) spline ); - int line_count = (spline.getAttributes() & DxfSpline::CLOSED) ? + layer->m_splines.push_back( spline ); + size_t line_count = (spline.getAttributes() & DxfSpline::CLOSED) ? spline.numVertices() - 2 : spline.numVertices() - 1; layer->merge(spline); layer->m_total_line_count += line_count; @@ -605,12 +614,17 @@ void DxfParser::openEntities( istream& stream, DxfToken& token, DxfBlock *block stream >> token; m_size += token.size; if ( insert.parse( token, this ) ) { - if ( insert.m_block ) { + if ( insert.m_blockName.length() ) { DxfLayer *layer = block; if (layer == NULL) { layer = insert.m_p_layer; + // we are in the entities section, unwind all the blocks + layer->insert( insert, this ); + } else { + // we are within a block, hold on until we load all of them + // before we can unwind them into the entities section + layer->m_inserts.push_back( insert ); } - layer->insert( insert, this ); } insert.clear(); subsection = ZEROTOKEN; @@ -631,7 +645,7 @@ void DxfParser::openEntities( istream& stream, DxfToken& token, DxfBlock *block if (m_communicator->IsCancelled()) { throw Communicator::CancelledException(); } - m_communicator->CommPostMessage( Communicator::CURRENT_RECORD, m_size ); + m_communicator->CommPostMessage( Communicator::CURRENT_RECORD, static_cast(m_size) ); } } } @@ -641,12 +655,12 @@ void DxfParser::openEntities( istream& stream, DxfToken& token, DxfBlock *block // Individual parsing of the types -DxfTableRow::DxfTableRow(const pstring& name) +DxfTableRow::DxfTableRow(const std::string& name) { m_name = name; } -bool DxfTableRow::parse( const DxfToken& token, DxfParser *parser ) +bool DxfTableRow::parse( const DxfToken& token, DxfParser * ) { bool parsed = false; @@ -681,7 +695,7 @@ bool DxfEntity::parse( const DxfToken& token, DxfParser *parser ) switch (token.code) { case 5: - m_tag = (pstring("0x") + token.data).c_int(); // tag is in hex + m_tag = std::stoi(std::string("0x") + token.data); // tag is in hex break; case 6: m_p_line_type = parser->getLineType( token.data ); @@ -732,13 +746,13 @@ bool DxfVertex::parse( const DxfToken& token, DxfParser *parser ) switch (token.code) { case 10: - x = token.data.c_double(); + x = std::stod(token.data); break; case 20: - y = token.data.c_double(); + y = std::stod(token.data); break; case 30: - z = token.data.c_double(); + z = std::stod(token.data); break; case 0: case 9: // 0 is standard vertex, 9 is for header section variables parsed = true; @@ -768,22 +782,22 @@ bool DxfLine::parse( const DxfToken& token, DxfParser *parser ) switch (token.code) { case 10: - m_start.x = token.data.c_double(); + m_start.x = std::stod(token.data); break; case 20: - m_start.y = token.data.c_double(); + m_start.y = std::stod(token.data); break; case 30: - m_start.z = token.data.c_double(); + m_start.z = std::stod(token.data); break; case 11: - m_end.x = token.data.c_double(); + m_end.x = std::stod(token.data); break; case 21: - m_end.y = token.data.c_double(); + m_end.y = std::stod(token.data); break; case 31: - m_end.z = token.data.c_double(); + m_end.z = std::stod(token.data); break; case 0: add(m_start); // <- add to region @@ -824,7 +838,7 @@ bool DxfPolyLine::parse( const DxfToken& token, DxfParser *parser ) if ( vertex.parse( token, parser ) ) { add(vertex); // <- add to region if (m_min.x == 0) { - cerr << "problem" << endl; + std::cerr << "problem" << std::endl; } m_vertices.push_back( vertex ); if ( token.data == "VERTEX" ) { // Another vertex... @@ -846,7 +860,7 @@ bool DxfPolyLine::parse( const DxfToken& token, DxfParser *parser ) } break; case 70: - m_attributes = token.data.c_int(); + m_attributes = std::stoi(token.data); default: DxfEntity::parse( token, parser ); // base class parse break; @@ -855,7 +869,7 @@ bool DxfPolyLine::parse( const DxfToken& token, DxfParser *parser ) return parsed; } -int DxfPolyLine::numVertices() const +size_t DxfPolyLine::numVertices() const { return m_vertices.size(); } @@ -915,9 +929,9 @@ bool DxfLwPolyLine::parse( const DxfToken& token, DxfParser *parser ) vertex.parse( token, parser ); break; case 70: - m_attributes = token.data.c_int(); + m_attributes = std::stoi(token.data); case 90: - m_expected_vertex_count = token.data.c_int(); + m_expected_vertex_count = std::stoi(token.data); default: DxfEntity::parse( token, parser ); // base class parse break; @@ -947,22 +961,22 @@ bool DxfArc::parse( const DxfToken& token, DxfParser *parser ) switch (token.code) { case 10: - m_centre.x = token.data.c_double(); + m_centre.x = std::stod(token.data); break; case 20: - m_centre.y = token.data.c_double(); + m_centre.y = std::stod(token.data); break; case 30: - m_centre.z = token.data.c_double(); + m_centre.z = std::stod(token.data); break; case 40: - m_radius = token.data.c_double(); + m_radius = std::stod(token.data); break; case 50: - m_start = token.data.c_double(); + m_start = std::stod(token.data); break; case 51: - m_end = token.data.c_double(); + m_end = std::stod(token.data); break; case 0: { @@ -1000,7 +1014,9 @@ int DxfArc::numSegments(int segments) const DxfVertex DxfArc::getVertex(int i, int segments) const { DxfVertex v = m_centre; - double ang = 2.0 * DXF_PI * double(i)/double(segments); + double range = 2.0 * DXF_PI; + if(m_start != m_end) range = (m_end - m_start) * DXF_PI / 180.0; + double ang = range * double(i)/double(segments); if (m_start != m_end) { ang += 2.0 * DXF_PI * (m_start / 360.0); } @@ -1035,6 +1051,144 @@ void DxfArc::reflect(double x, double y) } } + +DxfEllipse::DxfEllipse(int tag) : DxfEntity( tag ) +{ +} + +void DxfEllipse::clear() +{ + m_start = 0.0; + m_end = 0.0; + + DxfRegion::clear(); + DxfEntity::clear(); +} + +bool DxfEllipse::parse( const DxfToken& token, DxfParser *parser ) +{ + bool parsed = false; + + switch (token.code) { + case 10: + m_centre.x = std::stod(token.data); + break; + case 20: + m_centre.y = std::stod(token.data); + break; + case 30: + m_centre.z = std::stod(token.data); + break; + case 11: + m_majorAxisEndPoint.x = std::stod(token.data); + break; + case 21: + m_majorAxisEndPoint.y = std::stod(token.data); + break; + case 31: + m_majorAxisEndPoint.z = std::stod(token.data); + break; + case 210: + m_extrusionDirection.x = std::stod(token.data); + break; + case 220: + m_extrusionDirection.y = std::stod(token.data); + break; + case 230: + m_extrusionDirection.z = std::stod(token.data); + break; + case 40: + m_minorMajorAxisRatio = std::stod(token.data); + break; + case 41: + m_start = std::stod(token.data); + break; + case 42: + m_end = std::stod(token.data); + break; + case 0: + { + // just loop round if m_start is bigger than m_end + if (m_start > m_end) { + m_end += 360; + } + // technically should check for ellipse limits for tighter bounding box, + // but easier to give circular bounding box + DxfVertex bounds; + double xdiff = fabs(m_majorAxisEndPoint.x); + double ydiff = fabs(m_majorAxisEndPoint.y); + bounds.x = m_centre.x - xdiff; + bounds.y = m_centre.y - ydiff; + bounds.z = m_centre.z; + add(bounds); // <- add to region + bounds.x = m_centre.x + xdiff; + bounds.y = m_centre.y + ydiff; + bounds.z = m_centre.z; + add(bounds); // <- add to region + parsed = true; + } + break; + default: + parsed = DxfEntity::parse( token, parser ); // base class parse + break; + } + + return parsed; +} + +int DxfEllipse::numSegments(int segments) const +{ + return ((m_start == m_end) ? segments : (int(m_end - m_start) * segments / (2 * DXF_PI))); +} + +DxfVertex DxfEllipse::getVertex(int i, int segments) const +{ + DxfVertex v = m_centre; + double range = 2.0 * DXF_PI; + if(m_start != m_end) range = (m_end - m_start); + double ang = m_start + range * double(i)/double(segments); + + double c = cos(ang); + double s = sin(ang); + + double reverse = 1; + if(m_extrusionDirection.z < 0) reverse = -1; + + double xnew = c * m_majorAxisEndPoint.x - + m_minorMajorAxisRatio * s * m_majorAxisEndPoint.y; + double ynew = c * m_majorAxisEndPoint.y + + reverse * m_minorMajorAxisRatio * s * m_majorAxisEndPoint.x; + + v.x = m_centre.x + xnew; + v.y = m_centre.y + ynew; + v.z = m_centre.z; + return v; +} + +void DxfEllipse::reflect(double x, double y) +{ + if (x < 0) { + m_start = 180 - m_start; + m_end = 180 - m_end; + } + if (y < 0) { + m_start = 360 - m_start; + m_end = 360 - m_end; + } + while (m_start < 0) { + m_start += 360; + } + while (m_end < 0) { + m_end += 360; + } + if (x * y < 0) { + double temp; + temp = m_start; + m_start = m_end; + m_end = temp; + } +} + /////////////////////////////////////////////////////////////////////////// DxfCircle::DxfCircle(int tag) : DxfEntity( tag ) @@ -1053,16 +1207,16 @@ bool DxfCircle::parse( const DxfToken& token, DxfParser *parser ) switch (token.code) { case 10: - m_centre.x = token.data.c_double(); + m_centre.x = std::stod(token.data); break; case 20: - m_centre.y = token.data.c_double(); + m_centre.y = std::stod(token.data); break; case 30: - m_centre.z = token.data.c_double(); + m_centre.z = std::stod(token.data); break; case 40: - m_radius = token.data.c_double(); + m_radius = std::stod(token.data); break; case 0: { @@ -1097,7 +1251,7 @@ DxfVertex DxfCircle::getVertex(int i, int segments) const return v; } -void DxfCircle::reflect(double x, double y) +void DxfCircle::reflect(double , double ) { // reflect has no effect on a circle } @@ -1139,26 +1293,26 @@ bool DxfSpline::parse( const DxfToken& token, DxfParser *parser ) parsed = true; break; case 70: - m_attributes = token.data.c_int(); + m_attributes = std::stoi(token.data); break; case 72: - m_knot_count = token.data.c_int(); + m_knot_count = std::stoi(token.data); break; case 73: - m_ctrl_pt_count = token.data.c_int(); + m_ctrl_pt_count = std::stoi(token.data); break; case 40: - m_knots.push_back( token.data.c_double() ); + m_knots.push_back( std::stod(token.data) ); case 10: - vertex.x = token.data.c_double(); + vertex.x = std::stod(token.data); m_xyz |= 0x0001; break; case 20: - vertex.y = token.data.c_double(); + vertex.y = std::stod(token.data); m_xyz |= 0x0010; break; case 30: - vertex.z = token.data.c_double(); + vertex.z = std::stod(token.data); m_xyz |= 0x0100; break; default: @@ -1177,12 +1331,12 @@ bool DxfSpline::parse( const DxfToken& token, DxfParser *parser ) // Note: return control points not actual points! -int DxfSpline::numVertices() const +size_t DxfSpline::numVertices() const { return m_ctrl_pts.size(); } -const DxfVertex& DxfSpline::getVertex(int i) const +const DxfVertex& DxfSpline::getVertex(size_t i) const { return m_ctrl_pts[i]; } @@ -1203,7 +1357,7 @@ DxfInsert::DxfInsert(int tag) : DxfEntity( tag ) void DxfInsert::clear() { - m_block = NULL; + m_blockName = ""; m_translation.clear(); m_scale.clear(); @@ -1227,34 +1381,28 @@ bool DxfInsert::parse( const DxfToken& token, DxfParser *parser ) parsed = true; break; case 2: - // lookup in blocks table - { - size_t index = parser->m_blocks.searchindex(token.data); - if (index != paftl::npos) { - m_block = &(parser->m_blocks[index]); - } - } + m_blockName = token.data; break; case 10: - m_translation.x = token.data.c_double(); + m_translation.x = std::stod(token.data); break; case 20: - m_translation.y = token.data.c_double(); + m_translation.y = std::stod(token.data); break; case 30: - m_translation.z = token.data.c_double(); + m_translation.z = std::stod(token.data); break; case 41: - m_scale.x = token.data.c_double(); + m_scale.x = std::stod(token.data); break; case 42: - m_scale.y = token.data.c_double(); + m_scale.y = std::stod(token.data); break; case 43: - m_scale.z = token.data.c_double(); + m_scale.z = std::stod(token.data); break; case 50: - m_rotation = token.data.c_double(); + m_rotation = std::stod(token.data); break; default: DxfEntity::parse( token, parser ); // base class parse @@ -1266,7 +1414,7 @@ bool DxfInsert::parse( const DxfToken& token, DxfParser *parser ) /////////////////////////////////////////////////////////////////////////////// -DxfLineType::DxfLineType(const pstring& name) : DxfTableRow( name ) +DxfLineType::DxfLineType(const std::string& name) : DxfTableRow( name ) { } @@ -1296,7 +1444,7 @@ DxfVertex& DxfLine::getEnd() const /////////////////////////////////////////////////////////////////////////////// -DxfLayer::DxfLayer(const pstring& name) : DxfTableRow( name ) +DxfLayer::DxfLayer(const std::string& name) : DxfTableRow( name ) { m_total_line_count = 0; } @@ -1335,6 +1483,11 @@ const DxfArc& DxfLayer::getArc( int i ) const return m_arcs[i]; } +const DxfEllipse& DxfLayer::getEllipse( int i ) const +{ + return m_ellipses[i]; +} + const DxfCircle& DxfLayer::getCircle( int i ) const { return m_circles[i]; @@ -1345,32 +1498,37 @@ const DxfSpline& DxfLayer::getSpline( int i ) const return m_splines[i]; } -int DxfLayer::numPoints() const +size_t DxfLayer::numPoints() const { return m_points.size(); } -int DxfLayer::numLines() const +size_t DxfLayer::numLines() const { return m_lines.size(); } -int DxfLayer::numPolyLines() const +size_t DxfLayer::numPolyLines() const { return m_poly_lines.size(); } -int DxfLayer::numArcs() const +size_t DxfLayer::numArcs() const { return m_arcs.size(); } -int DxfLayer::numCircles() const +size_t DxfLayer::numEllipses() const +{ + return m_ellipses.size(); +} + +size_t DxfLayer::numCircles() const { return m_circles.size(); } -int DxfLayer::numSplines() const +size_t DxfLayer::numSplines() const { return m_splines.size(); } @@ -1381,69 +1539,93 @@ void DxfLayer::insert(DxfInsert& insert, DxfParser *parser) // munge in insert... bool scale = (insert.m_scale.x != 1.0 || insert.m_scale.y != 1.0 || insert.m_scale.z != 1.0); - bool rotate = (insert.m_rotation != 0.0); + bool rotate = (insert.m_rotation != 0.0 && insert.m_rotation < 359.9999999); if (insert.m_rotation < 0) { insert.m_rotation += 360; } - for (i = 0; i < insert.m_block->m_lines.size(); i++) { - m_lines.push_back(insert.m_block->m_lines[i]); + // lookup in blocks table + if (!parser->m_blocks.count(insert.m_blockName)) { + // throw exception + } + DxfBlock &block = parser->m_blocks[insert.m_blockName]; + + // unwind deeper inserts + for(i = 0; i < block.m_inserts.size(); i++) { + block.insert( block.m_inserts[i], parser); + } + // delete inserts at this level to avoid re-inserting them + // if the block is re-inserted + block.m_inserts.clear(); + + for (i = 0; i < block.m_lines.size(); i++) { + m_lines.push_back(block.m_lines[i]); + // rotate, translate, scale each line as specified in the insert + if (scale) + m_lines.back().scale(block.m_base_point,insert.m_scale); + if (rotate) + m_lines.back().rotate(block.m_base_point,insert.m_rotation); + m_lines.back().translate(insert.m_translation); + merge(m_lines.back()); // <- merge bounding box + } + for (i = 0; i < block.m_poly_lines.size(); i++) { + m_poly_lines.push_back(block.m_poly_lines[i]); // rotate, translate, scale each line as specified in the insert if (scale) - m_lines.tail().scale(insert.m_block->m_base_point,insert.m_scale); + m_poly_lines.back().scale(block.m_base_point,insert.m_scale); if (rotate) - m_lines.tail().rotate(insert.m_block->m_base_point,insert.m_rotation); - m_lines.tail().translate(insert.m_translation); - merge(m_lines.tail()); // <- merge bounding box + m_poly_lines.back().rotate(block.m_base_point,insert.m_rotation); + m_poly_lines.back().translate(insert.m_translation); + merge(m_poly_lines.back()); // <- merge bounding box } - for (i = 0; i < insert.m_block->m_poly_lines.size(); i++) { - m_poly_lines.push_back(insert.m_block->m_poly_lines[i]); + for (i = 0; i < block.m_arcs.size(); i++) { + m_arcs.push_back(block.m_arcs[i]); // rotate, translate, scale each line as specified in the insert if (scale) - m_poly_lines.tail().scale(insert.m_block->m_base_point,insert.m_scale); + m_arcs.back().scale(block.m_base_point,insert.m_scale); if (rotate) - m_poly_lines.tail().rotate(insert.m_block->m_base_point,insert.m_rotation); - m_poly_lines.tail().translate(insert.m_translation); - merge(m_poly_lines.tail()); // <- merge bounding box + m_arcs.back().rotate(block.m_base_point,insert.m_rotation); + m_arcs.back().translate(insert.m_translation); + merge(m_arcs.back()); // <- merge bounding box } - for (i = 0; i < insert.m_block->m_arcs.size(); i++) { - m_arcs.push_back(insert.m_block->m_arcs[i]); + for (i = 0; i < block.m_ellipses.size(); i++) { + m_ellipses.push_back(block.m_ellipses[i]); // rotate, translate, scale each line as specified in the insert if (scale) - m_arcs.tail().scale(insert.m_block->m_base_point,insert.m_scale); + m_ellipses.back().scale(block.m_base_point,insert.m_scale); if (rotate) - m_arcs.tail().rotate(insert.m_block->m_base_point,insert.m_rotation); - m_arcs.tail().translate(insert.m_translation); - merge(m_arcs.tail()); // <- merge bounding box + m_ellipses.back().rotate(block.m_base_point,insert.m_rotation); + m_ellipses.back().translate(insert.m_translation); + merge(m_ellipses.back()); // <- merge bounding box } - for (i = 0; i < insert.m_block->m_circles.size(); i++) { - m_circles.push_back(insert.m_block->m_circles[i]); + for (i = 0; i < block.m_circles.size(); i++) { + m_circles.push_back(block.m_circles[i]); // rotate, translate, scale each line as specified in the insert if (scale) - m_circles.tail().scale(insert.m_block->m_base_point,insert.m_scale); + m_circles.back().scale(block.m_base_point,insert.m_scale); // n.b., rotate does nothing with circles if (rotate) - m_circles.tail().rotate(insert.m_block->m_base_point,insert.m_rotation); - m_circles.tail().translate(insert.m_translation); - merge(m_circles.tail()); // <- merge bounding box + m_circles.back().rotate(block.m_base_point,insert.m_rotation); + m_circles.back().translate(insert.m_translation); + merge(m_circles.back()); // <- merge bounding box } - for (i = 0; i < insert.m_block->m_splines.size(); i++) { - m_splines.push_back(insert.m_block->m_splines[i]); + for (i = 0; i < block.m_splines.size(); i++) { + m_splines.push_back(block.m_splines[i]); // rotate, translate, scale each line as specified in the insert if (scale) - m_splines.tail().scale(insert.m_block->m_base_point,insert.m_scale); + m_splines.back().scale(block.m_base_point,insert.m_scale); if (rotate) - m_splines.tail().rotate(insert.m_block->m_base_point,insert.m_rotation); - m_splines.tail().translate(insert.m_translation); - merge(m_splines.tail()); // <- merge bounding box + m_splines.back().rotate(block.m_base_point,insert.m_rotation); + m_splines.back().translate(insert.m_translation); + merge(m_splines.back()); // <- merge bounding box } - m_total_line_count += insert.m_block->m_total_line_count; + m_total_line_count += block.m_total_line_count; } /////////////////////////////////////////////////////////////////////////////// -DxfBlock::DxfBlock(const pstring& name) : DxfLayer( name ) +DxfBlock::DxfBlock(const std::string& name) : DxfLayer( name ) { } @@ -1469,14 +1651,20 @@ DxfToken::DxfToken() code = -1; } -istream& operator >> (istream& stream, DxfToken& token) -{ - static pstring inputline; - stream >> inputline; - token.code = inputline.c_int(); - stream >> token.data; - token.size = inputline.length() + token.data.length() + 2; // might be missing a few end line characters --- never mind - return stream; +std::istream& operator >> (std::istream& stream, DxfToken& token) +{ + std::string codeInputLine; + std::getline(stream,codeInputLine); + token.code = std::stoi(codeInputLine); + std::string dataInputLine; + std::getline(stream,dataInputLine); + dXstring::ltrim(dataInputLine,'\r'); + dXstring::ltrim(dataInputLine,'\n'); + dXstring::rtrim(dataInputLine,'\r'); + dXstring::rtrim(dataInputLine,'\n'); + token.data = dataInputLine; + token.size = codeInputLine.length() + token.data.length() + 2; // might be missing a few end line characters --- never mind + return stream; } /////////////////////////////////////////////////////////////////////////////// diff --git a/genlib/dxfp.h b/salalib/parsers/dxfp.h similarity index 74% rename from genlib/dxfp.h rename to salalib/parsers/dxfp.h index 71c97850..cec11cd8 100644 --- a/genlib/dxfp.h +++ b/salalib/parsers/dxfp.h @@ -16,8 +16,7 @@ // DXF parser header file -#ifndef __DXFP_H__ -#define __DXFP_H__ +#pragma once /////////////////////////////////////////////////////////////////////////////// @@ -26,6 +25,10 @@ // The parser reads in vertices, lines and polylines, and stores them in the // defined layers. It also reads in any line types defined. +#include +#include +#include + class DxfToken; class DxfTableRow; @@ -48,8 +51,6 @@ class DxfParser; #include -using namespace std; - const double DXF_PI = 3.1415926535897932384626433832795; /////////////////////////////////////////////////////////////////////////////// @@ -59,11 +60,11 @@ const double DXF_PI = 3.1415926535897932384626433832795; class DxfToken { public: int code; - int size; - pstring data; + size_t size; + std::string data; // DxfToken(); - friend istream& operator >> (istream& stream, DxfToken& token); + friend std::istream& operator >> (std::istream& stream, DxfToken& token); }; /////////////////////////////////////////////////////////////////////////////// @@ -74,11 +75,12 @@ class DxfTableRow { friend class DxfParser; protected: - pstring m_name; + std::string m_name; public: - DxfTableRow( const pstring& name = "" ); - const pstring& getName() const + DxfTableRow( const std::string& name = "" ); + const std::string& getName() const { return m_name; } + virtual ~DxfTableRow(){} protected: virtual bool parse( const DxfToken& token, DxfParser *Parser ); public: @@ -101,6 +103,7 @@ class DxfEntity public: DxfEntity( int tag = -1 ); void clear(); // for reuse when parsing + virtual ~DxfEntity(){} protected: virtual bool parse( const DxfToken& token, DxfParser *parser ); }; @@ -187,7 +190,7 @@ class DxfRegion { void scale(const DxfVertex& base_vertex, const DxfVertex& scale) { m_min.scale(base_vertex, scale); m_max.scale(base_vertex, scale); } // rotate tricky... - void rotate(const DxfVertex& base_vertex, double angle) + void rotate(const DxfVertex&, double) { ; } void translate(const DxfVertex& translation) { m_min.translate(translation); m_max.translate(translation); } @@ -235,12 +238,12 @@ class DxfPolyLine : public DxfEntity, public DxfRegion protected: int m_attributes; int m_vertex_count; - prefvec m_vertices; + std::vector m_vertices; public: DxfPolyLine( int tag = -1 ); void clear(); // for reuse when parsing // - int numVertices() const; + size_t numVertices() const; const DxfVertex& getVertex(int i) const; int getAttributes() const; const DxfRegion& getBoundingBox(); @@ -329,6 +332,59 @@ class DxfArc : public DxfEntity, public DxfRegion bool parse( const DxfToken& token, DxfParser *parser ); }; + +class DxfEllipse : public DxfEntity, public DxfRegion +{ + friend class DxfParser; + DxfVertex m_centre; + DxfVertex m_majorAxisEndPoint; + DxfVertex m_extrusionDirection; + double m_minorMajorAxisRatio; + mutable double m_start; + double m_end; +public: + DxfEllipse( int tag = -1 ); + void clear(); // for reuse when parsing + // getVertex splits into number of segments + int numSegments(int segments) const; + DxfVertex getVertex(int i, int segments) const; + const DxfVertex& getCentre() const + { return m_centre; } + const double& getMinorMajorAxisRatio() const + { return m_minorMajorAxisRatio; } + int getAttributes() const; + const DxfRegion& getBoundingBox(); + // + // some basic manipulation + void scale(const DxfVertex& base_vertex, const DxfVertex& scale) + { m_centre.scale(base_vertex, scale); + + m_majorAxisEndPoint.x *= scale.x; + m_majorAxisEndPoint.y *= scale.y; + + // this is rather tricky to do, need to think more than just reflect around 0,0,0 + if (m_start != m_end && (scale.x < 0 || scale.y < 0)) { + reflect(scale.x, scale.y); + } + DxfRegion::scale(base_vertex, scale); + } + void reflect(double x, double y); + void rotate(const DxfVertex& base_vertex, double angle) + { m_centre.rotate(base_vertex, angle); + // this is rather tricky to do, need to think more than just rotate around 0,0,0 + if (m_start != m_end) { + m_start += angle; m_end += angle; + } + DxfRegion::rotate(base_vertex, angle); + } + void translate(const DxfVertex& translation) + { m_centre.translate(translation); + DxfRegion::translate(translation); } + // +protected: + bool parse( const DxfToken& token, DxfParser *parser ); +}; + class DxfCircle : public DxfEntity, public DxfRegion { friend class DxfParser; @@ -379,14 +435,14 @@ class DxfSpline : public DxfEntity, public DxfRegion int m_attributes; int m_ctrl_pt_count; int m_knot_count; - prefvec m_ctrl_pts; - pvecdouble m_knots; + std::vector m_ctrl_pts; + std::vector m_knots; public: DxfSpline( int tag = -1 ); void clear(); // for reuse when parsing // - int numVertices() const; - const DxfVertex& getVertex(int i) const; + size_t numVertices() const; + const DxfVertex& getVertex(size_t i) const; int getAttributes() const; // // some basic manipulation @@ -415,7 +471,7 @@ class DxfInsert : public DxfEntity, public DxfRegion friend class DxfParser; friend class DxfLayer; protected: - DxfBlock *m_block; + std::string m_blockName; DxfVertex m_translation; DxfVertex m_scale; double m_rotation; @@ -437,7 +493,7 @@ class DxfLineType : public DxfTableRow { friend class DxfParser; public: - DxfLineType( const pstring& name = "" ); + DxfLineType( const std::string& name = "" ); protected: bool parse( const DxfToken& token, DxfParser *parser ); }; @@ -449,38 +505,42 @@ class DxfLayer : public DxfTableRow, public DxfRegion friend class DxfParser; protected: // Originally was going to be clever, but it's far easier to have a list for each type: - prefvec m_points; - prefvec m_lines; - prefvec m_poly_lines; - prefvec m_arcs; - prefvec m_circles; - prefvec m_splines; - int m_total_point_count; - int m_total_line_count; + std::vector m_points; + std::vector m_lines; + std::vector m_poly_lines; + std::vector m_arcs; + std::vector m_ellipses; + std::vector m_circles; + std::vector m_splines; + std::vector m_inserts; + size_t m_total_point_count = 0; + size_t m_total_line_count = 0; public: - DxfLayer( const pstring& name = "" ); + DxfLayer( const std::string& name = "" ); // const DxfVertex& getPoint( int i ) const; const DxfLine& getLine( int i ) const; const DxfPolyLine& getPolyLine( int i ) const; const DxfArc& getArc( int i ) const; + const DxfEllipse& getEllipse( int i ) const; const DxfCircle& getCircle( int i ) const; const DxfSpline& getSpline( int i ) const; // - int numPoints() const; - int numLines() const; - int numPolyLines() const; - int numArcs() const; - int numCircles() const; - int numSplines() const; + size_t numPoints() const; + size_t numLines() const; + size_t numPolyLines() const; + size_t numArcs() const; + size_t numEllipses() const; + size_t numCircles() const; + size_t numSplines() const; // - int numTotalPoints() const + size_t numTotalPoints() const { return m_total_point_count; } - int numTotalLines() const + size_t numTotalLines() const { return m_total_line_count; } // // this merges an insert (so the insert remains flattened) - void insert( DxfInsert& insert, DxfParser *parser ); + void insert(DxfInsert& insert, DxfParser *parser); protected: bool parse( const DxfToken& token, DxfParser *parser ); }; @@ -492,7 +552,7 @@ class DxfBlock : public DxfLayer protected: DxfVertex m_base_point; public: - DxfBlock( const pstring& name = "" ); + DxfBlock( const std::string& name = "" ); // protected: bool parse( const DxfToken& token, DxfParser *parser ); @@ -510,41 +570,39 @@ class DxfParser { enum section_t { HEADER, CLASSES, TABLES, BLOCKS, ENTITIES, OBJECTS, _EOF }; enum subsection_t { EXTMIN, EXTMAX, LTYPE_TABLE, LTYPE_ROW, LAYER_TABLE, LAYER_ROW, BLOCK, - POINT, LINE, POLYLINE, LWPOLYLINE, ARC, CIRCLE, SPLINE, INSERT, VERTEX, + POINT, LINE, POLYLINE, LWPOLYLINE, ARC, ELLIPSE, CIRCLE, SPLINE, INSERT, VERTEX, ENDSEC }; protected: - comm_time_t m_time; + time_t m_time; protected: DxfRegion m_region; - pqvector m_layers; - pqvector m_blocks; - pqvector m_line_types; + std::map m_layers; + std::map m_blocks; + std::map m_line_types; // - long m_size; + size_t m_size; Communicator *m_communicator; public: DxfParser(Communicator *comm = NULL); // - istream& open( istream& stream ); + std::istream& open( std::istream& stream ); // - void openHeader( istream& stream ); - void openTables( istream& stream ); - void openBlocks( istream& stream ); - void openEntities( istream& stream, DxfToken& token, DxfBlock *block = NULL ); // cannot have a default token: it's a reference. Removed default to DxfToken() AT 29.04.11 + void openHeader( std::istream& stream ); + void openTables( std::istream& stream ); + void openBlocks( std::istream& stream ); + void openEntities( std::istream& stream, DxfToken& token, DxfBlock *block = NULL ); // cannot have a default token: it's a reference. Removed default to DxfToken() AT 29.04.11 // const DxfVertex& getExtMin() const; const DxfVertex& getExtMax() const; - const DxfLayer& getLayerNum( const int i ) const; - DxfLayer *getLayer( const pstring& layer_name ); // const; <- removed as will have to add layer when DXF hasn't declared one - const DxfLineType& getLineType( const int i ) const; - DxfLineType *getLineType( const pstring& line_type_name ); // const; + DxfLayer *getLayer( const std::string& layer_name ); // const; <- removed as will have to add layer when DXF hasn't declared one + DxfLineType *getLineType( const std::string& line_type_name ); // const; // - int numLayers() const; - int numLineTypes() const; + size_t numLayers() const; + size_t numLineTypes() const; // - friend istream& operator >> (istream& stream, DxfParser& dxfp); + friend std::istream& operator >> (std::istream& stream, DxfParser& dxfp); + + std::map getLayers() { return m_layers; } }; /////////////////////////////////////////////////////////////////////////////// - -#endif diff --git a/salalib/parsers/mapinfodata.cpp b/salalib/parsers/mapinfodata.cpp new file mode 100644 index 00000000..f4b011eb --- /dev/null +++ b/salalib/parsers/mapinfodata.cpp @@ -0,0 +1,585 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + + +#include "mapinfodata.h" +#include "salalib/mgraph.h" +#include "salalib/shapemap.h" +#include "salalib/axialmap.h" + +#include + +int MapInfoData::import(std::istream& miffile, std::istream& midfile, ShapeMap& map) +{ + int mapLoaded = MINFO_OK; + + // read the header... + if (!readheader(miffile)) { + return MINFO_HEADER; + } + + std::vector columnheads; + + AttributeTable& attributes = map.getAttributeTable(); + + // read mif table + if (!readcolumnheaders(miffile, columnheads)) { + return MINFO_TABLE; + } + + // set up a list of readable columns from the headers: + // + std::vector colnames; + std::vector readable, colindexes; + for (size_t i = 0; i < columnheads.size(); i++) { + dXstring::ltrim(columnheads[i]); + auto tokens = dXstring::split(columnheads[i], ' ',true); + if (dXstring::beginsWith(tokens[1],"Integer") + || dXstring::beginsWith(tokens[1],"Smallint") + || dXstring::beginsWith(tokens[1],"Decimal") + || dXstring::beginsWith(tokens[1],"Float")) + { + colnames.push_back(tokens[0]); + attributes.insertOrResetColumn(colnames.back()); + readable.push_back(i); + } + } + + for (std::string colname: colnames) { + colindexes.push_back(attributes.getColumnIndex(colname)); + } + + std::string textline; + std::vector> pointsets; + std::vector duplicates; + std::vector types; + + try { + // now read line data into the axial map + while (!miffile.eof()) { + dXstring::safeGetline(miffile, textline); + dXstring::ltrim(textline); + dXstring::toLower(textline); + if (textline.empty()) { + continue; + } + if (dXstring::beginsWith(textline,"point")) { + auto tokens = dXstring::split(textline,' ',true); + pointsets.push_back(std::vector()); + types.push_back(SalaShape::SHAPE_POINT); + pointsets.back().push_back(Point2f(stod(tokens[1]),stod(tokens[2]))); + } + if (dXstring::beginsWith(textline,"line")) { + auto tokens = dXstring::split(textline,' ',true); + pointsets.push_back(std::vector()); + types.push_back(SalaShape::SHAPE_LINE); + pointsets.back().push_back(Point2f(stod(tokens[1]),stod(tokens[2]))); + pointsets.back().push_back(Point2f(stod(tokens[3]),stod(tokens[4]))); + } + else if (dXstring::beginsWith(textline,"pline") || dXstring::beginsWith(textline,"region")) { + int type = dXstring::beginsWith(textline,"pline") ? SalaShape::SHAPE_POLY : (SalaShape::SHAPE_POLY | SalaShape::SHAPE_CLOSED); + // note: polylines, even multiple lines, are condensed into a single line + auto tokens = dXstring::split(textline,' ',true); + int multiple = 1; + if (tokens.size() > 1) { + if (tokens[1] == "multiple") { + multiple = stoi(tokens[2]); + } + else if (type & SalaShape::SHAPE_CLOSED) { + multiple = stoi(tokens[1]); + } + // if for some reason c_int fails: + if (multiple == 0) { + multiple = 1; + } + } + for (int i = 0; i < multiple; i++) { + int count = -1; + if ((type & SalaShape::SHAPE_CLOSED) != SalaShape::SHAPE_CLOSED && tokens.size() == 2) { + // token 2 can apparently be used for count in pline rather than a newline being used... + count = stoi(tokens[1]); + } + else { + dXstring::safeGetline(miffile, textline); + dXstring::ltrim(textline); + count = stoi(textline); + } + pointsets.push_back(std::vector()); + types.push_back(type); + for (int j = 0; j < count; j++) { + dXstring::safeGetline(miffile, textline); + dXstring::ltrim(textline); + auto tokens = dXstring::split(textline,' ',true); + pointsets.back().push_back(Point2f(stod(tokens[0]),stod(tokens[1]))); + } + if (i != 0) { + // warn about extraneous pline data + mapLoaded = MINFO_MULTIPLE; + duplicates.push_back(pointsets.size() - 1); + } + } + } + } + } + // TODO: Use the proper exception + catch (std::exception) { + // unhandled parsing exceptions return read error: + return MINFO_MIFPARSE; + } + + size_t nextduplicate = 0; + AttributeRow *lastrow; + + QtRegion region(pointsets[0][0],pointsets[0][0]); + for (size_t i = 0; i < pointsets.size(); i++) { + for (size_t j = 0; j < pointsets[i].size(); j++) { + region.encompass(pointsets[i][j]); + } + } + + try { + // switch lines into our format + map.init(pointsets.size(),region); + for (size_t i = 0; i < pointsets.size(); i++) { + bool open = false; + if ((types[i] & SalaShape::SHAPE_CLOSED) == 0) { + open = true; + } + map.makePolyShape(pointsets[i],open); + AttributeRow &row = *attributes.back().second; + // + // table data entries: + if (nextduplicate < duplicates.size() && duplicates[nextduplicate] == i) { + // duplicate last row: + for (int colindex: colindexes) { + row.setValue(colindex, lastrow->getValue(colindex)); + } + nextduplicate++; + } + else { + // read next row: + std::string line; + while (!midfile.eof() && line.empty()) { + dXstring::safeGetline(midfile, line); + } + if (line.empty()) { + return MINFO_OBJROWS; + } + bool instring = false; + size_t here = 0, first = 0, reading = 0, nextreadable = 0; + while (nextreadable < readable.size()) { + char next = line[here]; + if (next == '\"') { + instring = !instring; + } + here++; + if ((!instring && next == m_delimiter) || here >= line.length()) { + int length = (here < line.length()) ? here-first-1 : here-first; + std::string field = line.substr(first,length); + first = here; + if (reading == readable[nextreadable]) { + float val = stof(field); + row.setValue(colindexes[nextreadable],val); + nextreadable++; + } + reading++; + } + } + } + lastrow = &row; + } + } + // TODO: use a proper exception + catch (std::exception) { + // unhandled parsing exceptions return read error: + return MINFO_TABLE; + } + + return mapLoaded; +} +/* +bool MapInfoData::exportFile(std::ostream& miffile, std::ostream& midfile, const ShapeGraph& map) +{ + // if bounds has not been filled in, fill it in + if (m_bounds.empty()) { + char bounds[256]; + sprintf(bounds,"Bounds (%10f, %10f) (%10f, %10f)", map.m_region.bottom_left.x, + map.m_region.bottom_left.y, + map.m_region.top_right.x, + map.m_region.top_right.y); + m_bounds = bounds; + } + + // write the header... + writeheader(miffile); + + // write the mif table + writetable(miffile,midfile,map.m_attributes); + + miffile.precision(16); + + for (int i = 0; i < map.m_lines.size(); i++) { + miffile << "Line " << map.m_lines[i].line.start().x << " " + << map.m_lines[i].line.start().y << " " + << map.m_lines[i].line.end().x << " " + << map.m_lines[i].line.end().y << std::endl; + miffile << " Pen (1,2,0)" << std::endl; + } + + return true; +} +*/ +bool MapInfoData::exportFile(std::ostream& miffile, std::ostream& midfile, const PointMap& points) +{ + // if bounds has not been filled in, fill it in + if (m_bounds.empty()) { + char bounds[256]; + sprintf(bounds,"Bounds (%10f, %10f) (%10f, %10f)", points.m_region.bottom_left.x, + points.m_region.bottom_left.y, + points.m_region.top_right.x, + points.m_region.top_right.y); + m_bounds = bounds; + } + + // write the header... + writeheader(miffile); + + // write the mif table + writetable(miffile, midfile, points.getAttributeTable(), points.m_layers); + + miffile.precision(16); + + for (auto iter = points.getAttributeTable().begin(); iter != points.getAttributeTable().end(); iter++) { + PixelRef pix = iter->getKey().value; + Point2f p = points.depixelate(pix); + miffile << "Point " << p.x << " " << p.y << std::endl; + miffile << " Symbol (32,0,10)" << std::endl; + } + + return true; +} + +bool MapInfoData::exportFile(std::ostream& miffile, std::ostream& midfile, const ShapeMap& map) +{ + // if bounds has not been filled in, fill it in + if (m_bounds.empty()) { + char bounds[256]; + sprintf(bounds,"Bounds (%10f, %10f) (%10f, %10f)", map.getRegion().bottom_left.x, + map.getRegion().bottom_left.y, + map.getRegion().top_right.x, + map.getRegion().top_right.y); + m_bounds = bounds; + } + + miffile.precision(8); + midfile.precision(8); + + // write the header... + writeheader(miffile); + + // write the mid table + writetable(miffile, midfile, *map.m_attributes, map.m_layers); + + miffile.precision(16); + midfile.precision(16); + + for (auto shape: map.m_shapes) { + // note, attributes must align for this: + if (isObjectVisible(map.m_layers, map.getAttributeTable().getRow(AttributeKey(shape.first)))) { + const SalaShape& poly = shape.second; + if (poly.isPoint()) { + miffile << "POINT " << poly.getPoint().x << " " << poly.getPoint().y << std::endl; + miffile << " SYMBOL (32,0,10)" << std::endl; + } + else if (poly.isLine()) { + miffile << "LINE " << poly.getLine().start().x << " " + << poly.getLine().start().y << " " + << poly.getLine().end().x << " " + << poly.getLine().end().y << std::endl; + miffile << " PEN (1,2,0)" << std::endl; + } + else if (poly.isPolyLine()) { + miffile << "PLINE" << std::endl; + miffile << " " << poly.m_points.size() << std::endl; + for (auto& point: poly.m_points) { + miffile << point.x << " " << point.y << std::endl; + } + miffile << " PEN (1,2,0)" << std::endl; + } + else if (poly.isPolygon()) { + miffile << "REGION 1" << std::endl; + miffile << " " << poly.m_points.size() + 1 << std::endl; + for (auto& point: poly.m_points) { + miffile << point.x << " " << point.y << std::endl; + } + miffile << poly.m_points[0].x << " " << poly.m_points[0].y << std::endl; + miffile << " PEN (1,2,0)" << std::endl; + miffile << " BRUSH (2,16777215,16777215)" << std::endl; + miffile << " CENTER " << poly.getCentroid().x << " " << poly.getCentroid().y << std::endl; + } + } + } + + return true; +} + +bool MapInfoData::exportPolygons(std::ostream& miffile, std::ostream& midfile, const std::vector>& polygons, const QtRegion& region) +{ + // if bounds has not been filled in, fill it in + if (m_bounds.empty()) { + char bounds[256]; + sprintf(bounds,"Bounds (%10f, %10f) (%10f, %10f)", region.bottom_left.x, + region.bottom_left.y, + region.top_right.x, + region.top_right.y); + m_bounds = bounds; + } + + // write the header... + writeheader(miffile); + + // dummy attributes table: + AttributeTable attributes; + for (size_t i = 0; i < polygons.size(); i++) { + attributes.addRow(AttributeKey(i)); + } + + // dummy layers: + LayerManagerImpl layers; + + // write the mid table + writetable(miffile, midfile, attributes, layers); + + miffile.precision(16); + for (auto& polygon: polygons) { + Point2f centre; + miffile << "QtRegion 1" << std::endl; + miffile << " " << polygon.size() + 1 << std::endl; + for (auto& point: polygon) { + centre += point; + miffile << point.x << " " << point.y << std::endl; + } + miffile << polygon[0].x << " " << polygon[0].y << std::endl; + miffile << " Pen (1,2,0)" << std::endl; + miffile << " Brush (2,16777215,16777215)" << std::endl; + centre /= polygon.size(); + miffile << " Center " << centre.x << " " << centre.y << std::endl; + } + + return true; +} + + +/////////////////////////////////////////////////////////////////////// + +MapInfoData::MapInfoData() +{ + m_version = "Version 300"; + m_charset = "Charset \"WindowsLatin1\""; + m_delimiter = ','; + m_index = "Index 1"; + m_coordsys = "CoordSys NonEarth Units \"m\" "; + // note: m_bounds is filled in later +} + +bool MapInfoData::readheader(std::istream& miffile) +{ + std::string line; + + dXstring::safeGetline(miffile, m_version); + dXstring::safeGetline(miffile, m_charset); + dXstring::makeInitCaps(m_charset); + // this should read "Charset..." but some files have delimiter straight away... + if (dXstring::beginsWith(m_charset,"Delimiter")) { + line = m_charset; + m_charset = "Charset \"WindowsLatin1\""; + } + else { + dXstring::safeGetline(miffile, line); + } + size_t index = line.find_first_of("\""); + if (index == std::string::npos) { + return false; + } + m_delimiter = line[index+1]; + dXstring::safeGetline(miffile, line); + dXstring::makeInitCaps(line); + while (dXstring::beginsWith(line,"Index") || dXstring::beginsWith(line,"Unique")) { + m_index = line; + dXstring::safeGetline(miffile, line); + } + + dXstring::ltrim(line); + dXstring::makeInitCaps(line); + if (dXstring::beginsWith(line,"Coordsys")) { + line[5] = 'S'; // set back to CoordSys + // coordsys and bounds together in one line + auto boundIndex = line.find("Bounds"); + if(boundIndex != std::string::npos) { + m_coordsys = line.substr(0,boundIndex); + m_bounds = line.substr(boundIndex); + } else { + m_coordsys = line; + m_bounds = ""; + } + } + else { + return false; + } + + return true; +} + +bool MapInfoData::readcolumnheaders(std::istream& miffile, std::vector& columnheads) +{ + std::string line; + + dXstring::safeGetline(miffile, line); + dXstring::makeInitCaps(line); + auto bits = dXstring::split(line, ' '); + + if (line.find("Columns") == std::string::npos || bits.size() < 2 ) + { + return false; + } + int cols = stoi(bits[1]); + + for (int i = 0; i < cols; i++) { + dXstring::safeGetline(miffile, line); + dXstring::makeInitCaps(line); + columnheads.push_back(line); + } + + dXstring::safeGetline(miffile, line); + dXstring::makeInitCaps(line); + if (line != "Data") { + return false; + } + + return true; +} + +void MapInfoData::writeheader(std::ostream& miffile) +{ + miffile << m_version << std::endl; + miffile << m_charset << std::endl; + miffile << "Delimiter \"" << m_delimiter << "\"" << std::endl; + miffile << m_index << std::endl; + miffile << m_coordsys; + miffile << m_bounds << std::endl; +} + +// note: stopped using m_table and m_columnheads as of VERSION_MAPINFO_SHAPES +// simply hack up the table now for own purposes + +void MapInfoData::writetable(std::ostream& miffile, std::ostream& midfile, const AttributeTable& attributes, const LayerManagerImpl layers) +{ + miffile << "Columns " << attributes.getNumColumns() + 1 << std::endl; + /* + miffile << "Columns " << m_columnheads.size() + 1 + attributes.getColumnCount() << std::endl; + + for (int i = 0; i < m_columnheads.size(); i++) { + miffile << m_columnheads[i] << std::endl; + } + */ + miffile << " Depthmap_Ref Integer" << std::endl; + + // TODO: For compatibility write the columns in alphabetical order + // but the physical columns in the order inserted + + std::vector indices(attributes.getNumColumns()); + std::iota(indices.begin(), indices.end(), static_cast(0)); + + std::sort(indices.begin(), indices.end(), + [&](size_t a, size_t b) { + return attributes.getColumnName(a) < attributes.getColumnName(b); + }); + + for (int idx: indices) { + std::string colname = attributes.getColumnName(idx); + miffile << " "; + bool lastalpha = false; + for (size_t i = 0; i < colname.length(); i++) { + // get rid of any character that's not alphanumeric: + if (isalnum(colname[i])) { + miffile << colname[i]; + lastalpha = true; + } + else if (lastalpha) { + miffile << "_"; + lastalpha = false; + } + } + miffile << " Float" << std::endl; + } + + miffile << "Data" << std::endl << std::endl; + + for (auto iter = attributes.begin(); iter != attributes.end(); iter++) { + int rowKey = iter->getKey().value; + /* + if (k < m_table.size()) { + midfile << m_table[k] << m_delimiter; + } + */ + if (isObjectVisible(layers, iter->getRow())) { + midfile << rowKey; + for (int idx: indices) { + midfile << m_delimiter << iter->getRow().getValue(idx); + } + midfile << std::endl; + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +std::istream& MapInfoData::read(std::istream& stream) +{ + m_version = dXstring::readString(stream); + m_charset = dXstring::readString(stream); + m_delimiter = stream.get(); + m_index = dXstring::readString(stream); + m_coordsys = dXstring::readString(stream); + m_bounds = dXstring::readString(stream); + + return stream; +} + +std::ostream& MapInfoData::write(std::ostream& stream) +{ + dXstring::writeString(stream, m_version); + dXstring::writeString(stream, m_charset); + stream.put(m_delimiter); + dXstring::writeString(stream, m_index); + dXstring::writeString(stream, m_coordsys); + dXstring::writeString(stream, m_bounds); + /* + // No longer used as of VERSION_MAPINFO_SHAPES + int columns = m_columnheads.size(); + int rows = m_table.size(); + stream.write((char *)&columns, sizeof(columns)); + for (int i = 0; i < m_columnheads.size(); i++) { + m_columnheads[i].write(stream); + } + stream.write((char *)&rows, sizeof(rows)); + for (int j = 0; j < m_table.size(); j++) { + m_table[j].write(stream); + } + */ + return stream; +} diff --git a/salalib/MapInfoData.h b/salalib/parsers/mapinfodata.h similarity index 54% rename from salalib/MapInfoData.h rename to salalib/parsers/mapinfodata.h index 6576f217..b75707c0 100644 --- a/salalib/MapInfoData.h +++ b/salalib/parsers/mapinfodata.h @@ -14,16 +14,26 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#pragma once +#include "salalib/attributetable.h" +#include "salalib/layermanagerimpl.h" -#ifndef __MAPINFODATA_H__ -#define __MAPINFODATA_H__ +#include "genlib/p2dpoly.h" + +#include +#include +#include // imported and exported data // note: this is very basic and designed for axial line import / export only // MapInfoData is stored with axial map data +class ShapeMap; +class PointMap; +class AttributeTable; + class MapInfoData { friend class ShapeGraph; @@ -31,12 +41,12 @@ friend class ShapeGraphs; friend class ShapeMap; // protected: - pstring m_version; - pstring m_charset; + std::string m_version; + std::string m_charset; char m_delimiter; - pstring m_index; - pstring m_coordsys; - pstring m_bounds; + std::string m_index; + std::string m_coordsys; + std::string m_bounds; // // no longer use columnheads and table // -- where possible, added directly to the data @@ -46,19 +56,17 @@ friend class ShapeMap; public: MapInfoData(); // - int import(istream& miffile, istream& midfile, ShapeMap& map); + int import(std::istream& miffile, std::istream& midfile, ShapeMap& map); //bool exportFile(ostream& miffile, ostream& midfile, const ShapeGraph& map); // n.b., deprecated: use shapemap instead - bool exportFile(ostream& miffile, ostream& midfile, const PointMap& points); - bool exportFile(ostream& miffile, ostream& midfile, const ShapeMap& map); - bool exportPolygons(ostream& miffile, ostream& midfile, const prefvec& polygons, const QtRegion& region); + bool exportFile(std::ostream& miffile, std::ostream& midfile, const PointMap& points); + bool exportFile(std::ostream& miffile, std::ostream& midfile, const ShapeMap& map); + bool exportPolygons(std::ostream& miffile, std::ostream& midfile, const std::vector > &polygons, const QtRegion& region); // - bool readheader(istream& miffile); - bool readcolumnheaders(istream& miffile, istream& midfile, pvecstring& columnheads); - void writeheader(ostream& miffile); - void writetable(ostream& miffile, ostream& midfile, const AttributeTable& attributes); + bool readheader(std::istream& miffile); + bool readcolumnheaders(std::istream& miffile, std::vector& columnheads); + void writeheader(std::ostream& miffile); + void writetable(std::ostream& miffile, std::ostream& midfile, const AttributeTable& attributes, const LayerManagerImpl layers); // - istream& read(istream& stream, int version); - ostream& write(ostream& stream); + std::istream& read(std::istream& stream); + std::ostream& write(std::ostream& stream); }; - -#endif diff --git a/salalib/ntfp.cpp b/salalib/parsers/ntfp.cpp similarity index 54% rename from salalib/ntfp.cpp rename to salalib/parsers/ntfp.cpp index b2082153..4a20f7d0 100644 --- a/salalib/ntfp.cpp +++ b/salalib/parsers/ntfp.cpp @@ -1,5 +1,6 @@ // sala - a component of the depthmapX - spatial network analysis platform // Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2018 Petros Koutsolampros // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -17,24 +18,25 @@ // Quick OS land-line NTF parser -#include -#include -using namespace std; +#include "ntfp.h" -#include -#include -#include // for communicator +#include "genlib/p2dpoly.h" +#include "genlib/comm.h" // for communicator +#include "genlib/stringutils.h" +#include "genlib/containerutils.h" -#include "ntfp.h" +#include +#include +#include /////////////////////////////////////////////////////////////////////////////// -int NtfPoint::parse(const pstring& token, bool secondhalf /* = false */) +int NtfPoint::parse(const std::string& token, bool secondhalf /* = false */) { if (secondhalf) { - pstring second = token.substr(0,m_chars); - b = second.c_int(); + std::string second = token.substr(0,m_chars); + b = stoi(second); if (m_chars == 5) { b *= 100; } @@ -44,18 +46,18 @@ int NtfPoint::parse(const pstring& token, bool secondhalf /* = false */) if ((int)token.length() < m_chars) { return 0; } - pstring first = token.substr(0,m_chars); - a = first.c_int(); + std::string first = token.substr(0,m_chars); + a = stoi(first); if (m_chars == 5) { a *= 100; } return 1; } else { - pstring first = token.substr(0,m_chars); - pstring second = token.substr(m_chars,m_chars); - a = first.c_int(); - b = second.c_int(); + std::string first = token.substr(0,m_chars); + std::string second = token.substr(m_chars,m_chars); + a = stoi(first); + b = stoi(second); if (m_chars == 5) { a *= 100; b *= 100; @@ -66,7 +68,7 @@ int NtfPoint::parse(const pstring& token, bool secondhalf /* = false */) void NtfMap::fitBounds(const Line& li) { - if (m_region.isNull()) { + if (m_region.atZero()) { m_region = li; } else { @@ -74,15 +76,15 @@ void NtfMap::fitBounds(const Line& li) } } -void NtfMap::addGeom(int layer, NtfGeometry& geom) +void NtfMap::addGeom(size_t layerIdx, NtfGeometry& geom) { - m_line_count += geom.size(); - at(layer).m_line_count += geom.size(); - at(layer).push_back( geom ); - for (size_t i = 0; i < geom.size(); i++) { - fitBounds(geom[i]); + m_line_count += geom.lines.size(); + layers[layerIdx].m_line_count += geom.lines.size(); + layers[layerIdx].geometries.push_back( geom ); + for (size_t i = 0; i < geom.lines.size(); i++) { + fitBounds(geom.lines[i]); } - geom.clear(); + geom.lines.clear(); } /////////////////////////////////////////////////////////////////////////////// @@ -96,22 +98,12 @@ Line NtfMap::makeLine(const NtfPoint& a, const NtfPoint& b) ); } -// Quick mod - TV -#if defined(_WIN32) -void NtfMap::open(const pqvector& fileset, Communicator *comm) -#else -void NtfMap::open(const pqvector& fileset, Communicator *comm) -#endif +void NtfMap::open(const std::vector& fileset, Communicator *comm) { - // Quick mod - TV -#if defined(_WIN32) - __time64_t time = 0; -#else time_t time = 0; -#endif qtimer( time, 0 ); - pvecint featcodes; + std::vector featcodes; /* m_bottom_left.a = 2147483647; // 2^31 - 1 m_bottom_left.b = 2147483647; @@ -119,25 +111,24 @@ void NtfMap::open(const pqvector& fileset, Communicator *comm) m_top_right.b = -2147483647; */ m_line_count = 0; - if (size()) { - clear(); - } + layers.clear(); for (size_t i = 0; i < fileset.size(); i++) { - ifstream stream(fileset[i].c_str()); + std::ifstream stream(fileset[i].c_str()); int filetype = NTF_UNKNOWN; while (!stream.eof() && filetype == NTF_UNKNOWN) { - pstring line; - stream >> line; + std::string line; + dXstring::safeGetline(stream, line); if (line.length() > 2) { - if (compare(line, "02", 2)) { - if (compare(line, "02Land-Line", 11)) { + if (dXstring::beginsWith(line, "02")) { + std::transform(line.begin(), line.end(), line.begin(), ::tolower); + if (dXstring::beginsWith(line, "02land-line")) { filetype = NTF_LANDLINE; } - else if (compare(line, "02Meridian", 10)) { + else if (dXstring::beginsWith(line, "02meridian")) { filetype = NTF_MERIDIAN; } } @@ -152,62 +143,62 @@ void NtfMap::open(const pqvector& fileset, Communicator *comm) continue; } else if (filetype == NTF_LANDLINE) { - if (featcodes.add(1) != -1) - push_back( NtfLayer("Building outline") ); - if (featcodes.add(4) != -1) - push_back( NtfLayer("Building outline (overhead)") ); - if (featcodes.add(21) != -1) - push_back( NtfLayer("Road (public) edge") ); - if (featcodes.add(30) != -1) - push_back( NtfLayer("General line / minor building") ); - if (featcodes.add(32) != -1) - push_back( NtfLayer("General ground level / minor o'head detail") ); - if (featcodes.add(52) != -1) - push_back( NtfLayer("Minor detail") ); - if (featcodes.add(98) != -1) - push_back( NtfLayer("Road centreline") ); precision = 6; } else if (filetype == NTF_MERIDIAN) { - if (featcodes.add(3000) != -1) - push_back( NtfLayer("Motorway") ); - if (featcodes.add(3001) != -1) - push_back( NtfLayer("A-Road") ); - if (featcodes.add(3002) != -1) - push_back( NtfLayer("B-Road") ); - if (featcodes.add(3004) != -1) - push_back( NtfLayer("Minor Road") ); precision = 5; } NtfGeometry geom; NtfPoint lastpoint(precision), currpoint(precision); int parsing = 0; - int currpos = -1; + std::vector::iterator currpos; int currtoken = 0; - pvecstring tokens; + std::vector tokens; while (!stream.eof()) { - pstring line; - stream >> line; + std::string line; + dXstring::safeGetline(stream, line); if (line.length()) { - if (parsing == 0 && compare(line, "07", 2)) { + if (parsing == 0 && dXstring::beginsWith(line, "07")) { // Grab the easting and northing offset - pstring easting = line.substr(46,10); - pstring northing =line.substr(56,10); - m_offset.a = easting.c_int(); - m_offset.b = northing.c_int(); + std::string easting = line.substr(46,10); + std::string northing =line.substr(56,10); + m_offset.a = stoi(easting); + m_offset.b = stoi(northing); + } + if (parsing == 0 && dXstring::beginsWith(line, "05")) { + // Grab the feature codes + // Example without continuation: + // 050001 Building outline\0% + // Example with continuation: + // 050001 Building ou1% + // tline\0% + std::stringstream fullLine; + fullLine << line; + while(line.substr(line.length()-2,2) == "1%") { + // the last line had 1% so remove it + fullLine.seekp(-2, std::ios_base::end); + dXstring::safeGetline(stream, line); + fullLine << line; + } + line = fullLine.str(); + line = line.substr(0, line.length()-3); + std::string code = line.substr(2,4); + std::string name = line.substr(36); + if (depthmapX::addIfNotExists(featcodes, stoi(code))) + layers.push_back( NtfLayer(name) ); } - if (parsing == 0 && compare(line, "23", 2)) { - geom.clear(); + if (parsing == 0 && dXstring::beginsWith(line, "23")) { + geom.lines.clear(); // In Landline, check to see if it's a code we recognise: if (filetype == NTF_LANDLINE) { - pstring featcodestr = line.substr(16,4); - size_t pos = featcodes.searchindex( featcodestr.c_int() ); - if (pos != paftl::npos) { - at(pos).push_back( NtfGeometry() ); + std::string featcodestr = line.substr(16,4); + auto pos = std::find(featcodes.begin(), featcodes.end(), stoi(featcodestr) ); + if (pos != featcodes.end()) { + layers[size_t(std::distance(featcodes.begin(), pos))].geometries.push_back( NtfGeometry() ); parsing = 1; currpos = pos; } @@ -219,11 +210,11 @@ void NtfMap::open(const pqvector& fileset, Communicator *comm) } } else if (parsing == 1) { - if (compare(line, "21", 2)) { + if (dXstring::beginsWith(line, "21")) { tokens.clear(); // Some line data: // read to end, and possibly leave hanging: - tokens = line.tokenize(' ',true); + tokens = dXstring::split(line, ' ',true); tokens[0] = tokens[0].substr(13); lastpoint.parse(tokens[0]); currtoken = 1; @@ -231,20 +222,20 @@ void NtfMap::open(const pqvector& fileset, Communicator *comm) } } else if (parsing > 1) { - if (compare(line, "00", 2)) { - tokens = line.tokenize(' ',true); + if (dXstring::beginsWith(line, "00")) { + tokens = dXstring::split(line, ' ',true); tokens[0] = tokens[0].substr(2); currtoken = 0; } - else if (compare(line, "14", 2) && filetype == NTF_MERIDIAN) { + else if (dXstring::beginsWith(line, "14") && filetype == NTF_MERIDIAN) { // Meridian record for this line: // finish up and add if featcode is recognised // (goodness knows how we are supposed to know in advance what sort of feature we are given) if (line.length() > 25 && line.substr(23,2) == "FC") { - pstring featcodestr = line.substr(25,4); - size_t pos = featcodes.searchindex( featcodestr.c_int() ); - if (pos != paftl::npos) { - addGeom(pos,geom); + std::string featcodestr = line.substr(25,4); + auto pos = std::find(featcodes.begin(), featcodes.end(), stoi(featcodestr) ); + if (pos != featcodes.end()) { + addGeom(static_cast(std::distance(featcodes.begin(), pos)), geom); } } parsing = 0; @@ -254,7 +245,7 @@ void NtfMap::open(const pqvector& fileset, Communicator *comm) if (parsing == 2) { // hanging half point: currpoint.parse(tokens[0], true); Line li = makeLine(lastpoint, currpoint); - geom.push_back(li); + geom.lines.push_back(li); lastpoint = currpoint; currtoken = 1; } @@ -262,7 +253,7 @@ void NtfMap::open(const pqvector& fileset, Communicator *comm) int numbersparsed = currpoint.parse(tokens[i]); if (numbersparsed == 2) { Line li = makeLine(lastpoint, currpoint); - geom.push_back(li); + geom.lines.push_back(li); lastpoint = currpoint; } else if (numbersparsed == 1) { @@ -272,9 +263,9 @@ void NtfMap::open(const pqvector& fileset, Communicator *comm) parsing = 3; } } - if (tokens.tail()[tokens.tail().length()-2] == '0') { // 0 here indicates no continuation + if (tokens.back()[tokens.back().length()-2] == '0') { // 0 here indicates no continuation if (filetype == NTF_LANDLINE) { - addGeom(currpos,geom); + addGeom(static_cast(std::distance(featcodes.begin(), currpos)),geom); parsing = 0; } } diff --git a/salalib/ntfp.h b/salalib/parsers/ntfp.h similarity index 64% rename from salalib/ntfp.h rename to salalib/parsers/ntfp.h index 5c432c12..0299af8c 100644 --- a/salalib/ntfp.h +++ b/salalib/parsers/ntfp.h @@ -1,5 +1,6 @@ // sala - a component of the depthmapX - spatial network analysis platform // Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2018 Petros Koutsolampros // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -14,43 +15,46 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#pragma once - -#ifndef __NTFP_H__ -#define __NTFP_H__ +#include "genlib/p2dpoly.h" struct NtfPoint { - char m_chars; + int m_chars; int a; int b; - NtfPoint(char chars = 10) // apparently 10 is NTF default - { m_chars = chars; }; - int parse(const pstring& token, bool secondhalf = false); + NtfPoint(int chars = 10) // apparently 10 is NTF default + { m_chars = chars; } + int parse(const std::string& token, bool secondhalf = false); }; -class NtfGeometry : public prefvec +class NtfGeometry { public: + std::vector lines; NtfGeometry() {;} }; -class NtfLayer : public prefvec { +class NtfLayer { friend class NtfMap; protected: - pstring m_name; + std::string m_name; int m_line_count; public: - NtfLayer(const pstring& name = pstring()) - { m_name = name; m_line_count = 0; }; + int pad1 : 32; + std::vector geometries; + NtfLayer(const std::string& name = std::string()) + { m_name = name; m_line_count = 0; } int getLineCount() { return m_line_count; } - pstring getName() + std::string getName() { return m_name; } }; -class NtfMap : public prefvec +class NtfMap { public: + std::vector layers; enum {NTF_UNKNOWN, NTF_LANDLINE, NTF_MERIDIAN}; protected: NtfPoint m_offset; // note: in metres @@ -60,19 +64,12 @@ class NtfMap : public prefvec NtfMap() {;} Line makeLine(const NtfPoint& a, const NtfPoint& b); - // Modified by Dream -#if defined(_WIN32) - void open(const pqvector& fileset, Communicator *comm); -#else - void open(const pqvector& fileset, Communicator *comm); -#endif + void open(const std::vector &fileset, Communicator *comm); const QtRegion& getRegion() const { return m_region; } int getLineCount() const { return m_line_count; } protected: void fitBounds(const Line& li); - void addGeom(int layer, NtfGeometry& geom); + void addGeom(size_t layerIdx, NtfGeometry& geom); }; - -#endif diff --git a/salalib/tigerp.cpp b/salalib/parsers/tigerp.cpp similarity index 60% rename from salalib/tigerp.cpp rename to salalib/parsers/tigerp.cpp index 3440fcfe..f70c3ff5 100644 --- a/salalib/tigerp.cpp +++ b/salalib/parsers/tigerp.cpp @@ -1,5 +1,6 @@ // sala - a component of the depthmapX - spatial network analysis platform // Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2018, Petros Koutsolampros // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -19,62 +20,44 @@ // Quick Tiger line parser (type 1 records) +#include "salalib/parsers/tigerp.h" +#include "genlib/comm.h" #include #include -using namespace std; - -#include -#include - -#include -#include "tigerp.h" // at some point will need to extend to parsing record type 2 (chains) as well as record type 1 (node to node) // Thank you US Census Bureau -- this is a great easy flat file format: -// Quick mod - TV -#if defined(_WIN32) -void TigerMap::parse(const pqvector& fileset, Communicator *comm) -#else -void TigerMap::parse(const pqvector& fileset, Communicator *comm) -#endif +void TigerMap::parse(const std::vector& fileset, Communicator *comm) { - // Quick mod - TV -#if defined(_WIN32) - __time64_t time = 0; -#else - time_t time = 0; -#endif + time_t atime = 0; - qtimer( time, 0 ); + qtimer( atime, 0 ); for (size_t i = 0; i < fileset.size(); i++) { - ifstream stream(fileset[i].c_str()); + std::ifstream stream(fileset[i].c_str()); while (!stream.eof()) { - pstring line; - stream >> line; + std::string line; + std::getline(stream, line); if (line.length()) { // grab major code: - pstring code = line.substr(55,2); + std::string code = line.substr(55,2); if (code[0] == 'A' || code[0] == 'B') { - size_t index = searchindex(code); - if (index == paftl::npos) { - index = add(code,TigerCategory(),paftl::ADD_HERE); - } - int long1 = line.substr(190,10).c_int(); - int lat1 = line.substr(200,9).c_int(); - int long2 = line.substr(209,10).c_int(); - int lat2 = line.substr(219,9).c_int(); + auto iter = m_categories.insert(std::make_pair(code,TigerCategory())).first; + int long1 = stoi(line.substr(190,10)); + int lat1 = stoi(line.substr(200,9)); + int long2 = stoi(line.substr(209,10)); + int lat2 = stoi(line.substr(219,9)); Point2f p1(double(long1)/1e6,double(lat1)/1e6); Point2f p2(double(long2)/1e6,double(lat2)/1e6); Line li(p1,p2); - value(index).push_back(TigerChain()); - value(index).tail().push_back(li); + iter->second.chains.push_back(TigerChain()); + iter->second.chains.back().lines.push_back(li); if (!m_init) { m_region = li; m_init = true; @@ -86,7 +69,7 @@ void TigerMap::parse(const pqvector& fileset, Communicator *comm) } if (comm) { - if (qtimer( time, 500 )) { + if (qtimer( atime, 500 )) { if (comm->IsCancelled()) { throw Communicator::CancelledException(); } diff --git a/salalib/tigerp.h b/salalib/parsers/tigerp.h similarity index 71% rename from salalib/tigerp.h rename to salalib/parsers/tigerp.h index e770120f..15f73456 100644 --- a/salalib/tigerp.h +++ b/salalib/parsers/tigerp.h @@ -1,5 +1,6 @@ // sala - a component of the depthmapX - spatial network analysis platform // Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2018, Petros Koutsolampros // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -14,44 +15,41 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#pragma once - -// This is my code to make a set of axial lines from a set of boundary lines - -#ifndef __TIGERP_H__ -#define __TIGERP_H__ +#include "genlib/p2dpoly.h" +#include +#include // look up is the tiger (major) line category: // string is A1, A2, A3 (road types) or B1, B2 (railroad types) // C,D etc are not currently parsed, but given the nice file format // (thank you US Census Bureau!) they can easily be added -class TigerChain : public pvecline +class TigerChain { public: + std::vector lines; TigerChain() {;} }; -class TigerCategory : public prefvec +class TigerCategory { public: + std::vector chains; TigerCategory() {;} }; -class TigerMap : public pqmap +class TigerMap { protected: QtRegion m_region; bool m_init; public: + std::map m_categories; TigerMap() { m_init = false;} - // Modified by Dream -#if defined(_WIN32) - void parse(const pqvector& fileset, Communicator *communicator); -#else - void parse(const pqvector& fileset, Communicator *communicator); -#endif + void parse(const std::vector &fileset, Communicator *communicator); Point2f getBottomLeft() { return m_region.bottom_left; } @@ -60,5 +58,3 @@ class TigerMap : public pqmap QtRegion getRegion() { return m_region; } }; - -#endif diff --git a/salalib/pixelref.h b/salalib/pixelref.h new file mode 100644 index 00000000..73f3fd7f --- /dev/null +++ b/salalib/pixelref.h @@ -0,0 +1,176 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "genlib/p2dpoly.h" +#include + +class PixelRef +{ +public: + short x; + short y; + PixelRef( short ax = -1, short ay = -1 ) + { x = ax; y = ay; } + PixelRef( int i ) + { x = short(i >> 16); y = short(i & 0xffff); } + bool empty() + { return x == -1 && y == -1; } + PixelRef up() const + { return PixelRef(x, y + 1); } + PixelRef left() const + { return PixelRef(x - 1, y); } + PixelRef right() const + { return PixelRef(x + 1, y); } + PixelRef down() const + { return PixelRef(x, y - 1); } + short& operator [] (int i) + { return (i == XAXIS) ? x : y; } + bool within( const PixelRef bl, const PixelRef tr ) const + { return (x >= bl.x && x <= tr.x && y >= bl.y && y <= tr.y); } + bool encloses( PixelRef testpoint ) const + { return (testpoint.x >= 0 && testpoint.x < x && testpoint.y >= 0 && testpoint.y < y);} + // directions for the ngraph: + enum {NODIR = 0x00, HORIZONTAL = 0x01, VERTICAL = 0x02, POSDIAGONAL = 0x04, NEGDIAGONAL = 0x08, DIAGONAL = 0x0c, NEGHORIZONTAL = 0x10, NEGVERTICAL = 0x20}; + short& row(char dir) + { return (dir & VERTICAL) ? x : y; } + short& col(char dir) + { return (dir & VERTICAL) ? y : x; } + const short& row(char dir) const + { return (dir & VERTICAL) ? x : y; } + const short& col(char dir) const + { return (dir & VERTICAL) ? y : x; } + PixelRef& move(char dir) + { switch (dir) + { + case POSDIAGONAL: x++; y++; break; + case NEGDIAGONAL: x++; y--; break; + case HORIZONTAL: x++; break; + case VERTICAL: y++; break; + case NEGHORIZONTAL: x--; break; + case NEGVERTICAL: y--; break; + } + return *this; } + bool isodd() const + { return x % 2 == 1 && y % 2 == 1; } + bool iseven() const + { return x % 2 == 0 && y % 2 == 0; } + friend bool operator == (const PixelRef a, const PixelRef b); + friend bool operator != (const PixelRef a, const PixelRef b); + friend bool operator < (const PixelRef a, const PixelRef b); + friend bool operator > (const PixelRef a, const PixelRef b); + friend PixelRef operator + (const PixelRef a, const PixelRef b); + friend PixelRef operator - (const PixelRef a, const PixelRef b); + friend PixelRef operator / (const PixelRef a, const int factor); + friend double dist(const PixelRef a, const PixelRef b); + friend double angle(const PixelRef a, const PixelRef b, const PixelRef c); + operator int() const + { return ((int(x) << 16) + (int(y) & 0xffff)); } +}; + +const PixelRef NoPixel( -1, -1 ); + +inline bool operator == (const PixelRef a, const PixelRef b) +{ + return (a.x == b.x) && (a.y == b.y); +} +inline bool operator != (const PixelRef a, const PixelRef b) +{ + return (a.x != b.x) || (a.y != b.y); +} +inline bool operator < (const PixelRef a, const PixelRef b) +{ + return (a.x < b.x) || (a.x == b.x && a.y < b.y); +} +inline bool operator > (const PixelRef a, const PixelRef b) +{ + return (a.x > b.x) || (a.x == b.x && a.y > b.y); +} +inline PixelRef operator + (const PixelRef a, const PixelRef b) +{ + return PixelRef(a.x + b.x, a.y + b.y); +} +inline PixelRef operator - (const PixelRef a, const PixelRef b) +{ + return PixelRef(a.x - b.x, a.y - b.y); +} +inline PixelRef operator / (const PixelRef a, const int factor) +{ + return PixelRef(a.x / factor, a.y / factor); +} + +inline double dist(const PixelRef a, const PixelRef b) +{ + return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y)); +} + +inline double angle(const PixelRef a, const PixelRef b, const PixelRef c) +{ + if (c == NoPixel) { + return 0.0; + } + else { + // n.b. 1e-12 required for floating point error + return acos( double((a.x - b.x) * (b.x - c.x) + (a.y - b.y) * (b.y - c.y)) / + (sqrt(sqr(a.x - b.x) + sqr(a.y - b.y)) * sqrt(sqr(b.x - c.x) + sqr(b.y - c.y)) + 1e-12) ); + } +} + +// Now sizeof(PixelRef) == sizeof(int) better stored directly: +typedef std::vector PixelRefVector; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +struct PixelRefPair +{ + PixelRef a; + PixelRef b; + PixelRefPair(const PixelRef x = NoPixel, const PixelRef y = NoPixel) + { + a = x < y ? x : y; + b = x < y ? y : x; + } + friend bool operator == (const PixelRefPair& x, const PixelRefPair& y); + friend bool operator != (const PixelRefPair& x, const PixelRefPair& y); + friend bool operator < (const PixelRefPair& x, const PixelRefPair& y); + friend bool operator > (const PixelRefPair& x, const PixelRefPair& y); + +}; + +// note: these are made with a is always less than b +inline bool operator == (const PixelRefPair& x, const PixelRefPair& y) +{ + return (x.a == y.a && x.b == y.b); +} +inline bool operator != (const PixelRefPair& x, const PixelRefPair& y) +{ + return (x.a != y.a || x.b != y.b); +} +inline bool operator < (const PixelRefPair& x, const PixelRefPair& y) +{ + return ( (x.a == y.a) ? x.b < y.b : x.a < y.a ); +} +inline bool operator > (const PixelRefPair& x, const PixelRefPair& y) +{ + return ( (x.a == y.a) ? x.b > y.b : x.a > y.a ); +} + +struct hashPixelRef { + size_t operator()(const PixelRef &pixelRef) const{ + return std::hash()(int(pixelRef)); + } +}; diff --git a/salalib/point.cpp b/salalib/point.cpp new file mode 100644 index 00000000..da1221f1 --- /dev/null +++ b/salalib/point.cpp @@ -0,0 +1,73 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "salalib/point.h" +#include "salalib/ngraph.h" + +float Point::getBinDistance(int i) +{ + return m_node->bindistance(i); +} + +std::istream& Point::read(std::istream& stream) +{ + stream.read( (char *) &m_state, sizeof(m_state) ); + // block is the same size as m_noderef used to be for ease of replacement: + // (note block NO LONGER used!) + stream.read( (char *) &m_block, sizeof(m_block) ); + + int dummy = 0; + stream.read( reinterpret_cast(&dummy), sizeof(dummy) ); + + stream.read( (char *) &m_grid_connections, sizeof(m_grid_connections) ); + + + stream.read( (char *) &m_merge, sizeof(m_merge) ); + bool ngraph; + stream.read( (char *) &ngraph, sizeof(ngraph) ); + if (ngraph) { + m_node = std::unique_ptr(new Node()); + m_node->read(stream); + } + + stream.read((char *) &m_location, sizeof(m_location)); + + return stream; +} + +std::ostream &Point::write(std::ostream& stream) +{ + stream.write( (char *) &m_state, sizeof(m_state) ); + // block is the same size as m_noderef used to be for ease of replacement: + // note block is no longer used at all + stream.write( (char *) &m_block, sizeof(m_block) ); + int dummy = 0; + stream.write( (char *) &dummy, sizeof(dummy) ); + stream.write( (char *) &m_grid_connections, sizeof(m_grid_connections) ); + stream.write( (char *) &m_merge, sizeof(m_merge) ); + bool ngraph; + if (m_node) { + ngraph = true; + stream.write( (char *) &ngraph, sizeof(ngraph) ); + m_node->write(stream); + } + else { + ngraph = false; + stream.write( (char *) &ngraph, sizeof(ngraph) ); + } + stream.write((char *) &m_location, sizeof(m_location)); + return stream; +} diff --git a/salalib/point.h b/salalib/point.h new file mode 100644 index 00000000..32696dc7 --- /dev/null +++ b/salalib/point.h @@ -0,0 +1,181 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "genlib/p2dpoly.h" +#include "salalib/pixelref.h" +#include "salalib/ngraph.h" +#include +#include + +class Point { + friend class Bin; + friend class PointMap; + friend class MetaGraph; // <- for file conversion routines + friend class PafAgent; + friend class PafWalker; +public: + enum { EMPTY = 0x0001, FILLED = 0x0002, + BLOCKED = 0x0004, CONTEXTFILLED = 0x0008, // PARTBLOCKED = 0x0008 deprecated + SELECTED = 0x0010, EDGE = 0x0020, MERGED = 0x0040, // PINNED = 0x0020 deprecated + AGENTFILLED = 0x0080, AGENTFADE = 0x0100, AGENTA = 0x0200, AGENTB = 0x0400, AGENTC = 0x0800, + UPDATELINEADDED = 0x1000, UPDATELINEREMOVED = 0x2000, HIGHLIGHT = 0x4000, + AUGMENTED = 0x8000 // AV TV + }; + // note the order of these connections is important and used elsewhere: + enum { CONNECT_E = 0x01, CONNECT_NE = 0x02, CONNECT_N = 0x04, CONNECT_NW = 0x08, + CONNECT_W = 0x10, CONNECT_SW = 0x20, CONNECT_S = 0x40, CONNECT_SE = 0x80 }; + + // TODO: These intermediary variables are only used for storing arbitrary data during the + // analysis. They should be made into local variables and removed from this class + int m_misc; // <- undocounter / point seen register / agent reference number, etc + float m_dist; // used to speed up metric analysis + float m_cumangle; // cummulative angle -- used in metric analysis and angular analysis + PixelRef m_extent; // used to speed up graph analysis (not sure whether or not it breaks it!) + +protected: + int m_block; // not used, unlikely to be used, but kept for time being + int m_state; + char m_grid_connections; // this is a standard set of grid connections, with bits set for E,NE,N,NW,W,SW,S,SE + std::unique_ptr m_node; // graph links + Point2f m_location; // note: this is large, but it helps allow loading of non-standard grid points, + // whilst allowing them to be displayed as a visibility graph, also speeds up time to + // display + float m_color; // although display color for the point now introduced + PixelRef m_merge; // to merge with another point + // hmm... this is for my 3rd attempt at a quick line intersect algo: + // every line that goes through the gridsquare -- memory intensive I know, but what can you do: + // accuracy is imperative here! Calculated pre-fillpoints / pre-makegraph, and (importantly) it works. + std::vector m_lines; + int m_processflag; +public: + Point() + { m_state = EMPTY; m_block = 0; m_misc = 0; m_grid_connections = 0; m_node = nullptr; m_processflag = 0; m_merge = NoPixel; m_user_data = NULL; } + Point& operator = (const Point& p) + { + m_block = p.m_block; + m_state = p.m_state; + m_misc = p.m_misc; + m_grid_connections = p.m_grid_connections; + m_node = p.m_node ? std::unique_ptr(new Node(*p.m_node)) : nullptr; + m_location = p.m_location; + m_color = p.m_color; + m_merge = p.m_merge; + m_color = p.m_color; + m_extent = p.m_extent; + m_dist = p.m_dist; + m_cumangle = p.m_cumangle; + m_lines = p.m_lines; + m_processflag = p.m_processflag; + return *this; + } + Point(const Point& p) + { + m_block = p.m_block; + m_state = p.m_state; + m_misc = p.m_misc; + m_grid_connections = p.m_grid_connections; + m_node = p.m_node ? std::unique_ptr(new Node(*p.m_node)) : nullptr; + m_location = p.m_location; + m_color = p.m_color; + m_merge = p.m_merge; + m_color = p.m_color; + m_extent = p.m_extent; + m_dist = p.m_dist; + m_cumangle = p.m_cumangle; + m_lines = p.m_lines; + m_processflag = p.m_processflag; + } + // + bool empty() const + { return (m_state & EMPTY) == EMPTY; } + bool filled() const + { return (m_state & FILLED) == FILLED; } + bool blocked() const + { return (m_state & BLOCKED) == BLOCKED; } + bool contextfilled() const + { return (m_state & CONTEXTFILLED) == CONTEXTFILLED; } + bool edge() const + { return (m_state & EDGE) == EDGE; } + bool selected() const + { return (m_state & SELECTED) == SELECTED; } + // + // Augmented Vis + bool augmented() const + { return (m_state & AUGMENTED) == AUGMENTED; } + // + void set( int state, int undocounter = 0) + { + m_state = state | (m_state & Point::BLOCKED); // careful not to clear the blocked flag + m_misc = undocounter; + } + void setBlock(bool blocked = true) + { + if (blocked) + m_state |= Point::BLOCKED; + else + m_state &= ~Point::BLOCKED; + } + void setEdge() + { + m_state |= Point::EDGE; + } + // old blocking code + //void addBlock( int block ) + // { m_block |= block; } + //void setBlock( int block ) + // { m_block = block; } + //int getBlock() const + // { return m_block & 0x0000FFFF; } + //void addPartBlock( int block ) + // { m_block |= (block << 16); } + //int getPartBlock() const + // { return (m_block & 0xFFFF0000) >> 16; } + //int getAllBlock() const + // { return m_block | (m_block >> 16); } + //int fillBlocked() const + // { return m_block & 0x06600660; } + int getState() + { return m_state; } + int getMisc() // used as: undocounter, in graph construction, and an agent reference, as well as for making axial maps + { return m_misc; } + void setMisc(int misc) + { m_misc = misc; } + // note -- set merge pixel should be done only through merge pixels + PixelRef getMergePixel() { + return m_merge; + } + Node& getNode() + { return *m_node; } + bool hasNode() + { return m_node != nullptr; } + char getGridConnections() const + { return m_grid_connections; } + float getBinDistance(int i); +public: + std::istream &read(std::istream &stream); + std::ostream& write(std::ostream &stream); + // +protected: + // for user processing, set their own data on the point: + void *m_user_data; +public: + void *getUserData() + { return m_user_data; } + void setUserData(void *user_data) + { m_user_data = user_data; } +}; diff --git a/salalib/pointdata.cpp b/salalib/pointdata.cpp index 479c587e..810d5c89 100644 --- a/salalib/pointdata.cpp +++ b/salalib/pointdata.cpp @@ -18,181 +18,38 @@ // Point data -#include -#include -#include // for communicator - -#include -#include -#include -#include -#include "MapInfoData.h" -#include "isovist.h" - -// Metagraphs are used... -#include -#include - -///////////////////////////////////////////////////////////////////////////////// - -Point::~Point() -{ - if (m_node) { - delete m_node; - m_node = NULL; - delete m_attributes; - m_attributes = NULL; - } -} - -float Point::getBinDistance(int i) -{ - return m_node->bindistance(i); -} - -ifstream& Point::read(ifstream& stream, int version, int attr_count) -{ - if (m_node) { - delete m_node; - m_node = NULL; - delete m_attributes; - m_attributes = NULL; - } - stream.read( (char *) &m_state, sizeof(m_state) ); - // block is the same size as m_noderef used to be for ease of replacement: - // (note block NO LONGER used!) - stream.read( (char *) &m_block, sizeof(m_block) ); - if (version < VERSION_BLOCKEDQUAD) { - m_block = 0; - } - stream.read( (char *) &m_misc, sizeof(m_misc) ); - if (version >= VERSION_GRID_CONNECTIONS) { - stream.read( (char *) &m_grid_connections, sizeof(m_grid_connections) ); - } - if (version >= VERSION_NGRAPH_INTROD) { - stream.read( (char *) &m_merge, sizeof(m_merge) ); - bool ngraph; - stream.read( (char *) &ngraph, sizeof(ngraph) ); - if (ngraph) { - m_node = new Node; - m_node->read(stream, version); - if (version < VERSION_ATTRIBUTES_TABLE) { - // don't deal with this here, just get the attributes into memory - m_attributes = new AttrBody(-1,g_attr_header); - m_attributes->read( stream, attr_count ); - } - } - } - if (version >= VERSION_POINT_LOCATIONS) { - stream.read((char *) &m_location, sizeof(m_location)); - } - if (version < VERSION_SHAPE_MAPS) { - // old layer information - m_data_objects.read(stream); - } - if (version >= VERSION_BOUNDARYGRAPH && version < VERSION_NEWBOUNDARYGRAPH) { - // dummy pvecint to hold old format boundary nodes - pvecint old_boundary_nodes; - old_boundary_nodes.read(stream); - } - return stream; -} - -ofstream& Point::write(ofstream& stream, int version) -{ - stream.write( (char *) &m_state, sizeof(m_state) ); - // block is the same size as m_noderef used to be for ease of replacement: - // note block is no longer used at all - stream.write( (char *) &m_block, sizeof(m_block) ); - stream.write( (char *) &m_misc, sizeof(m_misc) ); - stream.write( (char *) &m_grid_connections, sizeof(m_grid_connections) ); - stream.write( (char *) &m_merge, sizeof(m_merge) ); - bool ngraph; - if (m_node) { - ngraph = true; - stream.write( (char *) &ngraph, sizeof(ngraph) ); - m_node->write(stream, version); - } - else { - ngraph = false; - stream.write( (char *) &ngraph, sizeof(ngraph) ); - } - stream.write((char *) &m_location, sizeof(m_location)); - return stream; -} -///////////////////////////////////////////////////////////////////////////////// +#include "salalib/pointdata.h" +#include "salalib/parsers/mapinfodata.h" // for mapinfo interface +#include "salalib/vgamodules/vgavisuallocal.h" +#include "salalib/vgamodules/vgavisualglobal.h" +#include "salalib/isovist.h" +#include "salalib/mgraph.h" // Metagraphs are used... +#include "salalib/ngraph.h" +#include "salalib/attributetable.h" +#include "salalib/attributetablehelpers.h" -int PointMaps::addNewMap(const pstring& name) -{ - pstring myname = name; - int counter = 1; - bool duplicate = true; - while (duplicate) { - duplicate = false; - for (size_t i = 0; i < size(); i++) { - if (at(i).getName() == myname) { - duplicate = true; - myname = pstringify(counter++,name+pstring(" %d")); - break; - } - } - } - push_back(PointMap(myname)); - tail().setSpacePixel(m_spacepix); - m_displayed_map = size() - 1; - return size() - 1; -} +#include "genlib/comm.h" // for communicator +#include "genlib/stringutils.h" +#include "genlib/containerutils.h" -bool PointMaps::read(ifstream& stream, int version) -{ - stream.read((char *) &m_displayed_map, sizeof(m_displayed_map)); - int count; - stream.read((char *) &count, sizeof(count)); - for (int i = 0; i < count; i++) { - push_back(PointMap()); - tail().setSpacePixel( (SuperSpacePixel *) this ); - tail().read( stream, version ); - } - return true; -} +#include +#include +#include -bool PointMaps::write(ofstream& stream, int version, bool displayedmaponly) -{ - if (!displayedmaponly) { - stream.write((char *) &m_displayed_map, sizeof(m_displayed_map)); - int count = size(); - stream.write((char *) &count, sizeof(count)); - for (int i = 0; i < count; i++) { - at(i).write( stream, version ); - } - } - else { - int dummy; - // displayed map is 0: - dummy = 0; - stream.write((char *) &dummy, sizeof(dummy)); - // count is 1 - dummy = 1; - stream.write((char *) &dummy, sizeof(dummy)); - // - at(m_displayed_map).write(stream, version); - } - return true; -} ///////////////////////////////////////////////////////////////////////////////// -PointMap::PointMap(const pstring& name) +PointMap::PointMap(const QtRegion& parentRegion, const std::vector& drawingFiles, const std::string& name): + m_parentRegion(&parentRegion), m_drawingFiles(&drawingFiles), m_points(0,0), + m_attributes(new AttributeTable()), m_attribHandle(new AttributeTableHandle(*m_attributes)) { m_name = name; - m_points = NULL; m_cols = 0; m_rows = 0; - m_point_count = 0; + m_filled_point_count = 0; - m_spacepix = NULL; m_spacing = 0.0; m_initialised = false; @@ -216,111 +73,41 @@ PointMap::PointMap(const pstring& name) m_displayed_attribute = -2; } -PointMap::~PointMap() -{ - if (m_points) { - // Trying to clear out the memory quicker -> predelete nodes and bins - for (int j = 0; j < m_cols; j++) { - for (int k = 0; k < m_rows; k++) { - if (m_points[j][k].m_node) { - delete m_points[j][k].m_node; - m_points[j][k].m_node = NULL; - } - } - } - for (int i = 0; i < m_cols; i++) { - delete [] m_points[i]; - } - delete [] m_points; - m_points = NULL; - m_cols = 0; - m_rows = 0; - m_point_count = 0; - } -} - -PointMap::PointMap(const PointMap& pointdata) -{ - construct(pointdata); -} - -PointMap& PointMap::operator = (const PointMap& pointdata) -{ - if (this != &pointdata) { - - if (m_points) { - for (int i = 0; i < m_cols; i++) { - delete [] m_points[i]; - } - delete [] m_points; - m_points = NULL; - m_cols = 0; - m_rows = 0; - } - construct(pointdata); - } - return *this; -} - -// Technically should not call a function from constructor! - -void PointMap::construct(const PointMap& pointdata) +void PointMap::copy(const PointMap& other) { - // NB Does not set SpacePixel - // You *must* set SpacePixel manually - - m_name = pointdata.m_name; - - m_cols = pointdata.m_cols; - m_rows = pointdata.m_rows; - - if (m_cols) { - m_points = new Point *[m_cols]; - for (int i = 0; i < m_cols; i++) { - m_points[i] = new Point [m_rows]; - for (int j = 0; j < m_rows; j++) { - m_points[i][j] = pointdata.m_points[i][j]; - } - } - } - else { - m_points = NULL; + m_name = other.getName(); + m_region = other.getRegion(); - } - - m_point_count = pointdata.m_point_count; + m_cols = other.getCols(); + m_rows = other.getRows(); + m_filled_point_count = other.getFilledPointCount(); - // You *must* set SpacePixel manually - m_spacepix = NULL; - m_spacing = pointdata.m_point_count; + m_spacing = other.getSpacing(); - m_initialised = pointdata.m_initialised; - m_blockedlines = false; // <- always false for a new point data - m_processed = pointdata.m_processed; - m_boundarygraph = pointdata.m_boundarygraph; + m_initialised = other.m_initialised; + m_blockedlines = other.m_blockedlines; + m_processed = other.m_processed; + m_boundarygraph = other.m_boundarygraph; - // All selection is turned off in new pointdata layer: - m_selection = NO_SELECTION; - m_undocounter = 0; + m_selection = other.m_selection; + m_pinned_selection = other.m_pinned_selection; + m_undocounter = other.m_undocounter; - // screen: all default params - m_viewing_deprecated = -1; - m_draw_step = 1; + // screen + m_viewing_deprecated = other.m_viewing_deprecated; + m_draw_step = other.m_draw_step; - s_bl = NoPixel; - s_tr = NoPixel; - curmergeline = -1; + s_bl = other.s_bl; + s_tr = other.s_tr; + curmergeline = other.curmergeline; + m_offset = other.m_offset; + m_bottom_left = other.m_bottom_left; - m_displayed_attribute = pointdata.m_displayed_attribute; + // -2 follows axial map convention, where -1 is the reference number + m_displayed_attribute = other.m_displayed_attribute; } - -// Quick mod - TV -#if defined(_WIN32) -void PointMap::communicate( __time64_t& atime, Communicator *comm, int record ) -#else void PointMap::communicate( time_t& atime, Communicator *comm, int record ) -#endif { if (comm) { if (qtimer( atime, 500 )) { @@ -332,23 +119,12 @@ void PointMap::communicate( time_t& atime, Communicator *comm, int record ) } } -bool PointMap::setSpacePixel(const SuperSpacePixel *spacepix) -{ - m_spacepix = (SuperSpacePixel *) spacepix; - - return true; -} - bool PointMap::setGrid(double spacing, const Point2f& offset) { - if (!m_spacepix) { - return false; - } - m_spacing = spacing; // note, the internal offset is the offset from the bottom left - double xoffset = fmod(m_spacepix->m_region.bottom_left.x + offset.x,m_spacing); - double yoffset = fmod(m_spacepix->m_region.bottom_left.y + offset.y,m_spacing); + double xoffset = fmod(m_parentRegion->bottom_left.x + offset.x,m_spacing); + double yoffset = fmod(m_parentRegion->bottom_left.y + offset.y,m_spacing); if (xoffset < m_spacing / 2.0) xoffset += m_spacing; if (xoffset > m_spacing / 2.0) @@ -360,33 +136,27 @@ bool PointMap::setGrid(double spacing, const Point2f& offset) m_offset = Point2f(-xoffset, -yoffset); - if (m_points) { - for (int i = 0; i < m_cols; i++) { - delete [] m_points[i]; - } - delete [] m_points; - m_points = NULL; - m_point_count = 0; + if (m_points.size() != 0) { + m_filled_point_count = 0; } m_undocounter = 0; // <- reset the undo counter... sorry... once you've done this you can't undo // A grid at the required spacing: - m_cols = (int) floor((xoffset + m_spacepix->m_region.width()) / m_spacing + 0.5) + 1; - m_rows = (int) floor((yoffset + m_spacepix->m_region.height()) / m_spacing + 0.5) + 1; + m_cols = (int) floor((xoffset + m_parentRegion->width()) / m_spacing + 0.5) + 1; + m_rows = (int) floor((yoffset + m_parentRegion->height()) / m_spacing + 0.5) + 1; - m_bottom_left = Point2f(m_spacepix->m_region.bottom_left.x + m_offset.x, - m_spacepix->m_region.bottom_left.y + m_offset.y); + m_bottom_left = Point2f(m_parentRegion->bottom_left.x + m_offset.x, + m_parentRegion->bottom_left.y + m_offset.y); m_region = QtRegion( Point2f(m_bottom_left.x-m_spacing/2.0, m_bottom_left.y-m_spacing/2.0), Point2f(m_bottom_left.x+double(m_cols-1)*m_spacing + m_spacing/2.0, m_bottom_left.y+double(m_rows-1)*m_spacing + m_spacing/2.0) ); - m_points = new Point *[m_cols]; - for (int j = 0; j < m_cols; j++) { - m_points[j] = new Point [m_rows]; - for (int k = 0; k < m_rows; k++) { - m_points[j][k].m_location = depixelate(PixelRef(j,k)); + m_points = depthmapX::ColumnMatrix(m_rows, m_cols); + for (size_t j = 0; j < m_cols; j++) { + for (size_t k = 0; k < m_rows; k++) { + m_points(k,j).m_location = depixelate(PixelRef(static_cast(j),static_cast(k))); } } @@ -402,7 +172,7 @@ bool PointMap::setGrid(double spacing, const Point2f& offset) bool PointMap::clearPoints() { - if (!m_point_count) { + if (!m_filled_point_count) { return false; } @@ -412,48 +182,48 @@ bool PointMap::clearPoints() m_undocounter++; if (m_selection == NO_SELECTION) { - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - if (m_points[i][j].filled()) { - m_points[i][j].set( Point::EMPTY, m_undocounter ); - } + for(auto& point: m_points) { + if(point.filled()) { + point.set( Point::EMPTY, m_undocounter ); } } - m_point_count = 0; + m_filled_point_count = 0; m_merge_lines.clear(); } else if (m_selection & SINGLE_SELECTION) { m_undocounter++; for (int i = s_bl.x; i <= s_tr.x; i++) { for (int j = s_bl.y; j <= s_tr.y; j++) { - if (m_points[i][j].m_state & (Point::SELECTED | Point::FILLED)) { - m_points[i][j].set( Point::EMPTY, m_undocounter ); - if (!m_points[i][j].m_merge.empty()) { - PixelRef p = m_points[i][j].m_merge; - m_merge_lines.remove_at(m_merge_lines.searchindex(PixelRefPair(PixelRef(i,j),p))); + Point& pnt = m_points(static_cast(j), static_cast(i)); + if (pnt.m_state & (Point::SELECTED | Point::FILLED)) { + pnt.set( Point::EMPTY, m_undocounter ); + if (!pnt.m_merge.empty()) { + PixelRef p = pnt.m_merge; + depthmapX::findAndErase(m_merge_lines, PixelRefPair(PixelRef(i,j),p)); getPoint(p).m_merge = NoPixel; getPoint(p).m_state &= ~Point::MERGED; } - m_point_count--; + m_filled_point_count--; } } } } else { // COMPOUND_SELECTION (note, need to test bitwise now) - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - if (m_points[i][j].m_state & (Point::SELECTED | Point::FILLED)) { - m_points[i][j].set( Point::EMPTY, m_undocounter ); - if (!m_points[i][j].m_merge.empty()) { - PixelRef p = m_points[i][j].m_merge; - m_merge_lines.remove_at(m_merge_lines.searchindex(PixelRefPair(PixelRef(i,j),p))); + for (size_t i = 0; i < m_cols; i++) { + for (size_t j = 0; j < m_rows; j++) { + Point& pnt = m_points(static_cast(j), static_cast(i)); + if (pnt.m_state & (Point::SELECTED | Point::FILLED)) { + pnt.set( Point::EMPTY, m_undocounter ); + if (!pnt.m_merge.empty()) { + PixelRef p = pnt.m_merge; + depthmapX::findAndErase(m_merge_lines, PixelRefPair(PixelRef(i,j),p)); getPoint(p).m_merge = NoPixel; getPoint(p).m_state &= ~Point::MERGED; } - m_point_count--; + m_filled_point_count--; } } - } + } } m_selection_set.clear(); @@ -467,25 +237,21 @@ bool PointMap::undoPoints() if (!m_undocounter) { return false; } - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - - if ( m_points[i][j].m_misc == m_undocounter) { - Point& p = m_points[i][j]; + for (auto& p: m_points) { + if ( p.m_misc == m_undocounter) { if (p.m_state & Point::FILLED) { - p.m_state &= ~Point::FILLED; - p.m_state |= Point::EMPTY; - p.m_misc = 0; // probably shouldn't set to 0 (can't undo) Eventually will implement 'redo' counter as well - m_point_count--; + p.m_state &= ~Point::FILLED; + p.m_state |= Point::EMPTY; + p.m_misc = 0; // probably shouldn't set to 0 (can't undo) Eventually will implement 'redo' counter as well + m_filled_point_count--; } else if (p.m_state & Point::EMPTY) { - p.m_state |= Point::FILLED; - p.m_state &= ~Point::EMPTY; - p.m_misc = 0; // probably shouldn't set to 0 (can't undo) Eventually will implement 'redo' counter as well - m_point_count++; + p.m_state |= Point::FILLED; + p.m_state &= ~Point::EMPTY; + p.m_misc = 0; // probably shouldn't set to 0 (can't undo) Eventually will implement 'redo' counter as well + m_filled_point_count++; } - } - } + } } m_undocounter--; // reduce undo counter @@ -505,94 +271,31 @@ PixelRef PointMap::pixelate( const Point2f& p, bool constrain, int scalefactor ) if (constrain) { if (ref.x < 0) ref.x = 0; - else if (ref.x >= m_cols * scalefactor) + else if (ref.x >= static_cast(m_cols * scalefactor)) ref.x = (m_cols * scalefactor) - 1; if (ref.y < 0) ref.y = 0; - else if (ref.y >= m_rows * scalefactor) + else if (ref.y >= static_cast(m_rows * scalefactor)) ref.y = (m_rows * scalefactor) - 1; } return ref; } -PixelRefList PointMap::getLayerPixels(int layer) -{ - PixelRefList pixels; - - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - size_t obj = m_points[i][j].m_data_objects.searchindex(layer); - if (obj != paftl::npos) { - pixels.push_back( PixelRef(i,j) ); - } - } - } - - return pixels; -} - -PixelRefList PointMap::getDataObjectPixels(int layer, int object) -{ - PixelRefList pixels; - - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - size_t obj = m_points[i][j].m_data_objects.searchindex(layer); - if (paftl::npos != -1 && m_points[i][j].m_data_objects[obj] == object) { - pixels.push_back( PixelRef(i,j) ); - } - } - } - - return pixels; -} - -// I've reverted to actually filling the lines, provided there's space to put a filled point in - -bool PointMap::fillLines() -{ - if (!m_spacepix || !m_initialised || !m_points) { - return false; - } - m_undocounter++; - for (size_t file = 0; file < m_spacepix->size(); file++) { - for (size_t layer = 0; layer < m_spacepix->at(file).size(); layer++) { - if (m_spacepix->at(file).at(layer).isShown()) { - for (size_t k = 0; k < m_spacepix->at(file).at(layer).getAllShapes().size(); k++) { - SalaShape& shape = m_spacepix->at(file).at(layer).getAllShapes().at(k); - if (shape.isLine()) { - fillLine(shape.getLine()); - } - else if (shape.isPolyLine() || shape.isPolygon()) { - for (size_t n = 0; n < shape.size() - 1; n++) { - fillLine(Line(shape[n],shape[n+1])); - } - if (shape.isPolygon()) { - fillLine( Line(shape.tail(),shape.head())); - } - } - } - } - } - } - return true; -} - void PointMap::fillLine(const Line& li) { - PixelRefList pixels = pixelateLine( li, 1 ); + PixelRefVector pixels = pixelateLine( li, 1 ); for (size_t j = 0; j < pixels.size(); j++) { if (getPoint(pixels[j]).empty()) { getPoint(pixels[j]).set( Point::FILLED, m_undocounter ); - m_point_count++; + m_filled_point_count++; } } } bool PointMap::blockLines() { - if (!m_spacepix || !m_initialised || !m_points) { + if (!m_initialised || m_points.size() == 0) { return false; } if (m_blockedlines) { @@ -601,45 +304,37 @@ bool PointMap::blockLines() // just ensure lines don't exist to start off with (e.g., if someone's been playing with the visible layers) unblockLines(); - size_t count = 0; - // This used to use a packed Linekey (file, layer, line), but // would require a key with (file, layer, shaperef, seg) when used with shaperef, // so just switched to an integer key: - for (size_t i = 0; i < m_spacepix->size(); i++) { - for (size_t j = 0; j < m_spacepix->at(i).size(); j++) { + for (const auto& pixelGroup: *m_drawingFiles) { + for (const auto& pixel: pixelGroup.m_spacePixels) { // chooses the first editable layer it can find: - if (m_spacepix->at(i).at(j).isShown()) { - for (size_t k = 0; k < m_spacepix->at(i).at(j).getAllShapes().size(); k++) { - SalaShape& shape = m_spacepix->at(i).at(j).getAllShapes().at(k); - if (shape.isLine()) { - blockLine(count++,shape.getLine()); - } - else if (shape.isPolyLine() || shape.isPolygon()) { - for (size_t n = 0; n < shape.size() - 1; n++) { - blockLine(count++,Line(shape[n],shape[n+1])); - } - if (shape.isPolygon()) { - blockLine(count++,Line(shape.tail(),shape.head())); - } - } - } + if (pixel.isShown()) { + std::vector newLines = pixel.getAllShapesAsLines(); + for (const auto& line: newLines) { + blockLine(Line(line.start(), line.end())); + } } } } - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { + for (size_t i = 0; i < m_cols; i++) { + for (size_t j = 0; j < m_rows; j++) { PixelRef curs = PixelRef( i, j ); Point& pt = getPoint( curs ); QtRegion viewport = regionate( curs, 1e-10 ); - for (size_t k = pt.m_lines.size() - 1; k != paftl::npos; k--) { - if (!pt.m_lines.value(k).crop( viewport )) { - // the pixelation is fairly rough to make sure that no point is missed: this just - // clears up if any point has been added in error: - pt.m_lines.remove_at(k); - } + std::vector::iterator iter = pt.m_lines.begin(), end = pt.m_lines.end(); + for(; iter != end; ) { + if (!iter->crop( viewport )) { + // the pixelation is fairly rough to make sure that no point is missed: this just + // clears up if any point has been added in error: + iter = pt.m_lines.erase(iter); + end = pt.m_lines.end(); + } else { + ++iter; + } } } } @@ -649,14 +344,14 @@ bool PointMap::blockLines() return true; } -void PointMap::blockLine(int key, const Line& li) +void PointMap::blockLine(const Line& li) { - pvector pixels = pixelateLineTouching(li,1e-10); + std::vector pixels = pixelateLineTouching(li,1e-10); // touching is generally better for ensuring lines pixelated completely, // although it may catch extra points... for (size_t n = 0; n < pixels.size(); n++) { - getPoint(pixels[n]).m_lines.add(key,li); + getPoint(pixels[n]).m_lines.push_back(li); getPoint(pixels[n]).setBlock(true); } } @@ -664,8 +359,8 @@ void PointMap::blockLine(int key, const Line& li) void PointMap::unblockLines(bool clearblockedflag) { // just ensure lines don't exist to start off with (e.g., if someone's been playing with the visible layers) - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { + for (size_t i = 0; i < m_cols; i++) { + for (size_t j = 0; j < m_rows; j++) { PixelRef curs = PixelRef(i,j); getPoint(curs).m_lines.clear(); if (clearblockedflag) { @@ -675,155 +370,6 @@ void PointMap::unblockLines(bool clearblockedflag) } } -// New blockLines code replaces: - -/* - char blah[64]; - sprintf(blah,"times %f\nsubtimes %f\n", times, subtimes); - MessageBox(NULL,blah,"Blah",MB_OK); - - for (int file = 0; file < m_spacepix->size(); file++) { - for (int layer = 0; layer < m_spacepix->at(file).size(); layer++) { - if (m_spacepix->at(file).at(layer).isShown()) { - const prefvec& lineset = m_spacepix->at(file).at(layer).getAllLines(); - for (int i = 0; i < lineset.size(); i++) { - Line line = lineset[i]; - // line.denormalScale( m_spacepix->m_region ); <- no longer required since standardised PointMap and SpacePixel - PixelRefList pixels = pixelateLine( line, 4 ); // pixelate at quadruple precision - for (int j = 0; j < pixels.size(); j++) { - PixelRef actual = pixels[j] / 4; - // now which bits a filled: - int block = 1; - block <<= (pixels[j].x % 4); - block <<= 4 * (pixels[j].y % 4); - getPoint(actual).addBlock( block ); - if (getPoint(actual).filled() && getPoint(actual).fillBlocked() ) { - m_point_count--; - getPoint(actual).set( Point::EMPTY, 0 ); // <- note, can't undo this - } - } - } - } - } - } - return true; -} -*/ - -///////////////////////////////////////////////////////////////////// - -/* -// These have not been recoded to work with shape maps rather than space pixels -// -- note that LineKey cannot be recoded due to possible changes in line mode - -// Instead use blocklines each time a line is added, removed or changed -// (That could be speeded up somewhat with a pixelate of the old and new positions of the line) - -void PointMap::addLineDynamic(LineKey ref,const Line& line) -{ - if (!m_spacepix || !m_initialised || !m_points) { - return; - } - - pvector pixels = pixelateLineTouching(line,1e-10); - for (int n = 0; n < pixels.size(); n++) - { - // right... we have a line over us... we need to tell everyone we can see that there's a change taking place - Point& pt = getPoint(pixels[n]); - if (pt.filled()) { - // just go through our current viewshed - for (int i = 0; i < 32; i++) { - pt.m_node->bin(i).first(); - while (!pt.m_node->bin(i).is_tail()) { - getPoint(pt.m_node->bin(i).cursor()).m_processflag |= q_opposite(i); - pt.m_node->bin(i).next(); - } - } - // and we'll have to reprocess ourselves: - pt.m_processflag = 0x00FF; - } - else { - // slightly trickier... we don't know who can see us! Go forth and find out: - sparkPixel2(pixels[n],2); // <- 2 means tell q_opposites that can see you to reprocess - } - } - // now everything's marked, we can go and add the line: - for (n = 0; n < pixels.size(); n++) - { - Point& pt = getPoint(pixels[n]); - int pos = pt.m_lines.add(ref,line); - QtRegion viewport = regionate( pixels[n], 1e-10 ); - if (!pt.m_lines[pos].crop( viewport )) { - // the pixelation is fairly rough to make sure that no point is missed: this just - // clears up if any point has been added in error: - pt.m_lines.remove_at(pos); - } - } -} - -void PointMap::removeLineDynamic(LineKey ref, const Line& line) -{ - if (!m_spacepix || !m_initialised || !m_points) { - return; - } - - pvector pixels = pixelateLineTouching(line,1e-10); - for (int n = 0; n < pixels.size(); n++) - { - Point& pt = getPoint(pixels[n]); - size_t pos = pt.m_lines.searchindex(ref); - if (pos != paftl::npos) { - pt.m_lines.remove_at(pos); - } - } - for (n = 0; n < pixels.size(); n++) { - // okay, line removed, now reprocess everything that can see us: - Point& pt = getPoint(pixels[n]); - pt.m_processflag = 0x00FF; - if (pt.filled()) { - sparkPixel2(pixels[n],3); // <- 3 means both reprocess us, and tell q_opposites that can see you to reprocess - } - else { - sparkPixel2(pixels[n],2); // <- 2 means tell q_opposites that can see you to reprocess - } - } - for (n = 0; n < pixels.size(); n++) { - // the pixels in the line will automatically flag *each other* as needing reprocessing: - // cancel this out since we've just done it! - Point& pt = getPoint(pixels[n]); - pt.m_processflag = 0x0000; - } -} -*/ -///////////////////////////////////////////////////////////////////////////////// - -// no longer used -- block points through block lines only -/* -bool PointMap::blockPoint(const Point2f& p, bool add) -{ - PixelRef pix = pixelate(p,true,4); - PixelRef actual = pix / 4; - // now which bits a filled: - int block = 1; - block <<= (pix.x % 4); - block <<= 4 * (pix.y % 4); - if (add) { - getPoint(actual).addBlock( block ); - if (getPoint(actual).fillBlocked()) { - if (getPoint(actual).filled()) { - m_point_count--; - getPoint(actual).set( Point::EMPTY, 0 ); // <- note, can't undo this - } - } - } - else { - int newblock = getPoint(actual).getBlock() & ~block; - getPoint(actual).setBlock( newblock ); - } - - return true; -} -*/ // still used through pencil tool bool PointMap::fillPoint(const Point2f& p, bool add) @@ -835,12 +381,15 @@ bool PointMap::fillPoint(const Point2f& p, bool add) } Point& pt = getPoint(pix); if (add && !pt.filled()) { - m_point_count++; + m_filled_point_count++; pt.set( Point::FILLED, ++m_undocounter ); } else if (!add && (pt.m_state & Point::FILLED)) { - m_point_count--; + m_filled_point_count--; pt.set( Point::EMPTY, ++m_undocounter ); + if (pt.m_merge != NoPixel) { + unmergePixel(pix); + } } return true; } @@ -852,10 +401,7 @@ bool PointMap::fillPoint(const Point2f& p, bool add) //AV TV // semifilled bool PointMap::makePoints(const Point2f& seed, int fill_type, Communicator *comm) { - if (!m_spacepix) { - return false; - } - if (!m_initialised || !m_points) { + if (!m_initialised || m_points.size() == 0) { return false; } if (comm) { @@ -870,6 +416,14 @@ bool PointMap::makePoints(const Point2f& seed, int fill_type, Communicator *comm return false; } + // check if seed point is actually visible from the centre of the cell + std::vector& linesTouching = getPoint(seedref).m_lines; + for(auto line: linesTouching) { + if(intersect_line_no_touch(line, Line(seed, getPoint(seedref).m_location))) { + return false; + } + } + if (!m_blockedlines) { blockLines(); } @@ -887,25 +441,20 @@ bool PointMap::makePoints(const Point2f& seed, int fill_type, Communicator *comm filltype = Point::AUGMENTED; getPoint(seedref).set( filltype, m_undocounter ); - m_point_count++; + m_filled_point_count++; // Now... start making lines: - pflipper surface; + pflipper surface; surface.a().push_back( seedref ); int added = 0; - // Quick mod - TV -#if defined(_WIN32) - __time64_t atime = 0; -#else time_t atime = 0; -#endif qtimer( atime, 0 ); while (surface.a().size() > 0) { - PixelRef& currpix = surface.a().tail(); + PixelRef& currpix = surface.a().back(); int result = 0; result |= expand( currpix, currpix.up(), surface.b(), filltype ); result |= expand( currpix, currpix.down(), surface.b(), filltype ); @@ -931,9 +480,9 @@ bool PointMap::makePoints(const Point2f& seed, int fill_type, Communicator *comm return true; } -int PointMap::expand( const PixelRef p1, const PixelRef p2, PixelRefList& list, int filltype) +int PointMap::expand( const PixelRef p1, const PixelRef p2, PixelRefVector& list, int filltype) { - if (p2.x < 0 || p2.x >= m_cols || p2.y < 0 || p2.y >= m_rows) { + if (p2.x < 0 || p2.x >= static_cast(m_cols) || p2.y < 0 || p2.y >= static_cast(m_rows)) { // 1 = off edge return 1; } @@ -942,22 +491,22 @@ int PointMap::expand( const PixelRef p1, const PixelRef p2, PixelRefList& list, return 2; } Line l(depixelate(p1),depixelate(p2)); - for (size_t i = 0; i < getPoint(p1).m_lines.size(); i++) + for (auto& line: getPoint(p1).m_lines) { - if (intersect_region(l, getPoint(p1).m_lines[i], m_spacing * 1e-10) && intersect_line(l, getPoint(p1).m_lines[i], m_spacing * 1e-10)) { + if (intersect_region(l, line, m_spacing * 1e-10) && intersect_line(l, line, m_spacing * 1e-10)) { // 4 = blocked return 4; } } - for (size_t j = 0; j < getPoint(p2).m_lines.size(); j++) + for (auto& line: getPoint(p2).m_lines) { - if (intersect_region(l, getPoint(p2).m_lines[j], m_spacing * 1e-10) && intersect_line(l, getPoint(p2).m_lines[j], m_spacing * 1e-10)) { + if (intersect_region(l, line, m_spacing * 1e-10) && intersect_line(l, line, m_spacing * 1e-10)) { // 4 = blocked return 4; } } getPoint(p2).set( filltype, m_undocounter ); - m_point_count++; + m_filled_point_count++; list.push_back( p2 ); // 8 = success @@ -965,30 +514,30 @@ int PointMap::expand( const PixelRef p1, const PixelRef p2, PixelRefList& list, } -void PointMap::outputPoints(ostream& stream, char delim) +void PointMap::outputPoints(std::ostream& stream, char delim) { - stream << "Ref" << delim << "x" << delim << "y" << endl; + stream << "Ref" << delim << "x" << delim << "y" << std::endl; stream.precision(12); int count = 0; - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { + for (size_t i = 0; i < m_cols; i++) { + for (size_t j = 0; j < m_rows; j++) { PixelRef curs = PixelRef( i, j ); if ( getPoint(curs).filled() ) { Point2f p = depixelate(curs); - stream << curs << delim << p.x << delim << p.y << endl; + stream << curs << delim << p.x << delim << p.y << std::endl; count++; } } } } -void PointMap::outputMergeLines(ostream& stream, char delim) +void PointMap::outputMergeLines(std::ostream& stream, char delim) { - stream << "x1" << delim << "y1" << delim << "x1" << delim << "y1" << endl; + stream << "x1" << delim << "y1" << delim << "x2" << delim << "y2" << std::endl; stream.precision(12); for (size_t i = 0; i < m_merge_lines.size(); i++) { @@ -996,104 +545,181 @@ void PointMap::outputMergeLines(ostream& stream, char delim) Line li(depixelate(m_merge_lines[i].a),depixelate(m_merge_lines[i].b)); stream << li.start().x << delim << li.start().y << delim - << li.end().x << delim << li.end().y << endl; + << li.end().x << delim << li.end().y << std::endl; } } ///////////////////////////////////////////////////////////////////////////////// -void PointMap::outputSummary(ostream& myout, char delimiter) +void PointMap::outputSummary(std::ostream& myout, char delimiter) { myout << "Ref" << delimiter << "x" << delimiter << "y"; - m_attributes.outputHeader(myout, delimiter); - myout.precision(12); + // TODO: For compatibility write the columns in alphabetical order + // but the physical columns in the order inserted + + std::vector indices(m_attributes->getNumColumns()); + std::iota(indices.begin(), indices.end(), static_cast(0)); + + std::sort(indices.begin(), indices.end(), + [&](size_t a, size_t b) { + return m_attributes->getColumnName(a) < m_attributes->getColumnName(b); + }); + for (int idx: indices) { + myout << delimiter << m_attributes->getColumnName(idx); + } + + myout << std::endl; + myout.precision(8); - for (int i = 0; i < m_attributes.getRowCount(); i++) { - if (m_attributes.isVisible(i)) { - PixelRef pix = m_attributes.getRowKey(i); + for (auto iter = m_attributes->begin(); iter != m_attributes->end(); iter++) { + PixelRef pix = iter->getKey().value; + if (isObjectVisible(m_layers, iter->getRow())) { myout << pix << delimiter; Point2f p = depixelate(pix); myout << p.x << delimiter << p.y; - m_attributes.outputRow(i, myout, delimiter); // , update_only = false + for (int idx: indices) { + myout << delimiter << iter->getRow().getValue(idx); + } + myout << std::endl; } } } -void PointMap::outputMif( ostream& miffile, ostream& midfile ) +void PointMap::outputMif( std::ostream& miffile, std::ostream& midfile ) { MapInfoData mapinfodata; mapinfodata.exportFile(miffile, midfile, *this); } -void PointMap::outputNet(ostream& netfile) +void PointMap::outputNet(std::ostream& netfile) { // this is a bid of a faff, as we first have to get the point locations, // then the connections from a lookup table... ickity ick ick... - pmap graph; - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - if (m_points[i][j].filled() && m_points[i][j].m_node) { + std::map graph; + for (size_t i = 0; i < m_cols; i++) { + for (size_t j = 0; j < m_rows; j++) { + Point& pnt = m_points(static_cast(j), static_cast(i)); + if (pnt.filled() && pnt.m_node) { PixelRef pix(i,j); - PixelRefList connections; - m_points[i][j].m_node->contents(connections); - graph.add(pix,connections); + PixelRefVector connections; + pnt.m_node->contents(connections); + graph.insert(std::make_pair(pix,connections)); } } } - netfile << "*Vertices " << graph.size() << endl; + netfile << "*Vertices " << graph.size() << std::endl; double maxdim = __max(m_region.width(),m_region.height()); Point2f offset = Point2f((maxdim - m_region.width())/(2.0*maxdim),(maxdim - m_region.height())/(2.0*maxdim)); - for (size_t j = 0; j < graph.size(); j++) { - Point2f p = depixelate(graph.key(j)); + size_t j = 0; + for (auto& iter: graph) { + auto graphKey = iter.first; + Point2f p = depixelate(graphKey); p.x = offset.x + (p.x - m_region.bottom_left.x) / maxdim; p.y = 1.0 - (offset.y + (p.y - m_region.bottom_left.y) / maxdim); - netfile << (j+1) << " \"" << graph.key(j) << "\" " << p.x << " " << p.y << endl; + netfile << (j+1) << " \"" << graphKey << "\" " << p.x << " " << p.y << std::endl; + j++; } - netfile << "*Edges" << endl; - for (size_t k = 0; k < graph.size(); k++) { - PixelRefList& list = graph.value(k); + netfile << "*Edges" << std::endl; + size_t k = 0; + for (auto& iter: graph) { + PixelRefVector& list = iter.second; for (size_t m = 0; m < list.size(); m++) { - size_t n = graph.searchindex(list[m]); - if (n != paftl::npos && k < n) { - netfile << (k+1) << " " << (n+1) << " 1" << endl; + size_t n = depthmapX::findIndexFromKey(graph, list[m]); + if (static_cast(n) != -1 && k < n) { + netfile << (k+1) << " " << (n+1) << " 1" << std::endl; } } } } -void PointMap::outputConnections(ostream& myout) +void PointMap::outputConnections(std::ostream& myout) { - myout << "#graph v1.0" << endl; - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - if (m_points[i][j].filled() && m_points[i][j].m_node) { + myout << "#graph v1.0" << std::endl; + for (size_t i = 0; i < m_cols; i++) { + for (size_t j = 0; j < m_rows; j++) { + Point& pnt = m_points(static_cast(j), static_cast(i)); + if (pnt.filled() && pnt.m_node) { PixelRef pix(i,j); Point2f p = depixelate(pix); myout << "node {\n" << " ref " << pix << "\n" << " origin " << p.x << " " << p.y << " " << 0.0 << "\n" - << " connections [" << endl; - myout << *(m_points[i][j].m_node); - myout << " ]\n}" << endl; + << " connections [" << std::endl; + myout << *(pnt.m_node); + myout << " ]\n}" << std::endl; } } } } -void PointMap::outputBinSummaries(ostream& myout) +void PointMap::outputConnectionsAsCSV(std::ostream& myout, std::string delim) +{ + myout << "RefFrom" << delim << "RefTo"; + std::unordered_set seenPix; + for (size_t i = 0; i < m_cols; i++) + { + for (size_t j = 0; j < m_rows; j++) + { + Point& pnt = m_points(static_cast(j), static_cast(i)); + if (pnt.filled() && pnt.m_node) + { + PixelRef pix(i,j); + seenPix.insert(pix); + for (int b = 0; b < 32; b++) + { + PixelRefVector hood; + pnt.m_node->bin(b).contents(hood); + for(size_t p = 0; p < hood.size(); p++) + { + if(!(std::find(seenPix.begin(), seenPix.end(), hood[p]) != seenPix.end())) + { + myout << std::endl << pix << delim << hood[p]; + } + } + } + } + } + } +} + +void PointMap::outputLinksAsCSV(std::ostream& myout, std::string delim) { - myout << "cols " << m_cols << " rows " << m_rows << endl; + myout << "RefFrom" << delim << "RefTo"; + std::unordered_set seenPix; + for (size_t i = 0; i < m_cols; i++) + { + for (size_t j = 0; j < m_rows; j++) + { + Point& pnt = m_points(static_cast(j), static_cast(i)); + if (pnt.filled() && pnt.m_node) + { + PixelRef mergePixelRef = pnt.getMergePixel(); + if(mergePixelRef != NoPixel) { + PixelRef pix(i,j); + if(seenPix.insert(pix).second) + { + seenPix.insert(mergePixelRef); + myout << std::endl << pix << delim << mergePixelRef; + } + } + } + } + } +} + +void PointMap::outputBinSummaries(std::ostream& myout) +{ + myout << "cols " << m_cols << " rows " << m_rows << std::endl; myout << "x\ty"; for (int i = 0; i < 32; i++) { myout << "\tbin" << i; } - myout << endl; + myout << std::endl; - int count = 0; - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { + for (size_t i = 0; i < m_cols; i++) { + for (size_t j = 0; j < m_rows; j++) { Point p = getPoint(PixelRef(i, j)); @@ -1110,7 +736,7 @@ void PointMap::outputBinSummaries(ostream& myout) } } - myout << endl; + myout << std::endl; } } } @@ -1127,10 +753,8 @@ void PointMap::setDisplayedAttribute(int col) else { m_displayed_attribute = col; } - // make a local copy of the display params for access speed: - m_display_params = m_attributes.getDisplayParams(m_displayed_attribute); - m_attributes.setDisplayColumn(m_displayed_attribute,true); + m_attribHandle->setDisplayColIndex(m_displayed_attribute); } ///////////////////////////////////////////////////////////////////////////////// @@ -1255,10 +879,10 @@ bool PointMap::getPointSelected() const return false; } -PafColor PointMap::getPointColor() const +PafColor PointMap::getPointColor(PixelRef pixelRef) const { PafColor color; - int state = pointState( cur ); + int state = pointState( pixelRef ); if (state & Point::HIGHLIGHT) { return PafColor( SALA_HIGHLIGHTED_COLOR ); } @@ -1268,7 +892,10 @@ PafColor PointMap::getPointColor() const else { if (state & Point::FILLED) { if (m_processed) { - return m_attributes.getDisplayColorByKey( cur ); + return dXreimpl::getDisplayColor(AttributeKey(pixelRef), + m_attributes->getRow(AttributeKey(pixelRef)), + *m_attribHandle.get(), + true); } else if (state & Point::EDGE) { return PafColor( 0x0077BB77 ); @@ -1287,6 +914,11 @@ PafColor PointMap::getPointColor() const return PafColor(); // <- note alpha channel set to transparent - will not be drawn } +PafColor PointMap::getCurrentPointColor() const +{ + return getPointColor( cur ); +} + ///////////////////////////////////////////////////////////////////////////////// // Selection stuff @@ -1298,12 +930,12 @@ bool PointMap::clearSel() if (m_selection == NO_SELECTION) { return false; } - for (size_t i = 0; i < m_selection_set.size(); i++) { - getPoint(m_selection_set[i]).m_state &= ~Point::SELECTED; + for (auto& sel: m_selection_set) { + getPoint(sel).m_state &= ~Point::SELECTED; } m_selection_set.clear(); m_selection = NO_SELECTION; - m_attributes.deselectAll(); + m_attributes->deselectAllRows(); return true; } @@ -1333,9 +965,10 @@ bool PointMap::setCurSel(QtRegion &r, bool add ) for (int i = s_bl.x; i <= s_tr.x; i++) { for (int j = s_bl.y; j <= s_tr.y; j++) { - if ((m_points[i][j].m_state & mask) && (~m_points[i][j].m_state & Point::SELECTED)) { - m_points[i][j].m_state |= Point::SELECTED; - m_selection_set.push_back( PixelRef(i,j) ); + Point& pnt = m_points(static_cast(j), static_cast(i)); + if ((pnt.m_state & mask) && (~pnt.m_state & Point::SELECTED)) { + pnt.m_state |= Point::SELECTED; + m_selection_set.insert( PixelRef(i,j) ); if (add) { m_selection &= ~SINGLE_SELECTION; m_selection |= COMPOUND_SELECTION; @@ -1343,8 +976,8 @@ bool PointMap::setCurSel(QtRegion &r, bool add ) else { m_selection |= SINGLE_SELECTION; } - if (m_points[i][j].m_node) { - m_attributes.selectRowByKey(PixelRef(i,j)); + if (pnt.m_node) { + m_attributes->getRow(AttributeKey(PixelRef(i,j))).setSelection(true); } } } @@ -1356,7 +989,7 @@ bool PointMap::setCurSel(QtRegion &r, bool add ) return true; } -bool PointMap::setCurSel(const pvecint& selset, bool add) +bool PointMap::setCurSel(const std::vector& selset, bool add) { // note: override cursel, can only be used with analysed pointdata: if (!add) { @@ -1367,136 +1000,35 @@ bool PointMap::setCurSel(const pvecint& selset, bool add) for (size_t i = 0; i < selset.size(); i++) { PixelRef pix = selset[i]; if (includes(pix)) { - int row = m_attributes.getRowid(pix); - if (row != -1) { - m_points[pix.x][pix.y].m_state |= Point::SELECTED; - if (m_attributes.selectRowByKey(pix)) { - m_selection_set.push_back(pix); + m_points(static_cast(pix.y), static_cast(pix.x)).m_state |= Point::SELECTED; + AttributeRow& row = m_attributes->getRow(AttributeKey(pix)); + if (!row.isSelected()) { + row.setSelection(true); + m_selection_set.insert(pix); } - } } } return true; } -// dangerous: used only for making a false selection set -bool PointMap::overrideSelPixel(PixelRef pix) -{ - m_selection = OVERRIDE_SELECTION; - if (!(m_points[pix.x][pix.y].m_state & Point::SELECTED)) { - m_points[pix.x][pix.y].m_state |= Point::SELECTED; - m_selection_set.push_back(pix); - } - return true; -} - -/* -bool PointMap::togglePin() -{ - // Just a keep it simple stupid version of this... won't happen that often - if (m_pinned_selection) { - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - if ( m_points[i][j].m_state & Point::PINNED ) { - m_points[i][j].m_state &= ~Point::PINNED; - } - } - } - m_pinned_set.clear(); - m_pinned_selection = false; - } - else if (m_selection != NO_SELECTION) { - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - if ( m_points[i][j].m_state & Point::SELECTED ) { - m_points[i][j].m_state &= ~Point::SELECTED; - m_points[i][j].m_state |= Point::PINNED; - } - } - } - m_pinned_set = m_selection_set; - m_selection_set.clear(); - m_selection = NO_SELECTION; - m_pinned_selection = true; - } - else { - return false; - } - return true; -} -*/ +// Helper function: is there a blocked point next to you? +// ...rather scruffily goes round the eight adjacent points... -/* -// DEPRECATED: REPLACED BY SHAPEMAP FUNCTION 21.08.05 +// This is being phased out, with the new "edge" points (which are the filled edges of the graph) -bool PointMap::convertSelToDataObject( MetaGraph& meta_graph ) +bool PointMap::blockedAdjacent( const PixelRef p ) const { - // Just a keep it simple stupid version of this too... - // will certainly happen more often, but why not? --- no brainer computing from now on - - if (m_selection != NO_SELECTION) { + bool ba = false; + PixelRef temp = p.right(); + PixelRef bounds(m_cols, m_rows); - int layer_ref = meta_graph.MetaGraph::getCurrentLayerRef(); - int object_ref; - try { - object_ref = meta_graph.MetaGraph::getCurrentLayer().addObject(); - } - catch (DataException e) { - if (e.errorCode() == DataException::LAYER_HAS_COLUMNS) { - return false; - } - else { - throw e; - } - } - - double pointcount = 0.0; - Point2f centroid; - - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - if ( m_points[i][j].m_state & Point::SELECTED ) { - m_points[i][j].m_state &= ~Point::SELECTED; - m_points[i][j].m_layer_objects.add(layer_ref, object_ref); - centroid += depixelate( PixelRef(i,j) ); - pointcount += 1.0; - } - } - } - m_selection_set.clear(); - m_selection = NO_SELECTION; - - centroid.scale( 1.0 / pointcount ); - meta_graph.MetaGraph::getCurrentLayer()[object_ref].setCentroid( centroid ); - - return true; - } - else { - - return true; // <- even though didn't make layer, there wasn't an error, just no points selected - } - return false; -} -*/ - -// Helper function: is there a blocked point next to you? -// ...rather scruffily goes round the eight adjacent points... - -// This is being phased out, with the new "edge" points (which are the filled edges of the graph) - -bool PointMap::blockedAdjacent( const PixelRef p ) const -{ - bool ba = false; - PixelRef temp = p.right(); - PixelRef bounds(m_cols, m_rows); - - if (bounds.encloses(temp) && getPoint(temp).blocked()) { // Right - ba = true; - } - else { - temp = temp.up(); - if (bounds.encloses(temp) && getPoint(temp).blocked()) { // Top right - ba = true; + if (bounds.encloses(temp) && getPoint(temp).blocked()) { // Right + ba = true; + } + else { + temp = temp.up(); + if (bounds.encloses(temp) && getPoint(temp).blocked()) { // Top right + ba = true; } else { temp = temp.left(); @@ -1541,43 +1073,23 @@ bool PointMap::blockedAdjacent( const PixelRef p ) const //////////////////////////////////////////////////////////////////////////////// -bool PointMap::read(ifstream& stream, int version ) +bool PointMap::read(std::istream& stream ) { - if (version >= VERSION_POINT_MAP_NAMES) { - m_name.read(stream); - } - else { - m_name = pstring("VGA Map"); - } + m_name = dXstring::readString(stream); + // NOTE: You MUST set m_spacepix manually! m_displayed_attribute = -1; - if (m_points) { - for (int i = 0; i < m_cols; i++) { - delete [] m_points[i]; - } - delete [] m_points; - m_points = NULL; - } - stream.read( (char *) &m_spacing, sizeof(m_spacing) ); - if (version < VERSION_STATE_RECORDED) { - if (version >= VERSION_SPARK_GRAPH_INTROD) { - bool redundant; - stream.read( (char *) &redundant, sizeof(redundant) ); - } - else { - double redundant; - stream.read( (char *) &redundant, sizeof(redundant) ); - } - } - - stream.read( (char *) &m_rows, sizeof(m_rows) ); - stream.read( (char *) &m_cols, sizeof(m_cols) ); + int rows, cols; + stream.read( reinterpret_cast(&rows), sizeof(rows) ); + stream.read( reinterpret_cast(&cols), sizeof(cols) ); + m_rows = static_cast(rows); + m_cols = static_cast(cols); - stream.read( (char *) &m_point_count, sizeof(m_point_count) ); + stream.read( (char *) &m_filled_point_count, sizeof(m_filled_point_count) ); stream.read( (char *) &m_bottom_left, sizeof(m_bottom_left) ); @@ -1586,104 +1098,57 @@ bool PointMap::read(ifstream& stream, int version ) Point2f(m_bottom_left.x+double(m_cols-1)*m_spacing + m_spacing/2.0, m_bottom_left.y+double(m_rows-1)*m_spacing + m_spacing/2.0) ); - // for old data versions: - int attr_count = -1, which_attributes = -1; - int displayed_attribute; // n.b., temp variable necessary to force recalc below - if (version >= VERSION_ATTRIBUTES_TABLE) { - // our data read - stream.read((char *)&displayed_attribute,sizeof(displayed_attribute)); - m_attributes.read( stream, version ); - } - else if (version >= VERSION_NGRAPH_INTROD) { - // ick, a very specific subset have this file format: - stream.read( (char *) &which_attributes, sizeof(which_attributes) ); - stream.read( (char *) &attr_count, sizeof(int) ); - } - m_points = new Point *[m_cols]; + // our data read + stream.read((char *)&displayed_attribute,sizeof(displayed_attribute)); + m_attributes->read( stream, m_layers ); + + m_points = depthmapX::ColumnMatrix(m_rows, m_cols); - for (int j = 0; j < m_cols; j++) { - m_points[j] = new Point [m_rows]; - // ...and read... - if (version >= VERSION_LAYERS_INTROD) { - for (int k = 0; k < m_rows; k++) { - m_points[j][k].read(stream,version,attr_count); - } - } - else if (version >= VERSION_EXTRA_POINT_DATA_INTROD) { - // Hmm... more untidiness from a previous incarnation - OldPoint2 *oldpoints = new OldPoint2 [m_rows]; - stream.read( (char *) oldpoints, sizeof(OldPoint2) * m_rows ); - for (int k = 0; k < m_rows; k++) { - m_points[j][k].m_block = oldpoints[k].m_noderef; // <- block is actually for something else! - m_points[j][k].m_state = oldpoints[k].m_state; - m_points[j][k].m_misc = oldpoints[k].m_misc; - } - } - else { - // Hmm... more untidiness from a previous incarnation - OldPoint1 *oldpoints = new OldPoint1 [m_rows]; - stream.read( (char *) oldpoints, sizeof(OldPoint1) * m_rows ); - for (int k = 0; k < m_rows; k++) { - m_points[j][k].m_block= oldpoints[k].m_noderef; // <- block is actually for something else! - m_points[j][k].m_state = oldpoints[k].m_state; + for (size_t j = 0; j < m_cols; j++) { + for (size_t k = 0; k < m_rows; k++) { + m_points(k, j).read(stream); + + // check if occdistance of any pixel's bin is set, meaning that + // the isovist analysis was done + if(!m_hasIsovistAnalysis) { + for(int b = 0; b < 32; b++) { + if(m_points(k, j).m_node && m_points(k, j).m_node->occdistance(b) > 0) { + m_hasIsovistAnalysis = true; + break; + } + } } } - for (int k = 0; k < m_rows; k++) { + + for (size_t k = 0; k < m_rows; k++) { + Point& pnt = m_points(k, j); // Old style point node reffing and also unselects selected nodes which would otherwise be difficult - if (version >= VERSION_QUICK_GRAPH_INTROD) { - // would soon be better simply to turn off the select flag.... - m_points[j][k].m_state &= ( Point::EMPTY | Point::FILLED | Point::MERGED | Point::BLOCKED | Point::CONTEXTFILLED | Point::EDGE); - } - else if (m_points[j][k].m_state == -1) { - m_points[j][k].m_state = Point::EMPTY; - } - else { - m_points[j][k].m_state = Point::FILLED; - } + + // would soon be better simply to turn off the select flag.... + pnt.m_state &= ( Point::EMPTY | Point::FILLED | Point::MERGED | Point::BLOCKED | Point::CONTEXTFILLED | Point::EDGE); + // Set the node pixel if it exists: - if (m_points[j][k].m_node) { - m_points[j][k].m_node->setPixel(PixelRef(j,k)); - } - // Set the point location if required: - if (version < VERSION_POINT_LOCATIONS) { - m_points[j][k].m_location = depixelate(PixelRef(j,k)); + if (pnt.m_node) { + pnt.m_node->setPixel(PixelRef(j,k)); } // Add merge line if merged: - if (!m_points[j][k].m_merge.empty()) { - m_merge_lines.add(PixelRefPair(PixelRef(j,k),m_points[j][k].m_merge)); + if (!pnt.m_merge.empty()) { + depthmapX::addIfNotExists(m_merge_lines, PixelRefPair(PixelRef(j,k),pnt.m_merge)); } } } - // this is my attempt to enter these into the new attribute table: - if (version >= VERSION_NGRAPH_INTROD && version < VERSION_ATTRIBUTES_TABLE) { - if (which_attributes != GraphVertexList::NONE) { - displayed_attribute = 0; - convertAttributes(which_attributes); - } - else { - displayed_attribute = -1; - } - } - - // and if the attribute tables are ready, calculate the direct grid connections: - if (version >= VERSION_NGRAPH_INTROD && version < VERSION_GRID_CONNECTIONS) { - addGridConnections(); - } - m_selection = NO_SELECTION; m_pinned_selection = false; m_initialised = true; m_blockedlines = false; - if (version >= VERSION_POINT_MAPS) { - stream.read((char *) &m_processed, sizeof(m_processed)); - stream.read((char *) &m_boundarygraph, sizeof(m_boundarygraph)); - } + stream.read((char *) &m_processed, sizeof(m_processed)); + stream.read((char *) &m_boundarygraph, sizeof(m_boundarygraph)); // now, as soon as loaded, must recalculate our screen display: // note m_displayed_attribute should be -2 in order to force recalc... @@ -1693,26 +1158,30 @@ bool PointMap::read(ifstream& stream, int version ) return true; } -bool PointMap::write( ofstream& stream, int version ) +bool PointMap::write( std::ostream& stream ) { - m_name.write(stream); + dXstring::writeString(stream, m_name); stream.write( (char *) &m_spacing, sizeof(m_spacing) ); - stream.write( (char *) &m_rows, sizeof(m_rows) ); - stream.write( (char *) &m_cols, sizeof(m_cols) ); + int rows = static_cast(m_rows); + int cols = static_cast(m_cols); + stream.write( reinterpret_cast(&rows), sizeof(rows) ); + stream.write( reinterpret_cast(&cols), sizeof(cols) ); - stream.write( (char *) &m_point_count, sizeof(m_point_count) ); + stream.write( (char *) &m_filled_point_count, sizeof(m_filled_point_count) ); stream.write( (char *) &m_bottom_left, sizeof(m_bottom_left) ); - stream.write( (char *) &m_displayed_attribute, sizeof(m_displayed_attribute) ); - m_attributes.write( stream, version ); + // TODO: Compatibility. The attribute columns will be stored sorted alphabetically + // so the displayed attribute needs to match that + int sortedDisplayedAttribute = m_attributes->getColumnSortedIndex(m_displayed_attribute); + stream.write( (char *) &sortedDisplayedAttribute, sizeof(sortedDisplayedAttribute) ); + + m_attributes->write( stream, m_layers ); - for (int j = 0; j < m_cols; j++) { - for (int k = 0; k < m_rows; k++) { - m_points[j][k].write( stream, version ); - } + for (auto& point: m_points) { + point.write( stream ); } stream.write((char *) &m_processed, sizeof(m_processed)); @@ -1723,175 +1192,19 @@ bool PointMap::write( ofstream& stream, int version ) //////////////////////////////////////////////////////////////////////////////// -// A horrible piece of code: this is to convert a file from the old format -// AttrHeader / AttrBody to the new format Attributes Table - -// This code converts attributes for all versions -// between VERSION_NGRAPH_INTROD and VERSION_ATTRIBUTES_TABLE - -void PointMap::convertAttributes(int which_attributes) -{ - if (which_attributes & GraphVertexList::BASIC) { - int connectivity_col = m_attributes.insertLockedColumn("Connectivity"); - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - if (m_points[i][j].m_attributes) { - // insert row... - int row = m_attributes.insertRow(PixelRef(i,j)); - float val; - val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::NEIGHBOURHOOD_SIZE); - m_attributes.setValue(row, connectivity_col, val); - } - } - } - } - if (which_attributes & GraphVertexList::LOCAL) { - int cluster_col = m_attributes.insertColumn("Visual Clustering Coefficient"); - int control_col = m_attributes.insertColumn("Visual Control"); - int controllability_col = m_attributes.insertColumn("Visual Controllability"); - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - if (m_points[i][j].m_attributes) { - int row = m_attributes.getRowid(PixelRef(i,j)); - float val; - val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::CLUSTER); - m_attributes.setValue(row, cluster_col, val); - val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::CONTROL_HILL); - m_attributes.setValue(row, control_col, val); - val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::CONTROL_TURN); - m_attributes.setValue(row, controllability_col, val); - } - } - } - } - if (which_attributes & GraphVertexList::GLOBAL) { - int entropy_col = m_attributes.insertColumn("Visual Entropy"); - int integ_hh_col = m_attributes.insertColumn("Visual Integration [HH]"); - int integ_tk_col = m_attributes.insertColumn("Visual Integration [Tekl]"); - int depth_col = m_attributes.insertColumn("Visual Mean Depth"); - int count_col = m_attributes.insertColumn("Visual Node Count"); - int rel_entropy_col = m_attributes.insertColumn("Visual Relativised Entropy"); - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - if (m_points[i][j].m_attributes) { - int row = m_attributes.getRowid(PixelRef(i,j)); - float val; - val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::ENTROPY); - m_attributes.setValue(row, entropy_col, val); - val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::REL_ENTROPY); - m_attributes.setValue(row, rel_entropy_col, val); - val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::INTEGRATION_HILL); - m_attributes.setValue(row, integ_hh_col, val); - val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::INTEGRATION_TEKL); - m_attributes.setValue(row, integ_tk_col, val); - val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::MEAN_DEPTH); - m_attributes.setValue(row, depth_col, val); - val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::GRAPH_SIZE); - m_attributes.setValue(row, count_col, val); - } - } - } - } - if (which_attributes & GraphVertexList::POINTDEPTH) { - int col = m_attributes.insertColumn("Visual Step Depth"); - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - if (m_points[i][j].m_attributes) { - int row = m_attributes.getRowid(PixelRef(i,j)); - float val; - val = (float) m_points[i][j].getAttributes().getAttr(AttrHeader::POINT_DEPTH); - m_attributes.setValue(row, col, val); - } - } - } - } - if (which_attributes & GraphVertexList::METRIC) { - int mspa_col = m_attributes.insertColumn("Metric Mean Shortest-Path Angle"); - int mspl_col = m_attributes.insertColumn("Metric Mean Shortest-Path Distance"); - int dist_col = m_attributes.insertColumn("Metric Mean Straight-Line Distance"); - int count_col = m_attributes.insertColumn("Metric Node Count"); - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - if (m_points[i][j].m_attributes) { - int row = m_attributes.getRowid(PixelRef(i,j)); - double val, total = m_points[i][j].getAttributes().getAttr(AttrHeader::METRIC_GRAPH_SIZE); - // - val = m_points[i][j].getAttributes().getAttr(AttrHeader::TOTAL_METRIC_ANGLE) / total; - m_attributes.setValue(row, mspa_col, float(val)); - val = m_points[i][j].getAttributes().getAttr(AttrHeader::TOTAL_METRIC_DEPTH) / total; - m_attributes.setValue(row, mspl_col, float(val)); - val = m_points[i][j].getAttributes().getAttr(AttrHeader::TOTAL_EUCLID_DIST) / total; - m_attributes.setValue(row, dist_col, float(val)); - // - m_attributes.setValue(row, count_col, float(total)); - } - } - } - } - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - if (m_points[i][j].m_attributes) { - delete m_points[i][j].m_attributes; - m_points[i][j].m_attributes = NULL; - } - } - } -} - -//////////////////////////////////////////////////////////////////////////////// - // Now what this class is actually for: making a visibility graph! // Visibility graph construction constants -pvecint g_primes; -prefvec g_gradients; - -int PointMap::remaining(int i, int j, int x, int y, int q) -{ - int x1,y1,ret = 0; - if (x > 0) { - if (q % 2 == 0) { - x1 = i / x; - } - else { - x1 = (m_cols - 1 - i) / x; - } - } - else { - ret = 1; - } - if (y > 0) { - if ((q / 2) % 2 == 0) { - y1 = j / y; - } - else { - y1 = (m_rows - 1 - j) / y; - } - } - else { - ret = -1; - } - if (ret == 1) { - return y1; - } - if (ret == -1) { - return x1; - } - return __min(x1, y1); -} - -// Helper for for making graph - -int PointMap::tagState(bool settag, bool sparkgraph) +int PointMap::tagState(bool settag) { m_selection_set.clear(); m_selection = NO_SELECTION; int count = 0; - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { + for (size_t i = 0; i < m_cols; i++) { + for (size_t j = 0; j < m_rows; j++) { PixelRef curs = PixelRef( i, j ); @@ -1914,473 +1227,180 @@ int PointMap::tagState(bool settag, bool sparkgraph) return count; } -////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////// + +#include "sparksieve2.h" + +// The fast way to generate graphs... attempt 2 +// This uses the new points line segments to allow quick overlap comparisons +// The spark method uses a 1024 long bit string to check against -// calculate 32 distances by explicit angle... +// writing the algo has thrown up something: it would be more appropriate to +// have lines between the grid points, rather than centred on the grid square, +// i.e.: +// +// .-. --- +// |X| not |.| (dots are the grid points) +// .-. --- +// +// Then wouldn't have to 'test twice' for the grid point being blocked... +// ...perhaps a tweak for a later date! -bool PointMap::binMap( Communicator *comm ) +bool PointMap::sparkGraph2( Communicator *comm, bool boundarygraph, double maxdist ) { // Note, graph must be fixed (i.e., having blocking pixels filled in) - if (!m_spacepix) { - return false; + + if (!m_blockedlines) { + blockLines(); } - // start the timer when you know the true count including fixed points + if (boundarygraph) { + for (size_t i = 0; i < m_cols; i++) { + for (size_t j = 0; j < m_rows; j++) { + PixelRef curs = PixelRef( static_cast(i), static_cast(j) ); + if ( getPoint( curs ).filled() && !getPoint( curs ).edge()) { + m_points(j, i).m_state &= ~Point::FILLED; + m_filled_point_count--; + } + } + } + } - // Quick mod - TV -#if defined(_WIN32) - __time64_t atime = 0; -#else + // attributes table set up + // n.b. these must be entered in alphabetical order to preserve col indexing: + int connectivity_col = m_attributes->insertOrResetLockedColumn("Connectivity"); + m_attributes->insertOrResetColumn("Point First Moment"); + m_attributes->insertOrResetColumn("Point Second Moment"); + + // pre-label --- allows faster node access later on + int count = tagState( true ); + + // start the timer when you know the true count including fixed points + time_t atime = 0; -#endif if (comm) { qtimer( atime, 0 ); - comm->CommPostMessage( Communicator::NUM_RECORDS, m_rows * m_cols ); - } - - int i = 0; - - float far_bin_dists[32]; - Point2f bin_vectors[32]; - Point2f diagonal = m_spacepix->m_region.top_right - m_spacepix->m_region.bottom_left; - Point2f east = diagonal.length() * Point2f(1.0,0.0); - for (i = 0; i < 32; i++) { - bin_vectors[i] = east; - east.rotate(0.0625 * M_PI); + comm->CommPostMessage( Communicator::NUM_RECORDS, count ); } - int count = 0; + count = 0; - for (i = 0; i < m_cols; i++) { + for (size_t i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { + for (size_t j = 0; j < m_rows; j++) { PixelRef curs = PixelRef( i, j ); - + if ( getPoint( curs ).getState() & Point::FILLED ) { - if (!getPoint(curs).m_node) { - getPoint( curs ).m_node = new Node; - m_attributes.insertRow( curs ); - } - - Point2f point = depixelate(curs); - - for (int k = 0; k < 32; k++) { - Line l(point, point + bin_vectors[k]); - l.crop(m_spacepix->m_region); - m_spacepix->cutLine(l);//,1); - far_bin_dists[k] = (float) l.length(); - } + getPoint( curs ).m_node = std::unique_ptr(new Node()); + m_attributes->addRow( AttributeKey(curs) ); - Point& pt = getPoint( curs ); - pt.getNode().setbindistances( far_bin_dists ); + sparkPixel2(curs,1,maxdist); // make flag of 1 suggests make this node, don't set reciprocral process flags on those you can see + // maxdist controls how far to see out to count++; // <- increment count if (comm) { if (qtimer( atime, 500 )) { if (comm->IsCancelled()) { - tagState( false, true ); // <- the state field has been used for tagging visited nodes... set back to a state variable + tagState( false ); // <- the state field has been used for tagging visited nodes... set back to a state variable + // (well, actually, no it hasn't!) + // Should clear all nodes and attributes here: + // Clear nodes + // Clear attributes + m_attributes->clear(); + m_displayed_attribute = -2; // throw Communicator::CancelledException(); } comm->CommPostMessage( Communicator::CURRENT_RECORD, count ); } - } - } - } - } - - return true; -} - - -////////////////////////////////////////////////////////////////////////////////// - -// The fast way to generate graphs! - -// #include "sparksieve.h" + } // if (comm) + } // if ( getPoint( curs ).getState() & Point::FILLED ) + } // rows + } // cols -// DEPRECATED!!!!!! -/* -bool PointMap::sparkGraph( Communicator *comm ) -{ - // Note, graph must be fixed (i.e., having blocking pixels filled in) - if (!m_spacepix) { - return false; - } + tagState( false ); // <- the state field has been used for tagging visited nodes... set back to a state variable - // pre-label --- allows faster node access later on - int count = tagState( true, true ); + // keeping lines blocked now is wasteful of memory... free the memory involved + unblockLines(false); - // start the timer when you know the true count including fixed points - int atime = 0; - if (comm) { - qtimer( atime, 0 ); - comm->CommPostMessage( Communicator::NUM_RECORDS, count ); - } + // and add grid connections + // (this is easier than trying to work it out per pixel as we calculate visibility) + addGridConnections(); - // attributes table set up - // n.b. these must be entered in alphabetical order to preserve col indexing: - int connectivity_col = m_attributes.insertLockedColumn("Connectivity"); - int maxradial_col = m_attributes.insertColumn("Isovist Maximum Radial"); - //int maxradial_node_col = m_attributes.insertColumn("Maximum Radial (Node ID)"); - int moment_col = m_attributes.insertColumn("Isovist Moment of Inertia"); - // - pvecint bins[ GraphVertex::bin_count ]; - pvector bins_b[32]; - static float far_bin_dists[32]; - for (int ii = 0; ii < 32; ii++) { - far_bin_dists[ii] = 0.0f; + // the graph is processed: + m_processed = true; + if (boundarygraph) { + m_boundarygraph = true; } - count = 0; - - for (int i = 0; i < m_cols; i++) { - - for (int j = 0; j < m_rows; j++) { - - PixelRef curs = PixelRef( i, j ); + // override and reset: + m_displayed_attribute = -2; + setDisplayedAttribute(connectivity_col); - if ( getPoint( curs ).getState() & Point::FILLED ) { + return true; +} - if (getPoint(curs).m_node) { - delete getPoint(curs).m_node; +bool PointMap::unmake(bool removeLinks) { + for (size_t i = 0; i < m_cols; i++) { + for (size_t j = 0; j < m_rows; j++) { + PixelRef curs = PixelRef(static_cast(i), static_cast(j)); + Point &pnt = getPoint(curs); + if (pnt.filled()) { + if(removeLinks) { + pnt.m_merge = NoPixel; + } + pnt.m_grid_connections = 0; + pnt.m_node = nullptr; + pnt.m_lines.clear(); + pnt.setBlock(false); } - getPoint( curs ).m_node = new Node; - - m_attributes.insertRow( curs ); - - int neighbourhood_size = 0; - int max_depth = 0; - int far_node = -1; - double far_dist = 0.0; - double total_dist_sqr = 0.0; - - // note: blocked points (for now) do not see out - for (int q = 0; q < 8; q++) { - - int standardbin; - switch (q) { - case 1: standardbin = 0; break; - case 3: standardbin = 32; break; - case 0: case 2: standardbin = 16; break; - case 4: case 5: standardbin = 24; break; - case 6: case 7: standardbin = 8; break; - } - - sparkSieve sieve( sparkSieve::rotateMask(getPoint(curs).getBlock(), q) ); + } + } - int depth = 0; + m_blockedlines = false; - for (depth = 1; sieve.hasGaps(); depth++) { + if(removeLinks) { + m_merge_lines.clear(); + } - pvecint trialsetin, trialsetout; + m_attributes->clear(); - for (int ind = 0; ind < depth + 1; ind++) { + m_processed = false; + m_boundarygraph = false; - // x and y are calculated using Grad's whichbin q quadrants + m_displayed_attribute = -2; - int x = (q >= 4 ? ind : depth); - int y = (q >= 4 ? depth : ind); - - PixelRef here = PixelRef( - i + (q % 2 ? x : -x), j + (q <= 1 || q >= 6 ? y : -y) ); + return true; +} - if (here.x < 0 || here.y < 0 || here.x >= m_cols || here.y >= m_rows) { - // Outside point grid - trialsetin.push_back( -1 ); - trialsetout.push_back( -1 ); - } - else if (getPoint(here).getBlock()) { - // Blocked - trialsetin.push_back( sparkSieve::rotateMask(getPoint(here).getBlock(),q) ); - trialsetout.push_back( -1 ); - } - else { - // Empty or (space) filled - trialsetin.push_back( 0 ); - trialsetout.push_back( -1 ); - } - } +// 'make' construct types are: +// 1 -- build this node +// 2 -- register the reciprocal q octant in nodes you can see as requiring processing - sieve.Sieve( trialsetin, trialsetout ); +bool PointMap::sparkPixel2(PixelRef curs, int make, double maxdist) +{ + static std::vector bins_b[32]; + static float far_bin_dists[32]; + for (int i = 0; i < 32; i++) { + far_bin_dists[i] = 0.0f; + } + int neighbourhood_size = 0; + double total_dist = 0.0; + double total_dist_sqr = 0.0; - for (int tri = ((q % 4 == 0 || (q + 1) % 4 == 0) ? 1 : 0); // avoid duplicating axes - tri < ((q / 4) ? depth : depth + 1); // avoid duplicating diagonals - tri++) { - if (trialsetout[tri] > -1) { + Point2f centre0 = depixelate(curs); - int quoi = trialsetout[tri]; + for (int q = 0; q < 8; q++) { - int x = (q >= 4 ? tri : depth); - int y = (q >= 4 ? depth : tri); + if (!((getPoint(curs).m_processflag) & (1 << q)) ) { + continue; + } - PixelRef here = PixelRef( - i + (q % 2 ? x : -x), j + (q <= 1 || q >= 6 ? y : -y) ); - - // oh god, yet another whichbin calculation... - int bin = ((q % 4 == 0 || (q + 1) % 4 == 0) ? - (standardbin - trialsetout[tri]) : - (standardbin + trialsetout[tri])); - - //if (!getPoint(here).empty()) { - - if (getPoint(here).getState() & Point::FILLED) { - // the blocked cells shouldn't contribute to point stats - // note m_spacing is used to scale far_dist appropriately - double this_dist = dist(here,curs) * m_spacing; - if (this_dist > far_dist) { - far_node = here; - far_dist = this_dist; - } - total_dist_sqr += this_dist * this_dist; - neighbourhood_size++; - - bins_b[bin].push_back( here ); - - } - - //} - } - } - } - } - Point2f point = depixelate(curs); - - // Remember to clear these bins in the make function! - Point& pt = getPoint( curs ); - pt.m_node->make(curs, bins_b, far_bin_dists, 0x00FF); - int row = m_attributes.insertRow( curs ); - m_attributes.setValue( row, connectivity_col, float(neighbourhood_size) ); - m_attributes.setValue( row, maxradial_col, float(far_dist) ); - //m_attributes.setValue( row, maxradial_node_col, far_node ); - m_attributes.setValue( row, moment_col, float(total_dist_sqr * m_spacing * m_spacing) ); - - count++; // <- increment count - - if (comm) { - if (qtimer( atime, 500 )) { - if (comm->IsCancelled()) { - tagState( false, true ); // <- the state field has been used for tagging visited nodes... set back to a state variable - // (well, actually, no it hasn't!) - // Should clear all nodes and attributes here: - // Clear nodes - for (int ii = 0; ii < m_cols; ii++) { - for (int jj = 0; jj < m_rows; jj++) { - if (m_points[ii][jj].m_node) { - delete m_points[ii][jj].m_node; - m_points[ii][jj].m_node = NULL; - } - } - } - // Clear attributes - m_attributes.clear(); - m_displayed_attribute = -2; - // - throw Communicator::CancelledException(); - } - comm->CommPostMessage( Communicator::CURRENT_RECORD, count ); - } - } - } - } - } - - tagState( false, true ); // <- the state field has been used for tagging visited nodes... set back to a state variable - - // override and reset: - m_displayed_attribute = -2; - setDisplayedAttribute(connectivity_col); - - return true; -} -*/ -//////////////////////////////////////////////////////////////////////////////////////////////// - -#include "sparksieve2.h" - -// The fast way to generate graphs... attempt 2 -// This uses the new points line segments to allow quick overlap comparisons -// The spark method uses a 1024 long bit string to check against - -// writing the algo has thrown up something: it would be more appropriate to -// have lines between the grid points, rather than centred on the grid square, -// i.e.: -// -// .-. --- -// |X| not |.| (dots are the grid points) -// .-. --- -// -// Then wouldn't have to 'test twice' for the grid point being blocked... -// ...perhaps a tweak for a later date! - -bool PointMap::sparkGraph2( Communicator *comm, bool boundarygraph, double maxdist ) -{ - // Note, graph must be fixed (i.e., having blocking pixels filled in) - if (!m_spacepix) { - return false; - } - - if (!m_blockedlines) { - blockLines(); - } - - if (boundarygraph) { - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - PixelRef curs = PixelRef( i, j ); - if ( getPoint( curs ).filled() && !getPoint( curs ).edge()) { - m_points[i][j].m_state &= ~Point::FILLED; - m_point_count--; - } - } - } - } - - // attributes table set up - // n.b. these must be entered in alphabetical order to preserve col indexing: - int connectivity_col = m_attributes.insertLockedColumn("Connectivity"); - m_attributes.insertColumn("Point First Moment"); - m_attributes.insertColumn("Point Second Moment"); - - // pre-label --- allows faster node access later on - int count = tagState( true, true ); - - // start the timer when you know the true count including fixed points - - // Quick mod - TV -#if defined(_WIN32) - __time64_t atime = 0; -#else - time_t atime = 0; -#endif - if (comm) { - qtimer( atime, 0 ); - comm->CommPostMessage( Communicator::NUM_RECORDS, count ); - } - - count = 0; - - for (int i = 0; i < m_cols; i++) { - - for (int j = 0; j < m_rows; j++) { - - PixelRef curs = PixelRef( i, j ); - - if ( getPoint( curs ).getState() & Point::FILLED ) { - - getPoint( curs ).m_node = new Node; - m_attributes.insertRow( curs ); - - sparkPixel2(curs,1,maxdist); // make flag of 1 suggests make this node, don't set reciprocral process flags on those you can see - // maxdist controls how far to see out to - - count++; // <- increment count - - if (comm) { - if (qtimer( atime, 500 )) { - if (comm->IsCancelled()) { - tagState( false, true ); // <- the state field has been used for tagging visited nodes... set back to a state variable - // (well, actually, no it hasn't!) - // Should clear all nodes and attributes here: - // Clear nodes - for (int ii = 0; ii < m_cols; ii++) { - for (int jj = 0; jj < m_rows; jj++) { - if (m_points[ii][jj].m_node) { - delete m_points[ii][jj].m_node; - m_points[ii][jj].m_node = NULL; - } - } - } - // Clear attributes - m_attributes.clear(); - m_displayed_attribute = -2; - // - throw Communicator::CancelledException(); - } - comm->CommPostMessage( Communicator::CURRENT_RECORD, count ); - } - } // if (comm) - } // if ( getPoint( curs ).getState() & Point::FILLED ) - } // rows - } // cols - - tagState( false, true ); // <- the state field has been used for tagging visited nodes... set back to a state variable - - // keeping lines blocked now is wasteful of memory... free the memory involved - unblockLines(false); - - // and add grid connections - // (this is easier than trying to work it out per pixel as we calculate visibility) - addGridConnections(); - - // the graph is processed: - m_processed = true; - if (boundarygraph) { - m_boundarygraph = true; - } - - // override and reset: - m_displayed_attribute = -2; - setDisplayedAttribute(connectivity_col); - - return true; -} - -// essentially does the same as sparkGraph2, but designed to go through only -// points tagged for revision, and without a communicator - -bool PointMap::dynamicSparkGraph2() -{ - for (int i = 0; i < m_cols; i++) { - - for (int j = 0; j < m_rows; j++) { - - PixelRef curs = PixelRef( i, j ); - - if ( getPoint( curs ).getState() & Point::FILLED ) { - - sparkPixel2(curs,1); // make flag of 1 suggests make this node, don't set reciprocral process flags on those you can see - - } - } - } - - // and add grid connections - // (this is easier than trying to work it out per pixel as we calculate visibility) - addGridConnections(); - - return true; -} - -// 'make' construct types are: -// 1 -- build this node -// 2 -- register the reciprocal q octant in nodes you can see as requiring processing - -bool PointMap::sparkPixel2(PixelRef curs, int make, double maxdist) -{ - static pvector bins_b[32]; - static float far_bin_dists[32]; - for (int i = 0; i < 32; i++) { - far_bin_dists[i] = 0.0f; - } - int neighbourhood_size = 0; - int max_depth = 0; - double total_dist = 0.0; - double total_dist_sqr = 0.0; - - Point2f centre0 = depixelate(curs); - - for (int q = 0; q < 8; q++) { - - if (!((getPoint(curs).m_processflag) & (1 << q)) ) { - continue; - } - - sparkSieve2 sieve(centre0, maxdist); - int depth = 0; + sparkSieve2 sieve(centre0, maxdist); + int depth = 0; // attempt 0 depth line tests by taken appropriate quadrant // from immediately around centre @@ -2421,20 +1441,18 @@ bool PointMap::sparkPixel2(PixelRef curs, int make, double maxdist) viewport0.top_right.y = centre0.y; break; } - pqmap lines0; - for (size_t m = 0; m < getPoint(curs).m_lines.size(); m++) + std::vector lines0; + for (const Line& line: getPoint(curs).m_lines) { - int key = getPoint(curs).m_lines.key(m); - Line l = getPoint(curs).m_lines.value(m); + Line l = line; if (l.crop(viewport0)) { - lines0.add(key,l); + lines0.push_back(l); } } - sieve.m_gaps.first(); sieve.block(lines0, q); sieve.collectgarbage(); - pvector addlist; + std::vector addlist; for (depth = 1; sieve.hasGaps(); depth++) { @@ -2472,16 +1490,14 @@ bool PointMap::sparkPixel2(PixelRef curs, int make, double maxdist) } // <- for (int q = 0; q < 8; q++) - Point2f point = depixelate(curs); - if (make & 1) { // The bins are cleared in the make function! Point& pt = getPoint( curs ); pt.m_node->make(curs, bins_b, far_bin_dists, pt.m_processflag); // note: make clears bins! - int row = m_attributes.getRowid( curs ); - m_attributes.setValue( row, "Connectivity", float(neighbourhood_size) ); - m_attributes.setValue( row, "Point First Moment", float(total_dist) ); - m_attributes.setValue( row, "Point Second Moment", float(total_dist_sqr) ); + AttributeRow& row = m_attributes->getRow( AttributeKey(curs) ); + row.setValue( "Connectivity", float(neighbourhood_size) ); + row.setValue( "Point First Moment", float(total_dist) ); + row.setValue( "Point Second Moment", float(total_dist_sqr) ); } else { // Clear bins by hand if not using them to make @@ -2496,19 +1512,18 @@ bool PointMap::sparkPixel2(PixelRef curs, int make, double maxdist) return true; } -bool PointMap::sieve2(sparkSieve2& sieve, pvector& addlist, int q, int depth, PixelRef curs) +bool PointMap::sieve2(sparkSieve2& sieve, std::vector& addlist, int q, int depth, PixelRef curs) { bool hasgaps = false; int firstind = 0; - for (sieve.m_gaps.first(); !sieve.m_gaps.is_tail(); (sieve.m_gaps)++) { + for (auto iter = sieve.m_gaps.begin(); iter != sieve.m_gaps.end(); ++iter) { // this goes through all open points - if ((*(sieve.m_gaps)).remove) { + if (iter->remove) { continue; } - for (int ind = (int)ceil((*(sieve.m_gaps)).start * (depth - 0.5) - 0.5); - ind <= (int) floor((*(sieve.m_gaps)).end * (depth + 0.5) + 0.5); ind++) { - + for (int ind = (int)ceil(iter->start * (depth - 0.5) - 0.5); + ind <= (int) floor(iter->end * (depth + 0.5) + 0.5); ind++) { if (ind < firstind) { continue; } @@ -2530,8 +1545,8 @@ bool PointMap::sieve2(sparkSieve2& sieve, pvector& addlist, int q, int if (includes(here)) { hasgaps = true; // centre gap checks to see if the point is blocked itself - bool centregap = (double(ind) >= ((*(sieve.m_gaps)).start * depth) && - double(ind) <= ((*(sieve.m_gaps)).end * depth)); + bool centregap = (double(ind) >= (iter->start * depth) && + double(ind) <= (iter->end * depth)); if (centregap && (getPoint(here).m_state & Point::FILLED)) { // don't repeat axes / diagonals @@ -2554,26 +1569,19 @@ bool PointMap::sieve2(sparkSieve2& sieve, pvector& addlist, int q, int //////////////////////////////////////////////////////////////////////////////////////////////// -bool PointMap::binDisplay(Communicator *comm) +bool PointMap::binDisplay(Communicator *) { - int bindisplay_col = m_attributes.insertColumn("Node Bins"); - - for (int i = 0; i < m_attributes.getRowCount(); i++) { - m_attributes.setValue( i, bindisplay_col, -1 ); - } + int bindisplay_col = m_attributes->insertOrResetColumn("Node Bins"); - for (size_t k = 0; k < m_selection_set.size(); k++) { - Point& p = getPoint(m_selection_set[k]); + for (auto& sel: m_selection_set) { + Point& p = getPoint(sel); // Code for colouring pretty bins: - int count = 1; - int dir = 0; for (int i = 0; i < 32; i++) { Bin& b = p.m_node->bin(i); b.first(); while(!b.is_tail()) { - int row = m_attributes.getRowid( b.cursor() ); - //m_attributes.setValue( row, bindisplay_col, float((i % 8) + 1) ); - m_attributes.setValue( row, bindisplay_col, float(b.distance()) ); + //m_attributes->setValue( row, bindisplay_col, float((i % 8) + 1) ); + m_attributes->getRow(AttributeKey(b.cursor())).setValue( bindisplay_col, float(b.distance()) ); b.next(); } } @@ -2586,998 +1594,81 @@ bool PointMap::binDisplay(Communicator *comm) return true; } -//////////////////////////////////////////////////////////////////////////////////////////////// - -// Isovist analysis -bool PointMap::analyseIsovist(Communicator *comm, MetaGraph& mgraph, bool simple_version) -{ - // note, BSP tree plays with comm counting... - comm->CommPostMessage( Communicator::NUM_STEPS, 2 ); - comm->CommPostMessage( Communicator::CURRENT_STEP, 1 ); - mgraph.makeBSPtree(comm); +// Merge connections... very fiddly indeed... using a simple method for now... +// ...and even that's too complicated... so I'll settle for a very, very simple +// merge points (just a reference to another point --- yes, that simple!) - comm->CommPostMessage( Communicator::CURRENT_STEP, 2 ); +// the first point should have been selected, the second is chosen now: - // Quick mod - TV -#if defined(_WIN32) - __time64_t atime = 0; -#else - time_t atime = 0; -#endif - if (comm) { - qtimer( atime, 0 ); - comm->CommPostMessage( Communicator::NUM_RECORDS, m_point_count ); +bool PointMap::mergePoints(const Point2f& p) +{ + if (!m_selection_set.size()) { + return false; } - int count = 0; - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - PixelRef curs = PixelRef( i, j ); - if (getPoint( curs ).filled()) { - count++; - if (getPoint( curs ).contextfilled() && !curs.iseven()) { - continue; - } - Isovist isovist; - mgraph.makeIsovist(depixelate(curs),isovist); - int row = m_attributes.getRowid(curs); - - isovist.setData(m_attributes,row, simple_version); - Node& node = getPoint(curs).getNode(); - pvector *occ = node.m_occlusion_bins; - size_t k; - for (k = 0; k < 32; k++) { - occ[k].clear(); - node.bin(k).setOccDistance(0.0f); - } - for (k = 0; k < isovist.getOcclusionPoints().size(); k++) { - const PointDist& pointdist = isovist.getOcclusionPoints().at(k); - int bin = whichbin(pointdist.m_point-depixelate(curs)); - // only occlusion bins with a certain distance recorded (arbitrary scale note!) - if (pointdist.m_dist > 1.5) { - PixelRef pix = pixelate(pointdist.m_point); - if (pix != curs) { - occ[bin].push_back(pix); - } - } - node.bin(bin).setOccDistance(pointdist.m_dist); - } - } - if (comm) { - if (qtimer( atime, 500 )) { - if (comm->IsCancelled()) { - throw Communicator::CancelledException(); - } - comm->CommPostMessage( Communicator::CURRENT_RECORD, count ); - } - } + // note that in a multiple selection, the point p is adjusted by the selection bounds + PixelRef bl = pixelate(m_sel_bounds.bottom_left); + PixelRef tr = pixelate(m_sel_bounds.top_right); + // + PixelRef offset = pixelate(p) - PixelRef(tr.x,bl.y); + // + for (auto& sel: m_selection_set) { + PixelRef a = sel; + PixelRef b = ((PixelRef)sel) + offset; + // check in limits: + if (includes(b) && getPoint(b).filled()) { + mergePixels(a,b); } } - + clearSel(); + return true; } -// Graph analysis tools - -bool PointMap::analyseVisual(Communicator *comm, Options& options, bool simple_version) +bool PointMap::unmergePoints() { - // Quick mod - TV -#if defined(_WIN32) - __time64_t atime = 0; -#else - time_t atime = 0; -#endif - if (comm) { - qtimer( atime, 0 ); - comm->CommPostMessage( Communicator::NUM_RECORDS, m_point_count ); + if (!m_selection_set.size()) { + return false; } - - // dX simple version test // TV -//#define _COMPILE_dX_SIMPLE_VERSION - -#ifndef _COMPILE_dX_SIMPLE_VERSION - int cluster_col, control_col, controllability_col; - if(!simple_version) { - if (options.local) { - cluster_col = m_attributes.insertColumn("Visual Clustering Coefficient"); - control_col = m_attributes.insertColumn("Visual Control"); - controllability_col = m_attributes.insertColumn("Visual Controllability"); - } + for (auto& sel: m_selection_set) { + PixelRef a = sel; + unmergePixel(a); } -#endif + clearSel(); + return true; +} - int entropy_col, rel_entropy_col, integ_dv_col, integ_pv_col, integ_tk_col, depth_col, count_col; - if (options.global) { - pstring radius_text; - if (options.radius != -1) { - radius_text = pstring(" R") + pstringify(int(options.radius),"%d"); - } +// Either of the pixels can be given here and the other will also be unmerged +bool PointMap::unmergePixel(PixelRef a) { + PixelRef c = getPoint(a).m_merge; + depthmapX::findAndErase(m_merge_lines, PixelRefPair(a,c)); + getPoint(c).m_merge = NoPixel; + getPoint(c).m_state &= ~Point::MERGED; + getPoint(a).m_merge = NoPixel; + getPoint(a).m_state &= ~Point::MERGED; + return true; +} - // n.b. these must be entered in alphabetical order to preserve col indexing: - // dX simple version test // TV -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - pstring entropy_col_text = pstring("Visual Entropy") + radius_text; - entropy_col = m_attributes.insertColumn(entropy_col_text.c_str()); - } -#endif - - pstring integ_dv_col_text = pstring("Visual Integration [HH]") + radius_text; - integ_dv_col = m_attributes.insertColumn(integ_dv_col_text.c_str()); - -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - pstring integ_pv_col_text = pstring("Visual Integration [P-value]") + radius_text; - integ_pv_col = m_attributes.insertColumn(integ_pv_col_text.c_str()); - pstring integ_tk_col_text = pstring("Visual Integration [Tekl]") + radius_text; - integ_tk_col = m_attributes.insertColumn(integ_tk_col_text.c_str()); - pstring depth_col_text = pstring("Visual Mean Depth") + radius_text; - depth_col = m_attributes.insertColumn(depth_col_text.c_str()); - pstring count_col_text = pstring("Visual Node Count") + radius_text; - count_col = m_attributes.insertColumn(count_col_text.c_str()); - pstring rel_entropy_col_text = pstring("Visual Relativised Entropy") + radius_text; - rel_entropy_col = m_attributes.insertColumn(rel_entropy_col_text.c_str()); - } -#endif - } - - int count = 0; - - for (int i = 0; i < m_cols; i++) { - - for (int j = 0; j < m_rows; j++) { - - PixelRef curs = PixelRef( i, j ); - - if ( getPoint( curs ).filled()) { - - if ((getPoint( curs ).contextfilled() && !curs.iseven()) || - (options.gates_only && getPoint(curs).getDataObject(DataLayers::GATES) == -1)) { - count++; - continue; - } - - if (options.global) { - - for (int ii = 0; ii < m_cols; ii++) { - for (int jj = 0; jj < m_rows; jj++) { - m_points[ii][jj].m_misc = 0; - m_points[ii][jj].m_extent = PixelRef(ii,jj); - } - } - - int total_depth = 0; - int total_nodes = 0; - - pvecint distribution; - prefvec search_tree; - search_tree.push_back(PixelRefList()); - search_tree.tail().push_back(curs); - - int level = 0; - while (search_tree[level].size()) { - search_tree.push_back(PixelRefList()); - distribution.push_back(0); - for (size_t n = search_tree[level].size() - 1; n != paftl::npos; n--) { - Point& p = getPoint(search_tree[level][n]); - if (p.filled() && p.m_misc != ~0) { - total_depth += level; - total_nodes += 1; - distribution.tail() += 1; - if ((int) options.radius == -1 || level < (int) options.radius && - (!p.contextfilled() || search_tree[level][n].iseven())) { - p.m_node->extractUnseen(search_tree[level+1],this,p.m_misc); - p.m_misc = ~0; - if (!p.m_merge.empty()) { - Point& p2 = getPoint(p.m_merge); - if (p2.m_misc != ~0) { - p2.m_node->extractUnseen(search_tree[level+1],this,p2.m_misc); // did say p.misc - p2.m_misc = ~0; - } - } - } - else { - p.m_misc = ~0; - } - } - search_tree[level].pop_back(); - } - level++; - } - int row = m_attributes.getRowid(curs); - // only set to single float precision after divide - // note -- total_nodes includes this one -- mean depth as per p.108 Social Logic of Space - if(!simple_version) { - m_attributes.setValue(row, count_col, float(total_nodes) ); // note: total nodes includes this one - } - // ERROR !!!!!! - if (total_nodes > 1) { - double mean_depth = double(total_depth) / double(total_nodes - 1); - if(!simple_version) { - m_attributes.setValue(row, depth_col, float(mean_depth) ); - } - // total nodes > 2 to avoid divide by 0 (was > 3) - if (total_nodes > 2 && mean_depth > 1.0) { - double ra = 2.0 * (mean_depth - 1.0) / double(total_nodes - 2); - // d-value / p-values from Depthmap 4 manual, note: node_count includes this one - double rra_d = ra / dvalue(total_nodes); - double rra_p = ra / pvalue(total_nodes); - double integ_tk = teklinteg(total_nodes, total_depth); - m_attributes.setValue(row,integ_dv_col,float(1.0/rra_d)); - if(!simple_version) { - m_attributes.setValue(row,integ_pv_col,float(1.0/rra_p)); - } - if (total_depth - total_nodes + 1 > 1) { - if(!simple_version) { - m_attributes.setValue(row,integ_tk_col,float(integ_tk)); - } - } - else { - if(!simple_version) { - m_attributes.setValue(row,integ_tk_col,-1.0f); - } - } - } - else { - m_attributes.setValue(row,integ_dv_col,(float)-1); - if(!simple_version) { - m_attributes.setValue(row,integ_pv_col,(float)-1); - m_attributes.setValue(row,integ_tk_col,(float)-1); - } - } - double entropy = 0.0, rel_entropy = 0.0, factorial = 1.0; - // n.b., this distribution contains the root node itself in distribution[0] - // -> chopped from entropy to avoid divide by zero if only one node - for (size_t k = 1; k < distribution.size(); k++) { - if (distribution[k] > 0) { - double prob = double(distribution[k]) / double(total_nodes - 1); - entropy -= prob * log2(prob); - // Formula from Turner 2001, "Depthmap" - factorial *= double(k + 1); - double q = (pow( mean_depth, double(k) ) / double(factorial)) * exp(-mean_depth); - rel_entropy += (float) prob * log2( prob / q ); - } - } - if(!simple_version) { - m_attributes.setValue(row, entropy_col, float(entropy) ); - m_attributes.setValue(row, rel_entropy_col, float(rel_entropy) ); - } - } - else { - if(!simple_version) { - m_attributes.setValue(row, depth_col,(float)-1); - m_attributes.setValue(row, entropy_col,(float)-1); - m_attributes.setValue(row, rel_entropy_col,(float)-1); - } - } - } - if (options.local) { - - int row = m_attributes.getRowid(curs); - - // This is much easier to do with a straight forward list: - PixelRefList neighbourhood; - PixelRefList totalneighbourhood; - getPoint(curs).m_node->contents(neighbourhood); - - int cluster = 0; - float control = 0.0f; - - for (size_t i = 0; i < neighbourhood.size(); i++) { - int intersect_size = 0, retro_size = 0; - Point& retpt = getPoint(neighbourhood[i]); - if (retpt.filled() && retpt.m_node) { - retpt.m_node->first(); - while (!retpt.m_node->is_tail()) { - retro_size++; - if (neighbourhood.searchindex(retpt.m_node->cursor()) != paftl::npos) { - intersect_size++; - } - totalneighbourhood.add(retpt.m_node->cursor()); // <- note add does nothing if member already exists - retpt.m_node->next(); - } - control += 1.0f / float(retro_size); - cluster += intersect_size; - } - } -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) { - if (neighbourhood.size() > 1) { - m_attributes.setValue(row, cluster_col, float(cluster / double(neighbourhood.size() * (neighbourhood.size() - 1.0))) ); - m_attributes.setValue(row, control_col, float(control) ); - m_attributes.setValue(row, controllability_col, float( double(neighbourhood.size()) / double(totalneighbourhood.size())) ); - } - else { - m_attributes.setValue(row, cluster_col, -1 ); - m_attributes.setValue(row, control_col, -1 ); - m_attributes.setValue(row, controllability_col, -1 ); - } - } -#endif - } - - count++; // <- increment count - } - if (comm) { - if (qtimer( atime, 500 )) { - if (comm->IsCancelled()) { - throw Communicator::CancelledException(); - } - comm->CommPostMessage( Communicator::CURRENT_RECORD, count ); - } - } - } - } - - if (options.global) { - setDisplayedAttribute(integ_dv_col); - } - else if (options.local) { -#ifndef _COMPILE_dX_SIMPLE_VERSION - if(!simple_version) - setDisplayedAttribute(cluster_col); -#endif - } - - return true; -} - -bool PointMap::analyseVisualPointDepth(Communicator *comm) -{ - // n.b., insert columns sets values to -1 if the column already exists - int col = m_attributes.insertColumn("Visual Step Depth"); - - for (int i = 0; i < m_attributes.getRowCount(); i++) { - PixelRef pix = m_attributes.getRowKey(i); - getPoint(pix).m_misc = 0; - getPoint(pix).m_extent = pix; - } - - prefvec search_tree; - search_tree.push_back(PixelRefList()); - for (size_t j = 0; j < m_selection_set.size(); j++) { - // need to convert from ints (m_selection_set) to pixelrefs for this op: - search_tree.tail().push_back(m_selection_set[j]); - } - - int level = 0; - while (search_tree[level].size()) { - search_tree.push_back(PixelRefList()); - for (size_t n = search_tree[level].size() - 1; n != paftl::npos; n--) { - Point& p = getPoint(search_tree[level][n]); - if (p.filled() && p.m_misc != ~0) { - int row = m_attributes.getRowid(search_tree[level][n]); - m_attributes.setValue(row,col,float(level)); - if (!p.contextfilled() || search_tree[level][n].iseven() || level == 0) { - p.m_node->extractUnseen(search_tree[level+1],this,p.m_misc); - p.m_misc = ~0; - if (!p.m_merge.empty()) { - Point& p2 = getPoint(p.m_merge); - if (p2.m_misc != ~0) { - int row = m_attributes.getRowid(p.m_merge); - m_attributes.setValue(row,col,float(level)); - p2.m_node->extractUnseen(search_tree[level+1],this,p2.m_misc); // did say p.misc - p2.m_misc = ~0; - } - } - } - else { - p.m_misc = ~0; - } - } - } - level++; - } - - // force redisplay: - m_displayed_attribute = -2; - setDisplayedAttribute(col); - - return true; -} - -// This is a slow algorithm, but should give the correct answer -// for demonstrative purposes - -bool PointMap::analyseMetric(Communicator *comm, Options& options) -{ - // Quick mod - TV -#if defined(_WIN32) - __time64_t atime = 0; -#else - time_t atime = 0; -#endif - if (comm) { - qtimer( atime, 0 ); - comm->CommPostMessage( Communicator::NUM_RECORDS, m_point_count ); - } - - pstring radius_text; - if (options.radius != -1.0) { - if (options.radius > 100.0) { - radius_text = pstring(" R") + pstringify(options.radius,"%.f"); - } - else if (m_region.width() < 1.0) { - radius_text = pstring(" R") + pstringify(options.radius,"%.4f"); - } - else { - radius_text = pstring(" R") + pstringify(options.radius,"%.2f"); - } - } - // n.b. these must be entered in alphabetical order to preserve col indexing: - pstring mspa_col_text = pstring("Metric Mean Shortest-Path Angle") + radius_text; - int mspa_col = m_attributes.insertColumn(mspa_col_text.c_str()); - pstring mspl_col_text = pstring("Metric Mean Shortest-Path Distance") + radius_text; - int mspl_col = m_attributes.insertColumn(mspl_col_text.c_str()); - pstring dist_col_text = pstring("Metric Mean Straight-Line Distance") + radius_text; - int dist_col = m_attributes.insertColumn(dist_col_text.c_str()); - pstring count_col_text = pstring("Metric Node Count") + radius_text; - int count_col = m_attributes.insertColumn(count_col_text.c_str()); - - int count = 0; - - for (int i = 0; i < m_cols; i++) { - - for (int j = 0; j < m_rows; j++) { - - PixelRef curs = PixelRef( i, j ); - - if ( getPoint( curs ).filled() ) { - - if ( options.gates_only && getPoint(curs).getDataObject(DataLayers::GATES) == -1) { - count++; - continue; - } - - for (int ii = 0; ii < m_cols; ii++) { - for (int jj = 0; jj < m_rows; jj++) { - m_points[ii][jj].m_misc = 0; - m_points[ii][jj].m_dist = -1.0f; - m_points[ii][jj].m_cumangle = 0.0f; - } - } - - float euclid_depth = 0.0f; - float total_depth = 0.0f; - float total_angle = 0.0f; - int total_nodes = 0; - - // note that m_misc is used in a different manner to analyseGraph / PointDepth - // here it marks the node as used in calculation only - - pqvector search_list; - search_list.add(MetricTriple(0.0f,curs,NoPixel)); - int level = 0; - while (search_list.size()) { - MetricTriple here = search_list[0]; - search_list.remove_at(0); - if (options.radius != -1.0 && (here.dist * m_spacing) > options.radius) { - break; - } - Point& p = getPoint(here.pixel); - // nb, the filled check is necessary as diagonals seem to be stored with 'gaps' left in - if (p.filled() && p.m_misc != ~0) { - p.m_node->extractMetric(search_list,this,here); - p.m_misc = ~0; - if (!p.m_merge.empty()) { - Point& p2 = getPoint(p.m_merge); - if (p2.m_misc != ~0) { - p2.m_cumangle = p.m_cumangle; - p2.m_node->extractMetric(search_list,this,MetricTriple(here.dist,p.m_merge,NoPixel)); - p2.m_misc = ~0; - } - } - total_depth += float(here.dist * m_spacing); - total_angle += p.m_cumangle; - euclid_depth += float(m_spacing * dist(here.pixel,curs)); - total_nodes += 1; - } - } - - int row = m_attributes.getRowid(curs); - m_attributes.setValue(row, mspa_col, float(double(total_angle) / double(total_nodes)) ); - m_attributes.setValue(row, mspl_col, float(double(total_depth) / double(total_nodes)) ); - m_attributes.setValue(row, dist_col, float(double(euclid_depth) / double(total_nodes)) ); - m_attributes.setValue(row, count_col, float(total_nodes) ); - - count++; // <- increment count - } - if (comm) { - if (qtimer( atime, 500 )) { - if (comm->IsCancelled()) { - throw Communicator::CancelledException(); - } - comm->CommPostMessage( Communicator::CURRENT_RECORD, count ); - } - } - } - } - - m_displayed_attribute = -2; - setDisplayedAttribute(mspl_col); - - return true; -} - -bool PointMap::analyseMetricPointDepth(Communicator *comm) -{ - // n.b., insert columns sets values to -1 if the column already exists - int path_angle_col = m_attributes.insertColumn("Metric Step Shortest-Path Angle"); - int path_length_col = m_attributes.insertColumn("Metric Step Shortest-Path Length"); - int dist_col; - if (m_selection_set.size() == 1) { - // Note: Euclidean distance is currently only calculated from a single point - dist_col = m_attributes.insertColumn("Metric Straight-Line Distance"); - } - - for (int i = 0; i < m_attributes.getRowCount(); i++) { - PixelRef pix = m_attributes.getRowKey(i); - getPoint(pix).m_misc = 0; - getPoint(pix).m_dist = -1.0f; - getPoint(pix).m_cumangle = 0.0f; - } - - // in order to calculate Penn angle, the MetricPair becomes a metric triple... - pqvector search_list; // contains root point - - for (size_t k = 0; k < m_selection_set.size(); k++) { - search_list.add(MetricTriple(0.0f,m_selection_set[k],NoPixel)); - } - - // note that m_misc is used in a different manner to analyseGraph / PointDepth - // here it marks the node as used in calculation only - int count = 0; - int level = 0; - while (search_list.size()) { - MetricTriple here = search_list[0]; - search_list.remove_at(0); - Point& p = getPoint(here.pixel); - // nb, the filled check is necessary as diagonals seem to be stored with 'gaps' left in - if (p.filled() && p.m_misc != ~0) { - p.m_node->extractMetric(search_list,this,here); - p.m_misc = ~0; - int row = m_attributes.getRowid(here.pixel); - m_attributes.setValue(row, path_length_col, float(m_spacing * here.dist) ); - m_attributes.setValue(row, path_angle_col, float(p.m_cumangle) ); - if (m_selection_set.size() == 1) { - // Note: Euclidean distance is currently only calculated from a single point - m_attributes.setValue(row, dist_col, float(m_spacing * dist(here.pixel,m_selection_set[0])) ); - } - if (!p.m_merge.empty()) { - Point& p2 = getPoint(p.m_merge); - if (p2.m_misc != ~0) { - p2.m_cumangle = p.m_cumangle; - int row = m_attributes.getRowid(p.m_merge); - m_attributes.setValue(row, path_length_col, float(m_spacing * here.dist) ); - m_attributes.setValue(row, path_angle_col, float(p2.m_cumangle) ); - if (m_selection_set.size() == 1) { - // Note: Euclidean distance is currently only calculated from a single point - m_attributes.setValue(row, dist_col, float(m_spacing * dist(p.m_merge,m_selection_set[0])) ); - } - p2.m_node->extractMetric(search_list,this,MetricTriple(here.dist,p.m_merge,NoPixel)); - p2.m_misc = ~0; - } - } - } - } - - m_displayed_attribute = -2; - setDisplayedAttribute(path_length_col); - - return true; -} - -/////////////////////////////////////////////////////////////////////////////////// - -// This is based on the Metric Step Depth calculation -// - -bool PointMap::analyseAngular(Communicator *comm, Options& options) -{ - // Quick mod - TV -#if defined(_WIN32) - __time64_t atime = 0; -#else - time_t atime = 0; -#endif - if (comm) { - qtimer( atime, 0 ); - comm->CommPostMessage( Communicator::NUM_RECORDS, m_point_count ); - } - - pstring radius_text; - if (options.radius != -1.0) { - if (m_region.width() > 100.0) { - radius_text = pstring(" R") + pstringify(options.radius,"%.f"); - } - else if (m_region.width() < 1.0) { - radius_text = pstring(" R") + pstringify(options.radius,"%.4f"); - } - else { - radius_text = pstring(" R") + pstringify(options.radius,"%.2f"); - } - } - // n.b. these must be entered in alphabetical order to preserve col indexing: - pstring mean_depth_col_text = pstring("Angular Mean Depth") + radius_text; - int mean_depth_col = m_attributes.insertColumn(mean_depth_col_text.c_str()); - pstring total_detph_col_text = pstring("Angular Total Depth") + radius_text; - int total_depth_col = m_attributes.insertColumn(total_detph_col_text.c_str()); - pstring count_col_text = pstring("Angular Node Count") + radius_text; - int count_col = m_attributes.insertColumn(count_col_text.c_str()); - - int count = 0; - - for (int i = 0; i < m_cols; i++) { - - for (int j = 0; j < m_rows; j++) { - - PixelRef curs = PixelRef( i, j ); - - if ( getPoint( curs ).filled() ) { - - if ( options.gates_only && getPoint(curs).getDataObject(DataLayers::GATES) == -1) { - count++; - continue; - } - - for (int ii = 0; ii < m_cols; ii++) { - for (int jj = 0; jj < m_rows; jj++) { - m_points[ii][jj].m_misc = 0; - m_points[ii][jj].m_dist = 0.0f; - m_points[ii][jj].m_cumangle = -1.0f; - } - } - - float total_angle = 0.0f; - int total_nodes = 0; - - // note that m_misc is used in a different manner to analyseGraph / PointDepth - // here it marks the node as used in calculation only - - pqvector search_list; - search_list.add(AngularTriple(0.0f,curs,NoPixel)); - getPoint(curs).m_cumangle = 0.0f; - int level = 0; - while (search_list.size()) { - AngularTriple here = search_list[0]; - search_list.remove_at(0); - if (options.radius != -1.0 && here.angle > options.radius) { - break; - } - Point& p = getPoint(here.pixel); - // nb, the filled check is necessary as diagonals seem to be stored with 'gaps' left in - if (p.filled() && p.m_misc != ~0) { - p.m_node->extractAngular(search_list,this,here); - p.m_misc = ~0; - if (!p.m_merge.empty()) { - Point& p2 = getPoint(p.m_merge); - if (p2.m_misc != ~0) { - p2.m_cumangle = p.m_cumangle; - p2.m_node->extractAngular(search_list,this,AngularTriple(here.angle,p.m_merge,NoPixel)); - p2.m_misc = ~0; - } - } - total_angle += p.m_cumangle; - total_nodes += 1; - } - } - - int row = m_attributes.getRowid(curs); - if (total_nodes > 0) { - m_attributes.setValue(row, mean_depth_col, float(double(total_angle) / double(total_nodes)) ); - } - m_attributes.setValue(row, total_depth_col, total_angle ); - m_attributes.setValue(row, count_col, float(total_nodes) ); - - count++; // <- increment count - } - if (comm) { - if (qtimer( atime, 500 )) { - if (comm->IsCancelled()) { - throw Communicator::CancelledException(); - } - comm->CommPostMessage( Communicator::CURRENT_RECORD, count ); - } - } - } - } - - m_displayed_attribute = -2; - setDisplayedAttribute(mean_depth_col); - - return true; -} - -bool PointMap::analyseAngularPointDepth(Communicator *comm) -{ - // n.b., insert columns sets values to -1 if the column already exists - int path_angle_col = m_attributes.insertColumn("Angular Step Depth"); - - for (int i = 0; i < m_attributes.getRowCount(); i++) { - PixelRef pix = m_attributes.getRowKey(i); - getPoint(pix).m_misc = 0; - getPoint(pix).m_dist = 0.0f; - getPoint(pix).m_cumangle = -1.0f; - } - - pqvector search_list; // contains root point - - for (size_t k = 0; k < m_selection_set.size(); k++) { - search_list.add(AngularTriple(0.0f,m_selection_set[k],NoPixel)); - getPoint(m_selection_set[k]).m_cumangle = 0.0f; - } - - // note that m_misc is used in a different manner to analyseGraph / PointDepth - // here it marks the node as used in calculation only - int count = 0; - int level = 0; - while (search_list.size()) { - AngularTriple here = search_list[0]; - search_list.remove_at(0); - Point& p = getPoint(here.pixel); - // nb, the filled check is necessary as diagonals seem to be stored with 'gaps' left in - if (p.filled() && p.m_misc != ~0) { - p.m_node->extractAngular(search_list,this,here); - p.m_misc = ~0; - int row = m_attributes.getRowid(here.pixel); - m_attributes.setValue(row, path_angle_col, float(p.m_cumangle) ); - if (!p.m_merge.empty()) { - Point& p2 = getPoint(p.m_merge); - if (p2.m_misc != ~0) { - p2.m_cumangle = p.m_cumangle; - int row = m_attributes.getRowid(p.m_merge); - m_attributes.setValue(row, path_angle_col, float(p2.m_cumangle) ); - p2.m_node->extractAngular(search_list,this,AngularTriple(here.angle,p.m_merge,NoPixel)); - p2.m_misc = ~0; - } - } - } - } - - m_displayed_attribute = -2; - setDisplayedAttribute(path_angle_col); - - return true; -} - -bool PointMap::analyseThruVision(Communicator *comm) -{ - // Quick mod - TV -#if defined(_WIN32) - __time64_t atime = 0; -#else - time_t atime = 0; -#endif - if (comm) { - qtimer( atime, 0 ); - comm->CommPostMessage( Communicator::NUM_RECORDS, m_point_count ); - } - - /* - // original version - int i; - for (i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - PixelRef curs = PixelRef( i, j ); - getPoint( curs ).m_misc = 0; - } - } - - for (i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - PixelRef curs = PixelRef( i, j ); - Point& p = getPoint(curs); - if ( getPoint( curs ).filled() ) { - p.m_node->first(); - while (!p.m_node->is_tail()) { - PixelRef x = p.m_node->cursor(); - Line l(depixelate(curs),depixelate(x)); - PixelRefList pixels = pixelateLine(l,1); - for (int k = 1; k < pixels.size() - 1; k++) { - getPoint(pixels[k]).m_misc += 1; - } - p.m_node->next(); - } - } - } - } - - int col = m_attributes.insertColumn("Through vision"); - - for (i = 0; i < m_attributes.getRowCount(); i++) { - PixelRef curs = m_attributes.getRowKey(i); - m_attributes.setValue(i,col,getPoint(curs).m_misc); - getPoint(curs).m_misc = 0; - } - - setDisplayedAttribute(col); - */ - - // current version (not sure of differences!) - int i; - for (i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - PixelRef curs = PixelRef( i, j ); - getPoint( curs ).m_misc = 0; - } - } - - int count = 0; - for (i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - pvecint seengates; - PixelRef curs = PixelRef( i, j ); - Point& p = getPoint(curs); - if ( getPoint( curs ).filled() ) { - p.m_node->first(); - while (!p.m_node->is_tail()) { - PixelRef x = p.m_node->cursor(); - Line li = Line(depixelate(x),depixelate(curs)); - PixelRefList pixels = quickPixelateLine(x,curs); - for (size_t k = 1; k < pixels.size() - 1; k++) { - getPoint(pixels[k]).m_misc += 1; - int index = m_attributes.getRowid(pixels[k]); - int gate = (index != -1) ? (int)m_attributes.getValue(index,g_col_gate) : -1; - if (gate != -1 && seengates.searchindex(gate) == paftl::npos) { - m_attributes.incrValue(index, g_col_gate_counts); - seengates.add(gate,paftl::ADD_HERE); - } - } - p.m_node->next(); - } - // only increment count for actual filled points - count++; - } - if (comm) { - if (qtimer( atime, 500 )) { - if (comm->IsCancelled()) { - throw Communicator::CancelledException(); - } - comm->CommPostMessage( Communicator::CURRENT_RECORD, count ); - } - } - } - } - - int col = m_attributes.insertColumn("Through vision"); - - for (i = 0; i < m_attributes.getRowCount(); i++) { - PixelRef curs = m_attributes.getRowKey(i); - m_attributes.setValue(i,col,(float)getPoint(curs).m_misc); - getPoint(curs).m_misc = 0; - } - - setDisplayedAttribute(-2); - setDisplayedAttribute(col); -/* - for (i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - PixelRef curs = PixelRef( i, j ); - Point& p = getPoint(curs); - int thisrow = m_attributes.getRowIndex(curs); - if ( getPoint( curs ).filled() ) { - p.m_node->first(); - while (!p.m_node->is_tail()) { - PixelRef x = p.m_node->cursor(); - Line l(depixelate(curs),depixelate(x)); - PixelRefList pixels = pixelateLine(l,1); - for (int k = 1; k < pixels.size() - 1; k++) { - getPoint(pixels[k]).m_misc += m_attributes.getValue(thisrow,col) * 0.001; - } - p.m_node->next(); - } - } - } - } - - int col2 = m_attributes.insertColumn("Through vision 2 step"); - - for (i = 0; i < m_attributes.getRowCount(); i++) { - PixelRef curs = m_attributes.getRowKey(i); - m_attributes.setValue(i,col2,getPoint(curs).m_misc); - getPoint(curs).m_misc = 0; - } - - for (i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - PixelRef curs = PixelRef( i, j ); - Point& p = getPoint(curs); - int thisrow = m_attributes.getRowIndex(curs); - if ( getPoint( curs ).filled() ) { - p.m_node->first(); - while (!p.m_node->is_tail()) { - PixelRef x = p.m_node->cursor(); - Line l(depixelate(curs),depixelate(x)); - PixelRefList pixels = pixelateLine(l,1); - for (int k = 1; k < pixels.size() - 1; k++) { - getPoint(pixels[k]).m_misc += m_attributes.getValue(thisrow,col2) * 0.001; - } - p.m_node->next(); - } - } - } - } - - int col3 = m_attributes.insertColumn("Through vision 3 step"); - - for (i = 0; i < m_attributes.getRowCount(); i++) { - PixelRef curs = m_attributes.getRowKey(i); - m_attributes.setValue(i,col3,getPoint(curs).m_misc); - getPoint(curs).m_misc = 0; - } -*/ - return true; -} - -/////////////////////////////////////////////////////////////////////////////////// - -// Merge connections... very fiddly indeed... using a simple method for now... -// ...and even that's too complicated... so I'll settle for a very, very simple -// merge points (just a reference to another point --- yes, that simple!) - -// the first point should have been selected, the second is chosen now: - -bool PointMap::mergePoints(const Point2f& p) -{ - if (!m_selection_set.size()) { - return false; - } - - // note that in a multiple selection, the point p is adjusted by the selection bounds - PixelRef bl = pixelate(m_sel_bounds.bottom_left); - PixelRef tr = pixelate(m_sel_bounds.top_right); - // - PixelRef offset = pixelate(p) - PixelRef(tr.x,bl.y); - // - for (size_t i = 0; i < m_selection_set.size(); i++) { - PixelRef a = m_selection_set[i]; - PixelRef b = ((PixelRef)m_selection_set[i]) + offset; - // check in limits: - if (includes(b) && getPoint(b).filled()) { - mergePixels(a,b); - } - } - clearSel(); - - return true; -} - -bool PointMap::unmergePoints() -{ - if (!m_selection_set.size()) { - return false; - } - for (size_t i = 0; i < m_selection_set.size(); i++) { - PixelRef a = m_selection_set[i]; - mergePixels(a,a); - } - clearSel(); - return true; -} - -bool PointMap::mergePixels(PixelRef a, PixelRef b) -{ - bool altered = false; - if (a == b && !getPoint(a).m_merge.empty()) { - PixelRef c = getPoint(a).m_merge; - m_merge_lines.remove_at(m_merge_lines.searchindex(PixelRefPair(a,c))); - getPoint(c).m_merge = NoPixel; - getPoint(c).m_state &= ~Point::MERGED; - getPoint(a).m_merge = NoPixel; - getPoint(a).m_state &= ~Point::MERGED; - altered = true; +bool PointMap::mergePixels(PixelRef a, PixelRef b) +{ + if (a == b && !getPoint(a).m_merge.empty()) { + unmergePixel(a); } if (a != b && getPoint(a).m_merge != b) { if (!getPoint(a).m_merge.empty()) { PixelRef c = getPoint(a).m_merge; - m_merge_lines.remove_at(m_merge_lines.searchindex(PixelRefPair(a,c))); + auto it = std::find(m_merge_lines.begin(), m_merge_lines.end(), PixelRefPair(a,c)); + if(it != m_merge_lines.end()) + m_merge_lines.erase(it); getPoint(c).m_merge = NoPixel; getPoint(c).m_state &= ~Point::MERGED; } if (!getPoint(b).m_merge.empty()) { PixelRef c = getPoint(b).m_merge; - m_merge_lines.remove_at(m_merge_lines.searchindex(PixelRefPair(b,c))); + auto it = std::find(m_merge_lines.begin(), m_merge_lines.end(), PixelRefPair(b,c)); + if(it != m_merge_lines.end()) + m_merge_lines.erase(it); getPoint(c).m_merge = NoPixel; getPoint(c).m_state &= ~Point::MERGED; } @@ -3585,20 +1676,19 @@ bool PointMap::mergePixels(PixelRef a, PixelRef b) getPoint(a).m_state |= Point::MERGED; getPoint(b).m_merge = a; getPoint(b).m_state |= Point::MERGED; - m_merge_lines.add(PixelRefPair(a,b)); - altered = true; + m_merge_lines.push_back(PixelRefPair(a,b)); } // actually this return now triggers redraw whatever // rather than passing back altered status (as a point must be deselected) - return true; // altered; + return true; } void PointMap::mergeFromShapeMap(const ShapeMap& shapemap) { - const pqmap& polygons = shapemap.getAllShapes(); - for (size_t i = 0; i < polygons.size(); i++) { - const SalaShape& poly = polygons[i]; + const std::map& polygons = shapemap.getAllShapes(); + for (auto polygon: polygons) { + const SalaShape& poly = polygon.second; if (poly.isLine()) { PixelRef a = pixelate(poly.getLine().start()); PixelRef b = pixelate(poly.getLine().end()); @@ -3609,390 +1699,11 @@ void PointMap::mergeFromShapeMap(const ShapeMap& shapemap) } } -////////////////////////////////////////////////////////////////////////////////// - -/* -bool PointMap::analyseGraph(Communicator *comm, Graph *graph) +bool PointMap::isPixelMerged(const PixelRef& a) { - int atime = 0; - if (comm) { - qtimer( atime, 0 ); - comm->CommPostMessage( Communicator::NUM_RECORDS, m_point_count ); - } - - int count = 0; - - SparkTree analyser_tree; - - for (int ii = 0; ii < m_cols; ii++) { - for (int jj = 0; jj < m_rows; jj++) { - PixelRef curs = PixelRef( ii, jj ); - if ( !getPoint( curs ).emptyorblocked() ) { - analyser_tree.set(curs); - } - } - } - analyser_tree.invert(); - - for (int i = 0; i < m_cols; i++) { - - for (int j = 0; j < m_rows; j++) { - - PixelRef curs = PixelRef( i, j ); - - if ( !getPoint( curs ).emptyorblocked() ) { - - SparkTree global = analyser_tree; - - int total_depth = 0; - int total_nodes = 0; - - prefvec search_tree; - - search_tree.push_back(PixelRefList()); - -// global.extractUnseen(search_tree[0], *getPoint( curs ).m_spark_tree); - - int level = 0; - while (search_tree[level].size()) { - search_tree.push_back(PixelRefList()); - for (int n = search_tree[level].size() - 1; n != paftl::npos; n--) { - Point& p = getPoint(search_tree[level][n]); - if (!p.emptyorblocked()) { - total_depth += level + 1; - total_nodes += 1; -// global.extractUnseen(search_tree[level+1],*p.m_spark_tree); - } - } - level++; - } - graph->m_nodes.getAttributes(getPoint(curs).m_noderef).intval(AttrHeader::DEPTH) = total_depth; - graph->m_nodes.getAttributes(getPoint(curs).m_noderef).intval(AttrHeader::GRAPH_SIZE) = total_nodes; - - count++; // <- increment count - } - - if (comm) { - if (qtimer( atime, 500 )) { - if (comm->IsCancelled()) { - throw Communicator::CancelledException(); - } - comm->CommPostMessage( Communicator::CURRENT_RECORD, count ); - } - } - } - } - - graph->m_nodes.setWhichAttributes( GraphVertexList::GLOBAL ); - - return true; -} -*/ -/* -bool PointMap::analysePointDepth(Communicator *comm, Graph *graph) -{ - SparkTree analyser_tree; - - for (int ii = 0; ii < m_cols; ii++) { - for (int jj = 0; jj < m_rows; jj++) { - PixelRef curs = PixelRef( ii, jj ); - if ( !getPoint( curs ).emptyorblocked() ) { - analyser_tree.set(curs); - } - } - } - analyser_tree.invert(); - - PixelRefList selset; - - for (int i = 0; i < m_cols; i++) { - - for (int j = 0; j < m_rows; j++) { - - for (int k = 0; k < m_selection_set.size(); k++) { - - PixelRef curs(i,j); - - if (m_selection_set[k] == getPoint(curs).getRef()) { - - selset.push_back(curs); - graph->m_nodes.getAttributes(getPoint(curs).getRef()).intval(AttrHeader::POINT_DEPTH) = 0; - - } - } - } - } - - prefvec search_tree; - search_tree.push_back(selset); - - int level = 0; - while (search_tree[level].size()) { - search_tree.push_back(PixelRefList()); - for (int n = search_tree[level].size() - 1; n != paftl::npos; n--) { - Point& p = getPoint(search_tree[level][n]); - if (!p.emptyorblocked()) { - graph->m_nodes.getAttributes(p.getRef()).intval(AttrHeader::POINT_DEPTH) = level; -// analyser_tree.extractUnseen(search_tree[level+1],*p.m_spark_tree); - } - } - level++; - } - - return true; -} -*/ -///////////////////////////////////////////////////////////////////////////////// - -// Optimization level: -// 0 --- fast --- 'empty' assumption and 'sensible' assumption -// 1 --- med --- 'sensible' assumption -// 2 --- slow --- no assumptions - -// I'm just going to junk this one completely! -/* -bool PointMap::makeGraph( Graph& graph, int optimization_level, Communicator *comm) -{ - makeConstants(); - - if (!m_spacepix) { - return false; - } - int atime = 0; - if (comm) { - qtimer( atime, 0 ); - comm->CommPostMessage( Communicator::NUM_RECORDS, 8 * m_point_count ); - } - - // pre-label --- allows faster node access later on - int count = tagState( true, false ); - - // tell the graph how many nodes you're going to write... makes things easy later on... - if (!graph.m_nodes.openwrite(count)) { - tagState( false, false ); - return false; - } - - // method 1b: getting a little less forceful still - - // for angular analysis: - // each is put in a 'bin' which can be retrieved later. - // the bins are first filled by the algorithm into separate pvectors - // next, when storing, the points are put into a list, and the references stored - // as a list afterwards --- this allows easy translation between straight depthmap - // and depthmap angular / agent - pmap bins[ GraphVertex::bin_count ]; - - count = 0; - - for (int i = 0; i < m_cols; i++) { - - for (int j = 0; j < m_rows; j++) { - - PixelRef curs = PixelRef( i, j ); - - int far_node = -1; - double far_dist = -1.0; - double total_dist = 0.0; - - if ( !getPoint( curs ).emptyorblocked() ) { - - int n = count / 8; - graph.m_nodes.add( n, GraphVertex() ); - - // q quadrants: - // - // \ 6 | 7 / - // 0 \ | / 1 - // - - - - - // 2 / | \ 3 - // / 4 | 5 \ - // - - for (int q = 0; q < 8; q++) { - - for (int r = 0; r < g_gradients.size(); r++) { - - if (r == 0 && (q == 2 || q == 3 || q == 5 || q == 7)) { // avoid duplicating 0,1 gradients - r++; - } - if (r == 1 && q / 4 == 1) { // avoid duplicating 1,1 gradients - r++; - } - - int x = g_gradients[r].x(q); - int y = g_gradients[r].y(q); - - int top = remaining(i,j,abs(x),abs(y),q); - - bool broken = false; - for (int here = 1; here <= top && !broken; here++) { - - PixelRef last( u(i,x,here-1), v(j,y,here-1) ); - PixelRef next( u(i,x,here), v(j,y,here) ); - - if ( getPoint( next ).emptyorblocked() ) { - if ( g_gradients[r].length < 5.0f || optimization_level != 0) { - // test anyway, just in case there's no pixel due to a coarse flood fill - Line line( depixelate(last), depixelate(next) ); - if (m_spacepix->intersect(line)) { - broken = true; // It really has been broken! Stop. - } - } - else { - broken = true; - } - } - else { - if (here == 1 && optimization_level != 2 && g_gradients[r].length > 25.0f) { - // make a resolution approximation: (code fully tested as of version 0.7b) - // (unfortunately, we can only do this once! - // --- otherwise pixel n - 1 is not guaranteed to have been tested) - PixelRef alpha, beta; - if (q / 4 == 0) { - if (q % 2 == 0) - alpha = next.right(); - else - alpha = next.left(); - if (q / 2 == 0) - beta = alpha.up(); - else - beta = alpha.down(); - } - else { - if (q / 2 == 2) - alpha = next.up(); - else - alpha = next.down(); - if (q % 2 == 0) - beta = alpha.right(); - else - beta = alpha.left(); - } - if (getPoint(alpha).m_misc != n && getPoint(beta).m_misc != n) { - broken = true; - } - } - if (!broken) { - // Standard testing - Line line( depixelate(last), depixelate(next) ); - if (!m_spacepix->intersect(line)) { - getPoint(next).m_misc = n; // <- mark that this was included in this isovist - // note m_spacing is used to scale far_dist appropriately - double this_dist = g_gradients[r].length * double(here) * m_spacing; - if (this_dist > far_dist) { - far_node = getPoint(here).getRef(); - far_dist = this_dist; - } - total_dist += this_dist; - // put the point in the appropriate bin ordered by distance - bins[ g_gradients[r].whichbin(q) ].add( this_dist, pointRef(next) ); - // test to see if this node is the far node - // old depthmap: - // graph.m_nodes[n].push_back( pointRef(next) ); - } - else { - broken = true; - } - } - } - } - } - count++; // <- increment count (note count = nodes * q - - if (comm) { - if (qtimer( atime, 500 )) { - if (comm->IsCancelled()) { - tagState( false, false ); // <- the state field has been used for tagging visited nodes... set back to a state variable - graph.m_nodes.clearAttributes(); // <- any attributes that have been filled in are dropped - graph.m_nodes.remove(); // <- drop the file before throwing exception - throw Communicator::CancelledException(); - } - comm->CommPostMessage( Communicator::CURRENT_RECORD, count ); - } - } - } - Point2f point = depixelate(curs); - graph.m_nodes[n].make( bins ); - // note m_spacing is used to scale far_dist appropriately - graph.m_nodes.commit(point, far_node, float(far_dist), float(total_dist)); - } - } - } - - tagState( false, false ); // <- the state field has been used for tagging visited nodes... set back to a state variable - - graph.m_nodes.close(); - - graph.m_nodes.setWhichAttributes( GraphVertexList::BASIC ); - - return true; -} -*/ -void makePrimes() -{ - for (int i = 1; i < 200; i++) { - bool pr = true; - for (size_t j = 1; j < g_primes.size(); j++) { // Note : ignore 1 - if (i % g_primes[j] == 0) { - pr = false; - break; - } - else if (g_primes[j] * g_primes[j] > i) { - pr = true; - break; - } - } - if (pr) { - g_primes.push_back(i); - } - } -} - -void makeGradients() -{ - // Slow... but can't be bothered to work this out better! - - g_gradients.push_back( Grad(1,0) ); - g_gradients.push_back( Grad(1,1) ); - - for (int i = 1; i < 200; i++) { - for (int j = 1; j < i; j++) { - if (g_primes.searchindex(i) != paftl::npos) { - g_gradients.push_back( Grad(i, j) ); - } - else if (j == 1) { - g_gradients.push_back( Grad(i, j) ); - } - else if (i % j != 0) { - bool pr = true; - for (size_t k = 1; k < g_primes.size(); k++) { // Note: ignore 1 - if (i % g_primes[k] == 0 && j % g_primes[k] == 0) { - pr = false; - break; - } - else if (g_primes[k] > j) { - pr = true; - break; - } - } - if (pr) { - g_gradients.push_back( Grad(i, j) ); - } - } - } - } + return !getPoint(a).m_merge.empty(); } -void PointMap::makeConstants() -{ - if (g_primes.size() == 0) { - makePrimes(); - } - if (g_gradients.size() == 0) { - makeGradients(); - } -} // -2 for point not in visibility graph, -1 for point has no data double PointMap::getLocationValue(const Point2f& point) @@ -4006,12 +1717,13 @@ double PointMap::getLocationValue(const Point2f& point) return val; } - int index = m_attributes.getRowid(pix); - if (index == -1) { + if (!getPoint(pix).filled()) { val = -2; } - else { - val = m_attributes.getValue(index,m_displayed_attribute); + else if (m_displayed_attribute == -1) { + val = static_cast(pix); + } else { + val = m_attributes->getRow(AttributeKey(pix)).getValue(m_displayed_attribute); } return val; @@ -4022,8 +1734,8 @@ double PointMap::getLocationValue(const Point2f& point) void PointMap::addGridConnections() { - for (int i = 0; i < m_attributes.getRowCount(); i++) { - PixelRef curs = m_attributes.getRowKey(i); + for (auto iter = m_attributes->begin(); iter != m_attributes->end(); iter++) { + PixelRef curs = iter->getKey().value; PixelRef node = curs.right(); Point& point = getPoint(curs); point.m_grid_connections = 0; @@ -4037,7 +1749,7 @@ void PointMap::addGridConnections() } bin.next(); } - char dir; + char dir = PixelRef::NODIR; if (i == 0) { dir = PixelRef::VERTICAL; } diff --git a/salalib/pointdata.h b/salalib/pointdata.h index 63c8796d..08518a67 100644 --- a/salalib/pointdata.h +++ b/salalib/pointdata.h @@ -18,17 +18,25 @@ #ifndef __POINTDATA_H__ #define __POINTDATA_H__ +#include "salalib/spacepixfile.h" +#include "genlib/exceptions.h" +#include "salalib/point.h" +#include "salalib/options.h" +#include "salalib/attributetable.h" +#include +#include +#include + class MetaGraph; class PointMap; class PafAgent; -class DataLayers; // deprecated, but still required for data conversion class ShapeMap; class OldPoint1 { friend class PointMap; protected: int m_noderef; - int m_state; + int m_state; }; class OldPoint2 { @@ -40,152 +48,31 @@ class OldPoint2 { }; class Bin; -class Node; class Isovist; struct PixelVec; -class Point { - friend class Bin; - friend class PointMap; - friend class MetaGraph; // <- for file conversion routines - friend class PafAgent; - friend class PafWalker; -public: - enum { EMPTY = 0x0001, FILLED = 0x0002, - BLOCKED = 0x0004, CONTEXTFILLED = 0x0008, // PARTBLOCKED = 0x0008 deprecated - SELECTED = 0x0010, EDGE = 0x0020, MERGED = 0x0040, // PINNED = 0x0020 deprecated - AGENTFILLED = 0x0080, AGENTFADE = 0x0100, AGENTA = 0x0200, AGENTB = 0x0400, AGENTC = 0x0800, - UPDATELINEADDED = 0x1000, UPDATELINEREMOVED = 0x2000, HIGHLIGHT = 0x4000, - AUGMENTED = 0x8000 // AV TV - }; - // note the order of these connections is important and used elsewhere: - enum { CONNECT_E = 0x01, CONNECT_NE = 0x02, CONNECT_N = 0x04, CONNECT_NW = 0x08, - CONNECT_W = 0x10, CONNECT_SW = 0x20, CONNECT_S = 0x40, CONNECT_SE = 0x80 }; -protected: - int m_block; // not used, unlikely to be used, but kept for time being - int m_state; - int m_misc; // <- undocounter / point seen register / agent reference number, etc - char m_grid_connections; // this is a standard set of grid connections, with bits set for E,NE,N,NW,W,SW,S,SE - Node *m_node; // graph links - Point2f m_location; // note: this is large, but it helps allow loading of non-standard grid points, - // whilst allowing them to be displayed as a visibility graph, also speeds up time to - // display - float m_color; // although display color for the point now introduced - PixelRef m_merge; // to merge with another point - PixelRef m_extent; // used to speed up graph analysis (not sure whether or not it breaks it!) - float m_dist; // used to speed up metric analysis - float m_cumangle; // cummulative angle -- used in metric analysis and angular analysis - // hmm... this is for my 3rd attempt at a quick line intersect algo: - // every line that goes through the gridsquare -- memory intensive I know, but what can you do: - // accuracy is imperative here! Calculated pre-fillpoints / pre-makegraph, and (importantly) it works. - pqmap m_lines; - // and when dynamic lines are being used, the process flag tells you which q octants to reprocess: - // - // Deprecated, kept for compatibility with previous versions: - AttrBody *m_attributes; // deprecated: now PointMap has an attribute table to handle this - pmap m_data_objects; // deprecated: (first int is data layer -- presumably the KEY not the index, second int is object ref) - // - int m_processflag; -public: - Point() - { m_state = EMPTY; m_block = 0; m_misc = 0; m_grid_connections = 0; m_node = NULL; m_attributes = NULL; m_processflag = 0; m_merge = NoPixel; m_user_data = NULL; } - Point& operator = (const Point& p) - { throw 1; } - Point(const Point& p) - { throw 1; } - ~Point(); - // - bool empty() const - { return (m_state & EMPTY) == EMPTY; } - bool filled() const - { return (m_state & FILLED) == FILLED; } - bool blocked() const - { return (m_state & BLOCKED) == BLOCKED; } - bool contextfilled() const - { return (m_state & CONTEXTFILLED) == CONTEXTFILLED; } - bool edge() const - { return (m_state & EDGE) == EDGE; } - bool selected() const - { return (m_state & SELECTED) == SELECTED; } - // - // Augmented Vis - bool augmented() const - { return (m_state & AUGMENTED) == AUGMENTED; } - // - void set( int state, int undocounter = 0) - { - m_state = state | (m_state & Point::BLOCKED); // careful not to clear the blocked flag - m_misc = undocounter; - } - void setBlock(bool blocked = true) - { - if (blocked) - m_state |= Point::BLOCKED; - else - m_state &= ~Point::BLOCKED; - } - void setEdge() - { - m_state |= Point::EDGE; - } - // old blocking code - //void addBlock( int block ) - // { m_block |= block; } - //void setBlock( int block ) - // { m_block = block; } - //int getBlock() const - // { return m_block & 0x0000FFFF; } - //void addPartBlock( int block ) - // { m_block |= (block << 16); } - //int getPartBlock() const - // { return (m_block & 0xFFFF0000) >> 16; } - //int getAllBlock() const - // { return m_block | (m_block >> 16); } - //int fillBlocked() const - // { return m_block & 0x06600660; } - int getState() - { return m_state; } - int getMisc() // used as: undocounter, in graph construction, and an agent reference, as well as for making axial maps - { return m_misc; } - void setMisc(int misc) - { m_misc = misc; } - int getDataObject( int layer ) { - size_t var = m_data_objects.searchindex( layer ); - if (var != paftl::npos) - return m_data_objects.at(var); - return -1; // note: not paftl::npos - } - // note -- set merge pixel should be done only through merge pixels - PixelRef getMergePixel() { - return m_merge; - } - Node& getNode() - { return *m_node; } - AttrBody& getAttributes() - { return *m_attributes; } - void setAttributes(const AttrBody& attr) - { if (m_attributes) delete m_attributes; - m_attributes = new AttrBody(attr); } - char getGridConnections() const - { return m_grid_connections; } - float getBinDistance(int i); -public: - ifstream& read(ifstream& stream, int version, int attr_count); - ofstream& write(ofstream& stream, int version); - // -protected: - // for user processing, set their own data on the point: - void *m_user_data; -public: - void *getUserData() - { return m_user_data; } - void setUserData(void *user_data) - { m_user_data = user_data; } -}; + class sparkSieve2; +namespace depthmapX +{ + enum PointMapExceptionType{NO_ISOVIST_ANALYSIS}; + class PointMapException: public depthmapX::RuntimeException { + private: + PointMapExceptionType m_errorType; + public: + PointMapException(PointMapExceptionType errorType, std::string message) : depthmapX::RuntimeException(message) + { + m_errorType = errorType; + } + PointMapExceptionType getErrorType() const { + return m_errorType; + } + }; +} + class PointMap : public PixelBase { friend class PointMaps; @@ -195,127 +82,135 @@ class PointMap : public PixelBase // pushValuesToLayer: this swaps values from a PointMap to a DataLayer, and it needs to be changed in the future // (e.g., when making DataLayers into ShapeMaps) friend class MetaGraph; +public: + bool m_hasIsovistAnalysis = false; + const std::vector& getDrawingFiles() { return *m_drawingFiles; } protected: - pstring m_name; - Point **m_points; // will contain the graph reference when created - //int m_rows; - //int m_cols; - int m_point_count; + std::string m_name; + const QtRegion* m_parentRegion; + const std::vector* m_drawingFiles; + depthmapX::ColumnMatrix m_points; // will contain the graph reference when created + int m_filled_point_count; double m_spacing; Point2f m_offset; Point2f m_bottom_left; - SuperSpacePixel *m_spacepix; bool m_initialised; bool m_blockedlines; bool m_processed; bool m_boundarygraph; int m_undocounter; - pqvector m_merge_lines; - // The attributes table replaces AttrHeader / AttrRow data format - AttributeTable m_attributes; + std::vector m_merge_lines; +private: + std::unique_ptr m_attributes; + std::unique_ptr m_attribHandle; + LayerManagerImpl m_layers; public: - PointMap(const pstring& name = pstring("VGA Map")); - PointMap(const PointMap& pointdata); - PointMap& operator = (const PointMap& pointdata); - void construct( const PointMap& pointdata ); - virtual ~PointMap(); - const pstring& getName() const + PointMap(const QtRegion& parentRegion, const std::vector& drawingFiles, + const std::string& name = std::string("VGA Map")); + virtual ~PointMap() {} + void copy(const PointMap& other); + const std::string& getName() const { return m_name; } - // - // Quick mod - TV -#if defined(_WIN32) - void communicate( __time64_t& atime, Communicator *comm, int record ); -#else + + PointMap(PointMap&& other): + m_parentRegion(std::move(other.m_parentRegion)), + m_drawingFiles(std::move(other.m_drawingFiles)), + m_points(std::move(other.m_points)), + m_attributes(std::move(other.m_attributes)), + m_attribHandle(std::move(other.m_attribHandle)), + m_layers(std::move(other.m_layers)) { + copy(other); + } + PointMap& operator =(PointMap&& other) { + m_parentRegion = std::move(other.m_parentRegion); + m_drawingFiles = std::move(other.m_drawingFiles); + m_points = std::move(other.m_points); + m_attributes = std::move(other.m_attributes); + m_attribHandle = std::move(other.m_attribHandle); + m_layers = std::move(other.m_layers); + copy(other); + return *this; + } + PointMap(const PointMap& ) = delete; + PointMap& operator =(const PointMap&) = delete; + void communicate( time_t& atime, Communicator *comm, int record ); -#endif // constrain is constrain to existing rows / cols PixelRef pixelate( const Point2f& p, bool constrain = true, int scalefactor = 1 ) const; - Point2f depixelate( const PixelRef& p, double scalefactor = 1.0 ) const; // Inlined below + Point2f depixelate( const PixelRef& p, double scalefactor = 1.0 ) const; // Inlined below QtRegion regionate( const PixelRef& p, double border ) const; // Inlined below - bool setSpacePixel(const SuperSpacePixel *spacepix); // (so different threads can use it... dangermouse!) bool setGrid(double spacing, const Point2f& offset = Point2f()); + std::vector> getMergedPixelPairs() + { + // unnecessary converter until the m_merge_lines variable is + // replaced with a std container + std::vector> mergedPixelPairs; + for (size_t i = 0; i < m_merge_lines.size(); i++) { + mergedPixelPairs.push_back(std::make_pair(m_merge_lines[i].a, m_merge_lines[i].b)); + } + return mergedPixelPairs; + } // bool isProcessed() const { return m_processed; } - bool isBoundaryGraph() const - { return m_boundarygraph; } - // - bool fillLines(); void fillLine(const Line& li); bool blockLines(); - void blockLine(int key, const Line& li); + void blockLine(const Line& li); void unblockLines(bool clearblockedflag = true); - void addLineDynamic(LineKey ref,const Line& line); - void removeLineDynamic(LineKey ref,const Line& line); bool fillPoint(const Point2f& p, bool add = true); // use add = false for remove point //bool blockPoint(const Point2f& p, bool add = true); // no longer used // - bool makePoints(const Point2f& seed, int fill_type, Communicator *comm = NULL); // Point2f non-reference deliberate + bool makePoints(const Point2f& seed, int fill_type, Communicator *comm = nullptr); // Point2f non-reference deliberate bool clearPoints(); // Clear *selected* points bool undoPoints(); bool canUndo() const { return !m_processed && m_undocounter != 0; } - // - bool importPoints(istream& stream); - void outputPoints( ostream& stream, char delim ); - void outputMergeLines(ostream& stream, char delim); - // - void makeConstants(); - int tagState(bool settag, bool sparkgraph = false); - bool binMap( Communicator *comm ); - bool sparkGraph( Communicator *comm ); - bool sparkGraph2( Communicator *comm, bool boundarygraph, double maxdist ); - bool dynamicSparkGraph2(); + void outputPoints(std::ostream& stream, char delim ); + void outputMergeLines(std::ostream& stream, char delim); + int tagState(bool settag); + bool sparkGraph2(Communicator *comm, bool boundarygraph, double maxdist ); + bool unmake(bool removeLinks); bool sparkPixel2(PixelRef curs, int make, double maxdist = -1.0); - bool sieve2(sparkSieve2& sieve, pvector& addlist, int q, int depth, PixelRef curs); + bool sieve2(sparkSieve2& sieve, std::vector& addlist, int q, int depth, PixelRef curs); // bool makeGraph( Graph& graph, int optimization_level = 0, Communicator *comm = NULL); // - bool binDisplay(Communicator *comm); - bool analyseIsovist(Communicator *comm, MetaGraph& mgraph, bool simple_version); - bool analyseVisual(Communicator *comm, Options& options, bool simple_version); - bool analyseVisualPointDepth(Communicator *comm); - bool analyseMetric(Communicator *comm, Options& options); - bool analyseMetricPointDepth(Communicator *comm); - bool analyseAngular(Communicator *comm, Options& options); - bool analyseAngularPointDepth(Communicator *comm); - bool analyseThruVision(Communicator *comm); + bool binDisplay(Communicator *); bool mergePoints(const Point2f& p); bool unmergePoints(); + bool unmergePixel(PixelRef a); bool mergePixels(PixelRef a, PixelRef b); void mergeFromShapeMap(const ShapeMap& shapemap); - // - void outputSummary(ostream& myout, char delimiter = '\t'); - void outputMif( ostream& miffile, ostream& midfile ); - void outputNet( ostream& netfile ); - void outputConnections(ostream& myout); - void outputBinSummaries(ostream& myout); - // - // scruffy little helper functions - int u(int i, int x, int s) const - { return i + (x * s); } - int v(int j, int y, int s) const - { return j + (y * s); } - int remaining(int i, int j, int x, int y, int q); - // - Point& getPoint(const PixelRef& p) const - { return m_points[p.x][p.y]; } + bool isPixelMerged(const PixelRef &a); + + void outputSummary(std::ostream& myout, char delimiter = '\t'); + void outputMif(std::ostream& miffile, std::ostream& midfile ); + void outputNet(std::ostream& netfile ); + void outputConnections(std::ostream& myout); + void outputBinSummaries(std::ostream& myout); + + const Point& getPoint(const PixelRef& p) const + { return m_points(static_cast(p.y), static_cast(p.x)); } + Point& getPoint(const PixelRef& p) + { return m_points(static_cast(p.y), static_cast(p.x)); } + depthmapX::BaseMatrix& getPoints() { return m_points; } const int& pointState( const PixelRef& p ) const - { return m_points[p.x][p.y].m_state; } - const int pointObject( const PixelRef& p, int layer_ref ) const - { size_t layer_index = m_points[p.x][p.y].m_data_objects.searchindex(layer_ref); - if (layer_index != paftl::npos) - return m_points[p.x][p.y].m_data_objects.at(layer_index); - return -1; } + { return m_points(static_cast(p.y), static_cast(p.x)).m_state; } // to be phased out bool blockedAdjacent( const PixelRef p ) const; // - int getPointCount() const - { return m_point_count; } + int getFilledPointCount() const + { return m_filled_point_count; } // + void requireIsovistAnalysis() + { + if(!m_hasIsovistAnalysis) { + throw depthmapX::PointMapException(depthmapX::PointMapExceptionType::NO_ISOVIST_ANALYSIS, "Current pointmap does not contain isovist analysis"); + } + } protected: - int expand( const PixelRef p1, const PixelRef p2, PixelRefList& list, int filltype ); + int expand( const PixelRef p1, const PixelRef p2, PixelRefVector& list, int filltype ); // - //void walk( PixelRef& start, int steps, Graph& graph, + //void walk( PixelRef& start, int steps, Graph& graph, // int parity, int dominant_axis, const int grad_pair[] ); // Selection functionality @@ -323,90 +218,82 @@ class PointMap : public PixelBase enum { NO_SELECTION = 0, SINGLE_SELECTION = 1, COMPOUND_SELECTION = 2, LAYER_SELECTION = 4, OVERRIDE_SELECTION = 8 }; int m_selection; bool m_pinned_selection; - pvecint m_selection_set; // n.b., m_selection_set stored as int for compatibility with other map layers - mutable PixelRef s_bl; + std::set m_selection_set; // n.b., m_selection_set stored as int for compatibility with other map layers + mutable PixelRef s_bl; mutable PixelRef s_tr; public: bool isSelected() const // does a selection exist { return m_selection != NO_SELECTION; } - bool isPinned() const - { return m_pinned_selection; } bool clearSel(); // clear the current selection bool setCurSel( QtRegion& r, bool add = false ); // set current selection - bool setCurSel( const pvecint& selset, bool add = false ); - bool overrideSelPixel(PixelRef pix); // set a pixel to selected: careful! - //bool togglePin(); - //bool convertSelToDataObject( MetaGraph& meta_graph ); + bool setCurSel(const std::vector &selset, bool add = false ); // Note: passed by ref, use with care in multi-threaded app - pvecint& getSelSet() + std::set& getSelSet() { return m_selection_set; } - const pvecint& getSelSet() const + const std::set& getSelSet() const { return m_selection_set; } // - PixelRefList getLayerPixels(int layer); - PixelRefList getDataObjectPixels(int layer, int object); - // + PixelRefVector getLayerPixels(int layer); + // Attribute functionality protected: // which attribute is currently displayed: mutable int m_displayed_attribute; public: - int addAttribute(const pstring& name) - { return m_attributes.insertColumn(name); } + int addAttribute(const std::string& name) + { return m_attributes->insertOrResetColumn(name); } void removeAttribute(int col) - { m_attributes.removeColumn(col); } - void setAttribute(PixelRef pix, const pstring& name, float val) - { m_attributes.setValue(m_attributes.getRowid(pix),name,val); } - void incrementAttribute(PixelRef pix, const pstring& name) - { m_attributes.incrValue(m_attributes.getRowid(pix),name); } - // I don't want to do this, but every so often you will need to update this table + { m_attributes->removeColumn(col); } + // I don't want to do this, but every so often you will need to update this table // use const version by preference AttributeTable& getAttributeTable() - { return m_attributes; } + { return *m_attributes.get(); } const AttributeTable& getAttributeTable() const - { return m_attributes; } + { return *m_attributes.get(); } + LayerManagerImpl& getLayers() + { return m_layers; } + const LayerManagerImpl& getLayers() const + { return m_layers; } + AttributeTableHandle& getAttributeTableHandle() + { return *m_attribHandle.get(); } + const AttributeTableHandle& getAttributeTableHandle() const + { return *m_attribHandle.get(); } public: double getDisplayMinValue() const - { return (m_displayed_attribute != -1) ? m_attributes.getMinValue(m_displayed_attribute) : 0; } + { return (m_displayed_attribute != -1) ? m_attributes->getColumn(m_displayed_attribute).getStats().min : 0; } - // Quick mod - TV -#if defined(_WIN32) double getDisplayMaxValue() const - { return (m_displayed_attribute != -1) ? m_attributes.getMaxValue(m_displayed_attribute) : pixelate(m_region.top_right); } -#else - double getDisplayMaxValue() const - { return (m_displayed_attribute != -1) ? m_attributes.getMaxValue(m_displayed_attribute) : pixelate(m_region.top_right).x; } -#endif - // - mutable DisplayParams m_display_params; + { return (m_displayed_attribute != -1) ? m_attributes->getColumn(m_displayed_attribute).getStats().max : pixelate(m_region.top_right).x; } + const DisplayParams& getDisplayParams() const - { return m_attributes.getDisplayParams(m_displayed_attribute); } + { return m_attributes->getColumn(m_displayed_attribute).getDisplayParams(); } // make a local copy of the display params for access speed: void setDisplayParams(const DisplayParams& dp, bool apply_to_all = false) { if (apply_to_all) - m_attributes.setDisplayParams(dp); - else - m_attributes.setDisplayParams(m_displayed_attribute, dp); - m_display_params = dp; } + m_attributes->setDisplayParams(dp); + else + m_attributes->getColumn(m_displayed_attribute).setDisplayParams(dp); + } // public: void setDisplayedAttribute( int col ); // use set displayed attribute instead unless you are deliberately changing the column order: void overrideDisplayedAttribute(int attribute) { m_displayed_attribute = attribute; } - // now, there is a slightly odd thing here: the displayed attribute can go out of step with the underlying + // now, there is a slightly odd thing here: the displayed attribute can go out of step with the underlying // attribute data if there is a delete of an attribute in idepthmap.h, so it just needs checking before returning! int getDisplayedAttribute() const - { if (m_displayed_attribute == m_attributes.m_display_column) return m_displayed_attribute; - if (m_attributes.m_display_column != -2) { - m_displayed_attribute = m_attributes.m_display_column; - m_display_params = m_attributes.getDisplayParams(m_displayed_attribute); + { + if (m_displayed_attribute == m_attribHandle->getDisplayColIndex()) return m_displayed_attribute; + if (m_attribHandle->getDisplayColIndex() != -2) { + m_displayed_attribute = m_attribHandle->getDisplayColIndex(); } return m_displayed_attribute; } - // - double getDisplayedAverage() - { return m_attributes.getAvgValue( m_displayed_attribute ); } - // + + float getDisplayedSelectedAvg() { + return(m_attributes->getSelAvg(m_displayed_attribute)); + } + double getLocationValue(const Point2f& point); // // Screen functionality @@ -429,8 +316,6 @@ class PointMap : public PixelBase bool findNextPoint() const; Point2f getNextPointLocation() const { return getPoint(cur).m_location; } - Point& getNextPoint() const - { return getPoint(cur); } bool findNextRow() const; Line getNextRow() const; bool findNextPointRow() const; @@ -442,7 +327,8 @@ class PointMap : public PixelBase bool findNextMergeLine() const; Line getNextMergeLine() const; bool getPointSelected() const; - PafColor getPointColor() const; + PafColor getPointColor(PixelRef pixelRef) const; + PafColor getCurrentPointColor() const; int getSelCount() { return (int) m_selection_set.size(); } const QtRegion& getSelBounds() const @@ -455,17 +341,18 @@ class PointMap : public PixelBase // this is an odd helper function, value in range 0 to 1 PixelRef pickPixel(double value) const; public: - bool read( ifstream& stream, int version ); - bool write( ofstream& stream, int version ); - void convertAttributes( int which_attributes ); + bool read(std::istream &stream); + bool write(std::ostream &stream); void addGridConnections(); // adds grid connections where graph does not include them + void outputConnectionsAsCSV(std::ostream &myout, std::string delim = ","); + void outputLinksAsCSV(std::ostream &myout, std::string delim = ","); }; // inlined to make thread safe inline Point2f PointMap::depixelate( const PixelRef& p, double scalefactor ) const { - return Point2f( m_bottom_left.x + m_spacing * scalefactor * double(p.x), + return Point2f( m_bottom_left.x + m_spacing * scalefactor * double(p.x), m_bottom_left.y + m_spacing * scalefactor * double(p.y) ); } @@ -481,42 +368,10 @@ inline QtRegion PointMap::regionate( const PixelRef& p, double border ) const ///////////////////////////////////////////////////////////////////////////////////// -class PointMaps : public prefvec -{ -protected: - int m_displayed_map; - SuperSpacePixel *m_spacepix; -public: - PointMaps() { m_displayed_map = -1; m_spacepix = NULL; } - virtual ~PointMaps() {;} - // - void setDisplayedPointMapRef(int i) - { m_displayed_map = i; } - PointMap& getDisplayedPointMap() - { return at(m_displayed_map); } - const PointMap& getDisplayedPointMap() const - { return at(m_displayed_map); } - int getDisplayedPointMapRef() const - { return m_displayed_map; } - int addNewMap(const pstring& name = pstring("VGA Map")); - void removeMap(int i) - { if (m_displayed_map >= i) m_displayed_map--; remove_at(i); } - // - void setSpacePixel(SuperSpacePixel *spacepix) - { m_spacepix = spacepix; for (size_t i = 0; i < size(); i++) at(i).setSpacePixel(spacepix); } - void redoBlockLines() // (flags blockedlines, but also flags that you need to rebuild a bsp tree if you have one) - { for (size_t i = 0; i < size(); i++) { at(i).m_blockedlines = false; } } - // - bool read( ifstream& stream, int version ); - bool write( ofstream& stream, int version, bool displayedmaponly = false ); -}; - -///////////////////////////////////////////////////////////////////////////////////// - // A helper class for metric integration // to allow a dist / PixelRef pair for easy sorting -// (have to do comparison operation on both dist and PixelRef as +// (have to do comparison operation on both dist and PixelRef as // otherwise would have a duplicate key for pqmap / pqvector) struct MetricTriple @@ -569,115 +424,6 @@ inline bool operator > (const AngularTriple& mp1, const AngularTriple& mp2) inline bool operator != (const AngularTriple& mp1, const AngularTriple& mp2) { return (mp1.angle != mp2.angle) || (mp1.pixel != mp2.pixel); } -// - -// A scruffy little helper class for the original makeGraph - -struct Grad { - int a; - int b; - float length; - float ratio; - Grad(int u = -1, int v = -1) - { - a = u; b = v; - length = (float) sqrt(double(u * u) + double(v * v)); - ratio = float(v) / float(u); // v is sometimes 0, thus v/u - } - int x(int dir) const { - int w; - if (dir / 4 == 0) - w = a; - else - w = b; - if (dir % 2 == 0) - w *= -1; - return w; - } - int y(int dir) const { - int w; - if (dir / 4 == 0) - w = b; - else - w = a; - if ((dir / 2) % 2 == 0) - w *= -1; - return w; - } - // q quadrants: - // - // \ 6 | 7 / - // 0 \ | / 1 - // - - - - - // 2 / | \ 3 - // / 4 | 5 \ - - int whichbin(int dir) const { - int w; - if (ratio == 0.0f) { // = 0 degrees (special case) - switch (dir) { - case 0: - return 16; - case 1: - return 0; - case 4: - return 24; - case 6: - return 8; - } - } - if (ratio < 0.2679491924311227f) { // < 15 degrees - w = 1; - } - else if (ratio < 0.5773502691896257f) { // < 30 degrees - w = 2; - } - else if (ratio < 1.0f) { // < 45 degrees - w = 3; - } - else { // = 45 degrees (special case) - switch (dir) { - case 0: - return 20; - case 1: - return 28; - case 2: - return 12; - case 3: - return 4; - } - } - switch (dir) { - case 0: - w = 16 + w; - break; - case 1: - w = 32 - w; - break; - case 2: - w = 16 - w; - break; - case 3: - w = 0 + w; - break; - case 4: - w = 24 - w; - break; - case 5: - w = 24 + w; - break; - case 6: - w = 8 + w; - break; - case 7: - w = 8 - w; - break; - } - return w; - } -}; - - // true grads are also similar to generated grads... // this scruffy helper function converts a true grad to a bin: @@ -691,7 +437,7 @@ inline int whichbin( const Point2f& grad ) // This is only for true gradients... // ...see below for calculated gradients - // + // // Octant: // + - // - \ 8 | 8 / + @@ -699,7 +445,7 @@ inline int whichbin( const Point2f& grad ) // ---- ---- // 16/ | \32 // + /24 | 24\ - - // - + + // - + if (fabs(grad.y) > fabs(grad.x)) { bin = 1; // temporary: label y priority @@ -763,24 +509,7 @@ inline int whichbin( const Point2f& grad ) else { bin += 4; } - /* - // True angular bins - if (ratio < 0.0984914033571642) { // 1/64 - // nop - } - else if (ratio < 0.3033466836073423) { // 3/64 - bin += 1; - } - else if (ratio < 0.5345111359507916) { // 5/64 - bin += 2; - } - else if (ratio < 0.8206787908286603) { // 7/64 - bin += 3; - } - else { - bin += 4; - } - */ + if (bin < 0) { bin = -bin; } @@ -825,10 +554,10 @@ inline int processoctant(int bin) inline int flagoctant(int bin) { int q = 0; - + // have to use two q octants if you are on diagonals or axes... switch (bin) { - case 0: + case 0: q |= 1 << 1; q |= 1 << 3; break; case 1: case 2: case 3: q |= 1 << 1; break; @@ -836,11 +565,11 @@ inline int flagoctant(int bin) q |= 1 << 1; q |= 1 << 7; break; case 5: case 6: case 7: q |= 1 << 7; break; - case 8: + case 8: q |= 1 << 7; q |= 1 << 6; break; case 9: case 10: case 11: q = 1 << 6; break; - case 12: + case 12: q |= 1 << 6; q |= 1 << 0; break; case 13: case 14: case 15: q |= 1 << 0; break; @@ -852,11 +581,11 @@ inline int flagoctant(int bin) q |= 1 << 2; q |= 1 << 4; break; case 21: case 22: case 23: q |= 1 << 4; break; - case 24: + case 24: q |= 1 << 4; q |= 1 << 5; break; case 25: case 26: case 27: q |= 1 << 5; break; - case 28: + case 28: q |= 1 << 5; q |= 1 << 3; break; case 29: case 30: case 31: q |= 1 << 3; break; @@ -870,15 +599,16 @@ inline int flagoctant(int bin) inline int q_opposite(int bin) { - int q = -1; int opposing_bin = (16 + bin) % 32; - // \ 6 | 7 / - // 0 \ | / 1 - // - - - - - // 2 / | \ 3 - // / 4 | 5 \ - + /* + * \ 6 | 7 / + * 0 \ | / 1 + * - - - - + * 2 / | \ 3 + * / 4 | 5 \ + */ + return flagoctant(opposing_bin); } diff --git a/salalib/salalib.pro b/salalib/salalib.pro deleted file mode 100644 index 80a61fb8..00000000 --- a/salalib/salalib.pro +++ /dev/null @@ -1,65 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2017-02-09T16:19:46 -# -#------------------------------------------------- -include(../defaults.pri) - - -QT -= qt -CONFIG -= qt -CONFIG -= app_bundle -DEFINES += _DEPTHMAP -TARGET = salalib -TEMPLATE = lib -CONFIG += staticlib c++11 - -DEFINES += SALALIB_LIBRARY - -SOURCES += \ - attributes.cpp \ - axialmap.cpp \ - connector.cpp \ - datalayer.cpp \ - idepthmap.cpp \ - idepthmapx.cpp \ - isovist.cpp \ - MapInfoData.cpp \ - mgraph.cpp \ - nagent.cpp \ - ngraph.cpp \ - ntfp.cpp \ - pointdata.cpp \ - salaprogram.cpp \ - shapemap.cpp \ - spacepix.cpp \ - sparksieve2.cpp \ - tigerp.cpp \ - topomet.cpp \ - vertex.cpp - -HEADERS += \ - attributes.h \ - axialmap.h \ - connector.h \ - datalayer.h \ - fileproperties.h \ - idepthmapx.h \ - isovist.h \ - MapInfoData.h \ - mgraph.h \ - nagent.h \ - ngraph.h \ - ntfp.h \ - pointdata.h \ - salaprogram.h \ - shapemap.h \ - spacepix.h \ - sparksieve2.h \ - tigerp.h \ - topomet.h \ - vertex.h \ - idepthmap.h - -DISTFILES += \ - salascript-tests.txt diff --git a/salalib/salaprogram.cpp b/salalib/salaprogram.cpp index 3aa9c396..653ae880 100644 --- a/salalib/salaprogram.cpp +++ b/salalib/salaprogram.cpp @@ -32,13 +32,18 @@ // User defined functions are not included yet, but should be fairly easy using a global function stack // alongside the global variable stack +#include "salalib/salaprogram.h" +#include "salalib/ngraph.h" +#include "salalib/shapemap.h" +#include "salalib/pointdata.h" +#include "salalib/connector.h" + #include #include #include +#include +#include -#include -#include -#include /////////////////////////////////////////////////////////////////////////////////////////////// @@ -46,11 +51,11 @@ bool g_sala_loaded = false; -prefvec g_sala_math_ops; -prefvec g_sala_comp_ops; -prefvec g_sala_logical_ops; -prefvec g_sala_global_funcs; -prefvec g_sala_member_funcs; +std::vector g_sala_math_ops; +std::vector g_sala_comp_ops; +std::vector g_sala_logical_ops; +std::vector g_sala_global_funcs; +std::vector g_sala_member_funcs; void loadSalaProgram() { @@ -131,7 +136,7 @@ SalaProgram::~SalaProgram() // use istrstream to make an istream from a string: // istrstream file(char *); -bool SalaProgram::parse(istream& program) +bool SalaProgram::parse(std::istream& program) { m_var_stack.clear(); m_error_stack.clear(); @@ -193,7 +198,7 @@ bool SalaProgram::parse(istream& program) parent->m_children.push_back(SalaCommand(this,parent,indent)); - SalaCommand &thiscommand = parent->m_children.tail(); + SalaCommand &thiscommand = parent->m_children.back(); try { line = thiscommand.parse(program,line); @@ -257,16 +262,7 @@ SalaObj SalaProgram::evaluate() // clear marks if they've been used: if (m_marked) { - AttributeTable *table = m_thisobj.getTable(); - for (int i = 0; i < table->getRowCount(); i++) { - // Quick mod - TV -#if defined(_WIN32) - table->setMark(i,SalaObj()); -#else - SalaObj objTmp = SalaObj(); - table->setMark(i,objTmp); -#endif - } + marks.clear(); m_marked = false; } @@ -276,29 +272,23 @@ SalaObj SalaProgram::evaluate() // this function is called by depthmapX to run a script to update a column // the operation is on a single node / row of the database combination -bool SalaProgram::runupdate(int col, const pvecint& selset) +bool SalaProgram::runupdate(int col, const std::set &selset) { AttributeTable *table = m_thisobj.getTable(); - bool pointmap = (m_thisobj.type & SalaObj::S_POINTMAP) ? true : false; // // note: reference, will change object directly, which is important for commands running the program int& row = m_thisobj.data.graph.node; m_col = col; if (selset.size()) { - for (size_t i = 0; i < selset.size(); i++) { - row = selset[i]; // *** NB! selsets for vga store pixelrefs keys, *all* others use rowids directly *** + for (auto& sel: selset) { + row = sel; try { SalaObj val = evaluate(); float v = (float) val.toDouble(); // note, toDouble will type check and throw if there's a problem - // Quick mod - TV -#if defined(_WIN32) - if (!_finite(v)) { -#else - if (!finite(v)) { -#endif + if (!std::isfinite(v)) { v = -1.0f; } - table->changeValue(pointmap ? table->getRowid(row) : row,m_col,v); + table->getRow(AttributeKey(sel)).setValue(m_col,v); } catch (SalaError e) { // error @@ -308,20 +298,15 @@ bool SalaProgram::runupdate(int col, const pvecint& selset) } } else { - for (int i = 0; i < table->getRowCount(); i++) { - row = pointmap ? table->getRowKey(i) : i; // *** NB! selsets for vga store pixelrefs keys, *all* others use rowids directly *** + for (auto iter = table->begin(); iter != table->end(); iter++) { + row = iter->getKey().value; try { SalaObj val = evaluate(); float v = (float) val.toDouble(); // note, toDouble will type check and throw if there's a problem - // Quick mod - TV -#if defined(_WIN32) - if (!_finite(v)) { -#else - if (!finite(v)) { -#endif + if (!std::isfinite(v)) { v = -1.0f; } - table->changeValue(i,m_col,v); + iter->getRow().setValue(m_col,v); } catch (SalaError e) { // error @@ -336,20 +321,17 @@ bool SalaProgram::runupdate(int col, const pvecint& selset) // this function is called by depthmapX to run a script to select values // the operation is on a single node / row of the database combination -bool SalaProgram::runselect(pvecint& selsetout, const pvecint& selsetin) +bool SalaProgram::runselect(std::vector &selsetout, const std::set& selsetin) { AttributeTable *table = m_thisobj.getTable(); - bool pointmap = (m_thisobj.type & SalaObj::S_POINTMAP) ? true : false; - // - int& row = m_thisobj.data.graph.node; + if (selsetin.size()) { - for (size_t i = 0; i < selsetin.size(); i++) { - row = selsetin[i]; // *** NB! selsets for vga store pixelrefs keys, *all* others use rowids directly *** + for (auto& key: selsetin) { try { SalaObj val = evaluate(); bool v = val.toBool(); // note, toBool will type check and throw if there's a problem if (v) { - selsetout.push_back(selsetin[i]); + selsetout.push_back(key); } } catch (SalaError e) { @@ -360,13 +342,13 @@ bool SalaProgram::runselect(pvecint& selsetout, const pvecint& selsetin) } } else { - for (int i = 0; i < table->getRowCount(); i++) { - row = pointmap ? table->getRowKey(i) : i; // *** NB! selsets for vga store pixelrefs keys, *all* others use rowids directly *** + for (auto iter = table->begin(); iter != table->end(); iter++) { + int key = iter->getKey().value; try { SalaObj val = evaluate(); bool v = val.toBool(); // note, toBool will type check and throw if there's a problem if (v) { - selsetout.push_back(row); + selsetout.push_back(key); } } catch (SalaError e) { @@ -379,14 +361,14 @@ bool SalaProgram::runselect(pvecint& selsetout, const pvecint& selsetin) return true; } -pstring SalaProgram::getLastErrorMessage() const +std::string SalaProgram::getLastErrorMessage() const { - const SalaError& error = m_error_stack.tail(); + const SalaError& error = m_error_stack.back(); if (error.lineno == -1) { return error.message; } else { - return error.message + " on line " + pstringify(error.lineno+1,"%d"); + return error.message + " on line " + dXstring::formatString(error.lineno+1,"%d"); } } @@ -401,7 +383,7 @@ SalaCommand::SalaCommand(SalaProgram *program, SalaCommand *parent, int indent, m_line = 0; } -int SalaCommand::parse(istream& program, int line) +int SalaCommand::parse(std::istream& program, int line) { m_func_stack.clear(); m_eval_stack.clear(); @@ -415,7 +397,6 @@ int SalaCommand::parse(istream& program, int line) int last = SP_FUNCTION; bool endloop = false; bool overridecache = false; - bool firstword = true; SalaBuffer buffer; char cache = ' '; // @@ -443,7 +424,7 @@ int SalaCommand::parse(istream& program, int line) program.get(); // take off closing quote and discard } // add even if the string constant is empty: - m_eval_stack.push_back( pstring(buffer) ); + m_eval_stack.push_back( std::string(buffer) ); buffer.clear(); last = SP_DATA; } @@ -501,7 +482,7 @@ int SalaCommand::parse(istream& program, int line) last = decode(buffer); buffer.clear(); } - last = decode(pstring(1,alpha)); + last = decode(std::string(1,alpha)); break; case '(': // note: the opening bracket forms a function @@ -679,7 +660,7 @@ int SalaCommand::parse(istream& program, int line) } if (alpha != EOF && alpha != 13) { // 13 ignored, as it appears \n is 10 in this stream... if (!isalphanum_(alpha) && alpha != '&' && alpha != '|') { // include & and | for and and or - throw SalaError("Unrecognised symbol ('" + pstring(1,alpha) + "')",m_line); + throw SalaError("Unrecognised symbol ('" + std::string(1,alpha) + "')",m_line); } buffer.add(alpha); } @@ -712,7 +693,7 @@ int SalaCommand::parse(istream& program, int line) // add the for iterator variable: m_program->m_var_stack.push_back(SalaObj()); int x = m_program->m_var_stack.size() - 1; - m_var_names.add(buffer,x); + m_var_names.insert(std::make_pair(buffer,x)); m_for_iter = SalaObj( SalaObj::S_VAR, x); // now check for 'in' while (alpha == ' ') { @@ -732,10 +713,10 @@ int SalaCommand::parse(istream& program, int line) } // push remaining functions onto eval stack: while (m_func_stack.size()) { - if (m_func_stack.tail().type & SalaObj::S_BRACKET) { + if (m_func_stack.back().type & SalaObj::S_BRACKET) { throw SalaError("Unmatched brackets",m_line); } - m_eval_stack.push_back(m_func_stack.tail()); + m_eval_stack.push_back(m_func_stack.back()); m_func_stack.pop_back(); } @@ -745,12 +726,12 @@ int SalaCommand::parse(istream& program, int line) return line; } -int SalaCommand::decode(pstring string) // string copied as makelower applied +int SalaCommand::decode(std::string string) // string copied as makelower applied { // ideally, some form of hashing the string should be performed so that // functions can be found quicker than a long list of "else ifs" int retvar = SP_NONE; - string.makelower(); + dXstring::toLower(string); if (m_command == SC_NONE) { if (string == "return") { @@ -791,7 +772,7 @@ int SalaCommand::decode(pstring string) // string copied as makelower applied m_last_string = string; // make a copy for debugging purposes return SP_NUMBER; } - if (string.findindex('.') != paftl::npos || string.findindex('e') != paftl::npos) { + if (string.find_first_of('.') != std::string::npos || string.find_first_of('e') != std::string::npos) { m_eval_stack.push_back( atof(string.c_str()) ); } else { @@ -868,8 +849,8 @@ int SalaCommand::decode(pstring string) // string copied as makelower applied } if (retvar == SP_NONE) { - size_t n = string.findindex("."); - if (n != paftl::npos) { + size_t n = string.find_first_of("."); + if (n != std::string::npos) { if (n > 0) { decode(string.substr(0,n)); } @@ -885,14 +866,16 @@ int SalaCommand::decode(pstring string) // string copied as makelower applied if (retvar == SP_NONE) { // see if it exists in the variable stack (walk up scope) SalaCommand *parent = m_parent; - size_t n = paftl::npos; + auto n = parent->m_var_names.end(); int x = -1; - while (parent != NULL && n == -1) { - n = parent->m_var_names.searchindex(string); - if (n != paftl::npos) { - x = parent->m_var_names.value(n); + while (parent != NULL) { + n = parent->m_var_names.find(string); + if (n != parent->m_var_names.end()) { + x = n->second; + parent = NULL; + } else { + parent = parent->m_parent; } - parent = parent->m_parent; } if (x != -1) { m_eval_stack.push_back( SalaObj( SalaObj::S_VAR, x) ); @@ -902,7 +885,7 @@ int SalaCommand::decode(pstring string) // string copied as makelower applied m_program->m_var_stack.push_back(SalaObj()); x = m_program->m_var_stack.size() - 1; // note: attach simply to your m_parent, not parent variable, which has walked up the stack - m_parent->m_var_names.add(string,x); + m_parent->m_var_names.insert(std::make_pair(string,x)); m_eval_stack.push_back( SalaObj( SalaObj::S_VAR, x) ); retvar = SP_DATA; } @@ -930,7 +913,7 @@ int SalaCommand::decode(pstring string) // string copied as makelower applied // a graph node / table row (for "select by query" and "edit connections") // a map (not yet implemented, but intended for scripting agents) -int SalaCommand::decode_member(const pstring& string, bool apply_to_this) +int SalaCommand::decode_member(const std::string& string, bool apply_to_this) { int retvar = SP_NONE; @@ -957,53 +940,53 @@ void SalaCommand::pushFunc(const SalaObj& func) // note comma is part of the "Bracket" class of things: if (func.type & SalaObj::S_BRACKET) { if (func.type == SalaObj::S_CLOSE_BRACKET) { - while (m_func_stack.size() && m_func_stack.tail().type != SalaObj::S_OPEN_BRACKET) { - m_eval_stack.push_back(m_func_stack.tail()); + while (m_func_stack.size() && m_func_stack.back().type != SalaObj::S_OPEN_BRACKET) { + m_eval_stack.push_back(m_func_stack.back()); m_func_stack.pop_back(); } if (m_func_stack.size()) { // don't necessarily pop it... if it's a group marker, we want to hang onto it: - if (m_func_stack.tail().data.count > 1) { - m_func_stack.tail().type = SalaObj::S_CONST_TUPLE; - m_eval_stack.push_back(m_func_stack.tail()); + if (m_func_stack.back().data.count > 1) { + m_func_stack.back().type = SalaObj::S_CONST_TUPLE; + m_eval_stack.push_back(m_func_stack.back()); } m_func_stack.pop_back(); // remove opening bracket } } else if (func.type == SalaObj::S_CLOSE_SQR_BRACKET) { - while (m_func_stack.size() && (m_func_stack.tail().type & SalaObj::S_OPEN_SQR_BRACKET) == 0) { - m_eval_stack.push_back(m_func_stack.tail()); + while (m_func_stack.size() && (m_func_stack.back().type & SalaObj::S_OPEN_SQR_BRACKET) == 0) { + m_eval_stack.push_back(m_func_stack.back()); m_func_stack.pop_back(); } if (m_func_stack.size()) { // don't pop it, always make a list from a make list command, even if it's only one item long: - if (m_func_stack.tail().type == SalaObj::S_OPEN_SQR_BRACKET_LIST || m_func_stack.tail().data.count > 1) { - m_func_stack.tail().type = SalaObj::S_CONST_LIST; - m_eval_stack.push_back(m_func_stack.tail()); + if (m_func_stack.back().type == SalaObj::S_OPEN_SQR_BRACKET_LIST || m_func_stack.back().data.count > 1) { + m_func_stack.back().type = SalaObj::S_CONST_LIST; + m_eval_stack.push_back(m_func_stack.back()); } m_func_stack.pop_back(); } } else if (func.type == SalaObj::S_COMMA) { // go and increment your associated group / list - while (m_func_stack.size() && m_func_stack.tail().type != SalaObj::S_OPEN_BRACKET && (m_func_stack.tail().type & SalaObj::S_OPEN_SQR_BRACKET) == 0) { - m_eval_stack.push_back(m_func_stack.tail()); + while (m_func_stack.size() && m_func_stack.back().type != SalaObj::S_OPEN_BRACKET && (m_func_stack.back().type & SalaObj::S_OPEN_SQR_BRACKET) == 0) { + m_eval_stack.push_back(m_func_stack.back()); m_func_stack.pop_back(); } if (m_func_stack.size()) { - m_func_stack.tail().data.count++; + m_func_stack.back().data.count++; } } else { m_func_stack.push_back( func ); } } - else if (!m_func_stack.size() || func.precedence() > m_func_stack.tail().precedence()) { // original: > + else if (!m_func_stack.size() || func.precedence() > m_func_stack.back().precedence()) { // original: > m_func_stack.push_back(func); } else { - while (m_func_stack.size() && func.precedence() <= m_func_stack.tail().precedence()) { // original <= - m_eval_stack.push_back(m_func_stack.tail()); + while (m_func_stack.size() && func.precedence() <= m_func_stack.back().precedence()) { // original <= + m_eval_stack.push_back(m_func_stack.back()); m_func_stack.pop_back(); } m_func_stack.push_back(func); @@ -1078,8 +1061,8 @@ void SalaCommand::evaluate(SalaObj& obj, bool& ret, bool& ifhandled) if (len != 0) { for (int i = 0; i < len; i++) { // reset all my stack (actually, all parent functions should do this!) - for (size_t j = 0; j < m_var_names.size(); j++) { - m_program->m_var_stack[m_var_names.value(j)].uninit(); + for (auto varName: m_var_names) { + m_program->m_var_stack[varName.second].uninit(); } m_program->m_var_stack[m_for_iter.data.var] = list.data.list.list->at(i); for (size_t k = 0; k < m_children.size(); k++) { @@ -1136,7 +1119,7 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) if (pointer < 0) { throw SalaError("Missing argument",m_line); } - register SalaObj data = m_eval_stack[pointer]; + SalaObj data = m_eval_stack[pointer]; pointer--; if (data.type == SalaObj::S_FUNCTION) { SalaObj::Func func = data.data.func; @@ -1146,7 +1129,7 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) switch (func) { case SalaObj::S_ADD: // Quick mod - TV -#if defined(_WIN32) +#if defined(_MSC_VER) data = evaluate(pointer,p_obj) + evaluate(pointer,p_obj); #else { @@ -1158,7 +1141,7 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) break; case SalaObj::S_SUBTRACT: // Quick mod - TV -#if defined(_WIN32) +#if defined(_MSC_VER) data = evaluate(pointer,p_obj) - evaluate(pointer,p_obj); #else { @@ -1173,7 +1156,7 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) break; case SalaObj::S_MINUS: // Quick mod - TV -#if defined(_WIN32) +#if defined(_MSC_VER) data = -evaluate(pointer,p_obj); #else { @@ -1184,7 +1167,7 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) break; case SalaObj::S_MULTIPLY: // Quick mod - TV -#if defined(_WIN32) +#if defined(_MSC_VER) data = evaluate(pointer,p_obj) * evaluate(pointer,p_obj); #else { @@ -1196,7 +1179,7 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) break; case SalaObj::S_DIVIDE: // Quick mod - TV -#if defined(_WIN32) +#if defined(_MSC_VER) data = evaluate(pointer,p_obj) / evaluate(pointer,p_obj); #else { @@ -1210,7 +1193,7 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) data = evaluate(pointer,p_obj); // Quick mod - TV -#if defined(_WIN32) +#if defined(_MSC_VER) data = evaluate(pointer,p_obj) % data; // reverse order #else { @@ -1226,7 +1209,7 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) case SalaObj::S_ASSIGN: data = evaluate(pointer,p_obj); // reverse order evaluate(pointer,p_obj); - if ((unsigned long)p_obj > 1) { + if (p_obj != nullptr) { *p_obj = data; } else { @@ -1252,6 +1235,8 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) throw SalaError("Cannot be applied to " + data.getTypeIndefArt() + data.getTypeStr(),m_line); } break; + default: + break; } } catch (SalaError e) @@ -1263,7 +1248,7 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) break; } } - e.lineno = m_line; throw e; + e.lineno = m_line; throw std::move(e); } } else if (group == SalaObj::S_LOGICAL_OPS) { @@ -1285,7 +1270,7 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) break; case SalaObj::S_EQ: // Quick mod - TV -#if defined(_WIN32) +#if defined(_MSC_VER) data = evaluate(pointer,p_obj) == evaluate(pointer,p_obj); #else { @@ -1297,7 +1282,7 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) break; case SalaObj::S_IS: // Quick mod - TV -#if defined(_WIN32) +#if defined(_MSC_VER) data = op_is(evaluate(pointer,p_obj),evaluate(pointer,p_obj)); #else { @@ -1309,7 +1294,7 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) break; case SalaObj::S_NEQ: // Quick mod - TV -#if defined(_WIN32) +#if defined(_MSC_VER) data = evaluate(pointer,p_obj) != evaluate(pointer,p_obj); #else { @@ -1322,7 +1307,7 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) case SalaObj::S_GT: data = evaluate(pointer,p_obj); // Quick mod - TV -#if defined(_WIN32) +#if defined(_MSC_VER) data = evaluate(pointer,p_obj) > data; // revese order #else { @@ -1334,7 +1319,7 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) case SalaObj::S_LT: data = evaluate(pointer,p_obj); // Quick mod - TV -#if defined(_WIN32) +#if defined(_MSC_VER) data = evaluate(pointer,p_obj) < data; // revese order #else { @@ -1347,7 +1332,7 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) data = evaluate(pointer,p_obj); // Quick mod - TV -#if defined(_WIN32) +#if defined(_MSC_VER) data = evaluate(pointer,p_obj) >= data; // revese order #else { @@ -1360,7 +1345,7 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) data = evaluate(pointer,p_obj); // Quick mod - TV -#if defined(_WIN32) +#if defined(_MSC_VER) data = evaluate(pointer,p_obj) <= data; // revese order #else { @@ -1369,6 +1354,8 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) } #endif break; + default: + break; } } catch (SalaError e) @@ -1386,7 +1373,7 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) break; } } - e.lineno = m_line; throw e; + e.lineno = m_line; throw std::move(e); } } else if (group == SalaObj::S_GLOBAL_FUNCS) { @@ -1453,6 +1440,8 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) case SalaObj::S_ATAN: data = atan(evaluate(pointer,p_obj).toDouble()); break; + default: + break; } } catch (SalaError e) @@ -1464,7 +1453,7 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) break; } } - e.lineno = m_line; throw e; + e.lineno = m_line; throw std::move(e); } } else if (group == SalaObj::S_MEMBER_FUNCS) { @@ -1495,18 +1484,18 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) throw SalaError("List is empty", m_line); } if (param.type == SalaObj::S_NONE) { - data = obj.data.list.list->tail(); + data = obj.data.list.list->back(); obj.data.list.list->pop_back(); } else { - pvector& list = *(obj.data.list.list); + std::vector& list = *(obj.data.list.list); int i = param.toInt(); if (i < 0) i += list.size(); if (i < 0 || i >= (int)list.size()) throw SalaError("Index out of range"); - data = list.at(i); - list.remove_at(i); + data = list[i]; + list.erase(list.begin() + i); } break; case SalaObj::S_FCLEAR: @@ -1522,18 +1511,17 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) switch (func) { case SalaObj::S_FVALUE: { - const pstring& str = param.toStringRef(); + const std::string& str = param.toStringRef(); AttributeTable *table = obj.getTable(); - int col = -1; - if (str != "Ref Number") { - col = table->getColumnIndex(str); - if (col == -1) { - throw SalaError(str + " is an unknown column",m_line); - } + if (str == "Ref Number") { + data = SalaObj(obj.data.graph.node); + } else { + if (!table->hasColumn(str)) { + throw SalaError(str + " is an unknown column",m_line); + } + data = SalaObj(table->getRow(AttributeKey(obj.data.graph.node)).getValue( + table->getColumnIndex(str))); } - // *** NB! vga is keyed off pixelrefs *all* others use rowids directly *** - // (this may seem an odd way to do it, but it speeds up connection hunting to use whichever method the map uses -- note idepthmap uses the method to access attributes) - data = SalaObj(table->getValue((obj.type == SalaObj::S_POINTMAPOBJ) ? table->getRowid(obj.data.graph.node) : obj.data.graph.node,col)); } break; case SalaObj::S_FSETVALUE: @@ -1541,19 +1529,19 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) if (param.length() != 2) { throw SalaError("Function takes 2 parameters"); } - const pstring& str = param.list_at(0).toStringRef(); + const std::string& str = param.list_at(0).toStringRef(); float val = (float) param.list_at(1).toDouble(); AttributeTable *table = obj.getTable(); int col = -1; if (str != "Ref Number") { - col = table->getColumnIndex(str); - if (col == -1) { + if (!table->hasColumn(str)) { throw SalaError(str + " is an unknown column",m_line); } + col = table->getColumnIndex(str); + } else { + throw SalaError("The reference number can not be changed",m_line); } - // *** NB! vga is keyed off pixelrefs *all* others use rowids directly *** - // (this may seem an odd way to do it, but it speeds up connection hunting to use whichever method the map uses -- note idepthmap uses the method to access attributes) - table->setValue((obj.type == SalaObj::S_POINTMAPOBJ) ? table->getRowid(obj.data.graph.node) : obj.data.graph.node, col, val); + table->getRow(AttributeKey(obj.data.graph.node)).setValue(col, val); data = SalaObj(); // returns none } break; @@ -1565,14 +1553,12 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) case SalaObj::S_FMARK: { param.ensureNone(); - AttributeTable *table = obj.getTable(); - data = table->getMark((obj.type == SalaObj::S_POINTMAPOBJ) ? table->getRowid(obj.data.graph.node) : obj.data.graph.node); + data = m_program->marks[obj.data.graph.node]; } break; case SalaObj::S_FSETMARK: { - AttributeTable *table = obj.getTable(); - table->setMark((obj.type == SalaObj::S_POINTMAPOBJ) ? table->getRowid(obj.data.graph.node) : obj.data.graph.node, param); + m_program->marks[obj.data.graph.node] = param; m_program->m_marked = true; // <- this tells the program to tidy up marks between executions data = SalaObj(); // returns none } @@ -1595,7 +1581,7 @@ SalaObj SalaCommand::evaluate(int& pointer, SalaObj* &p_obj) break; } } - e.lineno = m_line; throw e; + e.lineno = m_line; throw std::move(e); } } } @@ -1659,10 +1645,12 @@ SalaObj SalaCommand::connections(SalaObj graphobj, SalaObj param) } } else { - const Connector& connector = graphobj.data.graph.map.shape->getConnections().at(graphobj.data.graph.node); + int idx = std::distance(graphobj.data.graph.map.shape->getAllShapes().begin(), + graphobj.data.graph.map.shape->getAllShapes().find(graphobj.data.graph.node)); + const Connector& connector = graphobj.data.graph.map.shape->getConnections()[idx]; int mode = Connector::CONN_ALL; if (graphobj.data.graph.map.shape->isSegmentMap()) { - const pstring& str = param.toStringRef(); + const std::string& str = param.toStringRef(); if (str == "forward") { mode = Connector::SEG_CONN_FW; } @@ -1678,11 +1666,17 @@ SalaObj SalaCommand::connections(SalaObj graphobj, SalaObj param) } int count = connector.count(mode); list = SalaObj( SalaObj::S_LIST, count); - connector.first(); + int cursor = 0; for (int i = 0; i < count; i++) { - graphobj.data.graph.node = connector.cursor(mode); + int connectedIndex = connector.getConnectedRef(cursor, mode); + if (connectedIndex == -1) { + cursor = -1; + graphobj.data.graph.node = -1; + } else { + graphobj.data.graph.node = graphobj.data.graph.map.shape->getShapeRefFromIndex(connectedIndex)->first; + } list.data.list.list->at(i) = graphobj; - connector.next(); + cursor++; } } return list; diff --git a/salalib/salaprogram.h b/salalib/salaprogram.h index ee6ebe1f..e5022b7f 100644 --- a/salalib/salaprogram.h +++ b/salalib/salaprogram.h @@ -16,8 +16,16 @@ // along with this program. If not, see . -#ifndef __SALAPROGRAM_H__ -#define __SALAPROGRAM_H__ +#pragma once + +#include "salalib/attributetable.h" + +#include "genlib/stringutils.h" + +#include +#include +#include +#include class AttributeTable; class PointMap; @@ -42,8 +50,8 @@ inline bool isalpha_(char c) struct SalaError { int lineno; - pstring message; - SalaError(const pstring& m = pstring(), int li = -1) + std::string message; + SalaError(const std::string& m = std::string(), int li = -1) { message = m; lineno = li; } }; @@ -59,13 +67,13 @@ struct SalaStr { public: int *refcount; - pstring *string; + std::string *string; public: friend bool operator == (const SalaStr& a, const SalaStr& b); friend bool operator != (const SalaStr& a, const SalaStr& b); friend bool operator < (const SalaStr& a, const SalaStr& b); friend bool operator > (const SalaStr& a, const SalaStr& b); - // operator const pstring&() { return *string; } + // operator const std::string&() { return *string; } char char_at(size_t i) const { return string->operator[](i); } size_t length() const @@ -82,7 +90,7 @@ inline bool operator > (const SalaStr& a, const SalaStr& b) struct SalaList { int *refcount; - pvector *list; + std::vector *list; public: friend bool operator == (const SalaList& a, const SalaList& b); friend bool operator != (const SalaList& a, const SalaList& b); @@ -172,7 +180,7 @@ class SalaObj type = t; if (t & S_LIST) { data.list.refcount = new int(1); - data.list.list = new pvector; + data.list.list = new std::vector; } else { data.count = 1; @@ -185,8 +193,7 @@ class SalaObj type = t; if (t & S_LIST) { data.list.refcount = new int(1); - data.list.list = new pvector; - data.list.list->set(v); // set blanks + data.list.list = new std::vector(v); // set blanks } else { data.var = v; @@ -197,7 +204,7 @@ class SalaObj SalaObj(int a) { type = S_INT; data.i = a; } SalaObj(double a) { type = S_DOUBLE; data.f = a; } SalaObj(Func f) { type = S_FUNCTION; data.func = f; } - SalaObj(const pstring& a) { type = S_STRING; data.str.refcount = new int(1); data.str.string = new pstring(a); } + SalaObj(const std::string& a) { type = S_STRING; data.str.refcount = new int(1); data.str.string = new std::string(a); } // note, type required here as sometimes this will be an axial map, sometimes segment map, sometimes point map, // also not fully filled in until runtime, but still required by parse SalaObj(Type t, SalaGrf graph) @@ -213,8 +220,8 @@ class SalaObj bool toBool() const; int toInt() const; double toDouble() const; - pstring toString() const; - const pstring& toStringRef() const; + std::string toString() const; + const std::string& toStringRef() const; friend SalaObj op_is(SalaObj& a, SalaObj& b); friend SalaObj operator - (SalaObj& a); friend SalaObj operator + (SalaObj& a, SalaObj& b); @@ -233,7 +240,7 @@ class SalaObj friend bool operator <= (SalaObj& a, SalaObj& b); // operations for lists: SalaObj& list_at(int i); - SalaObj char_at(size_t i); // actually returns a string of the char -- note constant + SalaObj char_at(int i); // actually returns a string of the char -- note constant int length(); // check for no parameters void ensureNone() @@ -242,8 +249,8 @@ class SalaObj // operations for graphs / graph nodes: AttributeTable *getTable(); // - const pstring getTypeStr() const; - const pstring getTypeIndefArt() const; + const std::string getTypeStr() const; + const std::string getTypeIndefArt() const; }; // Quick mod - TV @@ -259,27 +266,27 @@ class SalaCommand // SalaProgram *m_program; // information about the running program (in particular, the global variable and error stack) SalaCommand *m_parent; - prefvec m_children; + std::vector m_children; // - pqmap m_var_names; + std::map m_var_names; // Command m_command; int m_indent; // vital for program flow due to Pythonesque syntax - pvector m_eval_stack; - pvector m_func_stack; + std::vector m_eval_stack; + std::vector m_func_stack; // SalaObj m_for_iter; // object used in a for loop // int m_line; // useful for debugging to know which line this command starts on - pstring m_last_string; // occassionally useful in debugging if the user does something unsyntactical + std::string m_last_string; // occassionally useful in debugging if the user does something unsyntactical // public: SalaCommand() { m_program = NULL; m_parent = NULL; m_indent = 0; m_command = SC_NONE; } SalaCommand(SalaProgram *program, SalaCommand *parent, int indent, Command command = SC_NONE); protected: - int parse(istream& program, int line); - int decode(pstring string); - int decode_member(const pstring& string, bool apply_to_this); + int parse(std::istream& program, int line); + int decode(std::string string); + int decode_member(const std::string& string, bool apply_to_this); void pushFunc(const SalaObj& func); // void evaluate(SalaObj& obj, bool& ret, bool& ifhandled); @@ -292,8 +299,8 @@ class SalaProgram friend class SalaCommand; // SalaCommand m_root_command; - pvector m_var_stack; - prefvec m_error_stack; + std::vector m_var_stack; + std::vector m_error_stack; // // column is stored away from the context, as it's not actually passed to the program itself, just used to update a column int m_col; @@ -302,15 +309,17 @@ class SalaProgram SalaObj m_thisobj; // bool m_marked; // this is used to tell the program that a node has been "marked" -- all marks are cleared at the end of the execution - // + // marks for state management in maps + std::map marks; + public: SalaProgram(SalaObj context); ~SalaProgram(); - bool parse(istream& program); + bool parse(std::istream& program); SalaObj evaluate(); - bool runupdate(int col, const pvecint& selset = pvecint()); - bool runselect(pvecint& selsetout, const pvecint& selsetin = pvecint()); - pstring getLastErrorMessage() const; + bool runupdate(int col, const std::set &selset = std::set()); + bool runselect(std::vector& selsetout, const std::set &selsetin = std::set()); + std::string getLastErrorMessage() const; }; inline SalaObj::SalaObj(const SalaObj& obj) @@ -421,7 +430,7 @@ inline bool SalaObj::toBool() const case S_INT: return data.i != 0; case S_DOUBLE: return data.f != 0.0; default: - throw SalaError(pstring("Cannot convert ") + getTypeIndefArt() + getTypeStr() + pstring(" to a boolean value")); + throw SalaError(std::string("Cannot convert ") + getTypeIndefArt() + getTypeStr() + std::string(" to a boolean value")); } return false; } @@ -430,8 +439,8 @@ inline int SalaObj::toInt() const switch(type) { case S_BOOL: return data.b ? 1 : 0; case S_INT: return data.i; - case S_DOUBLE: return int(floor(data.f)); // ensure properly implemented - default: throw SalaError(pstring("Cannot convert ") + getTypeIndefArt() + getTypeStr() + pstring(" to an integer value")); + case S_DOUBLE: return int(std::floor(data.f)); // ensure properly implemented + default: throw SalaError(std::string("Cannot convert ") + getTypeIndefArt() + getTypeStr() + std::string(" to an integer value")); } return 0; } @@ -441,24 +450,24 @@ inline double SalaObj::toDouble() const case S_BOOL: return data.b ? 1.0 : 0.0; case S_INT: return double(data.i); case S_DOUBLE: return data.f; - default: throw SalaError(pstring("Cannot convert ") + getTypeIndefArt() + getTypeStr() + pstring(" to a floating point number")); + default: throw SalaError(std::string("Cannot convert ") + getTypeIndefArt() + getTypeStr() + std::string(" to a floating point number")); } return 0.0; } -inline pstring SalaObj::toString() const +inline std::string SalaObj::toString() const { switch(type) { - case S_INT: return pstringify(data.i); - case S_DOUBLE: return pstringify(data.f); + case S_INT: return dXstring::formatString(data.i); + case S_DOUBLE: return dXstring::formatString(data.f); case S_STRING: return *(data.str.string); - default: throw SalaError(pstring("Cannot convert ") + getTypeIndefArt() + getTypeStr() + pstring(" to a string")); + default: throw SalaError(std::string("Cannot convert ") + getTypeIndefArt() + getTypeStr() + std::string(" to a string")); } - return pstring(); + return std::string(); } -inline const pstring& SalaObj::toStringRef() const +inline const std::string& SalaObj::toStringRef() const { if (type != S_STRING) { - throw SalaError(pstring("Cannot convert ") + getTypeIndefArt() + getTypeStr() + pstring(" to a string reference")); + throw SalaError(std::string("Cannot convert ") + getTypeIndefArt() + getTypeStr() + std::string(" to a string reference")); } return *(data.str.string); } @@ -472,7 +481,7 @@ inline SalaObj operator + (SalaObj& a, SalaObj& b) case SalaObj::S_NUMBER: return (a.type == SalaObj::S_INT) ? (double(a.data.i) + b.data.f) : (a.data.f + double(b.data.i)); case SalaObj::S_STRING: return SalaObj(*(a.data.str.string) + *(b.data.str.string)); - default: throw SalaError(pstring("Cannot add ") + a.getTypeIndefArt() + a.getTypeStr() + pstring(" to ") + b.getTypeIndefArt() + b.getTypeStr()); + default: throw SalaError(std::string("Cannot add ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" to ") + b.getTypeIndefArt() + b.getTypeStr()); } return SalaObj(); } @@ -484,7 +493,7 @@ inline SalaObj operator - (SalaObj& a, SalaObj& b) case SalaObj::S_DOUBLE: return SalaObj(a.data.f - b.data.f); case SalaObj::S_NUMBER: return (a.type == SalaObj::S_INT) ? (double(a.data.i) - b.data.f) : (a.data.f - double(b.data.i)); - default: throw SalaError(pstring("Cannot subtract ") + b.getTypeIndefArt() + b.getTypeStr() + pstring(" from ") + a.getTypeIndefArt() + a.getTypeStr()); + default: throw SalaError(std::string("Cannot subtract ") + b.getTypeIndefArt() + b.getTypeStr() + std::string(" from ") + a.getTypeIndefArt() + a.getTypeStr()); } return SalaObj(); } @@ -494,7 +503,7 @@ inline SalaObj operator - (SalaObj& a) case SalaObj::S_BOOL: throw SalaError("Cannot minus booleans"); case SalaObj::S_INT: return SalaObj(-a.data.i); case SalaObj::S_DOUBLE: return SalaObj(-a.data.f); - default: throw SalaError(pstring("Cannot minus ") + a.getTypeIndefArt() + a.getTypeStr()); + default: throw SalaError(std::string("Cannot minus ") + a.getTypeIndefArt() + a.getTypeStr()); } return SalaObj(); } @@ -505,7 +514,7 @@ inline SalaObj operator * (SalaObj& a, SalaObj& b) case SalaObj::S_DOUBLE: return SalaObj(a.data.f * b.data.f); case SalaObj::S_NUMBER: return (a.type == SalaObj::S_INT) ? (double(a.data.i) * b.data.f) : (a.data.f * double(b.data.i)); - default: throw SalaError(pstring("Cannot multiply ") + a.getTypeIndefArt() + a.getTypeStr() + pstring(" by ") + b.getTypeIndefArt() + b.getTypeStr()); + default: throw SalaError(std::string("Cannot multiply ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" by ") + b.getTypeIndefArt() + b.getTypeStr()); } return SalaObj(); } @@ -516,7 +525,7 @@ inline SalaObj operator % (SalaObj& a, SalaObj& b) case SalaObj::S_DOUBLE: return SalaObj(fmod(a.data.f,b.data.f)); case SalaObj::S_NUMBER: return (a.type == SalaObj::S_INT) ? fmod(double(a.data.i),b.data.f) : fmod(a.data.f,double(b.data.i)); - default: throw SalaError(pstring("Cannot multiply ") + a.getTypeIndefArt() + a.getTypeStr() + pstring(" by ") + b.getTypeIndefArt() + b.getTypeStr()); + default: throw SalaError(std::string("Cannot multiply ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" by ") + b.getTypeIndefArt() + b.getTypeStr()); } return SalaObj(); } @@ -527,7 +536,7 @@ inline SalaObj operator / (SalaObj& a, SalaObj& b) case SalaObj::S_DOUBLE: return SalaObj(a.data.f / b.data.f); case SalaObj::S_NUMBER: return (a.type == SalaObj::S_INT) ? (double(a.data.i) / b.data.f) : (a.data.f / double(b.data.i)); - default: throw SalaError(pstring("Cannot divide ") + a.getTypeIndefArt() + a.getTypeStr() + pstring(" by ") + a.getTypeIndefArt() + b.getTypeStr()); + default: throw SalaError(std::string("Cannot divide ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" by ") + a.getTypeIndefArt() + b.getTypeStr()); } return SalaObj(); } @@ -557,7 +566,7 @@ inline bool operator == (SalaObj& a, SalaObj& b) return (a.type == SalaObj::S_INT) ? (double(a.data.i) == b.data.f) : (a.data.f == double(b.data.i)); case SalaObj::S_STRING: return a.data.str == b.data.str; case SalaObj::S_LIST: return a.data.list == b.data.list; - default: throw SalaError(pstring("Cannot compare ") + a.getTypeIndefArt() + a.getTypeStr() + pstring(" with ") + b.getTypeIndefArt() + b.getTypeStr() + pstring(" using '=='")); + default: throw SalaError(std::string("Cannot compare ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" with ") + b.getTypeIndefArt() + b.getTypeStr() + std::string(" using '=='")); } return false; } @@ -586,7 +595,7 @@ inline bool operator != (SalaObj& a, SalaObj& b) return (a.type == SalaObj::S_INT) ? (double(a.data.i) != b.data.f) : (a.data.f != double(b.data.i)); case SalaObj::S_STRING: return a.data.str != b.data.str; case SalaObj::S_LIST: return a.data.list != b.data.list; - default: throw SalaError(pstring("Cannot compare ") + a.getTypeIndefArt() + a.getTypeStr() + pstring(" with ") + b.getTypeIndefArt() + b.getTypeStr() + pstring(" using '!='")); + default: throw SalaError(std::string("Cannot compare ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" with ") + b.getTypeIndefArt() + b.getTypeStr() + std::string(" using '!='")); } return false; } @@ -599,7 +608,7 @@ inline bool operator < (SalaObj& a, SalaObj& b) case SalaObj::S_NUMBER: return (a.type == SalaObj::S_INT) ? (double(a.data.i) < b.data.f) : (a.data.f < double(b.data.i)); case SalaObj::S_STRING: return a.data.str < b.data.str; - default: throw SalaError(pstring("Cannot compare ") + a.getTypeIndefArt() + a.getTypeStr() + pstring(" with ") + b.getTypeIndefArt() + b.getTypeStr() + pstring(" using '<'")); + default: throw SalaError(std::string("Cannot compare ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" with ") + b.getTypeIndefArt() + b.getTypeStr() + std::string(" using '<'")); } return false; } @@ -612,7 +621,7 @@ inline bool operator > (SalaObj& a, SalaObj& b) case SalaObj::S_NUMBER: return (a.type == SalaObj::S_INT) ? (double(a.data.i) > b.data.f) : (a.data.f > double(b.data.i)); case SalaObj::S_STRING: return a.data.str > b.data.str; - default: throw SalaError(pstring("Cannot compare ") + a.getTypeIndefArt() + a.getTypeStr() + pstring(" with ") + b.getTypeIndefArt() + b.getTypeStr() + pstring(" using '>'")); + default: throw SalaError(std::string("Cannot compare ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" with ") + b.getTypeIndefArt() + b.getTypeStr() + std::string(" using '>'")); } return false; } @@ -624,7 +633,7 @@ inline bool operator <= (SalaObj& a, SalaObj& b) case SalaObj::S_DOUBLE: return a.data.f <= b.data.f; case SalaObj::S_NUMBER: return (a.type == SalaObj::S_INT) ? (double(a.data.i) <= b.data.f) : (a.data.f <= double(b.data.i)); - default: throw SalaError(pstring("Cannot compare ") + a.getTypeIndefArt() + a.getTypeStr() + pstring(" with ") + b.getTypeIndefArt() + b.getTypeStr() + pstring(" using '<='")); + default: throw SalaError(std::string("Cannot compare ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" with ") + b.getTypeIndefArt() + b.getTypeStr() + std::string(" using '<='")); } return false; } @@ -636,7 +645,7 @@ inline bool operator >= (SalaObj& a, SalaObj& b) case SalaObj::S_DOUBLE: return a.data.f >= b.data.f; case SalaObj::S_NUMBER: return (a.type == SalaObj::S_INT) ? (double(a.data.i) >= b.data.f) : (a.data.f >= double(b.data.i)); - default: throw SalaError(pstring("Cannot compare ") + a.getTypeIndefArt() + a.getTypeStr() + pstring(" with ") + b.getTypeIndefArt() + b.getTypeStr() + pstring(" using '>='")); + default: throw SalaError(std::string("Cannot compare ") + a.getTypeIndefArt() + a.getTypeStr() + std::string(" with ") + b.getTypeIndefArt() + b.getTypeStr() + std::string(" using '>='")); } return false; } @@ -649,13 +658,13 @@ inline SalaObj& SalaObj::list_at(int i) throw SalaError("Index out of range"); return data.list.list->at(i); } -inline SalaObj SalaObj::char_at(size_t i) // actually returns a string of the char +inline SalaObj SalaObj::char_at(int i) // actually returns a string of the char { if (i < 0) i += data.str.length(); - if (i < 0 || i >= data.str.length()) + if (i < 0 || i >= static_cast(data.str.length())) throw SalaError("String index out of range"); - return SalaObj(pstring(1,data.str.char_at(i))); + return SalaObj(std::string(1,data.str.char_at(i))); } inline int SalaObj::length() { @@ -668,7 +677,7 @@ inline int SalaObj::length() ///////////////////////////////////////////////////////////////////////////////////// -inline const pstring SalaObj::getTypeStr() const +inline const std::string SalaObj::getTypeStr() const { switch(type) { case S_NONE: @@ -691,6 +700,8 @@ inline const pstring SalaObj::getTypeStr() const return "tuple"; case S_THIS: return "this"; + default: + break; } if (type & S_GRAPHOBJ) { return "graph object"; @@ -701,7 +712,7 @@ inline const pstring SalaObj::getTypeStr() const return "unknown type"; } -inline const pstring SalaObj::getTypeIndefArt() const +inline const std::string SalaObj::getTypeIndefArt() const { switch(type & ~S_GRAPHOBJ) { case S_FUNCTION: case S_BOOL: case S_DOUBLE: case S_STRING: case S_TUPLE: case S_LIST: @@ -714,7 +725,7 @@ inline const pstring SalaObj::getTypeIndefArt() const default: return "an "; // unknown type } - return pstring(); + return std::string(); } ///////////////////////////////////////////////////////////////////////////////////// @@ -757,9 +768,9 @@ struct SalaBuffer buffer[bufpos] = c; } void clear() { bufpos = -1; buffer[0] = '\0'; } - operator pstring() - { buffer[bufpos + 1] = '\0'; return pstring(buffer); } - const bool empty() + operator std::string() + { buffer[bufpos + 1] = '\0'; return std::string(buffer); } + bool empty() { return bufpos == -1; } }; @@ -772,9 +783,9 @@ struct SalaBuffer struct SalaFuncLabel { SalaObj::Func func; - pstring name; - pstring desc; - SalaFuncLabel(SalaObj::Func f = SalaObj::S_FNULL, const pstring& str = pstring(), const pstring& des = pstring()) { + std::string name; + std::string desc; + SalaFuncLabel(SalaObj::Func f = SalaObj::S_FNULL, const std::string& str = std::string(), const std::string& des = std::string()) { func = f; name = str; desc = des; } }; @@ -782,12 +793,8 @@ struct SalaFuncLabel struct SalaMemberFuncLabel : public SalaFuncLabel { SalaObj::Type type; - SalaMemberFuncLabel(SalaObj::Type t = SalaObj::S_NONE, SalaObj::Func f = SalaObj::S_FNULL, const pstring& str = pstring(), const pstring& des = pstring()) { + SalaMemberFuncLabel(SalaObj::Type t = SalaObj::S_NONE, SalaObj::Func f = SalaObj::S_FNULL, const std::string& str = std::string(), const std::string& des = std::string()) { type = t; func = f; name = str; desc = des; } }; - -///////////////////////////////////////////////////////////////////////////////////// - -#endif diff --git a/salalib/salascript-tests.txt b/salalib/salascript-tests.txt deleted file mode 100644 index 672307c9..00000000 --- a/salalib/salascript-tests.txt +++ /dev/null @@ -1,122 +0,0 @@ -# Test scripts - -# single dimension lists -x = [1,2] -x[1] = 10 -x[1] - -# multiple dimension lists -x = [[1,2],[3,4]] -x[0][1] = 10 -x[0][1] - -# range direct access -range(5,10)[2] - -# simple for with error: i should be uninitialised -x = 0 -for i in range(5,10): - x = x + i -i - -# for with else and 0 length ranges -int x = 0 -for i in range(2,value("Ref Number")): - x = x + i - x -else: - 0 - -# if, function of a function on a range -x = len(range(1,value("Ref Number"))) -if x == 2: - return 5 -elif x < 1: - return 10 -x -# first two objects should be set to 10, next to 5, and then ref number after that - -# simple if -if value("Ref Number") < 2: - 0 -elif value("Ref Number") == 3: - 5 -else - 10 - -# various member functions tests -this.value("Ref Number") -len(range(1,this.value("Ref Number"))) -range(1,this.value("Ref Number")).length() - -# member function again -x = [[1,2],[3,4]] -x.length() - -# Pythonesque curios: lists by reference -x = [1,2,3,4] -y = x -y[3] = 40 -x[3] -# should return 40 - - -# For a graph with 100000 segments for cpu timing: -x=value("Angular Connectivity")*value("Angular Step Depth")+value("Axial Line Ref")+value("Connectivity")/value("Segment Length")^value("T1024 Choice R1000 metric") -y=value("T1024 Choice R3000 metric")*value("T1024 Choice R4000 metric")/value("T1024 Choice R5000 metric")^value("T1024 Total Depth [Segment Length Wgt] R4000 metric") -y/x - -# Total Depth Calculation -total_depth = 0 -depth = 0 -pop_list = [this] -push_list = [] -setmark(true) -while len(pop_list): - total_depth = total_depth + depth - curs = pop_list.pop() - for i in curs.connections(): - if i.mark() is none: - i.setmark(true) - push_list.append(i) - if len(pop_list) == 0: - depth = depth + 1 - pop_list = push_list - push_list = [] -total_depth - -# Shortest Cycle -push_list = [] -pop_list = [] -live_paths = [] -setmark([-1,0]) -depth = 1 -path_index = 0 -for i in connections(): - pop_list.append([path_index,i]) - live_paths.append(1) - i.setmark([path_index,depth]) - path_index = path_index + 1 -if path_index < 2: - return -1 # no cycle possible -live_path_count = path_index -while len(pop_list) and live_path_count > 1: - curs = pop_list.pop() - path_index = curs[0] - this_node = curs[1] - live_paths[path_index] = live_paths[path_index] - 1 - for i in this_node.connections(): - if i.mark() is none: - i.setmark([path_index,depth+1]) - push_list.append([path_index,i]) - live_paths[path_index] = live_paths[path_index] + 1 - elif i.mark()[0] != path_index and i.mark()[0] != -1: - # found a cycle! - return i.mark()[1] + this_node.mark()[1] + 1 - if live_paths[path_index] == 0: - live_path_count = live_path_count - 1 - if len(pop_list) == 0: - depth = depth + 1 - pop_list = push_list - push_list = [] --1 # no cycle found diff --git a/salalib/segmmodules/CMakeLists.txt b/salalib/segmmodules/CMakeLists.txt new file mode 100644 index 00000000..17c8adf2 --- /dev/null +++ b/salalib/segmmodules/CMakeLists.txt @@ -0,0 +1,18 @@ +target_sources(salalib + PRIVATE + segmangular.cpp + segmmetric.cpp + segmtopological.cpp + segmtulip.cpp + segmtopologicalpd.cpp + segmmetricpd.cpp + segmtulipdepth.cpp + PUBLIC + segmangular.h + segmmetric.h + segmtopological.h + segmtulip.h + segmhelpers.h + segmmetricpd.h + segmtopologicalpd.h + segmtulipdepth.h) diff --git a/salalib/segmmodules/segmangular.cpp b/salalib/segmmodules/segmangular.cpp new file mode 100644 index 00000000..93d34e5e --- /dev/null +++ b/salalib/segmmodules/segmangular.cpp @@ -0,0 +1,171 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "salalib/segmmodules/segmangular.h" +#include "salalib/options.h" + +#include "genlib/stringutils.h" + +bool SegmentAngular::run(Communicator *comm, ShapeGraph &map, bool) { + + if (map.getMapType() != ShapeMap::SEGMENTMAP) { + return false; + } + + AttributeTable &attributes = map.getAttributeTable(); + + time_t atime = 0; + if (comm) { + qtimer(atime, 0); + comm->CommPostMessage(Communicator::NUM_RECORDS, map.getConnections().size()); + } + + // note: radius must be sorted lowest to highest, but if -1 occurs ("radius n") it needs to be last... + // ...to ensure no mess ups, we'll re-sort here: + bool radius_n = false; + std::vector radii; + for (double radius : m_radius_set) { + if (radius < 0) { + radius_n = true; + } else { + radii.push_back(radius); + } + } + if (radius_n) { + radii.push_back(-1.0); + } + + std::vector depth_col, count_col, total_col; + // first enter table values + for (int radius : radii) { + std::string radius_text = makeRadiusText(Options::RADIUS_ANGULAR, radius); + std::string depth_col_text = std::string("Angular Mean Depth") + radius_text; + attributes.insertOrResetColumn(depth_col_text.c_str()); + std::string count_col_text = std::string("Angular Node Count") + radius_text; + attributes.insertOrResetColumn(count_col_text.c_str()); + std::string total_col_text = std::string("Angular Total Depth") + radius_text; + attributes.insertOrResetColumn(total_col_text.c_str()); + } + + for (int radius : radii) { + std::string radius_text = makeRadiusText(Options::RADIUS_ANGULAR, radius); + std::string depth_col_text = std::string("Angular Mean Depth") + radius_text; + depth_col.push_back(attributes.getColumnIndex(depth_col_text.c_str())); + std::string count_col_text = std::string("Angular Node Count") + radius_text; + count_col.push_back(attributes.getColumnIndex(count_col_text.c_str())); + std::string total_col_text = std::string("Angular Total Depth") + radius_text; + total_col.push_back(attributes.getColumnIndex(total_col_text.c_str())); + } + + std::vector covered(map.getShapeCount()); + size_t i = 0; + for (auto & iter : attributes){ + for (size_t j = 0; j < map.getShapeCount(); j++) { + covered[j] = false; + } + std::vector> anglebins; + anglebins.push_back(std::make_pair(0.0f, SegmentData(0, i, SegmentRef(), 0, 0.0, 0))); + + std::vector total_depth; + std::vector node_count; + for (size_t r = 0; r < radii.size(); r++) { + total_depth.push_back(0.0); + node_count.push_back(0); + } + // node_count includes this one, but will be added in next algo: + while (anglebins.size()) { + auto iter = anglebins.begin(); + SegmentData lineindex = iter->second; + if (!covered[lineindex.ref]) { + covered[lineindex.ref] = true; + double depth_to_line = iter->first; + total_depth[lineindex.coverage] += depth_to_line; + node_count[lineindex.coverage] += 1; + anglebins.erase(iter); + Connector &line = map.getConnections()[lineindex.ref]; + if (lineindex.dir != -1) { + for (auto &segconn : line.m_forward_segconns) { + if (!covered[segconn.first.ref]) { + double angle = depth_to_line + segconn.second; + size_t rbin = lineindex.coverage; + while (rbin != radii.size() && radii[rbin] != -1 && angle > radii[rbin]) { + rbin++; + } + if (rbin != radii.size()) { + depthmapX::insert_sorted( + anglebins, std::make_pair(float(angle), + SegmentData(segconn.first, SegmentRef(), 0, 0.0, rbin))); + } + } + } + } + if (lineindex.dir != 1) { + for (auto &segconn : line.m_back_segconns) { + if (!covered[segconn.first.ref]) { + double angle = depth_to_line + segconn.second; + size_t rbin = lineindex.coverage; + while (rbin != radii.size() && radii[rbin] != -1 && angle > radii[rbin]) { + rbin++; + } + if (rbin != radii.size()) { + depthmapX::insert_sorted( + anglebins, std::make_pair(float(angle), + SegmentData(segconn.first, SegmentRef(), 0, 0.0, rbin))); + } + } + } + } + } else { + anglebins.erase(iter); + } + } + AttributeRow &row = iter.getRow(); + // set the attributes for this node: + int curs_node_count = 0; + double curs_total_depth = 0.0; + for (size_t r = 0; r < radii.size(); r++) { + curs_node_count += node_count[r]; + curs_total_depth += total_depth[r]; + row.setValue(count_col[r], float(curs_node_count)); + if (curs_node_count > 1) { + // note -- node_count includes this one -- mean depth as per p.108 Social Logic of Space + double mean_depth = curs_total_depth / double(curs_node_count - 1); + row.setValue(depth_col[r], float(mean_depth)); + row.setValue(total_col[r], float(curs_total_depth)); + } else { + row.setValue(depth_col[r], -1); + row.setValue(total_col[r], -1); + } + } + // + if (comm) { + if (qtimer(atime, 500)) { + if (comm->IsCancelled()) { + throw Communicator::CancelledException(); + } + comm->CommPostMessage(Communicator::CURRENT_RECORD, i); + } + } + i++; + } + + map.setDisplayedAttribute(-2); // <- override if it's already showing + map.setDisplayedAttribute(depth_col.back()); + + return true; +} diff --git a/salalib/segmmodules/segmangular.h b/salalib/segmmodules/segmangular.h new file mode 100644 index 00000000..629d0218 --- /dev/null +++ b/salalib/segmmodules/segmangular.h @@ -0,0 +1,31 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/isegment.h" + +class SegmentAngular : ISegment { + private: + std::set m_radius_set; + + public: + std::string getAnalysisName() const override { return "Angular Analysis"; } + bool run(Communicator *comm, ShapeGraph &map, bool) override; + SegmentAngular(std::set radius_set) : m_radius_set(radius_set) {} +}; diff --git a/salalib/topomet.h b/salalib/segmmodules/segmhelpers.h similarity index 59% rename from salalib/topomet.h rename to salalib/segmmodules/segmhelpers.h index 9516e102..6cc43904 100644 --- a/salalib/topomet.h +++ b/salalib/segmmodules/segmhelpers.h @@ -1,52 +1,54 @@ -// sala - a component of the depthmapX - spatial network analysis platform -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - - - -#ifndef __TOPOMET_H__ -#define __TOPOMET_H__ - -enum {TOPOMET_METHOD_TOPOLOGICAL = 0, TOPOMET_METHOD_METRIC = 1}; - -struct TopoMetSegmentRef { - int ref; - int dir; - double dist; - int previous; - bool done; - TopoMetSegmentRef(int r = -1, int d = -1, double di = 0.0, int p = -1) - { ref = r; dir = d; dist = di; previous = p; done = false; } -}; - -// should be double not float! - -struct TopoMetSegmentChoice { - double choice; - double wchoice; - TopoMetSegmentChoice() - { choice = 0.0; wchoice = 0.0; } -}; - -struct SegInfo { - double length; - int layer; - SegInfo() - { length = 0.0f; layer = 0; } -}; - - - -#endif +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +struct TopoMetSegmentRef { + int ref; + int dir; + double dist; + int previous; + bool done; + TopoMetSegmentRef(int r = -1, int d = -1, double di = 0.0, int p = -1) { + ref = r; + dir = d; + dist = di; + previous = p; + done = false; + } +}; + +// should be double not float! + +struct TopoMetSegmentChoice { + double choice; + double wchoice; + TopoMetSegmentChoice() { + choice = 0.0; + wchoice = 0.0; + } +}; + +struct SegInfo { + double length; + int layer; + SegInfo() { + length = 0.0f; + layer = 0; + } +}; diff --git a/salalib/segmmodules/segmmetric.cpp b/salalib/segmmodules/segmmetric.cpp new file mode 100644 index 00000000..64b8ba93 --- /dev/null +++ b/salalib/segmmodules/segmmetric.cpp @@ -0,0 +1,205 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "salalib/segmmodules/segmmetric.h" + +#include "genlib/stringutils.h" + +bool SegmentMetric::run(Communicator *comm, ShapeGraph &map, bool) { + + AttributeTable &attributes = map.getAttributeTable(); + + bool retvar = true; + + time_t atime = 0; + + if (comm) { + qtimer(atime, 0); + comm->CommPostMessage(Communicator::NUM_RECORDS, + (m_sel_only ? map.getSelSet().size() : map.getConnections().size())); + } + int reccount = 0; + + // record axial line refs for topological analysis + std::vector axialrefs; + // quick through to find the longest seg length + std::vector seglengths; + float maxseglength = 0.0f; + for (size_t cursor = 0; cursor < map.getShapeCount(); cursor++) { + AttributeRow& row = map.getAttributeRowFromShapeIndex(cursor); + axialrefs.push_back(row.getValue(attributes.getColumnIndex("Axial Line Ref"))); + seglengths.push_back(row.getValue(attributes.getColumnIndex("Segment Length"))); + if (seglengths.back() > maxseglength) { + maxseglength = seglengths.back(); + } + } + + std::string prefix, suffix; + int maxbin = 512; + prefix = "Metric "; + + if (m_radius != -1.0) { + suffix = dXstring::formatString(m_radius, " R%.f metric"); + } + std::string choicecol = prefix + "Choice" + suffix; + std::string wchoicecol = prefix + "Choice [SLW]" + suffix; + std::string meandepthcol = prefix + "Mean Depth" + suffix; + std::string wmeandepthcol = prefix + std::string("Mean Depth [SLW]") + suffix; + std::string totaldcol = prefix + "Total Depth" + suffix; + std::string totalcol = prefix + "Total Nodes" + suffix; + std::string wtotalcol = prefix + "Total Length" + suffix; + // + if (!m_sel_only) { + attributes.insertOrResetColumn(choicecol.c_str()); + attributes.insertOrResetColumn(wchoicecol.c_str()); + } + attributes.insertOrResetColumn(meandepthcol.c_str()); + attributes.insertOrResetColumn(wmeandepthcol.c_str()); + attributes.insertOrResetColumn(totaldcol.c_str()); + attributes.insertOrResetColumn(totalcol.c_str()); + attributes.insertOrResetColumn(wtotalcol.c_str()); + // + std::vector seen(map.getShapeCount()); + std::vector audittrail(map.getShapeCount()); + std::vector choicevals(map.getShapeCount()); + for (size_t cursor = 0; cursor < map.getShapeCount(); cursor++) { + AttributeRow& row = map.getAttributeRowFromShapeIndex(cursor); + if (m_sel_only && !row.isSelected()) { + continue; + } + for (size_t i = 0; i < map.getShapeCount(); i++) { + seen[i] = 0xffffffff; + } + std::vector list[512]; // 512 bins! + int bin = 0; + list[bin].push_back(cursor); + double rootseglength = seglengths[cursor]; + audittrail[cursor] = TopoMetSegmentRef(cursor, Connector::SEG_CONN_ALL, rootseglength * 0.5, -1); + int open = 1; + unsigned int segdepth = 0; + double total = 0.0, wtotal = 0.0, wtotaldepth = 0.0, totalsegdepth = 0.0, totalmetdepth = 0.0; + while (open != 0) { + while (list[bin].size() == 0) { + bin++; + segdepth += 1; + if (bin == maxbin) { + bin = 0; + } + } + // + TopoMetSegmentRef &here = audittrail[list[bin].back()]; + list[bin].pop_back(); + open--; + // + if (here.done) { + continue; + } else { + here.done = true; + } + // + double len = seglengths[here.ref]; + totalsegdepth += segdepth; + totalmetdepth += here.dist - len * 0.5; // preloaded with length ahead + wtotal += len; + wtotaldepth += len * (here.dist - len * 0.5); + total += 1; + // + Connector &axline = map.getConnections().at(here.ref); + int connected_cursor = -2; + + auto iter = axline.m_back_segconns.begin(); + bool backsegs = true; + + while (connected_cursor != -1) { + if (backsegs && iter == axline.m_back_segconns.end()) { + iter = axline.m_forward_segconns.begin(); + backsegs = false; + } + if (!backsegs && iter == axline.m_forward_segconns.end()) { + break; + } + + connected_cursor = iter->first.ref; + + if (seen[connected_cursor] > segdepth && static_cast(connected_cursor) != cursor) { + bool seenalready = (seen[connected_cursor] == 0xffffffff) ? false : true; + float length = seglengths[connected_cursor]; + audittrail[connected_cursor] = + TopoMetSegmentRef(connected_cursor, here.dir, here.dist + length, here.ref); + seen[connected_cursor] = segdepth; + if (m_radius == -1 || here.dist + length < m_radius) { + // puts in a suitable bin ahead of us... + open++; + // + // better to divide by 511 but have 512 bins... + list[(bin + int(floor(0.5 + 511 * length / maxseglength))) % 512].push_back(connected_cursor); + } + // not sure why this is outside the radius restriction + // (sel_only: with restricted selection set, not all lines will be labelled) + // (seenalready: need to check that we're not doing this twice, given the seen can go twice) + + // Quick mod - TV + if (!m_sel_only && connected_cursor > int(cursor) && + !seenalready) { // only one way paths, saves doing this twice + int subcur = connected_cursor; + while (subcur != -1) { + // in this method of choice, start and end lines are included + choicevals[subcur].choice += 1; + choicevals[subcur].wchoice += (rootseglength * length); + subcur = audittrail[subcur].previous; + } + } + } + iter++; + } + } + // also put in mean depth: + // + row.setValue(meandepthcol.c_str(), totalmetdepth / (total - 1)); + row.setValue(totaldcol.c_str(), totalmetdepth); + row.setValue(wmeandepthcol.c_str(), wtotaldepth / (wtotal - rootseglength)); + row.setValue(totalcol.c_str(), total); + row.setValue(wtotalcol.c_str(), wtotal); + // + if (comm) { + if (qtimer(atime, 500)) { + if (comm->IsCancelled()) { + throw Communicator::CancelledException(); + } + } + comm->CommPostMessage(Communicator::CURRENT_RECORD, reccount); + } + reccount++; + } + if (!m_sel_only) { + // note, I've stopped sel only from calculating choice values: + for (size_t cursor = 0; cursor < map.getShapeCount(); cursor++) { + AttributeRow& row = map.getAttributeRowFromShapeIndex(cursor); + row.setValue(choicecol.c_str(), choicevals[cursor].choice); + row.setValue(wchoicecol.c_str(), choicevals[cursor].wchoice); + } + } + + if (!m_sel_only) { + map.setDisplayedAttribute(attributes.getColumnIndex(choicecol.c_str())); + } else { + map.setDisplayedAttribute(attributes.getColumnIndex(meandepthcol.c_str())); + } + + return retvar; +} diff --git a/salalib/segmmodules/segmmetric.h b/salalib/segmmodules/segmmetric.h new file mode 100644 index 00000000..7e68455f --- /dev/null +++ b/salalib/segmmodules/segmmetric.h @@ -0,0 +1,34 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/segmmodules/segmhelpers.h" + +#include "salalib/isegment.h" + +class SegmentMetric : ISegment { + private: + double m_radius; + bool m_sel_only; + + public: + std::string getAnalysisName() const override { return "Metric Analysis"; } + bool run(Communicator *comm, ShapeGraph &map, bool) override; + SegmentMetric(double radius, bool sel_only) : m_radius(radius), m_sel_only(sel_only) {} +}; diff --git a/salalib/segmmodules/segmmetricpd.cpp b/salalib/segmmodules/segmmetricpd.cpp new file mode 100644 index 00000000..d54b6bf9 --- /dev/null +++ b/salalib/segmmodules/segmmetricpd.cpp @@ -0,0 +1,128 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "salalib/segmmodules/segmmetricpd.h" + +#include "genlib/stringutils.h" + +bool SegmentMetricPD::run(Communicator *, ShapeGraph &map, bool) { + + AttributeTable &attributes = map.getAttributeTable(); + + bool retvar = true; + + // record axial line refs for topological analysis + std::vector axialrefs; + // quick through to find the longest seg length + std::vector seglengths; + float maxseglength = 0.0f; + for (size_t cursor = 0; cursor < map.getShapeCount(); cursor++) { + AttributeRow &row = map.getAttributeRowFromShapeIndex(cursor); + axialrefs.push_back(row.getValue("Axial Line Ref")); + seglengths.push_back(row.getValue("Segment Length")); + if (seglengths.back() > maxseglength) { + maxseglength = seglengths.back(); + } + } + + int maxbin; + std::string prefix; + prefix = "Metric "; + maxbin = 512; + std::string depthcol = prefix + "Step Depth"; + + attributes.insertOrResetColumn(depthcol.c_str()); + + std::vector seen(map.getShapeCount()); + std::vector audittrail(map.getShapeCount()); + std::vector list[512]; // 512 bins! + int open = 0; + + for (size_t i = 0; i < map.getShapeCount(); i++) { + seen[i] = 0xffffffff; + } + for (auto &cursor : map.getSelSet()) { + seen[cursor] = 0; + open++; + double length = seglengths[cursor]; + audittrail[cursor] = TopoMetSegmentRef(cursor, Connector::SEG_CONN_ALL, length * 0.5, -1); + // better to divide by 511 but have 512 bins... + list[(int(floor(0.5 + 511 * length / maxseglength))) % 512].push_back(cursor); + AttributeRow &row = map.getAttributeRowFromShapeIndex(cursor); + row.setValue(depthcol.c_str(), 0); + } + + unsigned int segdepth = 0; + int bin = 0; + + while (open != 0) { + while (list[bin].size() == 0) { + bin++; + segdepth += 1; + if (bin == maxbin) { + bin = 0; + } + } + // + TopoMetSegmentRef &here = audittrail[list[bin].back()]; + list[bin].pop_back(); + open--; + // this is necessary using unsigned ints for "seen", as it is possible to add a node twice + if (here.done) { + continue; + } else { + here.done = true; + } + + Connector &axline = map.getConnections().at(here.ref); + int connected_cursor = -2; + + auto iter = axline.m_back_segconns.begin(); + bool backsegs = true; + + while (connected_cursor != -1) { + if (backsegs && iter == axline.m_back_segconns.end()) { + iter = axline.m_forward_segconns.begin(); + backsegs = false; + } + if (!backsegs && iter == axline.m_forward_segconns.end()) { + break; + } + + connected_cursor = iter->first.ref; + if (seen[connected_cursor] > segdepth) { + float length = seglengths[connected_cursor]; + seen[connected_cursor] = segdepth; + audittrail[connected_cursor] = + TopoMetSegmentRef(connected_cursor, here.dir, here.dist + length, here.ref); + // puts in a suitable bin ahead of us... + open++; + // + // better to divide by 511 but have 512 bins... + list[(bin + int(floor(0.5 + 511 * length / maxseglength))) % 512].push_back(connected_cursor); + AttributeRow &row = map.getAttributeRowFromShapeIndex(connected_cursor); + row.setValue(depthcol.c_str(), here.dist + length * 0.5); + } + iter++; + } + } + + map.setDisplayedAttribute(attributes.getColumnIndex(depthcol.c_str())); + + return retvar; +} diff --git a/salalib/segmmodules/segmmetricpd.h b/salalib/segmmodules/segmmetricpd.h new file mode 100644 index 00000000..3a508917 --- /dev/null +++ b/salalib/segmmodules/segmmetricpd.h @@ -0,0 +1,29 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/segmmodules/segmhelpers.h" + +#include "salalib/isegment.h" + +class SegmentMetricPD : ISegment { + public: + std::string getAnalysisName() const override { return "Metric Analysis"; } + bool run(Communicator *, ShapeGraph &map, bool) override; +}; diff --git a/salalib/segmmodules/segmtopological.cpp b/salalib/segmmodules/segmtopological.cpp new file mode 100644 index 00000000..7110ffb7 --- /dev/null +++ b/salalib/segmmodules/segmtopological.cpp @@ -0,0 +1,213 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "salalib/segmmodules/segmtopological.h" + +#include "genlib/stringutils.h" + +bool SegmentTopological::run(Communicator *comm, ShapeGraph &map, bool) { + + AttributeTable &attributes = map.getAttributeTable(); + + bool retvar = true; + + time_t atime = 0; + + if (comm) { + qtimer(atime, 0); + comm->CommPostMessage(Communicator::NUM_RECORDS, + (m_sel_only ? map.getSelSet().size() : map.getConnections().size())); + } + int reccount = 0; + + // record axial line refs for topological analysis + std::vector axialrefs; + // quick through to find the longest seg length + std::vector seglengths; + float maxseglength = 0.0f; + for (size_t cursor = 0; cursor < map.getShapeCount(); cursor++) { + AttributeRow& row = map.getAttributeRowFromShapeIndex(cursor); + axialrefs.push_back(row.getValue(attributes.getColumnIndex("Axial Line Ref"))); + seglengths.push_back(row.getValue(attributes.getColumnIndex("Segment Length"))); + if (seglengths.back() > maxseglength) { + maxseglength = seglengths.back(); + } + } + + std::string prefix, suffix; + int maxbin; + prefix = "Topological "; + maxbin = 2; + if (m_radius != -1.0) { + suffix = dXstring::formatString(m_radius, " R%.f metric"); + } + std::string choicecol = prefix + "Choice" + suffix; + std::string wchoicecol = prefix + "Choice [SLW]" + suffix; + std::string meandepthcol = prefix + "Mean Depth" + suffix; + std::string wmeandepthcol = prefix + std::string("Mean Depth [SLW]") + suffix; + std::string totaldcol = prefix + "Total Depth" + suffix; + std::string totalcol = prefix + "Total Nodes" + suffix; + std::string wtotalcol = prefix + "Total Length" + suffix; + // + if (!m_sel_only) { + attributes.insertOrResetColumn(choicecol.c_str()); + attributes.insertOrResetColumn(wchoicecol.c_str()); + } + attributes.insertOrResetColumn(meandepthcol.c_str()); + attributes.insertOrResetColumn(wmeandepthcol.c_str()); + attributes.insertOrResetColumn(totaldcol.c_str()); + attributes.insertOrResetColumn(totalcol.c_str()); + attributes.insertOrResetColumn(wtotalcol.c_str()); + // + std::vector seen(map.getShapeCount()); + std::vector audittrail(map.getShapeCount()); + std::vector choicevals(map.getShapeCount()); + for (size_t cursor = 0; cursor < map.getShapeCount(); cursor++) { + AttributeRow& row = map.getAttributeRowFromShapeIndex(cursor); + if (m_sel_only && !row.isSelected()) { + continue; + } + for (size_t i = 0; i < map.getShapeCount(); i++) { + seen[i] = 0xffffffff; + } + std::vector list[512]; // 512 bins! + int bin = 0; + list[bin].push_back(cursor); + double rootseglength = seglengths[cursor]; + audittrail[cursor] = TopoMetSegmentRef(cursor, Connector::SEG_CONN_ALL, rootseglength * 0.5, -1); + int open = 1; + unsigned int segdepth = 0; + double total = 0.0, wtotal = 0.0, wtotaldepth = 0.0, totalsegdepth = 0.0, totalmetdepth = 0.0; + while (open != 0) { + while (list[bin].size() == 0) { + bin++; + segdepth += 1; + if (bin == maxbin) { + bin = 0; + } + } + // + TopoMetSegmentRef &here = audittrail[list[bin].back()]; + list[bin].pop_back(); + open--; + // + if (here.done) { + continue; + } else { + here.done = true; + } + // + double len = seglengths[here.ref]; + totalsegdepth += segdepth; + totalmetdepth += here.dist - len * 0.5; // preloaded with length ahead + wtotal += len; + wtotaldepth += len * segdepth; + + total += 1; + // + Connector &axline = map.getConnections().at(here.ref); + int connected_cursor = -2; + + auto iter = axline.m_back_segconns.begin(); + bool backsegs = true; + + while (connected_cursor != -1) { + if (backsegs && iter == axline.m_back_segconns.end()) { + iter = axline.m_forward_segconns.begin(); + backsegs = false; + } + if (!backsegs && iter == axline.m_forward_segconns.end()) { + break; + } + + connected_cursor = iter->first.ref; + + if (seen[connected_cursor] > segdepth && static_cast(connected_cursor) != cursor) { + bool seenalready = (seen[connected_cursor] == 0xffffffff) ? false : true; + float length = seglengths[connected_cursor]; + int axialref = axialrefs[connected_cursor]; + audittrail[connected_cursor] = + TopoMetSegmentRef(connected_cursor, here.dir, here.dist + length, here.ref); + seen[connected_cursor] = segdepth; + if (m_radius == -1 || here.dist + length < m_radius) { + // puts in a suitable bin ahead of us... + open++; + // + if (axialrefs[here.ref] == axialref) { + list[bin].push_back(connected_cursor); + } else { + list[(bin + 1) % 2].push_back(connected_cursor); + seen[connected_cursor] = + segdepth + 1; // this is so if another node is connected directly to this one but + // is found later it is still handled -- note it can result in the + // connected cursor being added twice + } + } + // not sure why this is outside the radius restriction + // (sel_only: with restricted selection set, not all lines will be labelled) + // (seenalready: need to check that we're not doing this twice, given the seen can go twice) + + // Quick mod - TV + if (!m_sel_only && connected_cursor > int(cursor) && + !seenalready) { // only one way paths, saves doing this twice + int subcur = connected_cursor; + while (subcur != -1) { + // in this method of choice, start and end lines are included + choicevals[subcur].choice += 1; + choicevals[subcur].wchoice += (rootseglength * length); + subcur = audittrail[subcur].previous; + } + } + } + iter++; + } + } + // also put in mean depth: + row.setValue(meandepthcol.c_str(), totalsegdepth / (total - 1)); + row.setValue(totaldcol.c_str(), totalsegdepth); + row.setValue(wmeandepthcol.c_str(), wtotaldepth / (wtotal - rootseglength)); + row.setValue(totalcol.c_str(), total); + row.setValue(wtotalcol.c_str(), wtotal); + // + if (comm) { + if (qtimer(atime, 500)) { + if (comm->IsCancelled()) { + throw Communicator::CancelledException(); + } + } + comm->CommPostMessage(Communicator::CURRENT_RECORD, reccount); + } + reccount++; + } + if (!m_sel_only) { + // note, I've stopped sel only from calculating choice values: + for (size_t cursor = 0; cursor < map.getShapeCount(); cursor++) { + AttributeRow& row = map.getAttributeRowFromShapeIndex(cursor); + row.setValue(choicecol.c_str(), choicevals[cursor].choice); + row.setValue(wchoicecol.c_str(), choicevals[cursor].wchoice); + } + } + + if (!m_sel_only) { + map.setDisplayedAttribute(attributes.getColumnIndex(choicecol.c_str())); + } else { + map.setDisplayedAttribute(attributes.getColumnIndex(meandepthcol.c_str())); + } + + return retvar; +} diff --git a/salalib/segmmodules/segmtopological.h b/salalib/segmmodules/segmtopological.h new file mode 100644 index 00000000..c4824d67 --- /dev/null +++ b/salalib/segmmodules/segmtopological.h @@ -0,0 +1,34 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/segmmodules/segmhelpers.h" + +#include "salalib/isegment.h" + +class SegmentTopological : ISegment { + private: + double m_radius; + bool m_sel_only; + + public: + std::string getAnalysisName() const override { return "Topological Analysis"; } + bool run(Communicator *comm, ShapeGraph &map, bool) override; + SegmentTopological(double radius, bool sel_only) : m_radius(radius), m_sel_only(sel_only) {} +}; diff --git a/salalib/segmmodules/segmtopologicalpd.cpp b/salalib/segmmodules/segmtopologicalpd.cpp new file mode 100644 index 00000000..173cd01c --- /dev/null +++ b/salalib/segmmodules/segmtopologicalpd.cpp @@ -0,0 +1,133 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "salalib/segmmodules/segmtopologicalpd.h" + +#include "genlib/stringutils.h" + +bool SegmentTopologicalPD::run(Communicator *, ShapeGraph &map, bool) { + + AttributeTable &attributes = map.getAttributeTable(); + + bool retvar = true; + + // record axial line refs for topological analysis + std::vector axialrefs; + // quick through to find the longest seg length + std::vector seglengths; + float maxseglength = 0.0f; + for (size_t cursor = 0; cursor < map.getShapeCount(); cursor++) { + AttributeRow& row = map.getAttributeRowFromShapeIndex(cursor); + axialrefs.push_back(row.getValue("Axial Line Ref")); + seglengths.push_back(row.getValue("Segment Length")); + if (seglengths.back() > maxseglength) { + maxseglength = seglengths.back(); + } + } + + int maxbin = 2; + std::string prefix = "Topological "; + std::string depthcol = prefix + "Step Depth"; + + attributes.insertOrResetColumn(depthcol.c_str()); + + std::vector seen(map.getShapeCount()); + std::vector audittrail(map.getShapeCount()); + std::vector list[512]; // 512 bins! + int open = 0; + + for (size_t i = 0; i < map.getShapeCount(); i++) { + seen[i] = 0xffffffff; + } + for (auto &cursor : map.getSelSet()) { + seen[cursor] = 0; + open++; + double length = seglengths[cursor]; + audittrail[cursor] = TopoMetSegmentRef(cursor, Connector::SEG_CONN_ALL, length * 0.5, -1); + list[0].push_back(cursor); + attributes.getRow(AttributeKey(cursor)).setValue(depthcol.c_str(), 0); + } + + unsigned int segdepth = 0; + int bin = 0; + + while (open != 0) { + while (list[bin].size() == 0) { + bin++; + segdepth += 1; + if (bin == maxbin) { + bin = 0; + } + } + // + TopoMetSegmentRef &here = audittrail[list[bin].back()]; + list[bin].pop_back(); + open--; + // this is necessary using unsigned ints for "seen", as it is possible to add a node twice + if (here.done) { + continue; + } else { + here.done = true; + } + + Connector &axline = map.getConnections().at(here.ref); + int connected_cursor = -2; + + auto iter = axline.m_back_segconns.begin(); + bool backsegs = true; + + while (connected_cursor != -1) { + if (backsegs && iter == axline.m_back_segconns.end()) { + iter = axline.m_forward_segconns.begin(); + backsegs = false; + } + if (!backsegs && iter == axline.m_forward_segconns.end()) { + break; + } + + connected_cursor = iter->first.ref; + AttributeRow& row = map.getAttributeRowFromShapeIndex(connected_cursor); + if (seen[connected_cursor] > segdepth) { + float length = seglengths[connected_cursor]; + int axialref = axialrefs[connected_cursor]; + seen[connected_cursor] = segdepth; + audittrail[connected_cursor] = + TopoMetSegmentRef(connected_cursor, here.dir, here.dist + length, here.ref); + // puts in a suitable bin ahead of us... + open++; + // + if (axialrefs[here.ref] == axialref) { + list[bin].push_back(connected_cursor); + row.setValue(depthcol.c_str(), segdepth); + } else { + list[(bin + 1) % 2].push_back(connected_cursor); + seen[connected_cursor] = + segdepth + + 1; // this is so if another node is connected directly to this one but is found later it is + // still handled -- note it can result in the connected cursor being added twice + row.setValue(depthcol.c_str(), segdepth + 1); + } + } + iter++; + } + } + + map.setDisplayedAttribute(attributes.getColumnIndex(depthcol.c_str())); + + return retvar; +} diff --git a/salalib/segmmodules/segmtopologicalpd.h b/salalib/segmmodules/segmtopologicalpd.h new file mode 100644 index 00000000..a1aa3c72 --- /dev/null +++ b/salalib/segmmodules/segmtopologicalpd.h @@ -0,0 +1,29 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/segmmodules/segmhelpers.h" + +#include "salalib/isegment.h" + +class SegmentTopologicalPD : ISegment { + public: + std::string getAnalysisName() const override { return "Topological Analysis"; } + bool run(Communicator *, ShapeGraph &map, bool) override; +}; diff --git a/salalib/segmmodules/segmtulip.cpp b/salalib/segmmodules/segmtulip.cpp new file mode 100644 index 00000000..0466c0b1 --- /dev/null +++ b/salalib/segmmodules/segmtulip.cpp @@ -0,0 +1,724 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "salalib/segmmodules/segmtulip.h" + +#include "genlib/stringutils.h" + +bool SegmentTulip::run(Communicator *comm, ShapeGraph &map, bool) { + + if (map.getMapType() != ShapeMap::SEGMENTMAP) { + return false; + } + + // TODO: Understand what these parameters do. They were never truly provided in the original function + int weighting_col2 = -1; + int routeweight_col = -1; + bool interactive = true; + + AttributeTable &attributes = map.getAttributeTable(); + + int processed_rows = 0; + + time_t atime = 0; + + if (comm) { + qtimer(atime, 0); + comm->CommPostMessage(Communicator::NUM_RECORDS, + (m_sel_only ? map.getSelSet().size() : map.getConnections().size())); + } + + // note: radius must be sorted lowest to highest, but if -1 occurs ("radius n") it needs to be last... + // ...to ensure no mess ups, we'll re-sort here: + bool radius_n = false; + std::vector radius_unconverted; + for (int radius : m_radius_set) { + if (radius == -1.0) { + radius_n = true; + } else { + radius_unconverted.push_back(radius); + } + } + if (radius_n) { + radius_unconverted.push_back(-1.0); + } + + // retrieve weighted col data, as this may well be overwritten in the new analysis: + std::vector weights; + std::vector routeweights; // EF + std::string weighting_col_text; + + int tulip_bins = m_tulip_bins; + + if (m_weighted_measure_col != -1) { + weighting_col_text = attributes.getColumnName(m_weighted_measure_col); + for (size_t i = 0; i < map.getConnections().size(); i++) { + weights.push_back(map.getAttributeRowFromShapeIndex(i).getValue(m_weighted_measure_col)); + } + } else { // Normal run // TV + for (size_t i = 0; i < map.getConnections().size(); i++) { + weights.push_back(1.0f); + } + } + // EF routeweight* + std::string routeweight_col_text; + if (routeweight_col != -1) { + // we normalise the column values between 0 and 1 and reverse it so that high values can be treated as a 'low + // cost' - similar to the angular cost + double max_value = attributes.getColumn(routeweight_col).getStats().max; + routeweight_col_text = attributes.getColumnName(routeweight_col); + for (size_t i = 0; i < map.getConnections().size(); i++) { + routeweights.push_back(1.0 - (map.getAttributeRowFromShapeIndex(i).getValue(routeweight_col) / + max_value)); // scale and revert! + } + } else { // Normal run // TV + for (size_t i = 0; i < map.getConnections().size(); i++) { + routeweights.push_back(1.0f); + } + } + //*EF routeweight + + // EFEF* + // for origin-destination weighting + std::vector weights2; + std::string weighting_col_text2; + if (weighting_col2 != -1) { + weighting_col_text2 = attributes.getColumnName(weighting_col2); + for (size_t i = 0; i < map.getConnections().size(); i++) { + weights2.push_back(map.getAttributeRowFromShapeIndex(i).getValue(weighting_col2)); + } + } else { // Normal run // TV + for (size_t i = 0; i < map.getConnections().size(); i++) { + weights2.push_back(1.0f); + } + } + //*EFEF + + std::string tulip_text = std::string("T") + dXstring::formatString(tulip_bins, "%d"); + + // first enter the required attribute columns: + size_t r; + for (r = 0; r < radius_unconverted.size(); r++) { + std::string radius_text = makeRadiusText(m_radius_type, radius_unconverted[r]); + if (m_choice) { + // EF routeweight * + if (routeweight_col != -1) { + std::string choice_col_text = + tulip_text + " Choice [Route weight by " + routeweight_col_text + "]" + radius_text; + attributes.insertOrResetColumn(choice_col_text.c_str()); + if (m_weighted_measure_col != -1) { + std::string w_choice_col_text = tulip_text + " Choice [[Route weight by " + routeweight_col_text + + "][" + weighting_col_text + " Wgt]]" + radius_text; + + attributes.insertOrResetColumn(w_choice_col_text.c_str()); + } + // EFEF* + if (weighting_col2 != -1) { + std::string w_choice_col_text2 = tulip_text + " Choice [[Route weight by " + routeweight_col_text + + "][" + weighting_col_text + "-" + weighting_col_text2 + " Wgt]]" + + radius_text; + + attributes.insertOrResetColumn(w_choice_col_text2.c_str()); + } + //*EFEF + } + //*EF routeweight + else { // Normal run // TV + std::string choice_col_text = tulip_text + " Choice" + radius_text; + attributes.insertOrResetColumn(choice_col_text.c_str()); + if (m_weighted_measure_col != -1) { + std::string w_choice_col_text = + tulip_text + " Choice [" + weighting_col_text + " Wgt]" + radius_text; + attributes.insertOrResetColumn(w_choice_col_text.c_str()); + } + // EFEF* + if (weighting_col2 != -1) { + std::string w_choice_col_text2 = tulip_text + " Choice [" + weighting_col_text + "-" + + weighting_col_text2 + " Wgt]" + radius_text; + attributes.insertOrResetColumn(w_choice_col_text2.c_str()); + } + //*EFEF + } + } + + // EF routeweight * + if (routeweight_col != -1) { + std::string integ_col_text = tulip_text + " Integration [Route weight by " + routeweight_col_text + "]" + + radius_text; // <- note, the fact this is a tulip is unnecessary + std::string w_integ_col_text = tulip_text + " Integration [[Route weight by " + routeweight_col_text + + "][" + weighting_col_text + " Wgt]]" + radius_text; + + std::string count_col_text = tulip_text + " Node Count [Route weight by " + routeweight_col_text + "]" + + radius_text; // <- note, the fact this is a tulip is unnecessary + std::string td_col_text = tulip_text + " Total Depth [Route weight by " + routeweight_col_text + "]" + + radius_text; // <- note, the fact this is a tulip is unnecessary + // '[' comes after 'R' in ASCII, so this column will come after Mean Depth R... + std::string w_td_text = tulip_text + " Total Depth [[Route weight by " + routeweight_col_text + "][" + + weighting_col_text + " Wgt]]" + radius_text; + std::string total_weight_text = tulip_text + " Total " + weighting_col_text + " [Route weight by " + + routeweight_col_text + "]" + radius_text; + + attributes.insertOrResetColumn(integ_col_text.c_str()); + attributes.insertOrResetColumn(count_col_text.c_str()); + attributes.insertOrResetColumn(td_col_text.c_str()); + if (m_weighted_measure_col != -1) { + attributes.insertOrResetColumn(w_integ_col_text.c_str()); + attributes.insertOrResetColumn(w_td_text.c_str()); + attributes.insertOrResetColumn(total_weight_text.c_str()); + } + } + //*EF routeweight + else { // Normal run // TV + std::string integ_col_text = + tulip_text + " Integration" + radius_text; // <- note, the fact this is a tulip is unnecessary + std::string w_integ_col_text = tulip_text + " Integration [" + weighting_col_text + " Wgt]" + radius_text; + + std::string count_col_text = + tulip_text + " Node Count" + radius_text; // <- note, the fact this is a tulip is unnecessary + std::string td_col_text = + tulip_text + " Total Depth" + radius_text; // <- note, the fact this is a tulip is unnecessary + // '[' comes after 'R' in ASCII, so this column will come after Mean Depth R... + std::string w_td_text = tulip_text + " Total Depth [" + weighting_col_text + " Wgt]" + radius_text; + std::string total_weight_text = tulip_text + " Total " + weighting_col_text + radius_text; + + attributes.insertOrResetColumn(integ_col_text.c_str()); + attributes.insertOrResetColumn(count_col_text.c_str()); + attributes.insertOrResetColumn(td_col_text.c_str()); + if (m_weighted_measure_col != -1) { + attributes.insertOrResetColumn(w_integ_col_text.c_str()); + attributes.insertOrResetColumn(w_td_text.c_str()); + attributes.insertOrResetColumn(total_weight_text.c_str()); + } + } + } + std::vector choice_col, w_choice_col, w_choice_col2, count_col, integ_col, w_integ_col, td_col, w_td_col, + total_weight_col; + // then look them up! eek.... + for (r = 0; r < radius_unconverted.size(); r++) { + std::string radius_text = makeRadiusText(m_radius_type, radius_unconverted[r]); + if (m_choice) { + // EF routeweight * + if (routeweight_col != -1) { + std::string choice_col_text = + tulip_text + " Choice [Route weight by " + routeweight_col_text + "]" + radius_text; + choice_col.push_back(attributes.getColumnIndex(choice_col_text.c_str())); + if (m_weighted_measure_col != -1) { + std::string w_choice_col_text = tulip_text + " Choice [[Route weight by " + routeweight_col_text + + "][" + weighting_col_text + " Wgt]]" + radius_text; + w_choice_col.push_back(attributes.getColumnIndex(w_choice_col_text.c_str())); + } + // EFEF* + if (weighting_col2 != -1) { + std::string w_choice_col_text2 = tulip_text + " Choice [[Route weight by " + routeweight_col_text + + "][" + weighting_col_text + "-" + weighting_col_text2 + " Wgt]]" + + radius_text; + w_choice_col2.push_back(attributes.getColumnIndex(w_choice_col_text2.c_str())); + } + //*EFEF + } + //* EF routeweight + else { // Normal run // TV + std::string choice_col_text = tulip_text + " Choice" + radius_text; + choice_col.push_back(attributes.getColumnIndex(choice_col_text.c_str())); + if (m_weighted_measure_col != -1) { + std::string w_choice_col_text = + tulip_text + " Choice [" + weighting_col_text + " Wgt]" + radius_text; + w_choice_col.push_back(attributes.getColumnIndex(w_choice_col_text.c_str())); + } + // EFEF* + if (weighting_col2 != -1) { + std::string w_choice_col_text2 = tulip_text + " Choice [" + weighting_col_text + "-" + + weighting_col_text2 + " Wgt]" + radius_text; + w_choice_col2.push_back(attributes.getColumnIndex(w_choice_col_text2.c_str())); + } + //*EFEF + } + } + // EF routeweight * + if (routeweight_col != -1) { + std::string integ_col_text = tulip_text + " Integration [Route weight by " + routeweight_col_text + "]" + + radius_text; // <- note, the fact this is a tulip is unnecessary + std::string w_integ_col_text = tulip_text + " Integration [[Route weight by " + routeweight_col_text + + "][" + weighting_col_text + " Wgt]]" + radius_text; + + std::string count_col_text = tulip_text + " Node Count [Route weight by " + routeweight_col_text + "]" + + radius_text; // <- note, the fact this is a tulip is unnecessary + std::string td_col_text = tulip_text + " Total Depth [Route weight by " + routeweight_col_text + "]" + + radius_text; // <- note, the fact this is a tulip is unnecessary + std::string w_td_text = tulip_text + " Total Depth [[Route weight by " + routeweight_col_text + "][" + + weighting_col_text + " Wgt]]" + radius_text; + std::string total_weight_col_text = tulip_text + " Total " + weighting_col_text + " [Route weight by " + + routeweight_col_text + "]" + radius_text; + + integ_col.push_back(attributes.getColumnIndex(integ_col_text.c_str())); + count_col.push_back(attributes.getColumnIndex(count_col_text.c_str())); + td_col.push_back(attributes.getColumnIndex(td_col_text.c_str())); + if (m_weighted_measure_col != -1) { + // '[' comes after 'R' in ASCII, so this column will come after Mean Depth R... + w_integ_col.push_back(attributes.getColumnIndex(w_integ_col_text.c_str())); + w_td_col.push_back(attributes.getColumnIndex(w_td_text.c_str())); + total_weight_col.push_back(attributes.getColumnIndex(total_weight_col_text.c_str())); + } + } + //* EF routeweight + else { // Normal run // TV + std::string integ_col_text = + tulip_text + " Integration" + radius_text; // <- note, the fact this is a tulip is unnecessary + std::string w_integ_col_text = tulip_text + " Integration [" + weighting_col_text + " Wgt]" + radius_text; + + std::string count_col_text = + tulip_text + " Node Count" + radius_text; // <- note, the fact this is a tulip is unnecessary + std::string td_col_text = + tulip_text + " Total Depth" + radius_text; // <- note, the fact this is a tulip is unnecessary + std::string w_td_text = tulip_text + " Total Depth [" + weighting_col_text + " Wgt]" + radius_text; + std::string total_weight_col_text = tulip_text + " Total " + weighting_col_text + radius_text; + + integ_col.push_back(attributes.getColumnIndex(integ_col_text.c_str())); + count_col.push_back(attributes.getColumnIndex(count_col_text.c_str())); + td_col.push_back(attributes.getColumnIndex(td_col_text.c_str())); + if (m_weighted_measure_col != -1) { + // '[' comes after 'R' in ASCII, so this column will come after Mean Depth R... + w_integ_col.push_back(attributes.getColumnIndex(w_integ_col_text.c_str())); + w_td_col.push_back(attributes.getColumnIndex(w_td_text.c_str())); + total_weight_col.push_back(attributes.getColumnIndex(total_weight_col_text.c_str())); + } + } + } + + tulip_bins /= 2; // <- actually use semicircle of tulip bins + tulip_bins += 1; + + std::vector> bins(tulip_bins); + + // TODO: Replace these with STL + AnalysisInfo ***audittrail; + unsigned int **uncovered; + audittrail = new AnalysisInfo **[map.getConnections().size()]; + uncovered = new unsigned int *[map.getConnections().size()]; + for (size_t i = 0; i < map.getConnections().size(); i++) { + audittrail[i] = new AnalysisInfo *[radius_unconverted.size()]; + for (size_t j = 0; j < radius_unconverted.size(); j++) { + audittrail[i][j] = new AnalysisInfo[2]; + } + uncovered[i] = new unsigned int[2]; + } + std::vector radius; + for (r = 0; r < radius_unconverted.size(); r++) { + if (m_radius_type == Options::RADIUS_ANGULAR && radius_unconverted[r] != -1) { + radius.push_back(floor(radius_unconverted[r] * tulip_bins * 0.5)); + } else { + radius.push_back(radius_unconverted[r]); + } + } + // entered once for each segment + int length_col = attributes.getColumnIndex("Segment Length"); + std::vector lengths; + if (length_col != -1) { + for (size_t i = 0; i < map.getConnections().size(); i++) { + AttributeRow& row = map.getAttributeRowFromShapeIndex(i); + lengths.push_back(row.getValue(length_col)); + } + } + + int radiussize = radius.size(); + int radiusmask = 0; + for (int i = 0; i < radiussize; i++) { + radiusmask |= (1 << i); + } + + for (size_t cursor = 0; cursor < map.getConnections().size(); cursor++) { + AttributeRow &row = + map.getAttributeRowFromShapeIndex(cursor); + + if (m_sel_only) { + // could use m_selection_set.searchindex(rowid) to find + // if this row is selected as m_selection_set is ordered for axial and segment maps, etc + // BUT, actually quicker to check the tag in the attributes that shows it's selected + if (!row.isSelected()) { + continue; + } + } + + for (int k = 0; k < tulip_bins; k++) { + bins[k].clear(); + } + for (size_t j = 0; j < map.getConnections().size(); j++) { + for (int dir = 0; dir < 2; dir++) { + for (int k = 0; k < radiussize; k++) { + audittrail[j][k][dir].clearLine(); + } + uncovered[j][dir] = radiusmask; + } + } + + double rootseglength = row.getValue(length_col); + double rootweight = (m_weighted_measure_col != -1) ? weights[cursor] : 0.0; + + // setup: direction 0 (both ways), segment i, previous -1, segdepth (step depth) 0, metricdepth 0.5 * + // rootseglength, bin 0 + SegmentData segmentData(0, cursor, SegmentRef(), 0, 0.5 * rootseglength, radiusmask); + auto it = std::lower_bound(bins[0].begin(), bins[0].end(), segmentData); + if (it == bins[0].end() || segmentData != *it) { + bins[0].insert(it, segmentData); + } + // this version below is only designed to be used temporarily -- + // could be on an option? + // bins[0].push_back(SegmentData(0,rowid,SegmentRef(),0,0.0,radiusmask)); + int depthlevel = 0; + int opencount = 1; + size_t currentbin = 0; + while (opencount) { + while (!bins[currentbin].size()) { + depthlevel++; + currentbin++; + if (currentbin == static_cast(tulip_bins)) { + currentbin = 0; + } + } + SegmentData lineindex = bins[currentbin].back(); + bins[currentbin].pop_back(); + // + opencount--; + + int ref = lineindex.ref; + int dir = (lineindex.dir == 1) ? 0 : 1; + int coverage = lineindex.coverage & uncovered[ref][dir]; + if (coverage != 0) { + int rbin = 0; + int rbinbase; + if (lineindex.previous.ref != -1) { + uncovered[ref][dir] &= ~coverage; + while (((coverage >> rbin) & 0x1) == 0) + rbin++; + rbinbase = rbin; + while (rbin < radiussize) { + if (((coverage >> rbin) & 0x1) == 1) { + audittrail[ref][rbin][dir].depth = depthlevel; + audittrail[ref][rbin][dir].previous = lineindex.previous; + audittrail[lineindex.previous.ref][rbin][(lineindex.previous.dir == 1) ? 0 : 1].leaf = + false; + } + rbin++; + } + } else { + rbinbase = 0; + uncovered[ref][0] &= ~coverage; + uncovered[ref][1] &= ~coverage; + } + Connector &line = map.getConnections()[ref]; + float seglength; + int extradepth; + if (lineindex.dir != -1) { + for (auto &segconn : line.m_forward_segconns) { + rbin = rbinbase; + SegmentRef conn = segconn.first; + if ((uncovered[conn.ref][(conn.dir == 1 ? 0 : 1)] & coverage) != 0) { + // EF routeweight* + if (routeweight_col != -1) { // EF here we do the weighting of the angular cost by the + // weight of the next segment + // note that the content of the routeweights array is scaled between 0 and 1 and is + // reversed + // such that: = 1.0-(attributes.getValue(i, routeweight_col)/max_value) + extradepth = (int)floor(segconn.second * tulip_bins * 0.5 * routeweights[conn.ref]); + } + //*EF routeweight + else { + extradepth = (int)floor(segconn.second * tulip_bins * 0.5); + } + seglength = lengths[conn.ref]; + switch (m_radius_type) { + case Options::RADIUS_ANGULAR: + while (rbin != radiussize && radius[rbin] != -1 && + depthlevel + extradepth > (int)radius[rbin]) { + rbin++; + } + break; + case Options::RADIUS_METRIC: + while (rbin != radiussize && radius[rbin] != -1 && + lineindex.metricdepth + seglength * 0.5 > radius[rbin]) { + rbin++; + } + break; + case Options::RADIUS_STEPS: + if (rbin != radiussize && radius[rbin] != -1 && + lineindex.segdepth >= (int)radius[rbin]) { + rbin++; + } + break; + } + if ((coverage >> rbin) != 0) { + SegmentData sd(conn, SegmentRef(1, lineindex.ref), lineindex.segdepth + 1, + lineindex.metricdepth + seglength, (coverage >> rbin) << rbin); + size_t bin = (currentbin + tulip_bins + extradepth) % tulip_bins; + depthmapX::insert_sorted(bins[bin], sd); + opencount++; + } + } + } + } + if (lineindex.dir != 1) { + for (auto &segconn : line.m_back_segconns) { + rbin = rbinbase; + SegmentRef conn = segconn.first; + if ((uncovered[conn.ref][(conn.dir == 1 ? 0 : 1)] & coverage) != 0) { + // EF routeweight* + if (routeweight_col != -1) { // EF here we do the weighting of the angular cost by the + // weight of the next segment + // note that the content of the routeweights array is scaled between 0 and 1 and is + // reversed + // such that: = 1.0-(attributes.getValue(i, routeweight_col)/max_value) + extradepth = (int)floor(segconn.second * tulip_bins * 0.5 * routeweights[conn.ref]); + } + //*EF routeweight + else { + extradepth = (int)floor(segconn.second * tulip_bins * 0.5); + } + seglength = lengths[conn.ref]; + switch (m_radius_type) { + case Options::RADIUS_ANGULAR: + while (rbin != radiussize && radius[rbin] != -1 && + depthlevel + extradepth > (int)radius[rbin]) { + rbin++; + } + break; + case Options::RADIUS_METRIC: + while (rbin != radiussize && radius[rbin] != -1 && + lineindex.metricdepth + seglength * 0.5 > radius[rbin]) { + rbin++; + } + break; + case Options::RADIUS_STEPS: + if (rbin != radiussize && radius[rbin] != -1 && + lineindex.segdepth >= (int)radius[rbin]) { + rbin++; + } + break; + } + if ((coverage >> rbin) != 0) { + SegmentData sd(conn, SegmentRef(-1, lineindex.ref), lineindex.segdepth + 1, + lineindex.metricdepth + seglength, (coverage >> rbin) << rbin); + size_t bin = (currentbin + tulip_bins + extradepth) % tulip_bins; + depthmapX::insert_sorted(bins[bin], sd); + opencount++; + } + } + } + } + } + } + // set the attributes for this node: + for (int k = 0; k < radiussize; k++) { + // note, curs_total_depth must use double as mantissa can get too long for int in large systems + double curs_node_count = 0.0, curs_total_depth = 0.0; + double curs_total_weight = 0.0, curs_total_weighted_depth = 0.0; + size_t j; + for (j = 0; j < map.getConnections().size(); j++) { + // find dir according + bool m0 = ((uncovered[j][0] >> k) & 0x1) == 0; + bool m1 = ((uncovered[j][1] >> k) & 0x1) == 0; + if ((m0 | m1) != 0) { + int dir; + if (m0 & m1) { + // dir is the one with the lowest depth: + if (audittrail[j][k][0].depth < audittrail[j][k][1].depth) + dir = 0; + else + dir = 1; + } else { + // dir is simply the one that's filled in: + dir = m0 ? 0 : 1; + } + curs_node_count++; + curs_total_depth += audittrail[j][k][dir].depth; + curs_total_weight += weights[j]; + curs_total_weighted_depth += audittrail[j][k][dir].depth * weights[j]; + // + if (m_choice && audittrail[j][k][dir].leaf) { + // note, graph may be directed (e.g., for one way streets), so both ways must be included from + // now on: + SegmentRef here = SegmentRef(dir == 0 ? 1 : -1, j); + if (here.ref != static_cast(cursor)) { + int choicecount = 0; + double choiceweight = 0.0; + // EFEF* + double choiceweight2 = 0.0; + //*EFEF + while (here.ref != static_cast(cursor)) { // not rowid means not the current root for the path + int heredir = (here.dir == 1) ? 0 : 1; + // each node has the existing choicecount and choiceweight from previously encountered + // nodes added to it + audittrail[here.ref][k][heredir].choice += choicecount; + // nb, weighted values calculated anyway to save time on 'if' + audittrail[here.ref][k][heredir].weighted_choice += choiceweight; + // EFEF* + audittrail[here.ref][k][heredir].weighted_choice2 += choiceweight2; + //*EFEF + // if the node hasn't been encountered before, the choicecount and choiceweight is + // incremented for all remaining nodes to be encountered on the backwards route from it + if (!audittrail[here.ref][k][heredir].choicecovered) { + // this node has not been encountered before: this adds the choicecount and weight + // for this node, and flags it as visited + choicecount++; + choiceweight += weights[here.ref] * rootweight; + // EFEF* + choiceweight2 += weights2[here.ref] * rootweight; // rootweight! + //*EFEF + + audittrail[here.ref][k][heredir].choicecovered = true; + // note, for weighted choice, the start and end points have choice added to them: + if (m_weighted_measure_col != -1) { + audittrail[here.ref][k][heredir].weighted_choice += + (weights[here.ref] * rootweight) / 2.0; + // EFEF* + if (weighting_col2 != -1) { + audittrail[here.ref][k][heredir].weighted_choice2 += + (weights2[here.ref] * rootweight) / 2.0; // rootweight! + } + //*EFEF + } + } + here = audittrail[here.ref][k][heredir].previous; + } + // note, for weighted choice, the start and end points have choice added to them: + // (this is the summed weight for all starting nodes encountered in this path) + if (m_weighted_measure_col != -1) { + audittrail[here.ref][k][(here.dir == 1) ? 0 : 1].weighted_choice += choiceweight / 2.0; + // EFEF* + if (weighting_col2 != -1) { + audittrail[here.ref][k][(here.dir == 1) ? 0 : 1].weighted_choice2 += + choiceweight2 / 2.0; + } + //*EFEF + } + } + } + } + } + double total_depth_conv = curs_total_depth / ((tulip_bins - 1.0f) * 0.5f); + double total_weighted_depth_conv = curs_total_weighted_depth / ((tulip_bins - 1.0f) * 0.5f); + // + row.setValue(count_col[k], float(curs_node_count)); + if (curs_node_count > 1) { + // for dmap 8 and above, mean depth simply isn't calculated as for radius measures it is meaningless + row.setValue(td_col[k], total_depth_conv); + if (m_weighted_measure_col != -1) { + row.setValue(total_weight_col[k], float(curs_total_weight)); + row.setValue(w_td_col[k], float(total_weighted_depth_conv)); + } + } else { + row.setValue(td_col[k], -1); + if (m_weighted_measure_col != -1) { + row.setValue(total_weight_col[k], -1.0f); + row.setValue(w_td_col[k], -1.0f); + } + } + // for dmap 10 an above, integration is included! + if (total_depth_conv > 1e-9) { + row.setValue(integ_col[k], (float)(curs_node_count * curs_node_count / total_depth_conv)); + if (m_weighted_measure_col != -1) { + row.setValue(w_integ_col[k], + (float)(curs_total_weight * curs_total_weight / total_weighted_depth_conv)); + } + } else { + row.setValue(integ_col[k], -1); + if (m_weighted_measure_col != -1) { + row.setValue(w_integ_col[k], -1.0f); + } + } + } + // + processed_rows++; + // + if (comm) { + if (qtimer(atime, 500)) { + if (comm->IsCancelled()) { + // interactive is usual Depthmap: throw an exception if cancelled + if (interactive) { + for (size_t i = 0; i < map.getConnections().size(); i++) { + for (size_t j = 0; j < size_t(radiussize); j++) { + delete[] audittrail[i][j]; + } + delete[] audittrail[i]; + delete[] uncovered[i]; + } + delete[] audittrail; + delete[] uncovered; + throw Communicator::CancelledException(); + } else { + // in non-interactive mode, retain what's been processed already + break; + } + } + comm->CommPostMessage(Communicator::CURRENT_RECORD, cursor); + } + } + } + if (m_choice) { + for (size_t cursor = 0; cursor < map.getConnections().size(); cursor++) { + AttributeRow &row = + attributes.getRow(AttributeKey(depthmapX::getMapAtIndex(map.getAllShapes(), cursor)->first)); + for (size_t r = 0; r < radius.size(); r++) { + // according to Eva's correction, total choice and total weighted choice + // should already have been accumulated by radius at this stage + double total_choice = audittrail[cursor][r][0].choice + audittrail[cursor][r][1].choice; + double total_weighted_choice = + audittrail[cursor][r][0].weighted_choice + audittrail[cursor][r][1].weighted_choice; + // EFEF* + double total_weighted_choice2 = + audittrail[cursor][r][0].weighted_choice2 + audittrail[cursor][r][1].weighted_choice2; + //*EFEF + + // normalised choice now excluded for two reasons: + // a) not useful measure, b) in parallel calculations, cannot be calculated at this stage + // n.b., it is possible through the front end: the new choice takes into account bidirectional routes, + // so it should be normalised according to (n-1)(n-2) (maximum possible through routes) not + // (n-1)(n-2)/2 the relativised segment length weighted choice equation was + // (total_seg_length*total_seg_length-seg_length*seg_length)/2 again, drop the divide by 2 for the new + // implementation + // + // + row.setValue(choice_col[r], float(total_choice)); + if (m_weighted_measure_col != -1) { + row.setValue(w_choice_col[r], float(total_weighted_choice)); + // EFEF* + if (weighting_col2 != -1) { + row.setValue(w_choice_col2[r], float(total_weighted_choice2)); + } + //*EFEF + } + } + } + } + for (size_t i = 0; i < map.getConnections().size(); i++) { + for (int j = 0; j < radiussize; j++) { + delete[] audittrail[i][j]; + } + delete[] audittrail[i]; + delete[] uncovered[i]; + } + delete[] audittrail; + delete[] uncovered; + + map.setDisplayedAttribute(-2); // <- override if it's already showing + if (m_choice) { + map.setDisplayedAttribute(choice_col.back()); + } else { + map.setDisplayedAttribute(td_col.back()); + } + return processed_rows > 0; +} diff --git a/salalib/segmmodules/segmtulip.h b/salalib/segmmodules/segmtulip.h new file mode 100644 index 00000000..1dabb4c1 --- /dev/null +++ b/salalib/segmmodules/segmtulip.h @@ -0,0 +1,39 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/isegment.h" + +class SegmentTulip : ISegment { + private: + std::set m_radius_set; + bool m_sel_only; + int m_tulip_bins; + int m_weighted_measure_col; + int m_radius_type; + bool m_choice; + + public: + std::string getAnalysisName() const override { return "Tulip Analysis"; } + bool run(Communicator *comm, ShapeGraph &map, bool) override; + SegmentTulip(std::set radius_set, bool sel_only, int tulip_bins, int weighted_measure_col, int radius_type, + bool choice) + : m_radius_set(radius_set), m_sel_only(sel_only), m_tulip_bins(tulip_bins), + m_weighted_measure_col(weighted_measure_col), m_radius_type(radius_type), m_choice(choice) {} +}; diff --git a/salalib/segmmodules/segmtulipdepth.cpp b/salalib/segmmodules/segmtulipdepth.cpp new file mode 100644 index 00000000..46ae451c --- /dev/null +++ b/salalib/segmmodules/segmtulipdepth.cpp @@ -0,0 +1,112 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "salalib/segmmodules/segmtulipdepth.h" + +#include "genlib/stringutils.h" + +// revised to use tulip bins for faster analysis of large spaces + +bool SegmentTulipDepth::run(Communicator *, ShapeGraph &map, bool) { + + AttributeTable &attributes = map.getAttributeTable(); + + std::string stepdepth_col_text = "Angular Step Depth"; + int stepdepth_col = attributes.insertOrResetColumn(stepdepth_col_text.c_str()); + + // The original code set tulip_bins to 1024, divided by two and added one + // in order to duplicate previous code (using a semicircle of tulip bins) + size_t tulip_bins = 513; + + std::vector covered(map.getConnections().size()); + for (size_t i = 0; i < map.getConnections().size(); i++) { + covered[i] = false; + } + std::vector > bins(tulip_bins); + + int opencount = 0; + for (auto& sel: map.getSelSet()) { + int row = depthmapX::getMapAtIndex(map.getAllShapes(), sel)->first; + if (row != -1) { + bins[0].push_back(SegmentData(0,row,SegmentRef(),0,0.0,0)); + opencount++; + } + } + int depthlevel = 0; + auto binIter = bins.begin(); + int currentbin = 0; + while (opencount) { + while (binIter->empty()) { + depthlevel++; + binIter++; + currentbin++; + if (binIter == bins.end()) { + binIter = bins.begin(); + } + } + SegmentData lineindex; + if (binIter->size() > 1) { + // it is slightly slower to delete from an arbitrary place in the bin, + // but it is necessary to use random paths to even out the number of times through equal paths + int curr = pafrand() % binIter->size(); + auto currIter = binIter->begin() + curr; + lineindex = *currIter; + binIter->erase(currIter); + // note: do not clear choice values here! + } + else { + lineindex = binIter->front(); + binIter->pop_back(); + } + opencount--; + if (!covered[lineindex.ref]) { + covered[lineindex.ref] = true; + Connector& line = map.getConnections()[lineindex.ref]; + // convert depth from tulip_bins normalised to standard angle + // (note the -1) + double depth_to_line = depthlevel / ((tulip_bins - 1) * 0.5); + map.getAttributeRowFromShapeIndex(lineindex.ref).setValue(stepdepth_col,depth_to_line); + int extradepth; + if (lineindex.dir != -1) { + for (auto& segconn: line.m_forward_segconns) { + if (!covered[segconn.first.ref]) { + extradepth = (int) floor(segconn.second * tulip_bins * 0.5); + bins[(currentbin + tulip_bins + extradepth) % tulip_bins].push_back( + SegmentData(segconn.first,lineindex.ref,lineindex.segdepth+1,0.0,0)); + opencount++; + } + } + } + if (lineindex.dir != 1) { + for (auto& segconn: line.m_back_segconns) { + if (!covered[segconn.first.ref]) { + extradepth = (int) floor(segconn.second * tulip_bins * 0.5); + bins[(currentbin + tulip_bins + extradepth) % tulip_bins].push_back( + SegmentData(segconn.first,lineindex.ref,lineindex.segdepth+1,0.0,0)); + opencount++; + } + } + } + } + } + + map.setDisplayedAttribute(-2); // <- override if it's already showing + map.setDisplayedAttribute(stepdepth_col); + + return true; +} diff --git a/salalib/segmmodules/segmtulipdepth.h b/salalib/segmmodules/segmtulipdepth.h new file mode 100644 index 00000000..f1f0b0c3 --- /dev/null +++ b/salalib/segmmodules/segmtulipdepth.h @@ -0,0 +1,30 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/isegment.h" + +class SegmentTulipDepth : ISegment +{ +public: + std::string getAnalysisName() const override { + return "Tulip Analysis"; + } + bool run(Communicator *, ShapeGraph &map, bool) override; +}; diff --git a/salalib/shapemap.cpp b/salalib/shapemap.cpp index ca698f7b..d6b56ad2 100644 --- a/salalib/shapemap.cpp +++ b/salalib/shapemap.cpp @@ -14,21 +14,26 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +// This is my code to make a set of axial lines from a set of boundary lines +#include "salalib/shapemap.h" +#include "salalib/attributetable.h" +#include "salalib/attributetablehelpers.h" +#include "salalib/mgraph.h" // purely for the version info --- as phased out should replace +#include "salalib/parsers/mapinfodata.h" // for mapinfo interface -// This is my code to make a set of axial lines from a set of boundary lines +#include "genlib/comm.h" // for communicator +#include "genlib/containerutils.h" +#include "genlib/exceptions.h" +#include "genlib/stringutils.h" -#include #include +#include +#include +#include #include -#include -#include // for communicator - -#include // purely for the version info --- as phased out should replace -#include - -// for mapinfo interface -#include "MapInfoData.h" +#include +#include #ifndef _WIN32 #define _finite finite @@ -39,1934 +44,1817 @@ static const double TOLERANCE_A = 1e-9; // import TOLERANCE_B from axial map... static const double TOLERANCE_B = 1e-12; - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool SalaShape::read(ifstream& stream, int version) -{ - // defaults - m_draworder = -1; - m_selected = false; - - stream.read((char *)&m_type,sizeof(m_type)); - - int sss = sizeof(m_region); - stream.read((char *)&m_region,sizeof(m_region)); - - if (version >= VERSION_SHAPE_CENTROIDS) { - stream.read((char *)&m_centroid,sizeof(m_centroid)); - if (version >= VERSION_SHAPE_AREA_PERIMETER) { - stream.read((char *)&m_area,sizeof(m_area)); - stream.read((char *)&m_perimeter,sizeof(m_perimeter)); - } - } - else { - // old types were simply 1,2,3... these are now labelled using bits: - if (m_type == 3) { - m_type = SHAPE_POLY; - } - else if (m_type == 4) { - m_type = SHAPE_POLY | SHAPE_CLOSED; - } - } - pqvector::read(stream); - - if (version < VERSION_SHAPE_AREA_PERIMETER) { - if (m_type & SHAPE_POLY) { - setCentroidAreaPerim(); - } - else if (m_type & SHAPE_LINE) { - m_perimeter = m_region.length(); - } - } - - return true; -} - -bool SalaShape::write(ofstream& stream) -{ - stream.write((char *)&m_type,sizeof(m_type)); - stream.write((char *)&m_region,sizeof(m_region)); - stream.write((char *)&m_centroid,sizeof(m_centroid)); - stream.write((char *)&m_area,sizeof(m_area)); - stream.write((char *)&m_perimeter,sizeof(m_perimeter)); - pqvector::write(stream); - return true; -} - -void SalaShape::setCentroidAreaPerim() -{ - m_area = 0.0; - m_perimeter = 0.0; - m_centroid = Point2f(0,0); - for (size_t i = 0; i < size(); i++) { - Point2f& p1 = at(i); - Point2f& p2 = at((i+1)%size()); - double a_i = (p1.x * p2.y - p2.x * p1.y) / 2.0; - m_area += a_i; - a_i /= 6.0; - m_centroid.x += (p1.x+p2.x) * a_i; - m_centroid.y += (p1.y+p2.y) * a_i; - Point2f side = p2 - p1; - m_perimeter += side.length(); - } - m_type &= ~SHAPE_CCW; - if (sgn(m_area) == 1) { - m_type |= SHAPE_CCW; - } - m_centroid.scale(2.0/m_area); // note, *not* fabs(m_area) as it is then confused by clockwise ordered shapes - m_area = fabs(m_area); - if (isOpen()) { - // take off the automatically collected final side - Point2f side = tail() - head(); - m_perimeter -= side.length(); - } +bool SalaShape::read(std::istream &stream) { + // defaults + m_draworder = -1; + m_selected = false; + + stream.read((char *)&m_type, sizeof(m_type)); + + stream.read((char *)&m_region, sizeof(m_region)); + + stream.read((char *)&m_centroid, sizeof(m_centroid)); + + stream.read((char *)&m_area, sizeof(m_area)); + stream.read((char *)&m_perimeter, sizeof(m_perimeter)); + + dXreadwrite::readIntoVector(stream, m_points); + + return true; +} + +bool SalaShape::write(std::ofstream &stream) { + stream.write((char *)&m_type, sizeof(m_type)); + stream.write((char *)&m_region, sizeof(m_region)); + stream.write((char *)&m_centroid, sizeof(m_centroid)); + stream.write((char *)&m_area, sizeof(m_area)); + stream.write((char *)&m_perimeter, sizeof(m_perimeter)); + dXreadwrite::writeVector(stream, m_points); + return true; +} + +void SalaShape::setCentroidAreaPerim() { + m_area = 0.0; + m_perimeter = 0.0; + m_centroid = Point2f(0, 0); + for (size_t i = 0; i < m_points.size(); i++) { + Point2f &p1 = m_points[i]; + Point2f &p2 = m_points[(i + 1) % m_points.size()]; + double a_i = (p1.x * p2.y - p2.x * p1.y) / 2.0; + m_area += a_i; + a_i /= 6.0; + m_centroid.x += (p1.x + p2.x) * a_i; + m_centroid.y += (p1.y + p2.y) * a_i; + Point2f side = p2 - p1; + m_perimeter += side.length(); + } + m_type &= ~SHAPE_CCW; + if (sgn(m_area) == 1) { + m_type |= SHAPE_CCW; + } + m_centroid.scale(2.0 / m_area); // note, *not* fabs(m_area) as it is then confused by clockwise ordered shapes + m_area = fabs(m_area); + if (isOpen()) { + // take off the automatically collected final side + Point2f side = m_points.back() - m_points.front(); + m_perimeter -= side.length(); + } } // allows override of the above (used for isovists) -void SalaShape::setCentroid(const Point2f& p) -{ - m_centroid = p; -} +void SalaShape::setCentroid(const Point2f &p) { m_centroid = p; } // get the angular deviation along the length of a poly line: -double SalaShape::getAngDev() const -{ - double dev = 0.0; - for (size_t i = 1; i < size() - 1; i++) { - double ang = angle(at(i-1),at(i),at(i+1)); - - // Quick mod - TV -#if defined(_WIN32) - dev += abs(M_PI - ang); +double SalaShape::getAngDev() const { + double dev = 0.0; + for (size_t i = 1; i < m_points.size() - 1; i++) { + double ang = angle(m_points[i - 1], m_points[i], m_points[i + 1]); + + // Quick mod - TV +#if defined(_MSC_VER) + dev += abs(M_PI - ang); #else - (M_PI - ang) < 0.0 ? dev += (ang - M_PI) : dev += (M_PI - ang); -#endif - } - // convert to Iida Hillier units (0 to 2): - dev /= M_PI * 0.5; - return dev; + (M_PI - ang) < 0.0 ? dev += (ang - M_PI) : dev += (M_PI - ang); +#endif + } + // convert to Iida Hillier units (0 to 2): + dev /= M_PI * 0.5; + return dev; } - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // the replacement for datalayers -ShapeMap::ShapeMap(const pstring& name, int type) : m_attributes(name) -{ - m_name = name; - m_map_type = type; - m_hasgraph = false; - - // shape and object counters - m_obj_ref = -1; - m_shape_ref = -1; - // pixel map - m_pixel_shapes = NULL; - // - // -1 is the shape ref column (which will be shown by default) - m_displayed_attribute = -1; - m_display_shapes = NULL; - m_invalidate = false; - // for polygons: - m_show_lines = true; - m_show_fill = true; - m_show_centroids = false; - - // data (MUST be set before use) - m_tolerance = 0.0; - - m_selection = false; - - // note show is - m_show = true; - m_editable = false; - - m_bsp_tree = false; - m_bsp_root = NULL; - // - m_mapinfodata = NULL; +ShapeMap::ShapeMap(const std::string &name, int type) + : m_pixel_shapes(0, 0), m_attributes(new AttributeTable()), + m_attribHandle(new AttributeTableHandle(*m_attributes)) { + m_name = name; + m_map_type = type; + m_hasgraph = false; + + // shape and object counters + m_obj_ref = -1; + // -1 is the shape ref column (which will be shown by default) + m_displayed_attribute = -1; + m_invalidate = false; + // for polygons: + m_show_lines = true; + m_show_fill = true; + m_show_centroids = false; + + // data (MUST be set before use) + m_tolerance = 0.0; + + m_selection = false; + + // note show is + m_show = true; + m_editable = false; + + m_bsp_tree = false; + m_bsp_root = NULL; + // + m_hasMapInfoData = false; } -ShapeMap::~ShapeMap() -{ - if (m_bsp_root) { - delete m_bsp_root; - m_bsp_root = NULL; - } - if (m_pixel_shapes) { - for (int i = 0; i < m_cols; i++) { - delete [] m_pixel_shapes[i]; - } - delete [] m_pixel_shapes; - m_pixel_shapes = NULL; - } - if (m_display_shapes) { - delete [] m_display_shapes; - m_display_shapes = NULL; - } - if (m_mapinfodata) { - delete m_mapinfodata; - m_mapinfodata = NULL; - } +ShapeMap::~ShapeMap() { + if (m_bsp_root) { + delete m_bsp_root; + m_bsp_root = NULL; + } } ////////////////////////////////////////////////////////////////////////////////////////// // this can be reinit as well -void ShapeMap::init(int size, const QtRegion &r) -{ - if (m_pixel_shapes) { - for (int i = 0; i < m_cols; i++) { - delete [] m_pixel_shapes[i]; - } - delete [] m_pixel_shapes; - m_pixel_shapes = NULL; - } - if (m_display_shapes) { - delete [] m_display_shapes; - m_display_shapes = NULL; - } - m_rows = __min(__max(20,(int)sqrt((double)size)),32768); - m_cols = __min(__max(20,(int)sqrt((double)size)),32768); - if (m_region.isNull()) { - m_region = r; - } - else { - m_region = runion(m_region,r); - } - // calculate geom data: - m_tolerance = __max(m_region.width(), m_region.height()) * TOLERANCE_A; - // - m_pixel_shapes = new pqvector *[m_cols]; - for (int i = 0; i < m_cols; i++) { - m_pixel_shapes[i] = new pqvector[m_rows]; - } +void ShapeMap::init(int size, const QtRegion &r) { + m_display_shapes.clear(); + m_rows = __min(__max(20, (int)sqrt((double)size)), 32768); + m_cols = __min(__max(20, (int)sqrt((double)size)), 32768); + if (m_region.atZero()) { + m_region = r; + } else { + m_region = runion(m_region, r); + } + // calculate geom data: + m_tolerance = __max(m_region.width(), m_region.height()) * TOLERANCE_A; + // + m_pixel_shapes = depthmapX::ColumnMatrix>(m_rows, m_cols); } // this makes an exact copy, keep the reference numbers and so on: -void ShapeMap::copy(const ShapeMap& sourcemap, int copyflags) -{ - if ((copyflags & ShapeMap::COPY_GEOMETRY) == ShapeMap::COPY_GEOMETRY) { - m_shapes.clear(); - m_shape_ref = -1; - init(sourcemap.m_shapes.size(),sourcemap.m_region); - for (size_t i = 0; i < sourcemap.m_shapes.size(); i++) { - // using makeShape is actually easier than thinking about a total copy: - makeShape(sourcemap.m_shapes.value(i),sourcemap.m_shapes.key(i)); - // note that addShape automatically adds the attribute row - } - } - - if ((copyflags & ShapeMap::COPY_ATTRIBUTES) == ShapeMap::COPY_ATTRIBUTES) { - // assumes attribute rows are filled in already - for (int incol = 0; incol < sourcemap.m_attributes.getColumnCount(); incol++) { - int outcol = m_attributes.insertColumn(sourcemap.m_attributes.getColumnName(incol)); - // n.b. outcol not necessarily the same as incol, although row position in table (j) should match - for (int j = 0; j < sourcemap.m_attributes.getRowCount(); j++) { - m_attributes.setValue(j,outcol,sourcemap.m_attributes.getValue(j,incol)); - } - } - } - - if ((copyflags & ShapeMap::COPY_ATTRIBUTES) == ShapeMap::COPY_GRAPH) { - if (sourcemap.m_hasgraph) { - m_hasgraph = true; - // straight copy: - m_connectors = sourcemap.m_connectors; - m_links = sourcemap.m_links; - m_unlinks = sourcemap.m_unlinks; - } - } - - // copies mapinfodata (projection data) regardless of copy flags - if (sourcemap.getMapInfoData()) { - if (m_mapinfodata != NULL) { - delete m_mapinfodata; - } - m_mapinfodata = new MapInfoData; - m_mapinfodata->m_coordsys = sourcemap.getMapInfoData()->m_coordsys; - m_mapinfodata->m_bounds = sourcemap.getMapInfoData()->m_bounds; - } +void ShapeMap::copy(const ShapeMap &sourcemap, int copyflags) { + if ((copyflags & ShapeMap::COPY_GEOMETRY) == ShapeMap::COPY_GEOMETRY) { + m_shapes.clear(); + init(sourcemap.m_shapes.size(), sourcemap.m_region); + for (auto shape : sourcemap.m_shapes) { + // using makeShape is actually easier than thinking about a total copy: + makeShape(shape.second, shape.first); + // note that addShape automatically adds the attribute row + } + } + + if ((copyflags & ShapeMap::COPY_ATTRIBUTES) == ShapeMap::COPY_ATTRIBUTES) { + // assumes attribute rows are filled in already + + // TODO: Compatibility. The columns are sorted in the old implementation so + // they are also passed sorted in the conversion: + + std::vector indices(sourcemap.m_attributes->getNumColumns()); + std::iota(indices.begin(), indices.end(), static_cast(0)); + + std::sort(indices.begin(), indices.end(), [&](size_t a, size_t b) { + return sourcemap.m_attributes->getColumnName(a) < sourcemap.m_attributes->getColumnName(b); + }); + + for (int idx : indices) { + int outcol = m_attributes->insertOrResetColumn(sourcemap.m_attributes->getColumnName(idx)); + // n.b. outcol not necessarily the same as incol, although row position in table (j) should match + + auto targetIter = m_attributes->begin(); + for (auto sourceIter = sourcemap.m_attributes->begin(); sourceIter != sourcemap.m_attributes->end(); + sourceIter++) { + targetIter->getRow().setValue(outcol, sourceIter->getRow().getValue(idx)); + targetIter++; + } + } + } + + if ((copyflags & ShapeMap::COPY_ATTRIBUTES) == ShapeMap::COPY_GRAPH) { + if (sourcemap.m_hasgraph) { + m_hasgraph = true; + // straight copy: + m_connectors = sourcemap.m_connectors; + m_links = sourcemap.m_links; + m_unlinks = sourcemap.m_unlinks; + } + } + + // copies mapinfodata (projection data) regardless of copy flags + if (sourcemap.hasMapInfoData()) { + m_mapinfodata = MapInfoData(); + m_mapinfodata.m_coordsys = sourcemap.getMapInfoData().m_coordsys; + m_mapinfodata.m_bounds = sourcemap.getMapInfoData().m_bounds; + m_hasMapInfoData = true; + } } // Zaps all memory structures, apart from mapinfodata -void ShapeMap::clearAll() -{ - if (m_bsp_root) { - delete m_bsp_root; - m_bsp_root = NULL; - } - if (m_pixel_shapes) { - for (int i = 0; i < m_cols; i++) { - delete [] m_pixel_shapes[i]; - } - delete [] m_pixel_shapes; - m_pixel_shapes = NULL; - } - if (m_display_shapes) { - delete [] m_display_shapes; - m_display_shapes = NULL; - } - - m_shapes.clear(); - m_objects.clear(); - m_undobuffer.clear(); - m_connectors.clear(); - m_attributes.clear(); - m_links.clear(); - m_unlinks.clear(); - m_region = QtRegion(); - - m_obj_ref = -1; - m_shape_ref = -1; - m_displayed_attribute = -1; -} - +void ShapeMap::clearAll() { + if (m_bsp_root) { + delete m_bsp_root; + m_bsp_root = NULL; + } + m_display_shapes.clear(); -/////////////////////////////////////////////////////////////////////////////////////////// + m_shapes.clear(); + m_undobuffer.clear(); + m_connectors.clear(); + m_attributes->clear(); + m_links.clear(); + m_unlinks.clear(); + m_region = QtRegion(); -int ShapeMap::makePointShape(const Point2f& point, bool tempshape) -{ - bool bounds_good = true; - - if (!m_region.contains_touch(point)) { - bounds_good = false; - init(m_shapes.size(),QtRegion(point,point)); - } - - m_shape_ref++; - int x = m_shapes.add(m_shape_ref,SalaShape(point)); - - if (bounds_good) { - // note: also sets polygon bounding box: - makePolyPixels(m_shape_ref); - } - else { - // pixelate all polys in the pixel new structure: - for (size_t i = 0; i < m_shapes.size(); i++) { - makePolyPixels(m_shapes.key(i)); - } - } - - if (!tempshape) { - int rowid = m_attributes.insertRow(m_shape_ref); - m_newshape = true; - } - - return m_shape_ref; + m_obj_ref = -1; + m_displayed_attribute = -1; } -int ShapeMap::makeLineShape(const Line& line, bool through_ui, bool tempshape) -{ - // note, map must have editable flag on if we are to make a shape through the user interface: - if (through_ui && !m_editable) { - return -1; - } - - bool bounds_good = true; - - if (!(m_region.contains_touch(line.start()) && m_region.contains_touch(line.end()))) { - bounds_good = false; - init(m_shapes.size(),line); - } - - m_shape_ref++; - // note, shape constructor sets centroid, length etc - int rowid = m_shapes.add(m_shape_ref,SalaShape(line)); - - if (bounds_good) { - // note: also sets polygon bounding box: - makePolyPixels(m_shape_ref); - } - else { - // pixelate all polys in the pixel new structure: - for (size_t i = 0; i < m_shapes.size(); i++) { - makePolyPixels(m_shapes.key(i)); - } - } - - if (!tempshape) { - m_attributes.insertRow(m_shape_ref); - m_newshape = true; - } - - if (through_ui) { - // - // manually add connections: - if (m_hasgraph) { - if (isAxialMap()) { - connectIntersected(rowid,true); // "true" means line-line intersections only will be applied - } - else { - connectIntersected(rowid,false); - } - } - // if through ui, set undo counter: - m_undobuffer.push_back(SalaEvent(SalaEvent::SALA_CREATED,m_shape_ref)); - // update displayed attribute if through ui: - invalidateDisplayedAttribute(); - setDisplayedAttribute(m_displayed_attribute); - } - - return m_shape_ref; -} - -int ShapeMap::makePolyShape(const pvecpoint& points, bool open, bool tempshape) -{ - bool bounds_good = true; - - switch (points.size()) { - case 0: - return -1; - case 1: - return makePointShape(points[0],tempshape); - case 2: - return makeLineShape(Line(points[0],points[1]),false,tempshape); // false is not through ui: there really should be a through ui here? - } - - QtRegion region(points[0],points[0]); - size_t i; - for (i = 1; i < points.size(); i++) { - region.encompass(points[i]); - } - if (!m_region.contains_touch(region.bottom_left) || !m_region.contains_touch(region.top_right)) { - bounds_good = false; - init(m_shapes.size(),region); - } - - m_shape_ref++; - - size_t len = points.size(); - // NOTE: This is commented out deliberately - // Sometimes you really do want a polyline that forms a loop - /* - if (points.head() == points.tail()) { - len--; - open = false; - } - */ - - // not sure if it matters if the polygon is clockwise or anticlockwise... we'll soon tell! - - if (open) { - m_shapes.add(m_shape_ref,SalaShape(SalaShape::SHAPE_POLY)); - } - else { - m_shapes.add(m_shape_ref,SalaShape(SalaShape::SHAPE_POLY | SalaShape::SHAPE_CLOSED)); - } - for (i = 0; i < len; i++) { - m_shapes.tail().push_back(points[i]); - } - - if (bounds_good) { - // note: also sets polygon bounding box: - makePolyPixels(m_shape_ref); - } - else { - // pixelate all polys in the pixel new structure: - for (size_t i = 0; i < m_shapes.size(); i++) { - makePolyPixels(m_shapes.key(i)); - } - } - - if (!tempshape) { - // set centroid now also adds a few other things: as well as area, perimeter - m_shapes.tail().setCentroidAreaPerim(); - m_attributes.insertRow(m_shape_ref); - m_newshape = true; - } - - return m_shape_ref; -} - -int ShapeMap::makeShape(const SalaShape& poly, int override_shape_ref) -{ - // overridden shape cannot exist: - if (override_shape_ref != -1 && m_shapes.searchindex(override_shape_ref) != paftl::npos) { - return -1; // failure! - } - - bool bounds_good = true; - - if (!m_region.contains_touch(poly.m_region.bottom_left) || !m_region.contains_touch(poly.m_region.top_right)) { - bounds_good = false; - init(m_shapes.size(),poly.m_region); - } - - int shape_ref; - if (override_shape_ref == -1) { - m_shape_ref++; - shape_ref = m_shape_ref; - } - else { - if (override_shape_ref > m_shape_ref) { - m_shape_ref = override_shape_ref; - } - shape_ref = override_shape_ref; - } - - int rowid1 = m_shapes.add(shape_ref,poly); - - if (bounds_good) { - // note: also sets polygon bounding box: - makePolyPixels(shape_ref); - } - else { - // pixelate all polys in the pixel new structure: - for (size_t i = 0; i < m_shapes.size(); i++) { - makePolyPixels(m_shapes.key(i)); - } - } - - int rowid2 = m_attributes.insertRow(shape_ref); - -#ifdef _DEBUG - if (rowid1 != rowid2) { - // rowids should match, they're both pqmaps, but if someone is stupid enough to change it, they'll know pretty quickly: - throw pstring("Arrrrgghhh: important! insertRow does not index in the same way as add shapes, this will badly mess up the system!"); - } -#endif - - m_newshape = true; +/////////////////////////////////////////////////////////////////////////////////////////// - return shape_ref; +int ShapeMap::makePointShapeWithRef(const Point2f &point, int shape_ref, bool tempshape, + const std::map &extraAttributes) { + bool bounds_good = true; + + if (!m_region.contains_touch(point)) { + bounds_good = false; + init(m_shapes.size(), QtRegion(point, point)); + } + + m_shapes.insert(std::make_pair(shape_ref, SalaShape(point))); + + if (bounds_good) { + // note: also sets polygon bounding box: + makePolyPixels(shape_ref); + } else { + // pixelate all polys in the pixel new structure: + for (auto shape : m_shapes) { + makePolyPixels(shape.first); + } + } + + if (!tempshape) { + auto &row = m_attributes->addRow(AttributeKey(shape_ref)); + for (auto &attr : extraAttributes) { + row.setValue(attr.first, attr.second); + } + m_newshape = true; + } + + return shape_ref; +} + +int ShapeMap::makePointShape(const Point2f &point, bool tempshape, const std::map &extraAttributes) { + return makePointShapeWithRef(point, getNextShapeKey(), tempshape, extraAttributes); +} + +int ShapeMap::makeLineShapeWithRef(const Line &line, int shape_ref, bool through_ui, bool tempshape, + const std::map &extraAttributes) { + // note, map must have editable flag on if we are to make a shape through the user interface: + if (through_ui && !m_editable) { + return -1; + } + + bool bounds_good = true; + + if (!(m_region.contains_touch(line.start()) && m_region.contains_touch(line.end()))) { + bounds_good = false; + init(m_shapes.size(), line); + } + + // note, shape constructor sets centroid, length etc + m_shapes.insert(std::make_pair(shape_ref, SalaShape(line))); + + if (bounds_good) { + // note: also sets polygon bounding box: + makePolyPixels(shape_ref); + } else { + // pixelate all polys in the pixel new structure: + for (auto shape : m_shapes) { + makePolyPixels(shape.first); + } + } + + if (!tempshape) { + auto &row = m_attributes->addRow(AttributeKey(shape_ref)); + for (auto &attr : extraAttributes) { + row.setValue(attr.first, attr.second); + } + m_newshape = true; + } + + if (through_ui) { + // manually add connections: + if (m_hasgraph) { + int rowid = depthmapX::findIndexFromKey(m_shapes, shape_ref); + if (isAxialMap()) { + connectIntersected(rowid, true); // "true" means line-line intersections only will be applied + } else { + connectIntersected(rowid, false); + } + } + // if through ui, set undo counter: + m_undobuffer.push_back(SalaEvent(SalaEvent::SALA_CREATED, shape_ref)); + // update displayed attribute if through ui: + invalidateDisplayedAttribute(); + setDisplayedAttribute(m_displayed_attribute); + } + + return shape_ref; +} + +int ShapeMap::getNextShapeKey() { + if (m_shapes.size() == 0) + return 0; + return m_shapes.rbegin()->first + 1; +} + +int ShapeMap::makeLineShape(const Line &line, bool through_ui, bool tempshape, + const std::map &extraAttributes) { + return makeLineShapeWithRef(line, getNextShapeKey(), through_ui, tempshape, extraAttributes); +} + +int ShapeMap::makePolyShapeWithRef(const std::vector &points, bool open, int shape_ref, bool tempshape, + const std::map &extraAttributes) { + bool bounds_good = true; + + switch (points.size()) { + case 0: + return -1; + case 1: + return makePointShapeWithRef(points[0], shape_ref, tempshape); + case 2: + return makeLineShapeWithRef(Line(points[0], points[1]), shape_ref, false, + tempshape); // false is not through ui: there really should be a through ui here? + } + + QtRegion region(points[0], points[0]); + size_t i; + for (i = 1; i < points.size(); i++) { + region.encompass(points[i]); + } + if (!m_region.contains_touch(region.bottom_left) || !m_region.contains_touch(region.top_right)) { + bounds_good = false; + init(m_shapes.size(), region); + } + + size_t len = points.size(); + // NOTE: This is commented out deliberately + // Sometimes you really do want a polyline that forms a loop + /* + if (points.head() == points.tail()) { + len--; + open = false; + } + */ + + // not sure if it matters if the polygon is clockwise or anticlockwise... we'll soon tell! + + if (open) { + m_shapes.insert(std::make_pair(shape_ref, SalaShape(SalaShape::SHAPE_POLY))); + } else { + m_shapes.insert(std::make_pair(shape_ref, SalaShape(SalaShape::SHAPE_POLY | SalaShape::SHAPE_CLOSED))); + } + for (i = 0; i < len; i++) { + m_shapes.rbegin()->second.m_points.push_back(points[i]); + } + + if (bounds_good) { + // note: also sets polygon bounding box: + makePolyPixels(shape_ref); + } else { + // pixelate all polys in the pixel new structure: + for (auto shape : m_shapes) { + makePolyPixels(shape.first); + } + } + + if (!tempshape) { + // set centroid now also adds a few other things: as well as area, perimeter + m_shapes.rbegin()->second.setCentroidAreaPerim(); + + auto &row = m_attributes->addRow(AttributeKey(shape_ref)); + for (auto &attr : extraAttributes) { + row.setValue(attr.first, attr.second); + } + m_newshape = true; + } + + return shape_ref; +} + +int ShapeMap::makePolyShape(const std::vector &points, bool open, bool tempshape, + const std::map &extraAttributes) { + return makePolyShapeWithRef(points, open, getNextShapeKey(), tempshape, extraAttributes); +} + +int ShapeMap::makeShape(const SalaShape &poly, int override_shape_ref, const std::map &extraAttributes) { + // overridden shape cannot exist: + if (override_shape_ref != -1 && m_shapes.find(override_shape_ref) != m_shapes.end()) { + return -1; // failure! + } + + bool bounds_good = true; + + if (!m_region.contains_touch(poly.m_region.bottom_left) || !m_region.contains_touch(poly.m_region.top_right)) { + bounds_good = false; + init(m_shapes.size(), poly.m_region); + } + + int shape_ref; + if (override_shape_ref == -1) { + shape_ref = getNextShapeKey(); + } else { + shape_ref = override_shape_ref; + } + + m_shapes.insert(std::make_pair(shape_ref, poly)); + + if (bounds_good) { + // note: also sets polygon bounding box: + makePolyPixels(shape_ref); + } else { + // pixelate all polys in the pixel new structure: + for (auto shape : m_shapes) { + makePolyPixels(shape.first); + } + } + + auto &row = m_attributes->addRow(AttributeKey(shape_ref)); + for (auto &attr : extraAttributes) { + row.setValue(attr.first, attr.second); + } + + m_newshape = true; + + return shape_ref; } - ////////////////////////////////////////////////////////////////////////////////////////// // n.b., only works from current selection (and uses point selected attribute) -int ShapeMap::makeShapeFromPointSet(const PointMap& pointmap) -{ - bool bounds_good = true; - PixelRefList selset; - Point2f offset = Point2f(pointmap.getSpacing()/2,pointmap.getSpacing()/2); - for (size_t i = 0; i < pointmap.getSelSet().size(); i++) { - selset.push_back(pointmap.getSelSet().at(i)); - if (!m_region.contains_touch(pointmap.depixelate(selset[i])-offset) || !m_region.contains_touch(pointmap.depixelate(selset[i])+offset)) { - bounds_good = false; - } - } - if (!bounds_good) { - QtRegion r(pointmap.getRegion().bottom_left - offset,pointmap.getRegion().top_right + offset); - init(m_shapes.size(),r); - } - pmap relations; - for (size_t j = 0; j < selset.size(); j++) { - PixelRef pix = selset[j]; - int x = relations.add(pix,ShapeRef::SHAPE_EDGE); - if (pointmap.includes(pix.right()) && pointmap.getPoint(pix.right()).selected()) { - relations.value(x) &= ~ShapeRef::SHAPE_R; - } - if (pointmap.includes(pix.up()) && pointmap.getPoint(pix.up()).selected()) { - relations.value(x) &= ~ShapeRef::SHAPE_T; - } - if (pointmap.includes(pix.down()) && pointmap.getPoint(pix.down()).selected()) { - relations.value(x) &= ~ShapeRef::SHAPE_B; - } - if (pointmap.includes(pix.left()) && pointmap.getPoint(pix.left()).selected()) { - relations.value(x) &= ~ShapeRef::SHAPE_L; - } - } - // now find pixel with SHAPE_B | SHAPE_L - PixelRef minpix = NoPixel; - size_t k; - for (k = 0; k < relations.size(); k++) { - if ((relations.value(k) & (ShapeRef::SHAPE_B | ShapeRef::SHAPE_L)) == (ShapeRef::SHAPE_B | ShapeRef::SHAPE_L)) { - if ((minpix == NoPixel) || (relations.key(k) < (int)minpix)) { - minpix = relations.key(k); - } - } - } - // now follow round anticlockwise... - SalaShape poly(SalaShape::SHAPE_POLY | SalaShape::SHAPE_CLOSED); - pointPixelBorder(pointmap,relations,poly,ShapeRef::SHAPE_L,minpix,minpix,true); - - bool retvar = true; - - for (k = 0; k < relations.size(); k++) { - if (relations[k] != 0) { - // more than one shape! - return -1; - } - } - poly.setCentroidAreaPerim(); - - m_shape_ref++; - int rowid = m_shapes.add(m_shape_ref,poly); - - if (bounds_good) { - // note: also sets polygon bounding box: - makePolyPixels(m_shape_ref); - } - else { - // pixelate all polys in the pixel new structure: - for (size_t i = 0; i < m_shapes.size(); i++) { - makePolyPixels(m_shapes.key(i)); - } - } - - m_attributes.insertRow(m_shape_ref); - m_newshape = true; - - return m_shape_ref; +int ShapeMap::makeShapeFromPointSet(const PointMap &pointmap) { + bool bounds_good = true; + PixelRefVector selset; + Point2f offset = Point2f(pointmap.getSpacing() / 2, pointmap.getSpacing() / 2); + for (auto &sel : pointmap.getSelSet()) { + selset.push_back(sel); + if (!m_region.contains_touch(pointmap.depixelate(sel) - offset) || + !m_region.contains_touch(pointmap.depixelate(sel) + offset)) { + bounds_good = false; + } + } + if (!bounds_good) { + QtRegion r(pointmap.getRegion().bottom_left - offset, pointmap.getRegion().top_right + offset); + init(m_shapes.size(), r); + } + std::map relations; + for (size_t j = 0; j < selset.size(); j++) { + PixelRef pix = selset[j]; + auto relation = relations.insert(std::make_pair(pix, ShapeRef::SHAPE_EDGE)); + if (pointmap.includes(pix.right()) && pointmap.getPoint(pix.right()).selected()) { + relation.first->second &= ~ShapeRef::SHAPE_R; + } + if (pointmap.includes(pix.up()) && pointmap.getPoint(pix.up()).selected()) { + relation.first->second &= ~ShapeRef::SHAPE_T; + } + if (pointmap.includes(pix.down()) && pointmap.getPoint(pix.down()).selected()) { + relation.first->second &= ~ShapeRef::SHAPE_B; + } + if (pointmap.includes(pix.left()) && pointmap.getPoint(pix.left()).selected()) { + relation.first->second &= ~ShapeRef::SHAPE_L; + } + } + // now find pixel with SHAPE_B | SHAPE_L + PixelRef minpix = NoPixel; + + for (auto &relation : relations) { + if ((relation.second & (ShapeRef::SHAPE_B | ShapeRef::SHAPE_L)) == (ShapeRef::SHAPE_B | ShapeRef::SHAPE_L)) { + if ((minpix == NoPixel) || (relation.first < (int)minpix)) { + minpix = relation.first; + } + } + } + // now follow round anticlockwise... + SalaShape poly(SalaShape::SHAPE_POLY | SalaShape::SHAPE_CLOSED); + pointPixelBorder(pointmap, relations, poly, ShapeRef::SHAPE_L, minpix, minpix, true); + + for (auto relation : relations) { + if (relation.second != 0) { + // more than one shape! + return -1; + } + } + poly.setCentroidAreaPerim(); + + int new_shape_ref = getNextShapeKey(); + m_shapes.insert(std::make_pair(new_shape_ref, poly)); + + if (bounds_good) { + // note: also sets polygon bounding box: + makePolyPixels(new_shape_ref); + } else { + // pixelate all polys in the pixel new structure: + for (auto shape : m_shapes) { + makePolyPixels(shape.first); + } + } + + m_attributes->addRow(AttributeKey(new_shape_ref)); + m_newshape = true; + + return new_shape_ref; } /////////////////////////////////////////////////////////////////////////////////////////////////////// -bool ShapeMap::convertPointsToPolys(double poly_radius, bool selected_only) -{ - // I'm not sure quite how easy this will be... - QtRegion region; - - bool done_something = false; - - // replace the points with polys - for (size_t i = 0; i < m_shapes.size(); i++) { - if (selected_only && !m_attributes.isSelected(i)) { - continue; - } - if (m_shapes[i].isPoint()) { - done_something = true; - // remove old spatial index - removePolyPixels(m_shapes.key(i)); - // construct a poly from the point: - Point2f p = m_shapes[i].getCentroid(); - // - if (region.isNull()) { - region = QtRegion(p,p); - } - // replace with a polygon: - m_shapes[i] = SalaShape(SalaShape::SHAPE_POLY | SalaShape::SHAPE_CLOSED); - for (int k = 0; k < 8 ; k++) { - Point2f poly_p; - if (k == 0) { poly_p.x = p.x + poly_radius; poly_p.y = p.y; } - else if (k == 1) { poly_p.x = p.x + poly_radius * M_ROOT_1_2; poly_p.y = p.y + poly_radius * M_ROOT_1_2; } - else if (k == 2) { poly_p.x = p.x; poly_p.y = p.y + poly_radius; } - else if (k == 3) { poly_p.x = p.x - poly_radius * M_ROOT_1_2; poly_p.y = p.y + poly_radius * M_ROOT_1_2; } - else if (k == 4) { poly_p.x = p.x - poly_radius; poly_p.y = p.y; } - else if (k == 5) { poly_p.x = p.x - poly_radius * M_ROOT_1_2; poly_p.y = p.y - poly_radius * M_ROOT_1_2; } - else if (k == 6) { poly_p.x = p.x; poly_p.y = p.y - poly_radius; } - else if (k == 7) { poly_p.x = p.x + poly_radius * M_ROOT_1_2; poly_p.y = p.y - poly_radius * M_ROOT_1_2; } - region.encompass(poly_p); - m_shapes[i].push_back(poly_p); - } - m_shapes[i].setCentroidAreaPerim(); - } - } - - if (done_something) { - // spatially reindex (simplest just to redo everything) - init(m_shapes.size(),region); - - for (size_t j = 0; j < m_shapes.size(); j++) { - makePolyPixels(m_shapes.key(j)); - } - } - - return true; +bool ShapeMap::convertPointsToPolys(double poly_radius, bool selected_only) { + // I'm not sure quite how easy this will be... + QtRegion region; + + bool done_something = false; + + // replace the points with polys + for (auto shape : m_shapes) { + if (selected_only && !m_attributes->getRow(AttributeKey(shape.first)).isSelected()) { + continue; + } + if (shape.second.isPoint()) { + done_something = true; + // remove old spatial index + removePolyPixels(shape.first); + // construct a poly from the point: + Point2f p = shape.second.getCentroid(); + // + if (region.atZero()) { + region = QtRegion(p, p); + } + // replace with a polygon: + shape.second = SalaShape(SalaShape::SHAPE_POLY | SalaShape::SHAPE_CLOSED); + for (int k = 0; k < 8; k++) { + Point2f poly_p; + if (k == 0) { + poly_p.x = p.x + poly_radius; + poly_p.y = p.y; + } else if (k == 1) { + poly_p.x = p.x + poly_radius * M_ROOT_1_2; + poly_p.y = p.y + poly_radius * M_ROOT_1_2; + } else if (k == 2) { + poly_p.x = p.x; + poly_p.y = p.y + poly_radius; + } else if (k == 3) { + poly_p.x = p.x - poly_radius * M_ROOT_1_2; + poly_p.y = p.y + poly_radius * M_ROOT_1_2; + } else if (k == 4) { + poly_p.x = p.x - poly_radius; + poly_p.y = p.y; + } else if (k == 5) { + poly_p.x = p.x - poly_radius * M_ROOT_1_2; + poly_p.y = p.y - poly_radius * M_ROOT_1_2; + } else if (k == 6) { + poly_p.x = p.x; + poly_p.y = p.y - poly_radius; + } else if (k == 7) { + poly_p.x = p.x + poly_radius * M_ROOT_1_2; + poly_p.y = p.y - poly_radius * M_ROOT_1_2; + } + region.encompass(poly_p); + shape.second.m_points.push_back(poly_p); + } + shape.second.setCentroidAreaPerim(); + } + } + + if (done_something) { + // spatially reindex (simplest just to redo everything) + init(m_shapes.size(), region); + + for (auto shape : m_shapes) { + makePolyPixels(shape.first); + } + } + + return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////// -bool ShapeMap::moveShape(int shaperef, const Line& line, bool undoing) -{ - bool bounds_good = true; - - size_t rowid = m_shapes.searchindex(shaperef); - if (rowid == paftl::npos) { - return false; - } - - // remove shape from the pixel grid - removePolyPixels(shaperef); // done first, as all interface references use this list - - if (!undoing) { - // set undo counter, but only if this is not an undo itself: - m_undobuffer.push_back(SalaEvent(SalaEvent::SALA_MOVED,shaperef)); - m_undobuffer.tail().m_geometry = m_shapes.value(rowid); - m_undobuffer.tail().m_geometry.m_selected = false; // <- this m_selected really shouldn't be used -- should use attributes, but for some reason it is! - } - - if (!(m_region.contains_touch(line.start()) && m_region.contains_touch(line.end()))) { - bounds_good = false; - init(m_shapes.size(),line); - } - - m_shapes.value(rowid) = SalaShape(line); - - if (bounds_good) { - // note: also sets polygon bounding box: - makePolyPixels(shaperef); - } - else { - // pixelate all polys in the pixel new structure: - for (size_t i = 0; i < m_shapes.size(); i++) { - makePolyPixels(m_shapes.key(i)); - } - } - - // change connections: - if (m_hasgraph) { - // - pvecint oldconnections = m_connectors[rowid].m_connections; - m_connectors[rowid].m_connections.clear(); - pvecint& newconnections = m_connectors[rowid].m_connections; - // - int conn_col = m_attributes.getOrInsertLockedColumnIndex("Connectivity"); - int leng_col = -1; - // - int connectivity = 0; - if (isAxialMap()) { - // line connections optimised for line-line intersection - connectivity = getLineConnections( shaperef, newconnections, TOLERANCE_B*__max(m_region.height(),m_region.width())); - } - else { - connectivity = getShapeConnections( shaperef, newconnections, TOLERANCE_B*__max(m_region.height(),m_region.width())); - } - m_attributes.setValue(rowid, conn_col, (float) connectivity ); - if (isAxialMap()) { - leng_col = m_attributes.getOrInsertLockedColumnIndex("Line Length"); - m_attributes.setValue(rowid, leng_col, (float) m_shapes[rowid].getLength() ); - } - // - size_t k = 0; - // now go through our old connections, and remove ourself: - for (k = 0; k < oldconnections.size(); k++) { - int myplace = oldconnections[k]; - if (myplace != rowid) { // <- exclude self! - m_connectors[myplace].m_connections.remove(rowid); - m_attributes.decrValue(myplace,conn_col); - } - } - // now go through our new connections, and add ourself: - for (k = 0; k < newconnections.size(); k++) { - int myplace = newconnections[k]; - if (myplace != rowid) { // <- exclude self! - m_connectors[myplace].m_connections.add(rowid); - m_attributes.incrValue(myplace,conn_col); - } - } - // now check any unlinks still exist in our newconnections are unlinked again (argh...) - for (k = m_unlinks.size() - 1; k != paftl::npos; k--) { - int connb = -1; - if (m_unlinks[k].a == rowid) - connb = m_unlinks[k].b; - else if (m_unlinks[k].b == rowid) - connb = m_unlinks[k].a; - if (connb != -1) { - if (newconnections.searchindex(connb) == paftl::npos) { - // no longer required: - m_unlinks.remove_at(k); - } - else { - // enforce: - newconnections.remove(connb); - m_connectors[connb].m_connections.remove(rowid); - m_attributes.decrValue(connb,conn_col); - m_attributes.decrValue(rowid,conn_col); - } - } - } - // now check any links are actually required (argh...) - for (k = m_links.size() - 1; k != paftl::npos; k--) { - int connb = -1; - if (m_links[k].a == rowid) - connb = m_links[k].b; - else if (m_links[k].b == rowid) - connb = m_links[k].a; - if (connb != -1) { - if (newconnections.searchindex(connb) != paftl::npos) { - // no longer required: - m_links.remove_at(k); - } - else { - // enforce: - newconnections.add(connb); - m_connectors[connb].m_connections.add(rowid); - m_attributes.incrValue(connb,conn_col); - m_attributes.incrValue(rowid,conn_col); - } - } - } - // update displayed attribute for any changes: - invalidateDisplayedAttribute(); - setDisplayedAttribute(m_displayed_attribute); - } - - return true; +bool ShapeMap::moveShape(int shaperef, const Line &line, bool undoing) { + bool bounds_good = true; + + auto shapeIter = m_shapes.find(shaperef); + if (shapeIter == m_shapes.end()) { + return false; + } + + // remove shape from the pixel grid + removePolyPixels(shaperef); // done first, as all interface references use this list + + if (!undoing) { + // set undo counter, but only if this is not an undo itself: + m_undobuffer.push_back(SalaEvent(SalaEvent::SALA_MOVED, shaperef)); + m_undobuffer.back().m_geometry = shapeIter->second; + m_undobuffer.back().m_geometry.m_selected = + false; // <- this m_selected really shouldn't be used -- should use attributes, but for some reason it is! + } + + if (!(m_region.contains_touch(line.start()) && m_region.contains_touch(line.end()))) { + bounds_good = false; + init(m_shapes.size(), line); + } + + shapeIter->second = SalaShape(line); + + if (bounds_good) { + // note: also sets polygon bounding box: + makePolyPixels(shaperef); + } else { + // pixelate all polys in the pixel new structure: + for (auto shape : m_shapes) { + makePolyPixels(shape.first); + } + } + + int rowid = std::distance(m_shapes.begin(), shapeIter); + AttributeRow &row = m_attributes->getRow(AttributeKey(shapeIter->first)); + // change connections: + if (m_hasgraph) { + // + const std::vector oldconnections = m_connectors[size_t(rowid)].m_connections; + // + int conn_col = m_attributes->getOrInsertLockedColumn("Connectivity"); + int leng_col = -1; + // + if (isAxialMap()) { + // line connections optimised for line-line intersection + m_connectors[size_t(rowid)].m_connections = + getLineConnections(shaperef, TOLERANCE_B * __max(m_region.height(), m_region.width())); + } else { + m_connectors[size_t(rowid)].m_connections = + getShapeConnections(shaperef, TOLERANCE_B * __max(m_region.height(), m_region.width())); + } + + std::vector &newconnections = m_connectors[size_t(rowid)].m_connections; + row.setValue(conn_col, float(newconnections.size())); + if (isAxialMap()) { + leng_col = m_attributes->getOrInsertLockedColumn("Line Length"); + row.setValue(leng_col, (float)depthmapX::getMapAtIndex(m_shapes, rowid)->second.getLength()); + } + // + // now go through our old connections, and remove ourself: + for (int oldconnection : oldconnections) { + if (oldconnection != rowid) { // <- exclude self! + auto &connections = m_connectors[size_t(oldconnection)].m_connections; + depthmapX::findAndErase(connections, rowid); + auto &oldConnectionRow = getAttributeRowFromShapeIndex(oldconnection); + oldConnectionRow.incrValue(conn_col, -1.0f); + } + } + // now go through our new connections, and add ourself: + for (int newconnection : m_connectors[size_t(rowid)].m_connections) { + if (newconnection != rowid) { // <- exclude self! + depthmapX::insert_sorted(m_connectors[size_t(newconnection)].m_connections, rowid); + auto &newConnectionRow = getAttributeRowFromShapeIndex(newconnection); + newConnectionRow.incrValue(conn_col); + } + } + // now check any unlinks still exist in our newconnections are unlinked again (argh...) + for (auto revIter = m_unlinks.rbegin(); revIter != m_unlinks.rend(); ++revIter) { + int connb = -1; + if (revIter->a == rowid) + connb = revIter->b; + else if (revIter->b == rowid) + connb = revIter->a; + if (connb != -1) { + if (std::find(newconnections.begin(), newconnections.end(), connb) == newconnections.end()) { + // no longer required: + m_unlinks.erase(std::next(revIter).base()); + } else { + // enforce: + depthmapX::findAndErase(newconnections, connb); + depthmapX::findAndErase(m_connectors[size_t(connb)].m_connections, rowid); + auto &connbRow = getAttributeRowFromShapeIndex(connb); + connbRow.incrValue(conn_col, -1.0f); + row.incrValue(conn_col, -1.0f); + } + } + } + // now check any links are actually required (argh...) + for (auto revIter = m_links.rbegin(); revIter != m_links.rend(); ++revIter) { + int connb = -1; + if (revIter->a == rowid) + connb = revIter->b; + else if (revIter->b == rowid) + connb = revIter->a; + if (connb != -1) { + if (std::find(newconnections.begin(), newconnections.end(), connb) != newconnections.end()) { + // no longer required: + m_links.erase(std::next(revIter).base()); + } else { + // enforce: + depthmapX::insert_sorted(newconnections, connb); + depthmapX::insert_sorted(m_connectors[size_t(connb)].m_connections, rowid); + auto &connbRow = getAttributeRowFromShapeIndex(connb); + connbRow.incrValue(conn_col); + row.incrValue(conn_col); + } + } + } + // update displayed attribute for any changes: + invalidateDisplayedAttribute(); + setDisplayedAttribute(m_displayed_attribute); + } + + return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////// // some functions to make a polygon from the UI -int ShapeMap::polyBegin(const Line& line) -{ - // add geometry - bool bounds_good = true; - if (!(m_region.contains_touch(line.start()) && m_region.contains_touch(line.end()))) { - bounds_good = false; - init(m_shapes.size(),line); - } - m_shape_ref++; - int rowid = m_shapes.add(m_shape_ref,SalaShape(line)); - m_shapes.tail().m_centroid = line.getCentre(); - - if (bounds_good) { - // note: also sets polygon bounding box: - makePolyPixels(m_shape_ref); - } - else { - // pixelate all polys in the pixel new structure: - for (size_t i = 0; i < m_shapes.size(); i++) { - makePolyPixels(m_shapes.key(i)); - } - } - - // insert into attributes - m_attributes.insertRow(m_shape_ref); - // would usually set attributes here, but actually, really want - // to set the attributes only when the user completes the drawing - - // change connections: - if (m_hasgraph) { - // dummy for now to ensure there is a row in the connector table - // so all indices match... - m_connectors.push_back( Connector() ); - } - - // flag new shape - m_newshape = true; - - // set undo counter: - m_undobuffer.push_back(SalaEvent(SalaEvent::SALA_CREATED,m_shape_ref)); - - // update displayed attribute - invalidateDisplayedAttribute(); - setDisplayedAttribute(m_displayed_attribute); - - return m_shape_ref; -} +int ShapeMap::polyBegin(const Line &line) { + // add geometry + bool bounds_good = true; + if (!(m_region.contains_touch(line.start()) && m_region.contains_touch(line.end()))) { + bounds_good = false; + init(m_shapes.size(), line); + } -bool ShapeMap::polyAppend(const Point2f& point) -{ - // don't do anything too complex: - SalaShape& shape = m_shapes.tail(); - - // check you can actually do this first - if (!(shape.isLine() || shape.isPolyLine())) { - return false; - } - - // junk the old shape pixels: - removePolyPixels(m_shape_ref); - - bool bounds_good = true; - if (!m_region.contains_touch(point)) { - bounds_good = false; - init(m_shapes.size(),QtRegion(point,point)); - } - - if (shape.m_type == SalaShape::SHAPE_LINE) { - // convert it to a poly line: - shape.m_type = SalaShape::SHAPE_POLY; - shape.push_back(shape.m_region.t_start()); - shape.push_back(shape.m_region.t_end()); - } - // add new point: - shape.push_back(point); - - if (bounds_good) { - // note: also sets polygon bounding box: - makePolyPixels(m_shape_ref); - } - else { - // pixelate all polys in the pixel new structure: - for (size_t i = 0; i < m_shapes.size(); i++) { - makePolyPixels(m_shapes.key(i)); - } - } - - shape.setCentroidAreaPerim(); - - return true; -} + int new_shape_ref = getNextShapeKey(); + m_shapes.insert(std::make_pair(new_shape_ref, SalaShape(line))); + m_shapes.rbegin()->second.m_centroid = line.getCentre(); -bool ShapeMap::polyClose() -{ - // don't do anything too complex: - SalaShape& shape = m_shapes.tail(); + if (bounds_good) { + // note: also sets polygon bounding box: + makePolyPixels(new_shape_ref); + } else { + // pixelate all polys in the pixel new structure: + for (auto shape : m_shapes) { + makePolyPixels(shape.first); + } + } + + // insert into attributes + m_attributes->addRow(AttributeKey(new_shape_ref)); + // would usually set attributes here, but actually, really want + // to set the attributes only when the user completes the drawing - // check you can actually do this first - if (!shape.isPolyLine()) { - return false; - } + // change connections: + if (m_hasgraph) { + // dummy for now to ensure there is a row in the connector table + // so all indices match... + m_connectors.push_back(Connector()); + } - // junk the old shape pixels: - removePolyPixels(m_shape_ref); + // flag new shape + m_newshape = true; - shape.m_type |= SalaShape::SHAPE_CLOSED; + // set undo counter: + m_undobuffer.push_back(SalaEvent(SalaEvent::SALA_CREATED, new_shape_ref)); - makePolyPixels(m_shape_ref); + // update displayed attribute + invalidateDisplayedAttribute(); + setDisplayedAttribute(m_displayed_attribute); - return true; + return new_shape_ref; } -bool ShapeMap::polyCancel() -{ - // don't do anything too complex: - SalaShape& shape = m_shapes.tail(); +bool ShapeMap::polyAppend(int shape_ref, const Point2f &point) { + // don't do anything too complex: + SalaShape &shape = m_shapes.rbegin()->second; - // check you can actually do this first - if (!(shape.isLine() || shape.isPolyLine())) { - return false; - } + // check you can actually do this first + if (!(shape.isLine() || shape.isPolyLine())) { + return false; + } - m_undobuffer.pop_back(); - removeShape(m_shape_ref,true); + // junk the old shape pixels: + removePolyPixels(shape_ref); - // update displayed attribute - invalidateDisplayedAttribute(); - setDisplayedAttribute(m_displayed_attribute); + bool bounds_good = true; + if (!m_region.contains_touch(point)) { + bounds_good = false; + init(m_shapes.size(), QtRegion(point, point)); + } - return true; -} + if (shape.m_type == SalaShape::SHAPE_LINE) { + // convert it to a poly line: + shape.m_type = SalaShape::SHAPE_POLY; + shape.m_points.push_back(shape.m_region.t_start()); + shape.m_points.push_back(shape.m_region.t_end()); + } + // add new point: + shape.m_points.push_back(point); -// some functions to make a polygon from the DLL interface or scripting language + if (bounds_good) { + // note: also sets polygon bounding box: + makePolyPixels(shape_ref); + } else { + // pixelate all polys in the pixel new structure: + for (auto shape : m_shapes) { + makePolyPixels(shape.first); + } + } -void ShapeMap::shapeBegin() -{ - m_temppoints.clearnofree(); -} + shape.setCentroidAreaPerim(); -void ShapeMap::shapeVertex(const Point2f& p) -{ - m_temppoints.push_back(p); + return true; } -int ShapeMap::shapeEnd(bool open) -{ - int len = m_temppoints.size(); - if (len == 0) { - return -1; - } - - if (m_region.isNull()) { - m_region = QtRegion(m_temppoints[0],m_temppoints[0]); - } - for (int i = 0; i < len; i++) { - m_region.encompass(m_temppoints[i]); - } - - m_shape_ref++; - - int rowid = -1; - - if (len == 1) { - rowid = m_shapes.add(m_shape_ref,SalaShape(m_temppoints[0])); - } - else if (len == 2) { - rowid = m_shapes.add(m_shape_ref,SalaShape(Line(m_temppoints[0],m_temppoints[1]))); - } - else { - if (open) { - rowid = m_shapes.add(m_shape_ref,SalaShape(SalaShape::SHAPE_POLY)); - } - else { - rowid = m_shapes.add(m_shape_ref,SalaShape(SalaShape::SHAPE_POLY | SalaShape::SHAPE_CLOSED)); - } - if (rowid != -1) { - SalaShape& shape = m_shapes[rowid]; - for (int i = 0; i < len; i++) { - shape.push_back(m_temppoints[i]); - } - shape.setCentroidAreaPerim(); - } - } - - if (rowid != -1) { - m_attributes.insertRow(m_shape_ref); - - if (m_hasgraph) { - while (m_connectors.size() < m_shapes.size()) { - m_connectors.push_back( Connector() ); - } - } - } - - m_newshape = true; - - // note: this function returns rowid *not* shaperef - return rowid; -} - -// very simple, just remake the poly pixels -void ShapeMap::shapesCommit() -{ - init(m_shapes.size(),m_region); +bool ShapeMap::polyClose(int shape_ref) { + // don't do anything too complex: + SalaShape &shape = m_shapes.rbegin()->second; - for (size_t i = 0; i < m_shapes.size(); i++) { - makePolyPixels(m_shapes.key(i)); - } + // check you can actually do this first + if (!shape.isPolyLine()) { + return false; + } - invalidateDisplayedAttribute(); - setDisplayedAttribute(m_displayed_attribute); -} + // junk the old shape pixels: + removePolyPixels(shape_ref); + shape.m_type |= SalaShape::SHAPE_CLOSED; -/////////////////////////////////////////////////////////////////////////////////////////////////////// + makePolyPixels(shape_ref); -void ShapeMap::removeSelected() -{ - // note, map must have editable flag on if we are to remove shape: - if (!m_editable) { - return; - } - - // pray that the selection set is in order! - // (it should be: code currently uses add() throughout) - for (size_t i = m_selection_set.size(); i != paftl::npos; i--) { - removeShape(m_shapes.key(m_selection_set[i])); - } - m_selection_set.clear(); - m_selection = false; - - invalidateDisplayedAttribute(); - setDisplayedAttribute(m_displayed_attribute); + return true; } -void ShapeMap::removeShape(int shaperef, bool undoing) -{ - // remove shape from four keys: the pixel grid, the poly list, the attributes and the connections - removePolyPixels(shaperef); // done first, as all interface references use this list - - size_t rowid = m_shapes.searchindex(shaperef); - - if (!undoing) { // <- if not currently undoing another event, then add to the undo buffer: - m_undobuffer.push_back(SalaEvent(SalaEvent::SALA_DELETED,shaperef)); - m_undobuffer.tail().m_geometry = m_shapes.value(rowid); - m_undobuffer.tail().m_geometry.m_selected = false; // <- this m_selected really shouldn't be used -- should use attributes, but for some reason it is! - } - - if (rowid != paftl::npos) { - m_shapes.remove_at(rowid); - } - - if (m_hasgraph) { - // note that the connections have no key for speed when processing, - // we rely on the index order matching the index order of the shapes - // and the attributes, and simply change all references (ick!) - int conn_col = m_attributes.getColumnIndex("Connectivity"); - for (size_t i = m_connectors.size() - 1; i != paftl::npos; i--) { - if (i == rowid) { - continue; // it's going to be removed anyway - } - for (size_t j = m_connectors[i].m_connections.size() - 1; j != paftl::npos; j--) { - if (m_connectors[i].m_connections[j] == rowid) { - m_connectors[i].m_connections.remove_at(j); - if (conn_col != -1) { - m_attributes.decrValue(i,conn_col); - } - } - else if (m_connectors[i].m_connections[j] > (int)rowid) { - m_connectors[i].m_connections[j] -= 1; - } - } - // note, you cannot delete from a segment map, it's just too messy! - } - - m_connectors.remove_at(rowid); - - // take out explicit links and unlinks (note, undo won't restore these): - size_t k; - for (k = m_links.size() - 1; k != paftl::npos; k--) { - if (m_links[k].a == rowid || m_links[k].b == rowid) { - m_links.remove_at(k); - } - else { - if (m_links[k].a > (int)rowid) - m_links[k].a -= 1; - if (m_links[k].b > (int)rowid) - m_links[k].b -= 1; - } - } - for (k = m_unlinks.size() - 1; k != paftl::npos; k--) { - if (m_unlinks[k].a == rowid || m_unlinks[k].b == rowid) { - m_unlinks.remove_at(k); - } - else { - if (m_unlinks[k].a > (int)rowid) - m_unlinks[k].a -= 1; - if (m_unlinks[k].b > (int)rowid) - m_unlinks[k].b -= 1; - } - } - } - - // n.b., shaperef should have been used to create the row in the first place: - m_attributes.removeRow(shaperef); - - // if undoing the final shape, might as well reuse the shape ref: - if (undoing && shaperef == m_shape_ref) { - m_shape_ref--; - } - - m_newshape = true; - m_invalidate = true; -} +bool ShapeMap::polyCancel(int shape_ref) { + // don't do anything too complex: + SalaShape &shape = m_shapes.rbegin()->second; -void ShapeMap::undo() -{ - if (m_undobuffer.size() == 0) { - return; - } - - SalaEvent& event = m_undobuffer.tail(); - - if (event.m_action == SalaEvent::SALA_CREATED) { - - removeShape(event.m_shape_ref, true); // <- note, must tell remove shape it's an undo, or it will add this remove to the undo stack! - - } - else if (event.m_action == SalaEvent::SALA_DELETED) { - - makeShape(event.m_geometry,event.m_shape_ref); - int rowid = m_attributes.getRowid(event.m_shape_ref); - - if (rowid != -1 && m_hasgraph) { - // redo connections... n.b. TO DO this is intended to use the slower "any connection" method, so it can handle any sort of graph - // ...but that doesn't exist yet, so for the moment do lines: - // - // insert new connector at the row: - m_connectors.insert_at(rowid,Connector()); - // - // now go through all connectors, ensuring they're reindexed above this one: - // Argh! ...but, remember the reason we're doing this is for fast processing elsewhere - // -- this is a user triggered *undo*, they'll just have to wait: - for (size_t i = 0; i < m_connectors.size(); i++) { - for (size_t j = 0; j < m_connectors[i].m_connections.size(); j++) { - if (m_connectors[i].m_connections[j] >= rowid) { - m_connectors[i].m_connections[j] += 1; - } - } - } - // it gets worse, the links and unlinks will also be all over the shop due to the inserted row: - size_t j; - for (j = 0; j < m_links.size(); j++) { - if (m_links[j].a >= rowid) - m_links[j].a += 1; - if (m_links[j].b >= rowid) - m_links[j].b += 1; - } - for (j = 0; j < m_unlinks.size(); j++) { - if (m_unlinks[j].a >= rowid) - m_unlinks[j].a += 1; - if (m_unlinks[j].b >= rowid) - m_unlinks[j].b += 1; - } - // - // calculate this line's connections - int connectivity = getLineConnections(event.m_shape_ref,m_connectors[rowid].m_connections,TOLERANCE_B*__max(m_region.height(),m_region.width())); - // update: - int conn_col = m_attributes.getOrInsertLockedColumnIndex("Connectivity"); - m_attributes.setValue(rowid, conn_col, (float) connectivity ); - // - if (event.m_geometry.isLine()) { - int leng_col = m_attributes.getOrInsertLockedColumnIndex("Line Length"); - m_attributes.setValue(rowid, leng_col, (float) m_shapes[rowid].getLength() ); - } - // - // now go through our connections, and add ourself: - for (size_t k = 0; k < m_connectors[rowid].m_connections.size(); k++) { - int myplace = m_connectors[rowid].m_connections[k]; - if (myplace != rowid) { // <- exclude self! - m_connectors[myplace].m_connections.add(rowid); - m_attributes.incrValue(myplace,conn_col); - } - } - } - } - else if (event.m_action == SalaEvent::SALA_MOVED) { + // check you can actually do this first + if (!(shape.isLine() || shape.isPolyLine())) { + return false; + } - moveShape(event.m_shape_ref, event.m_geometry.getLine(), true); // <- note, must tell remove shape it's an undo, or it will add this remove to the undo stack! + m_undobuffer.pop_back(); + removeShape(shape_ref, true); - } + // update displayed attribute + invalidateDisplayedAttribute(); + setDisplayedAttribute(m_displayed_attribute); - m_undobuffer.pop_back(); + return true; +} - m_newshape = true; +/////////////////////////////////////////////////////////////////////////////////////////////////////// - invalidateDisplayedAttribute(); - setDisplayedAttribute(m_displayed_attribute); +bool ShapeMap::removeSelected() { + // note, map must have editable flag on if we are to remove shape: + if (!m_editable) { + return false; + } + + // pray that the selection set is in order! + // (it should be: code currently uses add() throughout) + for (auto &shapeRef : m_selection_set) { + removeShape(shapeRef); + } + m_selection_set.clear(); + m_selection = false; + + invalidateDisplayedAttribute(); + setDisplayedAttribute(m_displayed_attribute); + return true; +} + +void ShapeMap::removeShape(int shaperef, bool undoing) { + // remove shape from four keys: the pixel grid, the poly list, the attributes and the connections + removePolyPixels(shaperef); // done first, as all interface references use this list + + auto shapeIter = m_shapes.find(shaperef); + size_t rowid = std::distance(m_shapes.begin(), shapeIter); + + if (!undoing) { // <- if not currently undoing another event, then add to the undo buffer: + m_undobuffer.push_back(SalaEvent(SalaEvent::SALA_DELETED, shaperef)); + m_undobuffer.back().m_geometry = shapeIter->second; + m_undobuffer.back().m_geometry.m_selected = + false; // <- this m_selected really shouldn't be used -- should use attributes, but for some reason it is! + } + + if (shapeIter != m_shapes.end()) { + shapeIter = m_shapes.erase(shapeIter); + } + + if (m_hasgraph) { + // note that the connections have no key for speed when processing, + // we rely on the index order matching the index order of the shapes + // and the attributes, and simply change all references (ick!) + int conn_col = m_attributes->getColumnIndex("Connectivity"); + + // TODO: Replace with iterators + for (size_t i = m_connectors.size() - 1; static_cast(i) != -1; i--) { + if (i == rowid) { + continue; // it's going to be removed anyway + } + for (size_t j = m_connectors[i].m_connections.size() - 1; static_cast(j) != -1; j--) { + if (m_connectors[i].m_connections[j] == int(rowid)) { + m_connectors[i].m_connections.erase(m_connectors[i].m_connections.begin() + int(j)); + if (conn_col != -1) { + auto &row = getAttributeRowFromShapeIndex(i); + row.incrValue(conn_col, -1.0f); + } + } else if (m_connectors[i].m_connections[j] > int(rowid)) { + m_connectors[i].m_connections[j] -= 1; + } + } + // note, you cannot delete from a segment map, it's just too messy! + } + + m_connectors.erase(m_connectors.begin() + int(rowid)); + + // take out explicit links and unlinks (note, undo won't restore these): + for (auto revIter = m_links.rbegin(); revIter != m_links.rend(); ++revIter) { + if (revIter->a == static_cast(rowid) || revIter->b == static_cast(rowid)) { + m_links.erase(std::next(revIter).base()); + } else { + if (revIter->a > int(rowid)) + revIter->a -= 1; + if (revIter->b > int(rowid)) + revIter->b -= 1; + } + } + for (auto revIter = m_unlinks.rbegin(); revIter != m_unlinks.rend(); ++revIter) { + if (revIter->a == static_cast(rowid) || revIter->b == static_cast(rowid)) { + m_unlinks.erase(std::next(revIter).base()); + } else { + if (revIter->a > int(rowid)) + revIter->a -= 1; + if (revIter->b > int(rowid)) + revIter->b -= 1; + } + } + } + + // n.b., shaperef should have been used to create the row in the first place: + const AttributeKey shapeRefKey(shaperef); + m_attributes->removeRow(shapeRefKey); + + m_newshape = true; + m_invalidate = true; +} + +void ShapeMap::undo() { + if (m_undobuffer.size() == 0) { + return; + } + + SalaEvent &event = m_undobuffer.back(); + + if (event.m_action == SalaEvent::SALA_CREATED) { + + removeShape( + event.m_shape_ref, + true); // <- note, must tell remove shape it's an undo, or it will add this remove to the undo stack! + + } else if (event.m_action == SalaEvent::SALA_DELETED) { + + makeShape(event.m_geometry, event.m_shape_ref); + int rowid = std::distance(m_shapes.begin(), m_shapes.find(event.m_shape_ref)); + auto &row = m_attributes->getRow(AttributeKey(event.m_shape_ref)); + + if (rowid != -1 && m_hasgraph) { + // redo connections... n.b. TO DO this is intended to use the slower "any connection" method, so it can + // handle any sort of graph + // ...but that doesn't exist yet, so for the moment do lines: + // + // insert new connector at the row: + m_connectors[rowid] = Connector(); + // + // now go through all connectors, ensuring they're reindexed above this one: + // Argh! ...but, remember the reason we're doing this is for fast processing elsewhere + // -- this is a user triggered *undo*, they'll just have to wait: + for (size_t i = 0; i < m_connectors.size(); i++) { + for (size_t j = 0; j < m_connectors[i].m_connections.size(); j++) { + if (m_connectors[i].m_connections[j] >= rowid) { + m_connectors[i].m_connections[j] += 1; + } + } + } + // it gets worse, the links and unlinks will also be all over the shop due to the inserted row: + size_t j; + for (j = 0; j < m_links.size(); j++) { + if (m_links[j].a >= rowid) + m_links[j].a += 1; + if (m_links[j].b >= rowid) + m_links[j].b += 1; + } + for (j = 0; j < m_unlinks.size(); j++) { + if (m_unlinks[j].a >= rowid) + m_unlinks[j].a += 1; + if (m_unlinks[j].b >= rowid) + m_unlinks[j].b += 1; + } + // + // calculate this line's connections + m_connectors[size_t(rowid)].m_connections = + getLineConnections(event.m_shape_ref, TOLERANCE_B * __max(m_region.height(), m_region.width())); + // update: + int conn_col = m_attributes->getOrInsertLockedColumn("Connectivity"); + row.setValue(conn_col, float(m_connectors[rowid].m_connections.size())); + // + if (event.m_geometry.isLine()) { + int leng_col = m_attributes->getOrInsertLockedColumn("Line Length"); + row.setValue(leng_col, (float)depthmapX::getMapAtIndex(m_shapes, rowid)->second.getLength()); + } + // + // now go through our connections, and add ourself: + const std::vector &connections = m_connectors[size_t(rowid)].m_connections; + for (int connection : connections) { + if (connection != rowid) { // <- exclude self! + depthmapX::insert_sorted(m_connectors[size_t(connection)].m_connections, rowid); + auto &row = getAttributeRowFromShapeIndex(connection); + row.incrValue(conn_col); + } + } + } + } else if (event.m_action == SalaEvent::SALA_MOVED) { + + moveShape(event.m_shape_ref, event.m_geometry.getLine(), + true); // <- note, must tell remove shape it's an undo, or it will add this remove to the undo stack! + } + + m_undobuffer.pop_back(); + + m_newshape = true; + + invalidateDisplayedAttribute(); + setDisplayedAttribute(m_displayed_attribute); } /////////////////////////////////////////////////////////////////////////////////////////////////////// -void ShapeMap::makePolyPixels(int polyref) -{ - // first add into pixels, and ensure you have a bl, tr for the set (useful for testing later) - SalaShape& poly = m_shapes.search(polyref); - if (poly.isClosed()) { - pmap relations; - for (size_t k = 0; k < poly.size(); k++) { - int nextk = (k + 1) % poly.size(); - Line li(poly[k],poly[nextk]); - if (k == 0) { - poly.m_region = li; - } - else { - poly.m_region = runion(poly.m_region,li); - } - PixelRefList pixels = pixelateLine(li); - // debug - // int duplicate_shaperefs = 0; - // end debug - for (size_t i = 0; i < pixels.size(); i++) { - PixelRef pix = pixels[i]; - size_t x = m_pixel_shapes[pix.x][pix.y].searchindex(ShapeRef(polyref)); - if (x == paftl::npos) { - x = m_pixel_shapes[pix.x][pix.y].add(ShapeRef(polyref),paftl::ADD_HERE); - } - m_pixel_shapes[pix.x][pix.y][x].m_polyrefs.push_back(k); - relations.add(pixels[i],ShapeRef::SHAPE_EDGE); - } - } - // erase joined sides, and look for min: - PixelRef minpix = NoPixel; - for (size_t j = 0; j < relations.size(); j++) { - PixelRef pix = relations.key(j); - PixelRef nextpix; - nextpix = pix.right(); - if (includes(nextpix) && m_pixel_shapes[nextpix.x][nextpix.y].searchindex(ShapeRef(polyref)) != paftl::npos) { - relations.value(j) &= ~ShapeRef::SHAPE_R; - } - nextpix = pix.up(); - if (includes(nextpix) && m_pixel_shapes[nextpix.x][nextpix.y].searchindex(ShapeRef(polyref)) != paftl::npos) { - relations.value(j) &= ~ShapeRef::SHAPE_T; - } - nextpix = pix.down(); - if (includes(nextpix) && m_pixel_shapes[nextpix.x][nextpix.y].searchindex(ShapeRef(polyref)) != paftl::npos) { - relations.value(j) &= ~ShapeRef::SHAPE_B; - } - nextpix = pix.left(); - if (includes(nextpix) && m_pixel_shapes[nextpix.x][nextpix.y].searchindex(ShapeRef(polyref)) != paftl::npos) { - relations.value(j) &= ~ShapeRef::SHAPE_L; - } - if ((relations.value(j) & (ShapeRef::SHAPE_B | ShapeRef::SHAPE_L)) == (ShapeRef::SHAPE_B | ShapeRef::SHAPE_L)) { - if ((minpix == NoPixel) || (relations.key(j) < (int)minpix)) { - minpix = relations.key(j); - } - } - } - shapePixelBorder(relations,polyref,ShapeRef::SHAPE_L,minpix,minpix,true); - // go through any that aren't on the outer border: this will be internal edges, and will cause problems - // for point in polygon algorithms! - size_t i; - for (i = 0; i < relations.size(); i++) { - PixelRef pix = relations.key(i); - unsigned char& tags = m_pixel_shapes[pix.x][pix.y].search(polyref).m_tags; - if (tags == 0x00) { - tags |= ShapeRef::SHAPE_INTERNAL_EDGE; - } - } - // now, any remaining tags are internal sides, and need to be cleared through fill - // we could go either direction, but we just go left to right: - for (i = 0; i < relations.size(); i++) { - PixelRef pix = relations.key(i); - if (relations.value(i) & ShapeRef::SHAPE_R) { - int pos = 0; - do { - PixelRef nextpix = pix.right(); - if (!includes(nextpix)) { - // this shouldn't happen - break; - } - // returns -1 if cannot add due to already existing: - pos = m_pixel_shapes[nextpix.x][nextpix.y].add(ShapeRef(polyref,ShapeRef::SHAPE_CENTRE)); - pix = nextpix; - } while (pos != -1); - } - } - // Done...! This polygon is registered in the pixel polygon structure - } - else { - // Open shapes much easier! - switch (poly.m_type & SalaShape::SHAPE_TYPE) - { - case SalaShape::SHAPE_POINT: - { - PixelRef pix = pixelate(poly.m_centroid); - size_t x = m_pixel_shapes[pix.x][pix.y].searchindex(ShapeRef(polyref)); - if (x == paftl::npos) { - x = m_pixel_shapes[pix.x][pix.y].add(ShapeRef(polyref,ShapeRef::SHAPE_OPEN),paftl::ADD_HERE); - } - } - break; - case SalaShape::SHAPE_LINE: - { - PixelRefList pixels = pixelateLine(poly.m_region); - for (size_t i = 0; i < pixels.size(); i++) { - PixelRef pix = pixels[i]; - size_t x = m_pixel_shapes[pix.x][pix.y].searchindex(ShapeRef(polyref)); - if (x == paftl::npos) { - x = m_pixel_shapes[pix.x][pix.y].add(ShapeRef(polyref,ShapeRef::SHAPE_OPEN),paftl::ADD_HERE); - } - } - } - break; - case SalaShape::SHAPE_POLY: - for (size_t k = 0; k < poly.size() - 1; k++) { - int nextk = (k + 1); - Line li(poly[k],poly[nextk]); +void ShapeMap::makePolyPixels(int polyref) { + ShapeRef shapeRef = ShapeRef(polyref); + // first add into pixels, and ensure you have a bl, tr for the set (useful for testing later) + SalaShape &poly = m_shapes.find(polyref)->second; + if (poly.isClosed()) { + std::map relations; + for (size_t k = 0; k < poly.m_points.size(); k++) { + int nextk = int((k + 1) % poly.m_points.size()); + Line li(poly.m_points[k], poly.m_points[nextk]); if (k == 0) { - poly.m_region = li; - } - else { - poly.m_region = runion(poly.m_region,li); - } - PixelRefList pixels = pixelateLine(li); + poly.m_region = li; + } else { + poly.m_region = runion(poly.m_region, li); + } + PixelRefVector pixels = pixelateLine(li); + // debug + // int duplicate_shaperefs = 0; + // end debug for (size_t i = 0; i < pixels.size(); i++) { - PixelRef pix = pixels[i]; - size_t x = m_pixel_shapes[pix.x][pix.y].searchindex(ShapeRef(polyref)); - if (x == paftl::npos) { - x = m_pixel_shapes[pix.x][pix.y].add(ShapeRef(polyref,ShapeRef::SHAPE_OPEN),paftl::ADD_HERE); - } - m_pixel_shapes[pix.x][pix.y][x].m_polyrefs.push_back(k); + PixelRef pix = pixels[i]; + std::vector &pixShapes = + m_pixel_shapes(static_cast(pix.y), static_cast(pix.x)); + auto it = depthmapX::findBinary(pixShapes, shapeRef); + if (it == pixShapes.end()) { + pixShapes.push_back(shapeRef); + it = pixShapes.end() - 1; + } + it->m_polyrefs.push_back(k); + relations.insert(std::make_pair(pixels[i], ShapeRef::SHAPE_EDGE)); + } + } + // erase joined sides, and look for min: + PixelRef minpix = NoPixel; + for (auto &relation : relations) { + PixelRef pix = relation.first; + PixelRef nextpix; + nextpix = pix.right(); + if (includes(nextpix)) { + auto &pixShapes = m_pixel_shapes(static_cast(nextpix.y), static_cast(nextpix.x)); + if (depthmapX::findBinary(pixShapes, shapeRef) != pixShapes.end()) { + relation.second &= ~ShapeRef::SHAPE_R; + } + } + nextpix = pix.up(); + if (includes(nextpix)) { + auto &pixShapes = m_pixel_shapes(static_cast(nextpix.y), static_cast(nextpix.x)); + if (depthmapX::findBinary(pixShapes, shapeRef) != pixShapes.end()) { + relation.second &= ~ShapeRef::SHAPE_T; + } + } + nextpix = pix.down(); + if (includes(nextpix)) { + auto &pixShapes = m_pixel_shapes(static_cast(nextpix.y), static_cast(nextpix.x)); + if (depthmapX::findBinary(pixShapes, shapeRef) != pixShapes.end()) { + relation.second &= ~ShapeRef::SHAPE_B; + } + } + nextpix = pix.left(); + if (includes(nextpix)) { + auto &pixShapes = m_pixel_shapes(static_cast(nextpix.y), static_cast(nextpix.x)); + if (depthmapX::findBinary(pixShapes, shapeRef) != pixShapes.end()) { + relation.second &= ~ShapeRef::SHAPE_L; + } + } + if ((relation.second & (ShapeRef::SHAPE_B | ShapeRef::SHAPE_L)) == + (ShapeRef::SHAPE_B | ShapeRef::SHAPE_L)) { + if ((minpix == NoPixel) || (relation.first < int(minpix))) { + minpix = relation.first; + } + } + } + shapePixelBorder(relations, polyref, ShapeRef::SHAPE_L, minpix, minpix, true); + // go through any that aren't on the outer border: this will be internal edges, and will cause problems + // for point in polygon algorithms! + + for (auto &relation : relations) { + PixelRef pix = relation.first; + std::vector &pixShapes = m_pixel_shapes(static_cast(pix.y), static_cast(pix.x)); + const auto iter = depthmapX::findBinary(pixShapes, shapeRef); + if (iter == pixShapes.end()) + throw new depthmapX::RuntimeException("Poly reference not found"); + unsigned char &tags = iter->m_tags; + if (tags == 0x00) { + tags |= ShapeRef::SHAPE_INTERNAL_EDGE; + } + } + // now, any remaining tags are internal sides, and need to be cleared through fill + // we could go either direction, but we just go left to right: + for (auto &relation : relations) { + PixelRef pix = relation.first; + if (relation.second & ShapeRef::SHAPE_R) { + bool lastWasNotFound = true; + while (lastWasNotFound) { + PixelRef nextpix = pix.right(); + if (!includes(nextpix)) { + // this shouldn't happen + break; + } + // returns -1 if cannot add due to already existing: + lastWasNotFound = false; + std::vector &pixelShapes = + m_pixel_shapes(static_cast(nextpix.y), static_cast(nextpix.x)); + const auto it = depthmapX::findBinary(pixelShapes, shapeRef); + if (it == pixelShapes.end()) { + lastWasNotFound = true; + pixelShapes.push_back(ShapeRef(polyref, ShapeRef::SHAPE_CENTRE)); + } + pix = nextpix; + } + } + } + // Done...! This polygon is registered in the pixel polygon structure + } else { + // Open shapes much easier! + switch (poly.m_type & SalaShape::SHAPE_TYPE) { + case SalaShape::SHAPE_POINT: { + PixelRef pix = pixelate(poly.m_centroid); + std::vector &pixShapes = m_pixel_shapes(static_cast(pix.y), static_cast(pix.x)); + const auto it = depthmapX::findBinary(pixShapes, shapeRef); + if (it == pixShapes.end()) { + pixShapes.push_back(ShapeRef(polyref, ShapeRef::SHAPE_OPEN)); + } + } break; + case SalaShape::SHAPE_LINE: { + PixelRefVector pixels = pixelateLine(poly.m_region); + for (size_t i = 0; i < pixels.size(); i++) { + PixelRef pix = pixels[i]; + std::vector &pixShapes = + m_pixel_shapes(static_cast(pix.y), static_cast(pix.x)); + const auto it = depthmapX::findBinary(pixShapes, shapeRef); + if (it == pixShapes.end()) { + pixShapes.push_back(ShapeRef(polyref, ShapeRef::SHAPE_OPEN)); + } + } + } break; + case SalaShape::SHAPE_POLY: + for (size_t k = 0; k < poly.m_points.size() - 1; k++) { + int nextk = (k + 1); + Line li(poly.m_points[k], poly.m_points[nextk]); + if (k == 0) { + poly.m_region = li; + } else { + poly.m_region = runion(poly.m_region, li); + } + PixelRefVector pixels = pixelateLine(li); + for (size_t i = 0; i < pixels.size(); i++) { + PixelRef pix = pixels[i]; + std::vector &pixShapes = + m_pixel_shapes(static_cast(pix.y), static_cast(pix.x)); + auto it = depthmapX::findBinary(pixShapes, shapeRef); + if (it == pixShapes.end()) { + pixShapes.push_back(ShapeRef(polyref, ShapeRef::SHAPE_OPEN)); + it = pixShapes.end() - 1; + } + it->m_polyrefs.push_back(k); + } } - } - break; - } - } + break; + } + } } ///////////////////////////////////////////////////////////////////////////////////////////////// -void ShapeMap::shapePixelBorder(pmap& relations, int polyref, int side, PixelRef currpix, PixelRef minpix, bool first) -{ - if (!first && currpix == minpix && side == ShapeRef::SHAPE_L) { - // looped: - return; - } - size_t rel = relations.searchindex(currpix); - if (relations[rel] & side) { - m_pixel_shapes[currpix.x][currpix.y].search(polyref).m_tags |= side; - relations[rel] &= ~side; // <- clear to check all have been done later - side <<= 1; - if (side > ShapeRef::SHAPE_T) { - side = ShapeRef::SHAPE_L; - } - shapePixelBorder(relations,polyref,side,currpix,minpix,false); - } - else { - currpix.move( moveDir(side) ); - side >>= 1; - if (side < ShapeRef::SHAPE_L) { - side = ShapeRef::SHAPE_T; - } - shapePixelBorder(relations,polyref,side,currpix,minpix,false); - } +void ShapeMap::shapePixelBorder(std::map &relations, int polyref, int side, PixelRef currpix, + PixelRef minpix, bool first) { + if (!first && currpix == minpix && side == ShapeRef::SHAPE_L) { + // looped: + return; + } + auto relation = relations.find(currpix); + if (relation->second & side) { + std::vector &pixShapes = + m_pixel_shapes(static_cast(currpix.y), static_cast(currpix.x)); + const auto iter = depthmapX::findBinary(pixShapes, ShapeRef(polyref)); + if (iter == pixShapes.end()) + throw new depthmapX::RuntimeException("Poly reference not found"); + iter->m_tags |= side; + relation->second &= ~side; // <- clear to check all have been done later + side <<= 1; + if (side > ShapeRef::SHAPE_T) { + side = ShapeRef::SHAPE_L; + } + shapePixelBorder(relations, polyref, side, currpix, minpix, false); + } else { + currpix.move(moveDir(side)); + side >>= 1; + if (side < ShapeRef::SHAPE_L) { + side = ShapeRef::SHAPE_T; + } + shapePixelBorder(relations, polyref, side, currpix, minpix, false); + } } // note that this is almost exactly the same as shapePixelBorder -void ShapeMap::pointPixelBorder(const PointMap& pointmap, pmap& relations, SalaShape& poly, int side, PixelRef currpix, PixelRef minpix, bool first) -{ - if (!first && currpix == minpix && side == ShapeRef::SHAPE_L) { - // looped: - return; - } - size_t rel = relations.searchindex(currpix); - if (relations[rel] & side) { - poly.push_back(pointmap.depixelate(currpix)+pointOffset(pointmap,currpix,side)); - relations[rel] &= ~side; // <- clear to check all have been done later - side <<= 1; - if (side > ShapeRef::SHAPE_T) { - side = ShapeRef::SHAPE_L; - } - pointPixelBorder(pointmap,relations,poly,side,currpix,minpix,false); - } - else { - currpix.move( moveDir(side) ); - side >>= 1; - if (side < ShapeRef::SHAPE_L) { - side = ShapeRef::SHAPE_T; - } - pointPixelBorder(pointmap,relations,poly,side,currpix,minpix,false); - } +void ShapeMap::pointPixelBorder(const PointMap &pointmap, std::map &relations, SalaShape &poly, int side, + PixelRef currpix, PixelRef minpix, bool first) { + if (!first && currpix == minpix && side == ShapeRef::SHAPE_L) { + // looped: + return; + } + auto relation = relations.find(currpix); + if (relation->second & side) { + poly.m_points.push_back(pointmap.depixelate(currpix) + pointOffset(pointmap, side)); + relation->second &= ~side; // <- clear to check all have been done later + side <<= 1; + if (side > ShapeRef::SHAPE_T) { + side = ShapeRef::SHAPE_L; + } + pointPixelBorder(pointmap, relations, poly, side, currpix, minpix, false); + } else { + currpix.move(moveDir(side)); + side >>= 1; + if (side < ShapeRef::SHAPE_L) { + side = ShapeRef::SHAPE_T; + } + pointPixelBorder(pointmap, relations, poly, side, currpix, minpix, false); + } } ///////////////////////////////////////////////////////////////////////////////////////////////// -void ShapeMap::removePolyPixels(int polyref) -{ - size_t index = m_shapes.searchindex(polyref); - if (index == paftl::npos) { - return; - } - SalaShape& poly = m_shapes[index]; - if (poly.isClosed()) { - // easiest just to use scan lines to find internal pixels rather than trace a complex border: - PixelRef minpix = pixelate(poly.m_region.bottom_left); - PixelRef maxpix = pixelate(poly.m_region.top_right); - for (int x = minpix.x; x <= maxpix.x; x++) { - for (int y = minpix.y; y <= maxpix.y; y++) { - size_t pos = m_pixel_shapes[x][y].searchindex(polyref); - if (pos != paftl::npos) { - m_pixel_shapes[x][y].remove_at(pos); - } - } - } - } - else { - // open shapes easier still, as no need to find internal pixels: - switch (poly.m_type & SalaShape::SHAPE_TYPE) - { - case SalaShape::SHAPE_POINT: - { +void ShapeMap::removePolyPixels(int polyref) { + auto shapeIter = m_shapes.find(polyref); + if (shapeIter == m_shapes.end()) { + return; + } + SalaShape &poly = shapeIter->second; + if (poly.isClosed()) { + // easiest just to use scan lines to find internal pixels rather than trace a complex border: + PixelRef minpix = pixelate(poly.m_region.bottom_left); + PixelRef maxpix = pixelate(poly.m_region.top_right); + for (int x = minpix.x; x <= maxpix.x; x++) { + for (int y = minpix.y; y <= maxpix.y; y++) { + std::vector &pixShapes = m_pixel_shapes(static_cast(y), static_cast(x)); + const auto it = depthmapX::findBinary(pixShapes, ShapeRef(polyref)); + if (it != pixShapes.end()) + pixShapes.erase(it); + } + } + } else { + // open shapes easier still, as no need to find internal pixels: + switch (poly.m_type & SalaShape::SHAPE_TYPE) { + case SalaShape::SHAPE_POINT: { PixelRef pix = pixelate(poly.m_centroid); - int pos = m_pixel_shapes[pix.x][pix.y].searchindex(polyref); - if (pos != -1) { - m_pixel_shapes[pix.x][pix.y].remove_at(pos); - } - } - break; - case SalaShape::SHAPE_LINE: - { - PixelRefList list = pixelateLine(poly.m_region); - for (size_t i = 0; i < list.size(); i++) { - size_t pos = m_pixel_shapes[list[i].x][list[i].y].searchindex(polyref); - if (pos != paftl::npos) { - m_pixel_shapes[list[i].x][list[i].y].remove_at(pos); - } - } - } - break; - case SalaShape::SHAPE_POLY: - for (size_t k = 0; k < poly.size() - 1; k++) { - size_t nextk = (k + 1); - Line li(poly[k],poly[nextk]); - PixelRefList list = pixelateLine(li); + std::vector &pixShapes = m_pixel_shapes(static_cast(pix.y), static_cast(pix.x)); + const auto it = depthmapX::findBinary(pixShapes, ShapeRef(polyref)); + if (it != pixShapes.end()) + pixShapes.erase(it); + } break; + case SalaShape::SHAPE_LINE: { + PixelRefVector list = pixelateLine(poly.m_region); for (size_t i = 0; i < list.size(); i++) { - size_t pos = m_pixel_shapes[list[i].x][list[i].y].searchindex(polyref); - if (pos != paftl::npos) { - m_pixel_shapes[list[i].x][list[i].y].remove_at(pos); - } + std::vector &pixShapes = + m_pixel_shapes(static_cast(list[i].y), static_cast(list[i].x)); + const auto it = depthmapX::findBinary(pixShapes, ShapeRef(polyref)); + if (it != pixShapes.end()) + pixShapes.erase(it); + } + } break; + case SalaShape::SHAPE_POLY: + for (size_t k = 0; k < poly.m_points.size() - 1; k++) { + size_t nextk = (k + 1); + Line li(poly.m_points[k], poly.m_points[nextk]); + PixelRefVector list = pixelateLine(li); + for (size_t i = 0; i < list.size(); i++) { + std::vector &pixShapes = + m_pixel_shapes(static_cast(list[i].y), static_cast(list[i].x)); + const auto it = depthmapX::findBinary(pixShapes, ShapeRef(polyref)); + if (it != pixShapes.end()) + pixShapes.erase(it); + } } - } - break; - } - - } + break; + } + } } ///////////////////////////////////////////////////////////////////////////////////////////////// -int ShapeMap::moveDir(int side) -{ - int dir; - switch (side) - { - case ShapeRef::SHAPE_L: - dir = PixelRef::NEGHORIZONTAL; - break; - case ShapeRef::SHAPE_B: - dir = PixelRef::NEGVERTICAL; - break; - case ShapeRef::SHAPE_R: - dir = PixelRef::HORIZONTAL; - break; - case ShapeRef::SHAPE_T: - dir = PixelRef::VERTICAL; - break; - } - return dir; +int ShapeMap::moveDir(int side) { + int dir = PixelRef::NODIR; + switch (side) { + case ShapeRef::SHAPE_L: + dir = PixelRef::NEGHORIZONTAL; + break; + case ShapeRef::SHAPE_B: + dir = PixelRef::NEGVERTICAL; + break; + case ShapeRef::SHAPE_R: + dir = PixelRef::HORIZONTAL; + break; + case ShapeRef::SHAPE_T: + dir = PixelRef::VERTICAL; + break; + } + return dir; +} + +Point2f ShapeMap::pointOffset(const PointMap &pointmap, int side) { + Point2f p; + switch (side) { + case ShapeRef::SHAPE_L: + p = Point2f(-pointmap.getSpacing() / 2, 0.0); + break; + case ShapeRef::SHAPE_B: + p = Point2f(0.0, -pointmap.getSpacing() / 2); + break; + case ShapeRef::SHAPE_R: + p = Point2f(pointmap.getSpacing() / 2, 0.0); + break; + case ShapeRef::SHAPE_T: + p = Point2f(0.0, pointmap.getSpacing() / 2); + break; + } + return p; } -Point2f ShapeMap::pointOffset(const PointMap& pointmap, int currpix, int side) -{ - Point2f p; - switch (side) - { - case ShapeRef::SHAPE_L: - p = Point2f(-pointmap.getSpacing()/2,0.0); - break; - case ShapeRef::SHAPE_B: - p = Point2f(0.0,-pointmap.getSpacing()/2); - break; - case ShapeRef::SHAPE_R: - p = Point2f(pointmap.getSpacing()/2,0.0); - break; - case ShapeRef::SHAPE_T: - p = Point2f(0.0,pointmap.getSpacing()/2); - break; - } - return p; -} - -///////////////////////////////////////////////////////////////////////////////////////////////// - -// returns poly key for an attributes call / select command +// Point in poly testing (returns topmost displayed poly) -int ShapeMap::quickPointInPoly(const Point2f& p) const -{ - if (!m_region.contains(p)) { - return -1; - } - PixelRef pix = pixelate(p); - pqvector &shapes = m_pixel_shapes[pix.x][pix.y]; - int drawlast = -1; - int draworder = -1; - for (size_t i = 0; i < shapes.size(); i++) { - size_t x = m_shapes.searchindex(shapes[i].m_shape_ref); - if (x != paftl::npos && m_attributes.getDisplayPos(x) > draworder) { - drawlast = x; - draworder = m_attributes.getDisplayPos(x); - } - } - return drawlast; -} +int ShapeMap::pointInPoly(const Point2f &p) const { + if (!m_region.contains(p)) { + return -1; + } + std::vector testedshapes; + PixelRef pix = pixelate(p); + const std::vector &shapes = m_pixel_shapes(static_cast(pix.y), static_cast(pix.x)); + int drawlast = -1; + int draworder = -1; + + for (const ShapeRef &shape : shapes) { + auto iter = depthmapX::findBinary(testedshapes, shape.m_shape_ref); + if (iter != testedshapes.end()) { + continue; + } + testedshapes.insert(iter, int(shape.m_shape_ref)); -// Point in poly testing (returns topmost displayed poly) + int shapeindex = testPointInPoly(p, shape); -int ShapeMap::pointInPoly(const Point2f& p) const -{ - if (!m_region.contains(p)) { - return -1; - } - pvecint testedshapes; - pvecint testnodes; - PixelRef pix = pixelate(p); - pqvector &shapes = m_pixel_shapes[pix.x][pix.y]; - int drawlast = -1; - int draworder = -1; - for (size_t i = 0; i < shapes.size(); i++) { - const ShapeRef& shape = shapes[i]; - if (testedshapes.searchindex(shape.m_shape_ref) != paftl::npos) { - continue; - } - testedshapes.add(shape.m_shape_ref,paftl::ADD_HERE); - - int shapeindex = testPointInPoly(p,shape); - - // if there's a shapeindex, then add: - if (shapeindex != -1 && m_attributes.getDisplayPos(shapeindex) > draworder) { - drawlast = shapeindex; - draworder = m_attributes.getDisplayPos(shapeindex); - } - } - return drawlast; + // if there's a shapeindex, then add: + int currentDrawOrder = m_attribHandle->findInIndex(AttributeKey(shape.m_shape_ref)); + if (shapeindex != -1 && currentDrawOrder > draworder) { + drawlast = shapeindex; + draworder = currentDrawOrder; + } + } + return drawlast; } // Point in specific poly (by reference) -bool ShapeMap::pointInPoly(const Point2f& p, int polyref) const -{ - PixelRef pix = pixelate(p); - pqvector &shapes = m_pixel_shapes[pix.x][pix.y]; - size_t x = shapes.searchindex(ShapeRef(polyref)); - if (x != paftl::npos) { - return (testPointInPoly(p,shapes[x]) != -1); - } - return false; +bool ShapeMap::pointInPoly(const Point2f &p, int polyref) const { + PixelRef pix = pixelate(p); + const std::vector &shapes = m_pixel_shapes(static_cast(pix.y), static_cast(pix.x)); + const auto iter = depthmapX::findBinary(shapes, ShapeRef(polyref)); + if (iter != shapes.end()) { + return (testPointInPoly(p, *iter) != -1); + } + return false; } // similar to above, but builds a list -void ShapeMap::pointInPolyList(const Point2f& p, pvecint& shapeindexlist) const -{ - if (!m_region.contains(p)) { - return ; - } - pvecint testedshapes; - PixelRef pix = pixelate(p); - pqvector &shapes = m_pixel_shapes[pix.x][pix.y]; - for (size_t i = 0; i < shapes.size(); i++) { - const ShapeRef& shape = shapes[i]; - if (testedshapes.searchindex(shape.m_shape_ref) != paftl::npos) { - continue; - } - testedshapes.add(shape.m_shape_ref,paftl::ADD_HERE); - - int shapeindex = testPointInPoly(p,shape); - - // if there's a shapeindex, then add (note it is an add -- you may be passed a list again to expand) - if (shapeindex != -1) { - shapeindexlist.add(shapeindex); - } - } +std::vector ShapeMap::pointInPolyList(const Point2f &p) const { + std::vector shapeindexlist; + if (!m_region.contains(p)) { + return shapeindexlist; + } + std::vector testedshapes; + PixelRef pix = pixelate(p); + const std::vector &shapes = m_pixel_shapes(static_cast(pix.y), static_cast(pix.x)); + for (const ShapeRef &shape : shapes) { + auto iter = depthmapX::findBinary(testedshapes, shape.m_shape_ref); + if (iter != testedshapes.end()) { + continue; + } + testedshapes.insert(iter, int(shape.m_shape_ref)); + + int shapeindex = testPointInPoly(p, shape); + + // if there's a shapeindex, then add (note it is an add -- you may be passed a list again to expand) + if (shapeindex != -1) { + shapeindexlist.push_back(shapeindex); + } + } + std::sort(shapeindexlist.begin(), shapeindexlist.end()); + return shapeindexlist; } // note, lineref is only used as an "exclude self" test when called from getShapeConnections -void ShapeMap::lineInPolyList(const Line& li_orig, pvecint& shapeindexlist, int lineref, double tolerance) const -{ - if (!intersect_region(m_region,li_orig)) { - return; - } - Line li = li_orig; - if (!m_region.contains(li.start()) || !m_region.contains(li.end())) { - li.crop(m_region); - } - - pointInPolyList(li.start(),shapeindexlist); - pointInPolyList(li.end(),shapeindexlist); - - // only now pixelate and test for any other shapes: - PixelRefList list = pixelateLine(li); - for (size_t i = 0; i < list.size(); i++) { - PixelRef pix = list[i]; - if (includes(pix)) { - pqvector& shapes = m_pixel_shapes[pix.x][pix.y]; - for (size_t j = 0; j < shapes.size(); j++) { - const ShapeRef& shape = shapes[j]; - // slow to do this as it can repeat -- really need to use a linetest like structure to avoid retest of - // polygon lines - if (shape.m_shape_ref != lineref && shape.m_tags & (ShapeRef::SHAPE_EDGE | ShapeRef::SHAPE_INTERNAL_EDGE | ShapeRef::SHAPE_OPEN)) { - const SalaShape& poly = m_shapes.search(shape.m_shape_ref); - switch (poly.m_type & (SalaShape::SHAPE_LINE | SalaShape::SHAPE_POLY)) { - case SalaShape::SHAPE_LINE: - if (intersect_region(li,poly.m_region)) { - // note: in this case m_region is stored as a line: - if (intersect_line(li,poly.m_region,tolerance)) { - shapeindexlist.add(m_shapes.searchindex(shape.m_shape_ref)); - } - } - break; - case SalaShape::SHAPE_POLY: - { - for (int k = 0; k < shape.m_polyrefs.size(); k++) { - Line lineb = Line(poly[shape.m_polyrefs[k]],poly[((shape.m_polyrefs[k]+1)%poly.size())]); - if (intersect_region(li,lineb)) { - if (intersect_line(li,lineb,tolerance)) { - shapeindexlist.add(m_shapes.searchindex(shape.m_shape_ref)); - } +std::vector ShapeMap::lineInPolyList(const Line &li_orig, size_t lineref, double tolerance) const { + std::vector shapeindexlist; + if (!intersect_region(m_region, li_orig)) { + return shapeindexlist; + } + Line li = li_orig; + if (!m_region.contains(li.start()) || !m_region.contains(li.end())) { + li.crop(m_region); + } + + shapeindexlist = pointInPolyList(li.start()); + std::vector endShapeIndexList = pointInPolyList(li.end()); + shapeindexlist.insert(shapeindexlist.end(), endShapeIndexList.begin(), endShapeIndexList.end()); + + // only now pixelate and test for any other shapes: + PixelRefVector list = pixelateLine(li); + for (size_t i = 0; i < list.size(); i++) { + PixelRef pix = list[i]; + if (includes(pix)) { + const std::vector &shapes = + m_pixel_shapes(static_cast(pix.y), static_cast(pix.x)); + for (const ShapeRef &shape : shapes) { + // slow to do this as it can repeat -- really need to use a linetest like structure to avoid retest of + // polygon lines + if (shape.m_shape_ref != lineref && + shape.m_tags & (ShapeRef::SHAPE_EDGE | ShapeRef::SHAPE_INTERNAL_EDGE | ShapeRef::SHAPE_OPEN)) { + auto shapeIter = m_shapes.find(shape.m_shape_ref); + const SalaShape &poly = shapeIter->second; + switch (poly.m_type & (SalaShape::SHAPE_LINE | SalaShape::SHAPE_POLY)) { + case SalaShape::SHAPE_LINE: + if (intersect_region(li, poly.m_region)) { + // note: in this case m_region is stored as a line: + if (intersect_line(li, poly.m_region, tolerance)) { + shapeindexlist.push_back(int(std::distance(m_shapes.begin(), shapeIter))); + } } - } - } - break; - default: - break; - } - } - } - } - } -} - -void ShapeMap::polyInPolyList(int polyref, pvecint& shapeindexlist, double tolerance) const -{ - size_t index = m_shapes.searchindex(polyref); - if (index == paftl::npos) { - return; - } - const SalaShape& poly = m_shapes[index]; - if (poly.isClosed()) { // <- it ought to be, you shouldn't be using this function if not! - pvecint testedlist; - // easiest just to use scan lines to find internal pixels rather than trace a complex border: - PixelRef minpix = pixelate(poly.m_region.bottom_left); - PixelRef maxpix = pixelate(poly.m_region.top_right); - // pass one: shape centre of either object coincident automatically adds - int x; - for (x = minpix.x; x <= maxpix.x; x++) { - for (int y = minpix.y; y <= maxpix.y; y++) { - size_t pos = m_pixel_shapes[x][y].searchindex(polyref); - if (pos != paftl::npos) { - pqvector& shaperefs = m_pixel_shapes[x][y]; - // this has us in it, now looked through everything else: - for (size_t i = 0; i < shaperefs.size(); i++) { - ShapeRef& shaperef = shaperefs[i]; - if (i != pos && ((shaperefs[pos].m_tags & ShapeRef::SHAPE_CENTRE) || (shaperef.m_tags & ShapeRef::SHAPE_CENTRE))) { - if (testedlist.add(shaperef.m_shape_ref) != -1) { - shapeindexlist.add(m_shapes.searchindex(shaperef.m_shape_ref)); - } - } - } - } - } - } - // that was the easy bit... now, pass 2, for non centre things: - for (x = minpix.x; x <= maxpix.x; x++) { - for (int y = minpix.y; y <= maxpix.y; y++) { - size_t pos = m_pixel_shapes[x][y].searchindex(polyref); - if (pos != paftl::npos) { - pqvector& shaperefs = m_pixel_shapes[x][y]; - ShapeRef& shaperef = shaperefs[pos]; - if ((shaperef.m_tags & ShapeRef::SHAPE_CENTRE) == 0) { - // this has us in it, now looked through everything else: - for (size_t i = 0; i < shaperefs.size(); i++) { - ShapeRef& shaperefb = shaperefs[i]; - if (i != pos && testedlist.searchindex(shaperefb.m_shape_ref) == paftl::npos) { - size_t indexb = m_shapes.searchindex(shaperefb.m_shape_ref); - const SalaShape& polyb = m_shapes[indexb]; - if (polyb.isPoint()) { - if (testPointInPoly(polyb.getPoint(),shaperef) != -1) { - shapeindexlist.add((int)indexb); - } + break; + case SalaShape::SHAPE_POLY: { + for (size_t k = 0; k < shape.m_polyrefs.size(); k++) { + Line lineb = Line(poly.m_points[shape.m_polyrefs[k]], + poly.m_points[((shape.m_polyrefs[k] + 1) % poly.m_points.size())]); + if (intersect_region(li, lineb)) { + if (intersect_line(li, lineb, tolerance)) { + shapeindexlist.push_back(int(std::distance(m_shapes.begin(), shapeIter))); + } + } } - else if (polyb.isLine()) { - if (testPointInPoly(polyb.getLine().start(),shaperef) != -1 || testPointInPoly(polyb.getLine().end(),shaperef) != -1) { - testedlist.add(shaperefb.m_shape_ref,paftl::ADD_HERE); - shapeindexlist.add((int)indexb); - } - else { - for (int k = 0; k < shaperef.m_polyrefs.size(); k++) { - Line line = Line(poly[shaperef.m_polyrefs[k]],poly[((shaperef.m_polyrefs[k]+1)%poly.size())]); - if (intersect_region(line,polyb.getLine())) { - if (intersect_line(line,polyb.getLine(),tolerance)) { - testedlist.add(shaperefb.m_shape_ref,paftl::ADD_HERE); - shapeindexlist.add((int)indexb); - break; - } - } - } - } + } break; + default: + break; + } + } + } + } + } + std::sort(shapeindexlist.begin(), shapeindexlist.end()); + return shapeindexlist; +} + +std::vector ShapeMap::polyInPolyList(int polyref, double tolerance) const { + std::vector shapeindexlist; + auto shapeIter = m_shapes.find(polyref); + if (shapeIter == m_shapes.end()) { + return shapeindexlist; + } + const SalaShape &poly = shapeIter->second; + if (poly.isClosed()) { // <- it ought to be, you shouldn't be using this function if not! + std::vector testedlist; + // easiest just to use scan lines to find internal pixels rather than trace a complex border: + PixelRef minpix = pixelate(poly.m_region.bottom_left); + PixelRef maxpix = pixelate(poly.m_region.top_right); + // pass one: shape centre of either object coincident automatically adds + int x; + for (x = minpix.x; x <= maxpix.x; x++) { + for (int y = minpix.y; y <= maxpix.y; y++) { + const std::vector &pixShapes = + m_pixel_shapes(static_cast(y), static_cast(x)); + const auto iter = depthmapX::findBinary(pixShapes, ShapeRef(polyref)); + if (iter != pixShapes.end()) { + // this has us in it, now looked through everything else: + for (const ShapeRef &shapeRef : pixShapes) { + if (*iter != shapeRef && + ((iter->m_tags & ShapeRef::SHAPE_CENTRE) || (shapeRef.m_tags & ShapeRef::SHAPE_CENTRE))) { + auto iter = depthmapX::findBinary(testedlist, shapeRef.m_shape_ref); + if (iter == testedlist.end()) { + testedlist.insert(iter, shapeRef.m_shape_ref); + shapeindexlist.push_back( + int(depthmapX::findIndexFromKey(m_shapes, int(shapeRef.m_shape_ref)))); + } } - else if (polyb.isPolyLine()) { - if (testPointInPoly(polyb[shaperefb.m_polyrefs[0]],shaperef) != -1) { - testedlist.add(shaperefb.m_shape_ref,paftl::ADD_HERE); - shapeindexlist.add(indexb); - } - else { - for (int k = 0; k < shaperef.m_polyrefs.size(); k++) { - for (int kk = 0; kk < shaperefb.m_polyrefs.size(); kk++) { - Line line = Line(poly[shaperef.m_polyrefs[k]],poly[((shaperef.m_polyrefs[k]+1)%poly.size())]); - Line lineb = Line(polyb[shaperefb.m_polyrefs[kk]],polyb[((shaperefb.m_polyrefs[kk]+1)%polyb.size())]); - if (intersect_region(line,lineb)) { - if (intersect_line(line,lineb,tolerance)) { - if (testedlist.add(shaperefb.m_shape_ref) != -1) { - shapeindexlist.add(indexb); - break; - } - } + } + } + } + } + // that was the easy bit... now, pass 2, for non centre things: + for (x = minpix.x; x <= maxpix.x; x++) { + for (int y = minpix.y; y <= maxpix.y; y++) { + const std::vector &pixShapes = + m_pixel_shapes(static_cast(y), static_cast(x)); + const auto iter = depthmapX::findBinary(pixShapes, ShapeRef(polyref)); + if (iter != pixShapes.end()) { + const ShapeRef &shaperef = *iter; + if ((shaperef.m_tags & ShapeRef::SHAPE_CENTRE) == 0) { + // this has us in it, now looked through everything else: + for (auto &shaperefb : pixShapes) { + auto iter = depthmapX::findBinary(testedlist, shaperefb.m_shape_ref); + if (shaperef != shaperefb && iter == testedlist.end()) { + auto shapeIter = m_shapes.find(shaperefb.m_shape_ref); + size_t indexb = std::distance(m_shapes.begin(), shapeIter); + const SalaShape &polyb = shapeIter->second; + if (polyb.isPoint()) { + if (testPointInPoly(polyb.getPoint(), shaperef) != -1) { + shapeindexlist.push_back(int(indexb)); } - } - } - } - } - else { - // poly to poly, ick! - // first test one entirely inside the other - // any point at all will suffice to check this: however, we need to check that the polyref point *itself* is within the - // pixel, not just part of the line associated with it... - if ((pixelate(polyb[shaperefb.m_polyrefs[0]]) == PixelRef(x,y) && testPointInPoly(polyb[shaperefb.m_polyrefs[0]],shaperef) != -1) || - (pixelate(poly[shaperef.m_polyrefs[0]]) == PixelRef(x,y) && testPointInPoly(poly[shaperef.m_polyrefs[0]],shaperefb) != -1)) { - testedlist.add(shaperefb.m_shape_ref,paftl::ADD_HERE); - shapeindexlist.add(indexb); - } - else { - // now check crossing - bool breakit = false; - for (int k = 0; k < shaperef.m_polyrefs.size() && !breakit; k++) { - for (int kk = 0; kk < shaperefb.m_polyrefs.size(); kk++) { - Line line = Line(poly[shaperef.m_polyrefs[k]],poly[((shaperef.m_polyrefs[k]+1)%poly.size())]); - Line lineb = Line(polyb[shaperefb.m_polyrefs[kk]],polyb[((shaperefb.m_polyrefs[kk]+1)%polyb.size())]); - if (intersect_region(line,lineb)) { - if (intersect_line(line,lineb,tolerance)) { - testedlist.add(shaperefb.m_shape_ref,paftl::ADD_HERE); - shapeindexlist.add(indexb); - breakit = true; - break; - } + } else if (polyb.isLine()) { + if (testPointInPoly(polyb.getLine().start(), shaperef) != -1 || + testPointInPoly(polyb.getLine().end(), shaperef) != -1) { + testedlist.insert(iter, shaperefb.m_shape_ref); + shapeindexlist.push_back(int(indexb)); + } else { + for (size_t k = 0; k < shaperef.m_polyrefs.size(); k++) { + Line line = Line( + poly.m_points[shaperef.m_polyrefs[k]], + poly.m_points[((shaperef.m_polyrefs[k] + 1) % poly.m_points.size())]); + if (intersect_region(line, polyb.getLine())) { + if (intersect_line(line, polyb.getLine(), tolerance)) { + testedlist.insert(iter, shaperefb.m_shape_ref); + shapeindexlist.push_back(int(indexb)); + break; + } + } + } } - } - } - } + } else if (polyb.isPolyLine()) { + if (testPointInPoly(polyb.m_points[shaperefb.m_polyrefs[0]], shaperef) != -1) { + testedlist.insert(iter, shaperefb.m_shape_ref); + shapeindexlist.push_back(int(indexb)); + } else { + for (size_t k = 0; k < shaperef.m_polyrefs.size(); k++) { + for (size_t kk = 0; kk < shaperefb.m_polyrefs.size(); kk++) { + Line line = Line(poly.m_points[shaperef.m_polyrefs[k]], + poly.m_points[((shaperef.m_polyrefs[k] + 1) % + poly.m_points.size())]); + Line lineb = Line(polyb.m_points[shaperefb.m_polyrefs[kk]], + polyb.m_points[((shaperefb.m_polyrefs[kk] + 1) % + polyb.m_points.size())]); + if (intersect_region(line, lineb)) { + if (intersect_line(line, lineb, tolerance)) { + auto iterInternal = + depthmapX::findBinary(testedlist, shaperefb.m_shape_ref); + if (iterInternal == testedlist.end()) { + testedlist.insert(iterInternal, shaperefb.m_shape_ref); + shapeindexlist.push_back(int(indexb)); + break; + } + } + } + } + } + } + } else { + // poly to poly, ick! + // first test one entirely inside the other + // any point at all will suffice to check this: however, we need to check that the + // polyref point *itself* is within the pixel, not just part of the line associated + // with it... + if ((pixelate(polyb.m_points[shaperefb.m_polyrefs[0]]) == PixelRef(x, y) && + testPointInPoly(polyb.m_points[shaperefb.m_polyrefs[0]], shaperef) != -1) || + (pixelate(poly.m_points[shaperef.m_polyrefs[0]]) == PixelRef(x, y) && + testPointInPoly(poly.m_points[shaperef.m_polyrefs[0]], shaperefb) != -1)) { + testedlist.insert(iter, shaperefb.m_shape_ref); + shapeindexlist.push_back(int(indexb)); + } else { + // now check crossing + bool breakit = false; + for (size_t k = 0; k < shaperef.m_polyrefs.size() && !breakit; k++) { + for (size_t kk = 0; kk < shaperefb.m_polyrefs.size(); kk++) { + Line line = Line(poly.m_points[shaperef.m_polyrefs[k]], + poly.m_points[((shaperef.m_polyrefs[k] + 1) % + poly.m_points.size())]); + Line lineb = Line(polyb.m_points[shaperefb.m_polyrefs[kk]], + polyb.m_points[((shaperefb.m_polyrefs[kk] + 1) % + polyb.m_points.size())]); + if (intersect_region(line, lineb)) { + if (intersect_line(line, lineb, tolerance)) { + testedlist.insert(iter, shaperefb.m_shape_ref); + shapeindexlist.push_back(int(indexb)); + breakit = true; + break; + } + } + } + } + } + } + } } - } - } - } - } - } - } - - } - else { - throw pstring("this function is to be used for polygons only"); - } -} - -void ShapeMap::shapeInPolyList(const SalaShape& shape, pvecint& shapeindexlist) // note: no const due to poly in poly testing -{ - if (!intersect_region(m_region,shape.m_region)) { - // quick test that actually coincident - return; - } - if (shape.isPoint()) { - pointInPolyList(shape.getPoint(),shapeindexlist); - } - else if (shape.isLine()) { - lineInPolyList(shape.getLine(),shapeindexlist); - } - else if (shape.isPolyLine()) { - for (size_t i = 1; i < shape.size() - 1; i++) { - Line li(shape[i], shape[i-1]); - lineInPolyList(li,shapeindexlist); - } - } - else { - // first *add* the poly temporarily (note this may grow pixel set): - int ref = makePolyShape(shape, false, true); // false is closed poly, true is temporary shape - // do test: - polyInPolyList(ref, shapeindexlist); - // clean up: - removePolyPixels(ref); - size_t rowid = m_shapes.searchindex(ref); - m_shapes.remove_at(rowid); - m_shape_ref--; // also undo temporary shaperef, or it could get out of hand with lots of tests - } -} - -// helper for point in poly -- -// currently needs slight rewrite to avoid problem if point is in line with a vertex + } + } + } + } + + } else { + throw depthmapX::RuntimeException("this function is to be used for polygons only"); + } + std::sort(shapeindexlist.begin(), shapeindexlist.end()); + return shapeindexlist; +} + +std::vector ShapeMap::shapeInPolyList(const SalaShape &shape) // note: no const due to poly in poly testing +{ + std::vector shapeindexlist; + if (!intersect_region(m_region, shape.m_region)) { + // quick test that actually coincident + return shapeindexlist; + } + if (shape.isPoint()) { + shapeindexlist = pointInPolyList(shape.getPoint()); + } else if (shape.isLine()) { + shapeindexlist = lineInPolyList(shape.getLine()); + } else if (shape.isPolyLine()) { + for (size_t i = 1; i < shape.m_points.size() - 1; i++) { + Line li(shape.m_points[i], shape.m_points[i - 1]); + shapeindexlist = lineInPolyList(li); + } + } else { + // first *add* the poly temporarily (note this may grow pixel set): + int ref = makePolyShape(shape.m_points, false, true); // false is closed poly, true is temporary shape + // do test: + shapeindexlist = polyInPolyList(ref); + // clean up: + removePolyPixels(ref); + m_shapes.erase(m_shapes.find(ref)); + } + return shapeindexlist; +} + +// helper for point in poly -- +// currently needs slight rewrite to avoid problem if point is in line with a vertex // (counter incremented twice on touching implies not in poly when is) -int ShapeMap::testPointInPoly(const Point2f& p, const ShapeRef& shape) const -{ - size_t shapeindex = paftl::npos; - // simplist: in shape centre - if (shape.m_tags & ShapeRef::SHAPE_CENTRE) { - shapeindex = m_shapes.searchindex(shape.m_shape_ref); - } - // check not an open shape (cannot be inside) - else if ((shape.m_tags & ShapeRef::SHAPE_OPEN) == 0) { - const SalaShape& poly = m_shapes.search(shape.m_shape_ref); - if (poly.m_region.contains_touch(p)) { - // next simplest, on the outside border: - int alpha = 0; - int counter = 0; - int parity = 0; - if (shape.m_tags & ShapeRef::SHAPE_EDGE) { - // run a test line to the edge: - if (shape.m_tags & (ShapeRef::SHAPE_L | ShapeRef::SHAPE_R)) { - if (shape.m_tags & ShapeRef::SHAPE_L) { - parity = -1; - } - else if (shape.m_tags & ShapeRef::SHAPE_R) { - parity = +1; - } - for (int j = 0; j < shape.m_polyrefs.size(); j++) { - Line lineb = Line(poly[shape.m_polyrefs[j]],poly[((shape.m_polyrefs[j]+1)%poly.size())]); - if (lineb.bottom_left.y <= p.y && lineb.top_right.y >= p.y) { - // crosses or touches... but we need to check - // touching exception: - if (lineb.t_start().y == p.y) { - if (parity * lineb.t_start().x >= parity * p.x) { - alpha -= 1; - counter++; +int ShapeMap::testPointInPoly(const Point2f &p, const ShapeRef &shape) const { + auto shapeIter = m_shapes.end(); + // simplist: in shape centre + if (shape.m_tags & ShapeRef::SHAPE_CENTRE) { + shapeIter = m_shapes.find(shape.m_shape_ref); + } + // check not an open shape (cannot be inside) + else if ((shape.m_tags & ShapeRef::SHAPE_OPEN) == 0) { + shapeIter = m_shapes.find(shape.m_shape_ref); + const SalaShape &poly = shapeIter->second; + if (poly.m_region.contains_touch(p)) { + // next simplest, on the outside border: + int alpha = 0; + int counter = 0; + int parity = 0; + if (shape.m_tags & ShapeRef::SHAPE_EDGE) { + // run a test line to the edge: + if (shape.m_tags & (ShapeRef::SHAPE_L | ShapeRef::SHAPE_R)) { + if (shape.m_tags & ShapeRef::SHAPE_L) { + parity = -1; + } else if (shape.m_tags & ShapeRef::SHAPE_R) { + parity = +1; + } + for (size_t j = 0; j < shape.m_polyrefs.size(); j++) { + Line lineb = Line(poly.m_points[shape.m_polyrefs[j]], + poly.m_points[((shape.m_polyrefs[j] + 1) % poly.m_points.size())]); + if (lineb.bottom_left.y <= p.y && lineb.top_right.y >= p.y) { + // crosses or touches... but we need to check + // touching exception: + if (lineb.t_start().y == p.y) { + if (parity * lineb.t_start().x >= parity * p.x) { + alpha -= 1; + counter++; + } + } + // the other touching exception + else if (lineb.t_end().y == p.y) { + if (parity * lineb.t_end().x >= parity * p.x) { + alpha += 1; + // n.b., no counter here + } + } + // at this stage we know the line isn't horizontal, so we can find the intersection point: + else if (parity * (lineb.grad(XAXIS) * (p.y - lineb.ay()) + lineb.ax()) >= parity * p.x) { + counter++; + } } - } - // the other touching exception - else if (lineb.t_end().y == p.y) { - if (parity * lineb.t_end().x >= parity * p.x) { - alpha += 1; - // n.b., no counter here + } + } else { + if (shape.m_tags & ShapeRef::SHAPE_B) { + parity = -1; + } else if (shape.m_tags & ShapeRef::SHAPE_T) { + parity = +1; + } + for (size_t j = 0; j < shape.m_polyrefs.size(); j++) { + Line lineb = Line(poly.m_points[shape.m_polyrefs[j]], + poly.m_points[((shape.m_polyrefs[j] + 1) % poly.m_points.size())]); + if (lineb.bottom_left.x <= p.x && lineb.top_right.x >= p.x) { + // crosses or touches... but we need to check + // touching exception: + if (lineb.top_right.x == p.x) { + if (parity * lineb.by() >= parity * p.y) { + alpha -= 1; + counter++; + } + } + // the other touching exception + else if (lineb.bottom_left.x == p.x) { + if (parity * lineb.ay() >= parity * p.y) { + alpha += 1; + // n.b., no counter here + } + } + // at this stage we know the line isn't vertical, so we can find the intersection point: + else if (parity * (lineb.grad(YAXIS) * (p.x - lineb.ax()) + lineb.ay()) >= parity * p.y) { + counter++; + } } - } - // at this stage we know the line isn't horizontal, so we can find the intersection point: - else if (parity * (lineb.grad(XAXIS)*(p.y-lineb.ay()) + lineb.ax()) >= parity * p.x) { - counter++; - } - } - } - } - else { - if (shape.m_tags & ShapeRef::SHAPE_B) { - parity = -1; - } - else if (shape.m_tags & ShapeRef::SHAPE_T) { - parity = +1; - } - for (int j = 0; j < shape.m_polyrefs.size(); j++) { - Line lineb = Line(poly[shape.m_polyrefs[j]],poly[((shape.m_polyrefs[j]+1)%poly.size())]); - if (lineb.bottom_left.x <= p.x && lineb.top_right.x >= p.x) { - // crosses or touches... but we need to check - // touching exception: - if (lineb.top_right.x == p.x) { - if (parity * lineb.by() >= parity * p.y) { - alpha -= 1; - counter++; + } + } + if (counter % 2 != 0 && alpha == 0) { + shapeIter = m_shapes.find(shape.m_shape_ref); + } + } + // and now the pig -- it's somewhere in the middle of the poly: + else if (shape.m_tags & ShapeRef::SHAPE_INTERNAL_EDGE) { + std::vector testnodes; + size_t j; + for (j = 0; j < size_t(shape.m_polyrefs.size()); j++) { + depthmapX::addIfNotExists(testnodes, int(shape.m_polyrefs[j])); + } + PixelRef pix2 = pixelate(p); + const std::vector &pixelShapes = + m_pixel_shapes(static_cast(pix2.y), static_cast(pix2.x)); + // bit of code duplication like this, but easier on params to this function: + pix2.move(PixelRef::NEGVERTICAL); // move pix2 down, search for this shape... + auto iter = std::find(pixelShapes.begin(), pixelShapes.end(), shape.m_shape_ref); + while (iter != pixelShapes.end()) { + for (size_t k = 0; k < iter->m_polyrefs.size(); k++) { + depthmapX::addIfNotExists(testnodes, int(iter->m_polyrefs[k])); + } + pix2.move(PixelRef::NEGVERTICAL); // move pix2 down, search for this shape... + if (includes(pix2)) { + iter = std::find(pixelShapes.begin(), pixelShapes.end(), shape.m_shape_ref); + } else { + iter = pixelShapes.end(); + } + } + int alpha = 0; + int counter = 0; + int parity = -1; + for (j = 0; j < testnodes.size(); j++) { + Line lineb = + Line(poly.m_points[testnodes[j]], poly.m_points[((testnodes[j] + 1) % poly.m_points.size())]); + if (lineb.bottom_left.x <= p.x && lineb.top_right.x >= p.x) { + // crosses or touches... but we need to check + // touching exception: + if (lineb.top_right.x == p.x) { + if (parity * lineb.by() >= parity * p.y) { + alpha -= 1; + counter++; + } } - } - // the other touching exception - else if (lineb.bottom_left.x == p.x) { - if (parity * lineb.ay() >= parity * p.y) { - alpha += 1; - // n.b., no counter here + // the other touching exception + else if (lineb.bottom_left.x == p.x) { + if (parity * lineb.ay() >= parity * p.y) { + alpha += 1; + // n.b., no counter here + } } - } - // at this stage we know the line isn't vertical, so we can find the intersection point: - else if (parity * (lineb.grad(YAXIS)*(p.x-lineb.ax()) + lineb.ay()) >= parity * p.y) { - counter++; - } - } - } - } - if (counter % 2 != 0 && alpha == 0) { - shapeindex = m_shapes.searchindex(shape.m_shape_ref); - } - } - // and now the pig -- it's somewhere in the middle of the poly: - else if (shape.m_tags & ShapeRef::SHAPE_INTERNAL_EDGE) { - pvecint testnodes; - size_t j; - for (j = 0; j < size_t(shape.m_polyrefs.size()); j++) { // <- note, polyrefs is a subvec and has maximum number according to sizeof(T) - testnodes.add(shape.m_polyrefs[j]); - } - PixelRef pix2 = pixelate(p); - // bit of code duplication like this, but easier on params to this function: - pix2.move(PixelRef::NEGVERTICAL); // move pix2 down, search for this shape... - size_t nextindex = m_pixel_shapes[pix2.x][pix2.y].searchindex(shape.m_shape_ref); - while (nextindex != paftl::npos) { - const ShapeRef& shape2 = m_pixel_shapes[pix2.x][pix2.y][nextindex]; - for (int k = 0; k < shape2.m_polyrefs.size(); k++) { - testnodes.add(shape2.m_polyrefs[k]); - } - pix2.move(PixelRef::NEGVERTICAL); // move pix2 down, search for this shape... - if (includes(pix2)) { - nextindex = m_pixel_shapes[pix2.x][pix2.y].searchindex(shape.m_shape_ref); - } - else { - nextindex = paftl::npos; - } - } - int alpha = 0; - int counter = 0; - int parity = -1; - for (j = 0; j < testnodes.size(); j++) { - Line lineb = Line(poly[testnodes[j]],poly[((testnodes[j]+1)%poly.size())]); - if (lineb.bottom_left.x <= p.x && lineb.top_right.x >= p.x) { - // crosses or touches... but we need to check - // touching exception: - if (lineb.top_right.x == p.x) { - if (parity * lineb.by() >= parity * p.y) { - alpha -= 1; - counter++; - } - } - // the other touching exception - else if (lineb.bottom_left.x == p.x) { - if (parity * lineb.ay() >= parity * p.y) { - alpha += 1; - // n.b., no counter here - } - } - // at this stage we know the line isn't vertical, so we can find the intersection point: - else if (parity * (lineb.grad(YAXIS)*(p.x-lineb.ax()) + lineb.ay()) >= parity * p.y) { - counter++; - } - } - } - if (counter % 2 != 0 && alpha == 0) { - shapeindex = m_shapes.searchindex(shape.m_shape_ref); + // at this stage we know the line isn't vertical, so we can find the intersection point: + else if (parity * (lineb.grad(YAXIS) * (p.x - lineb.ax()) + lineb.ay()) >= parity * p.y) { + counter++; + } + } + } + if (counter % 2 != 0 && alpha == 0) { + shapeIter = m_shapes.find(shape.m_shape_ref); + } } - } - } - } - return (shapeindex == paftl::npos) ? -1 : int(shapeindex); // note convert to -1 + } + } + return (shapeIter == m_shapes.end()) ? -1 : std::distance(m_shapes.begin(), shapeIter); // note convert to -1 } // also note that you may want to find a close poly line or point @@ -1976,1600 +1864,1348 @@ int ShapeMap::testPointInPoly(const Point2f& p, const ShapeRef& shape) const // returns a rowid *not* a shape key -int ShapeMap::getClosestOpenGeom(const Point2f& p) const -{ - if (!m_region.contains(p)) { - return -1; - } - - PixelRef pix = pixelate(p); - - size_t index = paftl::npos; - double mindist = -1; - for (size_t i = 0; i < m_pixel_shapes[pix.x][pix.y].size(); i++) { - ShapeRef& ref = m_pixel_shapes[pix.x][pix.y][i]; - if (ref.m_tags & ShapeRef::SHAPE_OPEN) { - double thisdist = -1.0; - const SalaShape& poly = m_shapes.search(ref.m_shape_ref); - switch (poly.m_type) { - case SalaShape::SHAPE_POINT: - thisdist = dist(p,poly.m_centroid); - case SalaShape::SHAPE_LINE: - thisdist = dist(p,poly.m_region); // note, in this case m_region is a line +int ShapeMap::getClosestOpenGeom(const Point2f &p) const { + if (!m_region.contains(p)) { + return -1; + } + + PixelRef pix = pixelate(p); + + auto shapeIter = m_shapes.end(); + double mindist = -1; + const std::vector &shapeRefs = m_pixel_shapes(static_cast(pix.y), static_cast(pix.x)); + for (const ShapeRef &ref : shapeRefs) { + if (ref.m_tags & ShapeRef::SHAPE_OPEN) { + double thisdist = -1.0; + auto tempShapeIter = m_shapes.find(ref.m_shape_ref); + const SalaShape &poly = tempShapeIter->second; + switch (poly.m_type) { + case SalaShape::SHAPE_POINT: + thisdist = dist(p, poly.m_centroid); + case SalaShape::SHAPE_LINE: + thisdist = dist(p, poly.m_region); // note, in this case m_region is a line + break; + case SalaShape::SHAPE_POLY: + case SalaShape::SHAPE_POLY | SalaShape::SHAPE_CCW: // note CCW should never have happened, but it has + for (size_t j = 0; j < ref.m_polyrefs.size(); j++) { + Line line(poly.m_points[ref.m_polyrefs[j]], poly.m_points[ref.m_polyrefs[j] + 1]); + double tempthisdist = dist(p, line); + if (tempthisdist != -1 && (thisdist == -1 || tempthisdist < thisdist)) { + thisdist = tempthisdist; + } + } + break; + } + if (thisdist != -1.0 && (mindist == -1 || thisdist < mindist)) { + mindist = thisdist; + shapeIter = tempShapeIter; + } + } + } + + return (shapeIter == m_shapes.end()) ? -1 : std::distance(m_shapes.begin(), shapeIter); // note conversion to -1 +} + +Point2f ShapeMap::getClosestVertex(const Point2f &p) const { + Point2f vertex; // null by default + + if (!m_region.contains(p)) { + return vertex; // will be null in this case + } + + PixelRef pix = pixelate(p); + + double mindist = -1.0; + const std::vector &shapeRefs = m_pixel_shapes(static_cast(pix.y), static_cast(pix.x)); + for (const ShapeRef &ref : shapeRefs) { + double thisdist = -1.0; + Point2f thisvertex; + const SalaShape &poly = m_shapes.find(ref.m_shape_ref)->second; + switch (poly.m_type) { + case SalaShape::SHAPE_POINT: + thisvertex = poly.m_centroid; + thisdist = dist(p, thisvertex); break; - case SalaShape::SHAPE_POLY: case SalaShape::SHAPE_POLY | SalaShape::SHAPE_CCW: // note CCW should never have happened, but it has - for (int j = 0; j < ref.m_polyrefs.size(); j++) { - Line line(poly[ref.m_polyrefs[j]],poly[ref.m_polyrefs[j]+1]); - double tempthisdist = dist(p,line); - if (tempthisdist != -1 && (thisdist == -1 || tempthisdist < thisdist)) { - thisdist = tempthisdist; - } + case SalaShape::SHAPE_LINE: { + double d1 = dist(p, poly.m_region.start()); + double d2 = dist(p, poly.m_region.end()); + if (d1 < d2) { + thisvertex = poly.m_region.start(); + thisdist = d1; + } else { + thisvertex = poly.m_region.end(); + thisdist = d2; + } + } break; + default: // either a poly line or a polygon + for (size_t j = 0; j < ref.m_polyrefs.size(); j++) { + double d1 = dist(p, poly.m_points[ref.m_polyrefs[j]]); + // note this can be used for both open / closed with the % poly.size() + double d2 = dist(p, poly.m_points[(ref.m_polyrefs[j] + 1) % poly.m_points.size()]); + if (thisdist == -1 || d1 < thisdist) { + thisvertex = poly.m_points[ref.m_polyrefs[j]]; + thisdist = d1; + } + if (d2 < thisdist) { + thisvertex = poly.m_points[(ref.m_polyrefs[j] + 1) % poly.m_points.size()]; + thisdist = d2; + } } break; - } - if (thisdist != -1.0 && (mindist == -1 || thisdist < mindist)) { + } + if (thisdist != -1.0 && (mindist == -1.0 || thisdist < mindist)) { mindist = thisdist; - index = m_shapes.searchindex(ref.m_shape_ref); - } - } - } + vertex = thisvertex; + } + } - return (index == paftl::npos) ? -1 : int(index); // note conversion to -1 -} - -Point2f ShapeMap::getClosestVertex(const Point2f& p) const -{ - Point2f vertex; // null by default - - if (!m_region.contains(p)) { - return vertex; // will be null in this case - } - - PixelRef pix = pixelate(p); - - double mindist = -1.0; - for (size_t i = 0; i < m_pixel_shapes[pix.x][pix.y].size(); i++) { - ShapeRef& ref = m_pixel_shapes[pix.x][pix.y][i]; - double thisdist = -1.0; - Point2f thisvertex; - const SalaShape& poly = m_shapes.search(ref.m_shape_ref); - switch (poly.m_type) { - case SalaShape::SHAPE_POINT: - thisvertex = poly.m_centroid; - thisdist = dist(p,thisvertex); - break; - case SalaShape::SHAPE_LINE: - { - double d1 = dist(p,poly.m_region.start()); - double d2 = dist(p,poly.m_region.end()); - if (d1 < d2) { - thisvertex = poly.m_region.start(); - thisdist = d1; - } - else { - thisvertex = poly.m_region.end(); - thisdist = d2; - } - } - break; - default: // either a poly line or a polygon - for (int j = 0; j < ref.m_polyrefs.size(); j++) { - double d1 = dist(p,poly[ref.m_polyrefs[j]]); - // note this can be used for both open / closed with the % poly.size() - double d2 = dist(p,poly[(ref.m_polyrefs[j]+1)%poly.size()]); - if (thisdist == -1 || d1 < thisdist) { - thisvertex = poly[ref.m_polyrefs[j]]; - thisdist = d1; - } - if (d2 < thisdist) { - thisvertex = poly[(ref.m_polyrefs[j]+1)%poly.size()]; - thisdist = d2; - } - } - break; - } - if (thisdist != -1.0 && (mindist == -1.0 || thisdist < mindist)) { - mindist = thisdist; - vertex = thisvertex; - } - } - - return vertex; + return vertex; } // nb, uses full BSP tree test: #include "isovist.h" -int ShapeMap::getClosestLine(const Point2f& p) const -{ - // not the best place to check this, but we must all the same: - if (m_newshape) { - m_bsp_tree = false; - } +int ShapeMap::getClosestLine(const Point2f &p) const { + // not the best place to check this, but we must all the same: + if (m_newshape) { + m_bsp_tree = false; + } - if (!m_bsp_tree) { - makeBSPtree(); - } + if (!m_bsp_tree) { + makeBSPtree(); + } - int index = -1; + int index = -1; - if (m_bsp_tree) { // <- check there is actually something in the tree! - Isovist iso; - index = iso.getClosestLine(m_bsp_root, p); - } + if (m_bsp_tree) { // <- check there is actually something in the tree! + Isovist iso; + index = iso.getClosestLine(m_bsp_root, p); + } - return index; + return index; } -void ShapeMap::getShapeCuts(const Line& li_orig, pvector& cuts) -{ - if (!intersect_region(li_orig,m_region)) { - return; - } - Line li = li_orig; - if (!m_region.contains(li.start()) || !m_region.contains(li.end())) { - li.crop(m_region); - } - int axis = YAXIS; - if (li.width() > li.height()) { - axis = XAXIS; - } - PixelRefList pixels = pixelateLine(li); - pvector tested; - for (size_t i = 0; i < pixels.size(); i++) { - PixelRef& pix = pixels[i]; - if (includes(pix)) { // <- note, for some reason, this pixel may be off edge (line crop problem?) - for (size_t j = 0; j < m_pixel_shapes[pix.x][pix.y].size(); j++) { - ShapeRef& shaperef = m_pixel_shapes[pix.x][pix.y][j]; - if (!shaperef.m_polyrefs.isEmpty()) { - int len = shaperef.m_polyrefs.size(); - for (int k = 0; k < len; k++) { - int x = shaperef.m_polyrefs[k]; - if (tested.searchindex(IntPair(shaperef.m_shape_ref,x)) == paftl::npos) { - SalaShape& poly = m_shapes.search(shaperef.m_shape_ref); - - // Quick mod - TV -#if defined(_WIN32) - Line& li2 = Line(poly[x],poly[(x+1)%poly.size()]); -#else - Line li2(poly[x], poly[(x+1) % poly.size()]); -#endif - if (intersect_region(li,li2)) { - // note: in this case m_region is stored as a line: - if (intersect_line(li,li2)) { - // find intersection point and add: - cuts.add(ValuePair(shaperef.m_shape_ref,li.intersection_point(li2,axis,1e-9)),paftl::ADD_DUPLICATE); // note: added key not rowid - } - } - tested.add(IntPair(shaperef.m_shape_ref,x),paftl::ADD_HERE); - } - } - } - else { - // this is a non-poly, so check just the shape_ref: - if (tested.searchindex(IntPair(shaperef.m_shape_ref,-1)) == paftl::npos) { - SalaShape& poly = m_shapes.search(shaperef.m_shape_ref); - // n.b. points cannot be intersected (and since we won't return to the pix, don't need to be added to the tested list - if (poly.isLine()) { - if (intersect_region(li,poly.m_region)) { - // note: in this case m_region is stored as a line: - if (intersect_line(li,poly.m_region)) { - // find intersection point and add: - cuts.add(ValuePair(shaperef.m_shape_ref,li.intersection_point(poly.m_region,axis,1e-9)),paftl::ADD_DUPLICATE); // note: added key not rowid - } - } - tested.add(IntPair(shaperef.m_shape_ref,-1),paftl::ADD_HERE); - } - } - } - } - } - } -} - -void ShapeMap::cutLine(Line& li) //, short dir) -{ - pvector cuts; - getShapeCuts(li,cuts); -/* - bool same = false; - if (dir == li.direction()) { - same = true; - } - - if (cuts.size()) { - if (li.width() > li.height()) { - // these are xaxis cuts - if (li.rightward() == same) { - // in the correct order: - li = Line(li.point_on_line(cuts.head().value,XAXIS),li.end()); - } - else { - // in reverse order: - li = Line(li.start(),li.point_on_line(cuts.tail().value,XAXIS)); - } - } - else { - if (li.upward()) { - li = Line(li.point_on_line(cuts.head().value,YAXIS),li.end()); - } - else { - // in reverse order: - li = Line(li.start(),li.point_on_line(cuts.tail().value,YAXIS)); - } - } - } - */ - - if (cuts.size()) { - if (li.width() > li.height()) { - if (li.rightward()) { - li = Line(li.start(),li.point_on_line(cuts.head().value,XAXIS)); - } - else { - li = Line(li.point_on_line(cuts.tail().value,XAXIS),li.end()); - } - } - else { - if (li.upward()) { - li = Line(li.t_start(),li.point_on_line(cuts.head().value,YAXIS)); - } - else { - li = Line(li.t_start(),li.point_on_line(cuts.tail().value,YAXIS)); - } - } - } - -} - -///////////////////////////////////////////////////////////////////////////////// - -// buffering type function, just for points for the time being - -int ShapeMap::withinRadius(const Point2f& pt, double radius, pvecint& bufferset) -{ - // first, get all the pixels within the radius (using square as simpler) - PixelRef bl = pixelate( Point2f(pt.x - radius, pt.y - radius) ); - PixelRef tr = pixelate( Point2f(pt.x + radius, pt.y + radius) ); - // go through testing line distances to each shape: - pvector tested; - for (int i = bl.x; i <= tr.x; i++) { - for (int j = bl.y; j <= tr.y; j++) { - for (size_t k = 0; k < m_pixel_shapes[i][j].size(); k++) { - ShapeRef& shaperef = m_pixel_shapes[i][j][k]; - int len = shaperef.m_polyrefs.size(); - if (len == 0) { - // this is a non-poly, so check just the shape_ref: - if (tested.searchindex(IntPair(shaperef.m_shape_ref,-1)) == paftl::npos) { - size_t shapeindex = m_shapes.searchindex(shaperef.m_shape_ref); - SalaShape& poly = m_shapes[shapeindex]; - if (poly.isPoint() && dist(pt,poly.getPoint()) < radius) { - bufferset.add(int(shapeindex)); - } - else if (dist(pt,poly.getLine()) < radius) { // if poly is line - bufferset.add(int(shapeindex)); - } - tested.add(IntPair(shaperef.m_shape_ref,-1),paftl::ADD_HERE); - } - } - else { - for (int p = 0; p < len; p++) { - int q = shaperef.m_polyrefs[p]; - if (tested.searchindex(IntPair(shaperef.m_shape_ref,q)) == paftl::npos) { - size_t shapeindex = m_shapes.searchindex(shaperef.m_shape_ref); - SalaShape& poly = m_shapes[shapeindex]; - Line li( poly[q], poly[(q+1)%poly.size()] ); - if (dist(pt,li) < radius) { - bufferset.add(int(shapeindex)); - } - tested.add(IntPair(shaperef.m_shape_ref,q),paftl::ADD_HERE); - } - } - } - } - } - } - // finally, do a quick point in poly test for any polygons in the centre pixel - // only need to check the shape ref as everything else will have been picked up above - PixelRef centre = pixelate(pt); - for (size_t k = 0; k < m_pixel_shapes[centre.x][centre.y].size(); k++) { - ShapeRef& shaperef = m_pixel_shapes[centre.x][centre.y][k]; - if (shaperef.m_tags & ShapeRef::SHAPE_CENTRE) { - bufferset.add( m_shapes.searchindex(shaperef.m_shape_ref) ); - } - } - return bufferset.size(); -} - -///////////////////////////////////////////////////////////////////////////////// - // code to add intersections when shapes are added to the graph one by one: -int ShapeMap::connectIntersected(int rowid, bool linegraph) -{ - int shaperef = m_shapes.key(rowid); - int conn_col = m_attributes.getOrInsertColumnIndex("Connectivity"); - m_attributes.setColumnLock(conn_col); - int leng_col = -1; - if (linegraph) { - // historically line length has always been added at this point - leng_col = m_attributes.getOrInsertLockedColumnIndex("Line Length"); - } - // all indices should match... this grows connectors if necessary to same length as shapes - while (m_connectors.size() < m_shapes.size()) { - m_connectors.push_back( Connector() ); - } - int connectivity = linegraph ? - getLineConnections( shaperef, m_connectors[rowid].m_connections, TOLERANCE_B*__max(m_region.height(),m_region.width())) : - getShapeConnections( shaperef, m_connectors[rowid].m_connections, TOLERANCE_B*__max(m_region.height(),m_region.width())); - m_attributes.setValue(rowid, conn_col, (float) connectivity ); - if (linegraph) { - m_attributes.setValue(rowid, leng_col, (float) m_shapes[rowid].getLength() ); - } - // now go through our connections, and add ourself: - for (size_t k = 0; k < m_connectors[rowid].m_connections.size(); k++) { - int myplace = m_connectors[rowid].m_connections[k]; - if (myplace != rowid) { // <- exclude self! - m_connectors[myplace].m_connections.add(rowid); - m_attributes.incrValue(myplace,conn_col); - } - } - return connectivity; +int ShapeMap::connectIntersected(int rowid, bool linegraph) { + auto shaperefIter = depthmapX::getMapAtIndex(m_shapes, rowid); + int conn_col = m_attributes->getOrInsertLockedColumn("Connectivity"); + int leng_col = -1; + if (linegraph) { + // historically line length has always been added at this point + leng_col = m_attributes->getOrInsertLockedColumn("Line Length"); + } + // all indices should match... this grows connectors if necessary to same length as shapes + while (m_connectors.size() < m_shapes.size()) { + m_connectors.push_back(Connector()); + } + m_connectors[size_t(rowid)].m_connections = + linegraph ? getLineConnections(shaperefIter->first, TOLERANCE_B * __max(m_region.height(), m_region.width())) + : getShapeConnections(shaperefIter->first, TOLERANCE_B * __max(m_region.height(), m_region.width())); + + auto &row = getAttributeRowFromShapeIndex(rowid); + row.setValue(conn_col, float(m_connectors[size_t(rowid)].m_connections.size())); + if (linegraph) { + row.setValue(leng_col, (float)shaperefIter->second.getLength()); + } + // now go through our connections, and add ourself: + const std::vector &connections = m_connectors[size_t(rowid)].m_connections; + for (int connection : connections) { + if (connection != rowid) { // <- exclude self! + depthmapX::insert_sorted(m_connectors[size_t(connection)].m_connections, rowid); + auto &connectionRow = getAttributeRowFromShapeIndex(connection); + connectionRow.incrValue(conn_col); + } + } + return m_connectors[size_t(rowid)].m_connections.size(); } // this assumes this is a line map (to speed up axial map creation) // use the other version, getShapeConnections for arbitrary shape-shape connections // note, connections are listed by rowid in list, *not* reference number // (so they may vary: must be checked carefully when shapes are removed / added) -int ShapeMap::getLineConnections(int lineref, pvecint& connections, double tolerance) -{ - SalaShape& poly = m_shapes.search(lineref); - if (!poly.isLine()) { - return 0; - } - const Line& l = poly.getLine(); - - pvecint testedshapes; - - // As of version 10, self-connections are *not* added - // In the past: - // it's useful to have yourself in your connections list - // (apparently! -- this needs checking, as most of the time it is then checked to exclude self again!) - // connections.add(m_shapes.searchindex(lineref)); - - testedshapes.add(lineref); - - int num_intersections = 0; - - PixelRefList list = pixelateLine( l ); - - for (size_t i = 0; i < list.size(); i++) { - pqvector& shapes = m_pixel_shapes[ list[i].x ][ list[i].y ]; - for (size_t j = 0; j < shapes.size(); j++) { - ShapeRef& shape = shapes[j]; - if (testedshapes.searchindex(shape.m_shape_ref) != paftl::npos) { - continue; - } - testedshapes.add(shape.m_shape_ref,paftl::ADD_HERE); - if ((shape.m_tags & ShapeRef::SHAPE_OPEN) == ShapeRef::SHAPE_OPEN) { - try { - const Line& line = m_shapes.search(shape.m_shape_ref).getLine(); - if ( intersect_region(line, l, line.length() * tolerance) ) { - // n.b. originally this followed the logic that we must normalise intersect_line properly: tolerance * line length one * line length two - // in fact, works better if it's just line.length() * tolerance... - if ( intersect_line(line, l, line.length() * tolerance) ) { - connections.add(m_shapes.searchindex(shape.m_shape_ref)); - num_intersections++; - } - } - } - catch (pexception) { - // the lineref may have been deleted -- this is supposed to be tidied up - // just ignore... - } - } - } - } - - return num_intersections; +std::vector ShapeMap::getLineConnections(int lineref, double tolerance) { + std::vector connections; + + SalaShape &poly = m_shapes.find(lineref)->second; + if (!poly.isLine()) { + return std::vector(); + } + const Line &l = poly.getLine(); + + std::unordered_set shapesToTest; + + // As of version 10, self-connections are *not* added + // In the past: + // it's useful to have yourself in your connections list + // (apparently! -- this needs checking, as most of the time it is then checked to exclude self again!) + // connections.add(m_shapes.searchindex(lineref)); + + shapesToTest.insert(lineref); + + PixelRefVector list = pixelateLine(l); + + for (size_t i = 0; i < list.size(); i++) { + const std::vector &shapeRefs = + m_pixel_shapes(static_cast(list[i].y), static_cast(list[i].x)); + for (const ShapeRef &shape : shapeRefs) { + shapesToTest.insert(shape); + } + } + for (ShapeRef shape : shapesToTest) { + if ((shape.m_tags & ShapeRef::SHAPE_OPEN) == ShapeRef::SHAPE_OPEN) { + const Line &line = m_shapes.find(int(shape.m_shape_ref))->second.getLine(); + if (intersect_region(line, l, line.length() * tolerance)) { + // n.b. originally this followed the logic that we must normalise intersect_line properly: tolerance * + // line length one * line length two in fact, works better if it's just line.length() * tolerance... + if (intersect_line(line, l, line.length() * tolerance)) { + depthmapX::insert_sorted(connections, + depthmapX::findIndexFromKey(m_shapes, int(shape.m_shape_ref))); + } + } + } + } + + return connections; } // this is only problematic as there is lots of legacy code with shape-in-shape testing, -int ShapeMap::getShapeConnections(int shaperef, pvecint& connections, double tolerance) -{ - // In versions prior to 10, note that unlike getLineConnections, self-connection is excluded by all of the following functions - // As of version 10, both getShapeConnections and getLineConnections exclude self-connection - - size_t index = m_shapes.searchindex(shaperef); - if (index != paftl::npos) { - SalaShape& shape = m_shapes[index]; - if (shape.isPoint()) { - // a point is simple, it never intersects itself: - pointInPolyList(shape.getPoint(),connections); - } - else if (shape.isPolygon()) { - // a closed poly is actually quite simple too as we already have code using a polyref: - polyInPolyList(shaperef,connections,tolerance); - } - else if (shape.isLine()) { - // line is a bit slow because there's no tested shape as in getLineConnections, but similar: - lineInPolyList(shape.getLine(),connections,shaperef,tolerance); - } - else if (shape.isPolyLine()) { - // this is the worst for efficiency: potential for many possible retries of the same shape: - for (size_t i = 1; i < shape.size() - 1; i++) { - Line li(shape[i-1], shape[i]); - lineInPolyList(li,connections,shaperef,tolerance); - } - } - } - - return connections.size(); +std::vector ShapeMap::getShapeConnections(int shaperef, double tolerance) { + // In versions prior to 10, note that unlike getLineConnections, self-connection is excluded by all of the + // following functions As of version 10, both getShapeConnections and getLineConnections exclude self-connection + + std::vector connections; + + auto shapeIter = m_shapes.find(shaperef); + if (shapeIter != m_shapes.end()) { + SalaShape &shape = shapeIter->second; + if (shape.isPoint()) { + // a point is simple, it never intersects itself: + connections = pointInPolyList(shape.getPoint()); + } else if (shape.isPolygon()) { + // a closed poly is actually quite simple too as we already have code using a polyref: + connections = polyInPolyList(shaperef, tolerance); + } else if (shape.isLine()) { + // line is a bit slow because there's no tested shape as in getLineConnections, but similar: + connections = lineInPolyList(shape.getLine(), shaperef, tolerance); + } else if (shape.isPolyLine()) { + // this is the worst for efficiency: potential for many possible retries of the same shape: + for (size_t i = 1; i < shape.m_points.size() - 1; i++) { + Line li(shape.m_points[i - 1], shape.m_points[i]); + connections = lineInPolyList(li, shaperef, tolerance); + } + } + } + + return connections; } // for any geometry, not just line to lines -void ShapeMap::makeShapeConnections() -{ - if (m_hasgraph) { - m_connectors.clear(); - m_attributes.clear(); - m_links.clear(); - m_unlinks.clear(); - - // note, expects these to be numbered 0, 1... - int conn_col = m_attributes.insertLockedColumn("Connectivity"); - - for (size_t i = 0; i < m_shapes.size(); i++) { - int key = m_shapes.key(i); - int rowid = m_attributes.insertRow(key); - // all indices should match... - m_connectors.push_back( Connector() ); - int connectivity = getShapeConnections( key, m_connectors[i].m_connections, TOLERANCE_B*__max(m_region.height(),m_region.width())); - m_attributes.setValue(rowid, conn_col, (float) connectivity ); - } - - m_displayed_attribute = -1; // <- override if it's already showing - setDisplayedAttribute(conn_col); - } +void ShapeMap::makeShapeConnections() { + if (m_hasgraph) { + m_connectors.clear(); + m_attributes->clear(); + m_links.clear(); + m_unlinks.clear(); + + // note, expects these to be numbered 0, 1... + int conn_col = m_attributes->insertOrResetLockedColumn("Connectivity"); + + int i = -1; + for (auto shape : m_shapes) { + i++; + int key = shape.first; + auto &row = m_attributes->addRow(AttributeKey(key)); + // all indices should match... + m_connectors.push_back(Connector()); + m_connectors[i].m_connections = + getShapeConnections(key, TOLERANCE_B * __max(m_region.height(), m_region.width())); + row.setValue(conn_col, float(m_connectors[i].m_connections.size())); + } + + m_displayed_attribute = -1; // <- override if it's already showing + setDisplayedAttribute(conn_col); + } } - ///////////////////////////////////////////////////////////////////////////////// // note: uses rowid not key -double ShapeMap::getLocationValue(const Point2f& point) const -{ - double val = -1.0; - int x = pointInPoly(point); - if (x == -1) { - // try looking for a polyline instead - x = getClosestOpenGeom(point); - } - if (x != -1) { - val = m_attributes.getValue(x,m_displayed_attribute); - } - return (x == -1) ? -2.0 : val; // -2.0 is returned when point cannot be associated with a poly +double ShapeMap::getLocationValue(const Point2f &point) const { + double val = -1.0; + int x = pointInPoly(point); + if (x == -1) { + // try looking for a polyline instead + x = getClosestOpenGeom(point); + } + if (x != -1) { + int key = getShapeRefFromIndex(x)->first; + if (m_displayed_attribute == -1) { + val = static_cast(key); + } else { + auto &row = m_attributes->getRow(AttributeKey(key)); + val = row.getValue(m_displayed_attribute); + } + } + return (x == -1) ? -2.0 : val; // -2.0 is returned when point cannot be associated with a poly +} + +bool ShapeMap::setCurSel(QtRegion &r, bool add) { + if (add == false) { + clearSel(); + } + + if (r.bottom_left == r.top_right) { + // note: uses index not key + int index = pointInPoly(r.bottom_left); + if (index == -1) { + // try looking for a polyline instead + index = getClosestOpenGeom(r.bottom_left); + } + if (index != -1) { + auto shapeIter = getShapeRefFromIndex(index); + if (m_selection_set.insert(shapeIter->first).second) { + auto &row = m_attributes->getRow(AttributeKey(shapeIter->first)); + row.setSelection(true); + } + shapeIter->second.m_selected = true; + m_selection = true; + } + } else { + PixelRef bl = pixelate(r.bottom_left); + PixelRef tr = pixelate(r.top_right); + for (int i = bl.x; i <= tr.x; i++) { + for (int j = bl.y; j <= tr.y; j++) { + const std::vector &shapeRefs = + m_pixel_shapes(static_cast(j), static_cast(i)); + for (const ShapeRef &shape : shapeRefs) { + // relies on indices of shapes and attributes being aligned + auto &shapeIter = m_shapes.at(shape.m_shape_ref); + if (intersect_region(r, shapeIter.m_region)) { + shapeIter.m_selected = true; + m_selection = true; + } + } + } + } + // actually probably often faster to set flag and later record list: + for (auto shape : m_shapes) { + if (shape.second.m_selected) { + if (m_selection_set.insert(shape.first).second) { + auto &row = m_attributes->getRow(AttributeKey(shape.first)); + row.setSelection(true); + } + } + } + } + + return m_selection; } -bool ShapeMap::setCurSel( QtRegion& r, bool add ) -{ - if (add == false) { - clearSel(); - } - - if (r.bottom_left == r.top_right) { - // note: uses index not key - int index = pointInPoly(r.bottom_left); - if (index == -1) { - // try looking for a polyline instead - index = getClosestOpenGeom(r.bottom_left); - } - if (index != -1) { - // relies on indices of shapes and attributes being aligned - if (m_selection_set.add(index) != -1) { - m_attributes.selectRowByIndex(index); - } - m_shapes.value(index).m_selected = true; - m_selection = true; - } - } - else { - PixelRef bl = pixelate(r.bottom_left); - PixelRef tr = pixelate(r.top_right); - for (int i = bl.x; i <= tr.x; i++) { - for (int j = bl.y; j <= tr.y; j++) { - for (size_t k = 0; k < m_pixel_shapes[i][j].size(); k++) { - // relies on indices of shapes and attributes being aligned - size_t x = m_shapes.searchindex(m_pixel_shapes[i][j][k].m_shape_ref); - if (x != paftl::npos && intersect_region(r,m_shapes.value(x).m_region)) { - m_shapes.value(x).m_selected = true; - m_selection = true; - } - } - } - } - // actually probably often faster to set flag and later record list: - for (size_t x = 0; x < m_shapes.size(); x++) { - if (m_shapes.value(x).m_selected) { - if (m_selection_set.add(x) != -1) { - m_attributes.selectRowByIndex(x); - } - } - } - } +// this version is used by setSelSet in MetaGraph, ultimately called from CTableView and PlotView +bool ShapeMap::setCurSel(const std::vector &selset, bool add) { + // note: override cursel, can only be used with analysed pointdata: + if (!add) { + clearSel(); + } + for (int shapeRef : selset) { + if (m_selection_set.insert(shapeRef).second) { + auto &row = m_attributes->getRow(AttributeKey(shapeRef)); + row.setSelection(true); + } + m_shapes.at(shapeRef).m_selected = true; + m_selection = true; + } + return m_selection; +} - return m_selection; +// this version is used when setting a selection set via the scripting language +bool ShapeMap::setCurSelDirect(const std::vector &selset, bool add) { + // note: override cursel, can only be used with analysed pointdata: + if (!add) { + clearSel(); + } + for (int shapeRef : selset) { + if (m_selection_set.insert(shapeRef).second) { + auto &row = m_attributes->getRow(AttributeKey(shapeRef)); + row.setSelection(true); + } + m_shapes.at(shapeRef).m_selected = true; + m_selection = true; + } + return m_selection; +} + +float ShapeMap::getDisplayedSelectedAvg() { return (m_attributes->getSelAvg(m_displayed_attribute)); } + +bool ShapeMap::clearSel() { + // note, only clear if need be, as m_attributes->deselectAll is slow + if (m_selection_set.size()) { + m_attributes->deselectAllRows(); + m_selection = false; + for (auto &shapeRef : m_selection_set) { + m_shapes.at(shapeRef).m_selected = false; + } + m_selection_set.clear(); + } + return true; +} + +QtRegion ShapeMap::getSelBounds() { + QtRegion r; + if (m_selection_set.size()) { + for (auto &shapeRef : m_selection_set) { + r = runion(r, m_shapes.at(shapeRef).getBoundingBox()); + } + } + return r; +} + +bool ShapeMap::selectionToLayer(const std::string &name) { + bool retvar = false; + if (m_selection_set.size()) { + dXreimpl::pushSelectionToLayer(*m_attributes, m_layers, name); + retvar = m_layers.isLayerVisible(m_layers.getLayerIndex(name)); + if (retvar) { + clearSel(); + } + } + return retvar; } -// this version is used by setSelSet in MetaGraph, ultimately called from CTableView and PlotView -bool ShapeMap::setCurSel(const pvecint& selset, bool add) -{ - // note: override cursel, can only be used with analysed pointdata: - if (!add) { - clearSel(); - } - for (size_t i = 0; i < selset.size(); i++) { - size_t index = m_shapes.searchindex(selset[i]); // relies on aligned indices for attributes and shapes - if (index != paftl::npos) { - if (m_selection_set.add(int(index)) != -1) { - m_attributes.selectRowByIndex(int(index)); - } - m_shapes[index].m_selected = true; - m_selection = true; - } - } - return m_selection; +///////////////////////////////////////////////////////////////////////////////////////////////// + +bool ShapeMap::read(std::istream &stream) { + // turn off selection / editable etc + m_selection = false; + m_editable = false; + m_show = true; // <- by default show + m_map_type = ShapeMap::EMPTYMAP; + + // clear old BSP tree (if exists) + m_bsp_tree = false; + m_bsp_root = NULL; + + // clear old: + m_display_shapes.clear(); + m_shapes.clear(); + m_attributes->clear(); + m_connectors.clear(); + m_links.clear(); + m_unlinks.clear(); + m_undobuffer.clear(); + + // name + m_name = dXstring::readString(stream); + + stream.read((char *)&m_map_type, sizeof(m_map_type)); + + stream.read((char *)&m_show, sizeof(m_show)); + stream.read((char *)&m_editable, sizeof(m_editable)); + + // PixelBase read + // read extents: + stream.read((char *)&m_region, sizeof(m_region)); + // read rows / cols + int rows, cols; + stream.read(reinterpret_cast(&rows), sizeof(rows)); + stream.read(reinterpret_cast(&cols), sizeof(cols)); + m_rows = static_cast(rows); + m_cols = static_cast(cols); + // calculate geom data: + m_tolerance = __max(m_region.width(), m_region.height()) * TOLERANCE_A; + + // read next object ref to be used: + stream.read((char *)&m_obj_ref, sizeof(m_obj_ref)); + int depr_int; + stream.read((char *)&depr_int, sizeof(depr_int)); + + // read shape data + int count = 0; + stream.read((char *)&count, sizeof(count)); + for (int j = 0; j < count; j++) { + int key; + stream.read((char *)&key, sizeof(key)); + auto iter = m_shapes.insert(std::make_pair(key, SalaShape())).first; + iter->second.read(stream); + } + + // read object data (currently unused) + // PK: As the above comment (and others regarding the m_objects + // functionality) suggest, these are no longer used so they can + // just be skipped if ever found + stream.read((char *)&count, sizeof(count)); + for (int k = 0; k < count; k++) { + int key; + stream.read((char *)&key, sizeof(key)); + unsigned int size; + stream.read((char *)&size, sizeof(size)); + stream.ignore(sizeof(int) * std::streamsize(size)); + } + // read attribute data + m_attributes->read(stream, m_layers); + stream.read((char *)&m_displayed_attribute, sizeof(m_displayed_attribute)); + + if (int(m_displayed_attribute) >= 0) { + std::vector indices(m_attributes->getNumColumns()); + std::iota(indices.begin(), indices.end(), static_cast(0)); + + std::sort(indices.begin(), indices.end(), + [&](size_t a, size_t b) { return m_attributes->getColumnName(a) < m_attributes->getColumnName(b); }); + m_displayed_attribute = indices[m_displayed_attribute]; + } + + // prepare pixel map: + m_pixel_shapes = depthmapX::ColumnMatrix>(m_rows, m_cols); + // Now add the pixel shapes pixel map: + // pixelate all polys in the pixel structure: + for (auto shape : m_shapes) { + makePolyPixels(shape.first); + } + + // shape connections: + count = 0; + stream.read((char *)&count, sizeof(count)); + for (int i = 0; i < count; i++) { + m_connectors.push_back(Connector()); + m_connectors[size_t(i)].read(stream); + } + dXreadwrite::readIntoVector(stream, m_links); + dXreadwrite::readIntoVector(stream, m_unlinks); + + // some miscellaneous extra data for mapinfo files + m_hasMapInfoData = false; + char x = stream.get(); + if (x == 'm') { + m_mapinfodata = MapInfoData(); + m_mapinfodata.read(stream); + m_hasMapInfoData = true; + } + + invalidateDisplayedAttribute(); + setDisplayedAttribute(m_displayed_attribute); + + return true; +} + +bool ShapeMap::write(std::ofstream &stream) { + // name + dXstring::writeString(stream, m_name); + + stream.write((char *)&m_map_type, sizeof(m_map_type)); + stream.write((char *)&m_show, sizeof(m_show)); + stream.write((char *)&m_editable, sizeof(m_editable)); + + // PixelBase write + // write extents: + stream.write((char *)&m_region, sizeof(m_region)); + // write rows / cols + int rows = static_cast(m_rows); + int cols = static_cast(m_cols); + stream.write(reinterpret_cast(&rows), sizeof(rows)); + stream.write(reinterpret_cast(&cols), sizeof(cols)); + + // write next object ref to be used: + stream.write((char *)&m_obj_ref, sizeof(m_obj_ref)); + + // left here for backwards-compatibility + // TODO: Remove at next iteration of the .graph file format + int largest_shape_ref = m_shapes.empty() ? -1 : m_shapes.rbegin()->first; + stream.write((char *)&largest_shape_ref, sizeof(largest_shape_ref)); + + // write shape data + int count = m_shapes.size(); + stream.write((char *)&count, sizeof(count)); + for (auto shape : m_shapes) { + int key = shape.first; + stream.write((char *)&key, sizeof(key)); + shape.second.write(stream); + } + // write object data (currently unused) + count = 0; + stream.write((char *)&count, sizeof(count)); + + // write attribute data + m_attributes->write(stream, m_layers); + + // TODO: Compatibility. The attribute columns will be stored sorted alphabetically + // so the displayed attribute needs to match that + int sortedDisplayedAttribute = m_attributes->getColumnSortedIndex(m_displayed_attribute); + stream.write((char *)&sortedDisplayedAttribute, sizeof(sortedDisplayedAttribute)); + + // write connections data + count = m_connectors.size(); + stream.write((char *)&count, sizeof(count)); + + for (int i = 0; i < count; i++) { + m_connectors[i].write(stream); + } + dXreadwrite::writeVector(stream, m_links); + dXreadwrite::writeVector(stream, m_unlinks); + + // some miscellaneous extra data for mapinfo files + if (m_hasMapInfoData) { + stream.put('m'); + m_mapinfodata.write(stream); + } else { + stream.put('x'); + } + + return true; } -// this version is used when setting a selection set via the scripting language -bool ShapeMap::setCurSelDirect(const pvecint& selset, bool add) -{ - // note: override cursel, can only be used with analysed pointdata: - if (!add) { - clearSel(); - } - for (size_t i = 0; i < selset.size(); i++) { - int index = selset[i]; // relies on aligned indices for attributes and shapes - if (index != -1) { - if (m_selection_set.add(index) != -1) { - m_attributes.selectRowByIndex(index); - } - m_shapes[index].m_selected = true; - m_selection = true; - } - } - return m_selection; +bool ShapeMap::output(std::ofstream &stream, char delimiter) { + stream << "Ref"; + if ((m_map_type & LINEMAP) == 0) { + stream << delimiter << "cx" << delimiter << "cy"; + } else { + stream << delimiter << "x1" << delimiter << "y1" << delimiter << "x2" << delimiter << "y2"; + } + + // TODO: For compatibility write the columns in alphabetical order + // but the physical columns in the order inserted + + std::vector indices(m_attributes->getNumColumns()); + std::iota(indices.begin(), indices.end(), static_cast(0)); + + std::sort(indices.begin(), indices.end(), + [&](size_t a, size_t b) { return m_attributes->getColumnName(a) < m_attributes->getColumnName(b); }); + for (int idx : indices) { + stream << delimiter << m_attributes->getColumnName(idx); + } + + stream << std::endl; + + for (auto iter = m_attributes->begin(); iter != m_attributes->end(); iter++) { + int key = iter->getKey().value; + if (isObjectVisible(m_layers, iter->getRow())) { + stream << key; + auto shape = m_shapes[key]; + if ((m_map_type & LINEMAP) == 0) { + stream << delimiter << shape.m_centroid.x << delimiter << shape.m_centroid.y; + } else { + stream.precision(12); // TODO: Here for compatibility with old version + const Line &li = shape.getLine(); + stream << delimiter << li.start().x << delimiter << li.start().y << delimiter << li.end().x + << delimiter << li.end().y; + } + stream.precision(8); // TODO: Here for compatibility with old version + for (int idx : indices) { + stream << delimiter << iter->getRow().getValue(idx); + } + stream << std::endl; + } + } + return true; } +bool ShapeMap::importPoints(const std::vector &points, const depthmapX::Table &data) { + // assumes that points and data come in the same order -bool ShapeMap::clearSel() -{ - // note, only clear if need be, as m_attributes.deselectAll is slow - if (m_selection_set.size()) { - m_attributes.deselectAll(); - m_selection = false; - for (size_t i = 0; i < m_selection_set.size(); i++) { - m_shapes.value(m_selection_set[i]).m_selected = false; - } - m_selection_set.clear(); - } - return true; + std::vector shape_refs; + + for (auto &point : points) { + shape_refs.push_back(makePointShape(point)); + } + + bool dataImported = importData(data, shape_refs); + + invalidateDisplayedAttribute(); + setDisplayedAttribute(-1); + + return dataImported; } -QtRegion ShapeMap::getSelBounds() -{ - QtRegion r; - if (m_selection_set.size()) { - r = m_shapes.value(m_selection_set[0]).getBoundingBox(); - for (size_t i = 1; i < m_selection_set.size(); i++) { - r = runion(r, m_shapes.value(m_selection_set[i]).getBoundingBox()); - } - } - return r; +bool ShapeMap::importPointsWithRefs(const std::map &points, const depthmapX::Table &data) { + // assumes that points and data come in the same order + + std::vector shape_refs; + + for (auto &point : points) { + shape_refs.push_back(makePointShapeWithRef(point.second, point.first)); + } + + bool dataImported = importData(data, shape_refs); + + invalidateDisplayedAttribute(); + setDisplayedAttribute(-1); + + return dataImported; } -bool ShapeMap::selectionToLayer(const pstring& name) -{ - bool retvar = false; - if (m_selection_set.size()) { - retvar = m_attributes.selectionToLayer(name); - if (retvar) { - clearSel(); - } - } - return retvar; +bool ShapeMap::importLines(const std::vector &lines, const depthmapX::Table &data) { + // assumes that lines and data come in the same order + + std::vector shape_refs; + + for (auto &line : lines) { + shape_refs.push_back(makeLineShape(line)); + } + + bool dataImported = importData(data, shape_refs); + + invalidateDisplayedAttribute(); + setDisplayedAttribute(-1); + + return dataImported; } -///////////////////////////////////////////////////////////////////////////////////////////////// +bool ShapeMap::importLinesWithRefs(const std::map &lines, const depthmapX::Table &data) { + // assumes that lines and data come in the same order -bool ShapeMap::read( ifstream& stream, int version, bool drawinglayer ) -{ - // turn off selection / editable etc - m_selection = false; - m_editable = false; - m_show = true; // <- by default show - m_map_type = ShapeMap::EMPTYMAP; - - // clear old BSP tree (if exists) - m_bsp_tree = false; - m_bsp_root = NULL; - - // clear old: - if (m_pixel_shapes) { - for (int i = 0; i < m_cols; i++) { - delete [] m_pixel_shapes[i]; - } - delete [] m_pixel_shapes; - m_pixel_shapes = NULL; - } - if (m_display_shapes) { - delete [] m_display_shapes; - m_display_shapes = NULL; - } - m_objects.clear(); - m_shapes.clear(); - m_attributes.clear(); - m_connectors.clear(); - m_links.clear(); - m_unlinks.clear(); - m_undobuffer.clear(); - - // read in an old file: - if (drawinglayer && version < VERSION_DRAWING_SHAPES) { - // the data in the file is for a SpacePixel - // the easiest solution, although not the most memory effective, is to read in the space pixel, - // and convert to a shape map: - SpacePixel layer; - layer.read(stream,version); - m_name = layer.m_name; - m_show = layer.m_show; - m_editable = false; // <- don't take from spacepixel in case conflicts in some way - m_region = layer.m_region; - m_rows = layer.m_rows; - m_cols = layer.m_cols; - m_tolerance = __max(m_region.width(), m_region.height()) * TOLERANCE_A; - m_shape_ref = -1; - for (size_t i = 0; i < layer.m_lines.size(); i++) { - m_shape_ref++; - int index = m_shapes.add(m_shape_ref, SalaShape(layer.m_lines[i].line)); - // insert a dummy attribute row: - m_attributes.insertRow(m_shape_ref); - // note: as this is always a drawing layer, no need to set shape attributes - } - // prepare pixel map (using same number of cols and rows as the original spacepixel for convenience) - m_pixel_shapes = new pqvector *[m_cols]; - for (int j = 0; j < m_cols; j++) { - m_pixel_shapes[j] = new pqvector[m_rows]; - } - // Now add the pixel shapes pixel map: - // pixelate all polys in the pixel structure: - for (size_t k = 0; k < m_shapes.size(); k++) { - makePolyPixels(m_shapes.key(k)); - } - // set to read in display attribute: - // note that even though it's only a drawing layer, this still needs to be done - invalidateDisplayedAttribute(); - setDisplayedAttribute(-1); - - // all done - return true; - } - - // name - m_name.read(stream); - - if (version >= VERSION_MAP_TYPES) { - stream.read( (char *) &m_map_type, sizeof(m_map_type)); - } - else { - // old versions data maps or drawing maps, - // the axial reader will override this with its own map type designation if necessary - if (drawinglayer) { - m_map_type = DRAWINGMAP; - } - else { - m_map_type = DATAMAP; - } - } - - if (version >= VERSION_DRAWING_SHAPES_B) { - stream.read( (char *) &m_show, sizeof(m_show) ); - stream.read( (char *) &m_editable, sizeof(m_editable) ); - } - - // PixelBase read - // read extents: - stream.read( (char *) &m_region, sizeof(m_region) ); - // read rows / cols - stream.read( (char *) &m_rows, sizeof(m_rows) ); - stream.read( (char *) &m_cols, sizeof(m_cols) ); - // calculate geom data: - m_tolerance = __max(m_region.width(), m_region.height()) * TOLERANCE_A; - - // read next object ref to be used: - stream.read((char *) &m_obj_ref, sizeof(m_obj_ref)); - stream.read((char *) &m_shape_ref, sizeof(m_shape_ref)); - - // read shape data - int count = 0; - stream.read((char *) &count, sizeof(count)); - for (int j = 0; j < count; j++) { - int key; - stream.read((char *) &key, sizeof(key)); - int index = m_shapes.add(key, SalaShape()); - m_shapes.value(index).read(stream,version); - } - if (version < VERSION_SHAPE_CENTROIDS) { - // manually set centroid according to type: - for (size_t i = 0; i < m_shapes.size(); i++) { - switch (m_shapes[i].m_type & SalaShape::SHAPE_TYPE) { - case SalaShape::SHAPE_POINT: - m_shapes[i].m_centroid = m_shapes[i].m_region.bottom_left; - break; - case SalaShape::SHAPE_LINE: - m_shapes[i].m_centroid = m_shapes[i].m_region.getCentre(); - break; - case SalaShape::SHAPE_POLY: - m_shapes[i].setCentroidAreaPerim(); - break; - default: - break; - } - } - } - - // read object data (currently unused) - stream.read((char *) &count, sizeof(count)); - for (int k = 0; k < count; k++) { - int key; - stream.read((char *) &key, sizeof(key)); - int index = m_objects.add(key, SalaObject()); - m_objects.value(index).read(stream,version); - } - // read attribute data - m_attributes.read(stream,version); - stream.read((char *)&m_displayed_attribute,sizeof(m_displayed_attribute)); - - // prepare pixel map: - m_pixel_shapes = new pqvector *[m_cols]; - int i; - for (i = 0; i < m_cols; i++) { - m_pixel_shapes[i] = new pqvector[m_rows]; - } - // Now add the pixel shapes pixel map: - // pixelate all polys in the pixel structure: - for (size_t j = 0; j < m_shapes.size(); j++) { - makePolyPixels(m_shapes.key(j)); - } - - // later versions can have shape connections: - if (version >= VERSION_AXIAL_SHAPES) { - int count; - stream.read((char *)&count,sizeof(count)); - for (int i = 0; i < count; i++) { - m_connectors.push_back(Connector()); - m_connectors[i].read(stream,version); - if (version < VERSION_NO_SELF_CONNECTION) { - size_t self = m_connectors[i].m_connections.searchindex(i); - if (self != paftl::npos) { - m_connectors[i].m_connections.remove_at(self); - } - } - } - m_links.read(stream); - m_unlinks.read(stream); - } - - // some miscellaneous extra data for mapinfo files - if (m_mapinfodata) { - delete m_mapinfodata; - m_mapinfodata = NULL; - } - if (version >= VERSION_MAPINFO_SHAPES) { - char x = stream.get(); - if (x == 'm') { - m_mapinfodata = new MapInfoData; - m_mapinfodata->read(stream,version); - } - } - - invalidateDisplayedAttribute(); - setDisplayedAttribute(m_displayed_attribute); - - return true; + std::vector shape_refs; + + for (auto &line : lines) { + shape_refs.push_back(makeLineShapeWithRef(line.second, line.first)); + } + + bool dataImported = importData(data, shape_refs); + + invalidateDisplayedAttribute(); + setDisplayedAttribute(-1); + + return dataImported; } -bool ShapeMap::write( ofstream& stream, int version ) -{ - // name - m_name.write(stream); - - stream.write( (char *) &m_map_type, sizeof(m_map_type)); - stream.write( (char *) &m_show, sizeof(m_show) ); - stream.write( (char *) &m_editable, sizeof(m_editable) ); - - // PixelBase write - // write extents: - stream.write( (char *) &m_region, sizeof(m_region) ); - // write rows / cols - stream.write( (char *) &m_rows, sizeof(m_rows) ); - stream.write( (char *) &m_cols, sizeof(m_cols) ); - - // write next object ref to be used: - stream.write((char *) &m_obj_ref, sizeof(m_obj_ref)); - stream.write((char *) &m_shape_ref, sizeof(m_shape_ref)); - - // write shape data - int count = m_shapes.size(); - stream.write((char *) &count, sizeof(count)); - for (int j = 0; j < count; j++) { - int key = m_shapes.key(j); - stream.write((char *) &key, sizeof(key)); - m_shapes.value(j).write(stream); - } - // write object data (currently unused) - count = m_objects.size(); - stream.write((char *) &count, sizeof(count)); - for (int k = 0; k < count; k++) { - int key = m_objects.key(k); - stream.write((char *) &key, sizeof(key)); - m_objects.value(k).write(stream); - } - // write attribute data - m_attributes.write(stream,version); - stream.write((char *)&m_displayed_attribute,sizeof(m_displayed_attribute)); - - // write connections data - count = m_connectors.size(); - stream.write((char *)&count,sizeof(count)); - - for (int i = 0; i < count; i++) { - m_connectors[i].write(stream); - } - m_links.write(stream); - m_unlinks.write(stream); - - // some miscellaneous extra data for mapinfo files - if (m_mapinfodata) { - stream.put('m'); - m_mapinfodata->write(stream); - } - else { - stream.put('x'); - } - - return true; +bool ShapeMap::importPolylines(const std::vector &polylines, const depthmapX::Table &data) { + // assumes that lines and data come in the same order + + std::vector shape_refs; + + for (auto &polyline : polylines) { + shape_refs.push_back(makePolyShape(polyline.m_vertices, !polyline.m_closed)); + } + + bool dataImported = importData(data, shape_refs); + + invalidateDisplayedAttribute(); + setDisplayedAttribute(-1); + + return dataImported; } -bool ShapeMap::output( ofstream& stream, char delimiter, bool updated_only ) -{ - stream << "Ref"; - if ((m_map_type & LINEMAP) == 0) { - stream << delimiter << "cx" << delimiter << "cy"; - } - else { - stream << delimiter << "x1" << delimiter << "y1" << delimiter << "x2" << delimiter << "y2"; - } - m_attributes.outputHeader(stream, delimiter, updated_only); - - stream.precision(12); - for (int i = 0; i < m_attributes.getRowCount(); i++) { - if (m_attributes.isVisible(i)) { - stream << m_attributes.getRowKey(i); - if ((m_map_type & LINEMAP) == 0) { - stream << delimiter << m_shapes[i].m_centroid.x << delimiter << m_shapes[i].m_centroid.y; - } - else { - const Line& li = m_shapes[i].getLine(); - stream << delimiter << li.start().x << delimiter << li.start().y << delimiter << li.end().x << delimiter << li.end().y; - } - m_attributes.outputRow(i,stream,delimiter,updated_only); - } - } - return true; +bool ShapeMap::importPolylinesWithRefs(const std::map &polylines, + const depthmapX::Table &data) { + // assumes that lines and data come in the same order + + std::vector shape_refs; + + for (auto &polyline : polylines) { + shape_refs.push_back( + makePolyShapeWithRef(polyline.second.m_vertices, !polyline.second.m_closed, polyline.first)); + } + + bool dataImported = importData(data, shape_refs); + + invalidateDisplayedAttribute(); + setDisplayedAttribute(-1); + + return dataImported; } -// simple text file to a data map -// to start with, we'll just use fixed format: -// tab delimited -- x1,y1,x2,y2 implies line data -// x,y implies point data +bool ShapeMap::importData(const depthmapX::Table &data, std::vector shape_refs) { + for (auto &column : data) { + std::string colName = column.first; + std::replace(colName.begin(), colName.end(), '_', ' '); + dXstring::makeInitCaps(colName); -bool ShapeMap::importTxt(istream& stream, bool csv) -{ - pstring inputline; - stream >> inputline; - - // if not known to be csv or tab delimited, try both: - if (!csv) { - size_t n = inputline.findindex('\t'); - // if can't find tabs, then try commas: - if (n == paftl::npos) { - n = inputline.findindex(','); - if (n == paftl::npos) { - // neither tabs nor commas - return false; - } - else { - // found commas - csv = true; - } - } - } - - // check for a tab delimited header line... - pvecstring strings = inputline.tokenize(csv ? ',' : '\t'); - if (strings.size() < 2) { - return false; - } - - size_t i; - for (i = 0; i < strings.size(); i++) { - if (!strings[i].empty()) { - strings[i].makelower(); - strings[i].ltrim('\"'); - strings[i].rtrim('\"'); - } - } - - int xcol = -1, ycol = -1, x1col = -1, y1col = -1, x2col = -1, y2col = -1; - for (i = 0; i < strings.size(); i++) { - if (strings[i] == "x" || strings[i] == "easting") - xcol = i; - else if (strings[i] == "y" || strings[i] == "northing") - ycol = i; - else if (strings[i] == "x1") - x1col = i; - else if (strings[i] == "x2") - x2col = i; - else if (strings[i] == "y1") - y1col = i; - else if (strings[i] == "y2") - y2col = i; - else { - strings[i].replace('_',' '); - strings[i].makeinitcaps(); - if (strings[i].empty() || m_attributes.insertColumn(strings[i]) == -1) { + if (colName.empty()) + continue; + + int colIndex = m_attributes->insertOrResetColumn(colName); + + if (colIndex == -1) { // error adding column (e.g., duplicate column names) - return false; - } - } - } - - // Quick mod - TV - unsigned int cols = strings.size(); - - bool pts = (xcol != -1 && ycol != -1); - bool lns = (x1col != -1 && y1col != -1 && x2col != -1 && y2col != -1); - - if (!pts && !lns) { - return false; - } - - // note, these have been ordered alphabetically by the attribute table, so we need to find out what they are now: - pvecint colmap; - prefvec > colcodes; - for (i = 0; i < strings.size(); i++) { - if (i != xcol && i != ycol && i != x1col && i != y1col && i != x2col && i != y2col) { - colmap.push_back( m_attributes.getColumnIndex(strings[i]) ); - } - } - - QtRegion region; - prefvec points; - prefvec lines; - Point2f p1, p2; - - prefvec table; - - while (!stream.eof()) { - stream >> inputline; - if (!inputline.empty()) { - pvecstring strings = inputline.tokenize(csv ? ',' : '\t'); - if (!strings.size()) { continue; - } - // there was a check for the right number of columns here, but - // note my tokenize is removing a final blank column ocassionally so ignore oddly format cols (and hope they have at least fields required) - table.push_back( pvecfloat() ); - for (size_t i = 0; i < cols; i++) { - if (i >= strings.size()) { - if (i == xcol || i == ycol || i == x1col || i == y1col) { - return false; - } - else { - table.tail().push_back( -1.0f); - } - } - else { - try { - if (i == xcol || i == x1col) - p1.x = strings[i].c_double(); - else if (i == ycol || i == y1col) - p1.y = strings[i].c_double(); - else if (i == x2col) - p2.x = strings[i].c_double(); - else if (i == y2col) - p2.y = strings[i].c_double(); - else { - if (strings[i].is_double()) { - table.tail().push_back( (float) strings[i].c_double() ); - } - else { - // the data column we're on - // Quick mod - TV - unsigned int datacol = table.tail().size(); - while (colcodes.size() <= datacol) { - colcodes.push_back( pqmap() ); // <- note due to numbering need one for each - } - if (colcodes[datacol].size() < 32) { - size_t n = colcodes[datacol].searchindex(strings[i]); - if (n == paftl::npos) { - n = colcodes[datacol].add(strings[i],colcodes[datacol].size()); - } - if (colcodes[datacol].size() == 32) { - // Quick mod - TV - // quit trying to code like this: - for (unsigned int j = 0; j < table.size(); j++) { - table[j][datacol] = -1.0f; - } - table.tail().push_back( -1.0f ); - } - else { - table.tail().push_back( colcodes[datacol][n] ); - } - } - else { - table.tail().push_back( -1.0f ); + } + + std::unordered_map colcodes; + + for (size_t i = 0; i < column.second.size(); i++) { + std::string cellValue = column.second[i]; + double value = 0; + if (dXstring::isDouble(cellValue)) { + value = stod(cellValue); + } else { + std::unordered_map::iterator cellAt = colcodes.find(cellValue); + if (cellAt == colcodes.end()) { + + // TODO: + // It seems that the original intention here was that if we are past 32 unique + // values, we should stop trying to make the column categorical and fill the rest + // of the values with -1.0f. It's not possible to test the original implementation + // because the app crashes if we load a file with more than 32 unique values. When + // and if we have a robust implementation of an attribute table that allows for + // both categorical and plain string attributes this should be re-examined for a + // better way to classify the column as either. Meanwhile after this threshold (32) + // we set the whole column to -1 so that it does not give the impression it worked + // when it's actually half-baked + + if (colcodes.size() >= 32) { + for (size_t j = 0; j < column.second.size(); j++) { + m_attributes->getRow(AttributeKey(shape_refs[j])).setValue(colIndex, -1.0f); } - } - } - } - catch (pstring::exception) { - return false; - } - } - } - if (pts) { - points.push_back(p1); - if (points.size() == 1) { - region = QtRegion(points.tail(),points.tail()); - } - else { - region = runion(region,QtRegion(points.tail(),points.tail())); + continue; + } else { + value = colcodes.size(); + colcodes.insert(std::make_pair(cellValue, colcodes.size())); + } + } else { + value = cellAt->second; + } } - } - else { - lines.push_back(Line(p1,p2)); - if (lines.size() == 1) { - region = lines.tail(); - } - else { - region = runion(region,lines.tail()); - } - } - } - } - - // need at least one point: - if (!(points.size() || lines.size())) { - return false; - } - - if (pts) { - init(points.size(),region); - for (i = 0; i < points.size(); i++) { - makePointShape(points[i]); - for (int j = 0; j < m_attributes.getColumnCount(); j++) { - m_attributes.setValue(i,colmap[j],table[i][j]); - } - } - } - else { - init(lines.size(),region); - for (i = 0; i < lines.size(); i++) { - makeLineShape(lines[i]); - for (int j = 0; j < m_attributes.getColumnCount(); j++) { - m_attributes.setValue(i,colmap[j],table[i][j]); - } - } - } - - // display an attribute: - invalidateDisplayedAttribute(); - setDisplayedAttribute(-1); - - return true; + m_attributes->getRow(AttributeKey(shape_refs[i])).setValue(colIndex, value); + } + } + return true; } - ////////////////////////////////////////////////////////////////////////////////// -void ShapeMap::setDisplayedAttribute(int col) const -{ - if (!m_invalidate && m_displayed_attribute == col) { - return; - } - m_displayed_attribute = col; - m_invalidate = true; +void ShapeMap::setDisplayedAttribute(int col) { + if (!m_invalidate && m_displayed_attribute == col) { + return; + } + m_displayed_attribute = col; + m_invalidate = true; - // always override at this stage: - m_attributes.setDisplayColumn(m_displayed_attribute,true); + // always override at this stage: + m_attribHandle->setDisplayColIndex(m_displayed_attribute); - m_invalidate = false; + m_invalidate = false; } ////////////////////////////////////////////////////////////////////////////////// // this is all very similar to spacepixel, apart from a few minor details -void ShapeMap::makeViewportShapes( const QtRegion& viewport ) const -{ - if (m_invalidate) { - return; - } - - if (!m_display_shapes || m_newshape) { - if (m_display_shapes) - delete [] m_display_shapes; - m_display_shapes = new int [m_shapes.size()]; - m_newshape = false; - for (size_t i = 0; i < m_shapes.size(); i++) { - m_display_shapes[i] = -1; - } - } - - m_current = -1; // note: findNext expects first to be labelled -1 - - PixelRef bl = pixelate( viewport.bottom_left ); - PixelRef tr = pixelate( viewport.top_right ); - - for (int i = bl.x; i <= tr.x; i++) { - for (int j = bl.y; j <= tr.y; j++) { - for (size_t k = 0; k < m_pixel_shapes[i][j].size(); k++) { - // copy the index to the correct draworder position (draworder is formatted on display attribute) - int x = m_attributes.getRowid(m_pixel_shapes[i][j][k].m_shape_ref); - if (m_attributes.isVisible(x)) { - m_display_shapes[m_attributes.getDisplayPos(x)] = x; +void ShapeMap::makeViewportShapes(const QtRegion &viewport) const { + if (m_invalidate) { + return; + } + + if (m_display_shapes.empty() || m_newshape) { + m_display_shapes.assign(m_shapes.size(), -1); + m_newshape = false; + } + + m_current = -1; // note: findNext expects first to be labelled -1 + + PixelRef bl = pixelate(viewport.bottom_left); + PixelRef tr = pixelate(viewport.top_right); + + for (int i = bl.x; i <= tr.x; i++) { + for (int j = bl.y; j <= tr.y; j++) { + const std::vector &shapeRefs = m_pixel_shapes(static_cast(j), static_cast(i)); + for (const ShapeRef &shape : shapeRefs) { + // copy the index to the correct draworder position (draworder is formatted on display attribute) + int x = std::distance(m_shapes.begin(), m_shapes.find(shape.m_shape_ref)); + AttributeKey shapeRefKey(shape.m_shape_ref); + if (isObjectVisible(m_layers, m_attributes->getRow(shapeRefKey))) { + m_display_shapes[m_attribHandle->findInIndex(shapeRefKey)] = x; + } } - } - } - } + } + } - m_curlinkline = -1; - m_curunlinkpoint = -1; + m_curlinkline = -1; + m_curunlinkpoint = -1; } -bool ShapeMap::findNextShape(bool& nextlayer) const -{ - // note: will not work immediately after a new poly has been added: makeViewportShapes first - if (m_invalidate || m_newshape) { - return false; - } - - while (++m_current < (int)m_shapes.size() && m_display_shapes[m_current] == -1 ); - - if (m_current < (int)m_shapes.size()) { - return true; - } - else { - m_current = (int)m_shapes.size(); - nextlayer = true; - return false; - } +bool ShapeMap::findNextShape(bool &nextlayer) const { + // note: will not work immediately after a new poly has been added: makeViewportShapes first + if (m_invalidate || m_newshape) { + return false; + } + + while (++m_current < (int)m_shapes.size() && m_display_shapes[m_current] == -1) + ; + + if (m_current < (int)m_shapes.size()) { + return true; + } else { + m_current = (int)m_shapes.size(); + nextlayer = true; + return false; + } } -const SalaShape& ShapeMap::getNextShape() const -{ - int x = m_display_shapes[m_current]; // x has display order in it - m_display_shapes[m_current] = -1; // you've drawn it - return m_shapes[x]; +const SalaShape &ShapeMap::getNextShape() const { + int x = m_display_shapes[m_current]; // x has display order in it + m_display_shapes[m_current] = -1; // you've drawn it + return depthmapX::getMapAtIndex(m_shapes, x)->second; } /////////////////////////////////////////////////////////////////////////////////// -pqvector SalaShape::getClippingSet(QtRegion& clipframe) const -{ - pqvector edgeset; - bool last_inside = (clipframe.contains_touch(at(0))) ? true : false; - bool found_inside = last_inside; - for (size_t i = 1; i < size(); i++) { - bool next_inside = (clipframe.contains_touch(at(i))) ? true : false; - found_inside |= next_inside; - if (last_inside != next_inside) { - if (last_inside) { - EdgeU eu = clipframe.getCutEdgeU(at(i-1),at(i)); - edgeset.push_back(SalaEdgeU(i,false,eu)); - } - else { - EdgeU eu = clipframe.getCutEdgeU(at(i),at(i-1)); - edgeset.push_back(SalaEdgeU(i-1,true,eu)); - } - } - last_inside = next_inside; - } - if (!found_inside) { - // note: deliberately add a single empty SalaEdgeU if this polygon is never inside the frame - edgeset.push_back(SalaEdgeU()); - } - return edgeset; +std::vector SalaShape::getClippingSet(QtRegion &clipframe) const { + std::vector edgeset; + bool last_inside = (clipframe.contains_touch(m_points[0])) ? true : false; + bool found_inside = last_inside; + for (size_t i = 1; i < m_points.size(); i++) { + bool next_inside = (clipframe.contains_touch(m_points[i])) ? true : false; + found_inside |= next_inside; + if (last_inside != next_inside) { + if (last_inside) { + EdgeU eu = clipframe.getCutEdgeU(m_points[i - 1], m_points[i]); + edgeset.push_back(SalaEdgeU(i, false, eu)); + } else { + EdgeU eu = clipframe.getCutEdgeU(m_points[i], m_points[i - 1]); + edgeset.push_back(SalaEdgeU(i - 1, true, eu)); + } + } + last_inside = next_inside; + } + if (!found_inside) { + // note: deliberately add a single empty SalaEdgeU if this polygon is never inside the frame + edgeset.push_back(SalaEdgeU()); + } + return edgeset; } - /////////////////////////////////////////////////////////////////////////////////// // copied from SpacePixel -PixelRef ShapeMap::pixelate( const Point2f& p, bool constrain, int ) const -{ - PixelRef r; - - Point2f p1 = p; - p1.normalScale(m_region); - - if (constrain) { - if (p1.x <= 0.0) { - r.x = 0; - } - else if (p1.x >= 1.0) { - r.x = m_cols - 1; - } - else { - r.x = short(floor(p1.x * m_cols)); - } - } - else { - r.x = short(floor(p1.x * m_cols)); - } - - if (constrain) { - if (p1.y <= 0.0) { - r.y = 0; - } - else if (p1.y >= 1.0) { - r.y = m_rows - 1; - } - else { - r.y = short(floor(p1.y * m_rows)); - } - } - else { - r.y = short(floor(p1.y * m_rows)); - } - - return r; +PixelRef ShapeMap::pixelate(const Point2f &p, bool constrain, int) const { + PixelRef r; + + Point2f p1 = p; + p1.normalScale(m_region); + + if (constrain) { + if (p1.x <= 0.0) { + r.x = 0; + } else if (p1.x >= 1.0) { + r.x = m_cols - 1; + } else { + r.x = short(floor(p1.x * m_cols)); + } + } else { + r.x = short(floor(p1.x * m_cols)); + } + + if (constrain) { + if (p1.y <= 0.0) { + r.y = 0; + } else if (p1.y >= 1.0) { + r.y = m_rows - 1; + } else { + r.y = short(floor(p1.y * m_rows)); + } + } else { + r.y = short(floor(p1.y * m_rows)); + } + + return r; +} + +void ShapeMap::copyMapInfoBaseData(const ShapeMap &sourceMap) { + m_mapinfodata = MapInfoData(); + m_mapinfodata.m_coordsys = sourceMap.getMapInfoData().m_coordsys; + m_mapinfodata.m_bounds = sourceMap.getMapInfoData().m_bounds; + m_hasMapInfoData = true; } /////////////////////////////////////////////////////////////////////////////////// -int ShapeMap::loadMifMap(istream& miffile, istream& midfile) -{ - m_mapinfodata = new MapInfoData; - - return m_mapinfodata->import(miffile, midfile, *this); +int ShapeMap::loadMifMap(std::istream &miffile, std::istream &midfile) { + m_mapinfodata = MapInfoData(); + int retvar = m_mapinfodata.import(miffile, midfile, *this); + if (retvar == MINFO_OK) + m_hasMapInfoData = true; + return retvar; } /////////////////////////////////////////////////////////////////////////////////////////////////// -bool ShapeMap::outputMifMap(ostream& miffile, ostream& midfile) const -{ - if (!m_mapinfodata) { - MapInfoData mapinfodata; - mapinfodata.exportFile(miffile, midfile, *this); - } - else { - m_mapinfodata->exportFile(miffile, midfile, *this); - } - - return true; -} +bool ShapeMap::outputMifMap(std::ostream &miffile, std::ostream &midfile) { + if (!m_hasMapInfoData) { + MapInfoData mapinfodata; + mapinfodata.exportFile(miffile, midfile, *this); + } else { + m_mapinfodata.exportFile(miffile, midfile, *this); + } + return true; +} ///////////////////////////////////////////////////////////////////////////////// // Code for explicit linking / unlinking -bool ShapeMap::linkShapes(const Point2f& p) -{ - if (m_selection_set.size() != 1) { - return false; - } - int index1 = m_selection_set[0]; - // note: uses rowid not key - int index2 = pointInPoly(p); - if (index2 == -1) { - // try looking for a polyline instead - index2 = getClosestOpenGeom(p); - } - if (index2 == -1) { - return false; - } - clearSel(); - - linkShapes(index1, index2); - - return true; -} - -bool ShapeMap::linkShapes(int index1, int index2, bool refresh) -{ - int conn_col = m_attributes.getOrInsertLockedColumnIndex("Connectivity"); - bool update = false; - - if (index1 != index2) { - // link these lines... - // first look for explicit unlinks and clear - OrderedIntPair link(index1,index2); - size_t unlinkindex = m_unlinks.searchindex(link); - if (unlinkindex != paftl::npos) { - m_unlinks.remove_at(unlinkindex); - update = true; - } - else { - // then check not linked already - size_t linkindex1 = m_connectors[index1].m_connections.searchindex(index2); - size_t linkindex2 = m_connectors[index2].m_connections.searchindex(index1); - if (linkindex1 == paftl::npos && linkindex2 == paftl::npos) { - // finally, link the two lines - m_links.add(link); +bool ShapeMap::linkShapes(const Point2f &p) { + if (m_selection_set.size() != 1) { + return false; + } + int index1 = std::distance(m_shapes.begin(), m_shapes.find(*m_selection_set.begin())); + // note: uses rowid not key + int index2 = pointInPoly(p); + if (index2 == -1) { + // try looking for a polyline instead + index2 = getClosestOpenGeom(p); + } + if (index2 == -1) { + return false; + } + clearSel(); + + linkShapes(index1, index2); + + return true; +} + +bool ShapeMap::linkShapesFromRefs(int ref1, int ref2, bool refresh) { + int index1 = depthmapX::findIndexFromKey(m_shapes, ref1); + int index2 = depthmapX::findIndexFromKey(m_shapes, ref2); + return linkShapes(index1, index2, refresh); +} + +bool ShapeMap::linkShapes(int index1, int index2, bool refresh) { + int conn_col = m_attributes->getOrInsertLockedColumn("Connectivity"); + bool update = false; + + if (index1 != index2) { + // link these lines... + // first look for explicit unlinks and clear + OrderedIntPair link(index1, index2); + auto unlinkiter = std::find(m_unlinks.begin(), m_unlinks.end(), link); + if (unlinkiter != m_unlinks.end()) { + m_unlinks.erase(unlinkiter); update = true; - } - } - } - - if (update) { - m_connectors[index1].m_connections.add(index2); - m_connectors[index2].m_connections.add(index1); - m_attributes.incrValue(index1, conn_col); - m_attributes.incrValue(index2, conn_col); - if (refresh && getDisplayedAttribute() == conn_col) { - invalidateDisplayedAttribute(); - setDisplayedAttribute(conn_col); // <- reflect changes to connectivity counts - } - } - - return update; + } else { + // then check not linked already + auto &connections1 = m_connectors[size_t(index1)].m_connections; + auto &connections2 = m_connectors[size_t(index2)].m_connections; + auto linkIter1 = std::find(connections1.begin(), connections1.end(), index2); + auto linkIter2 = std::find(connections2.begin(), connections2.end(), index1); + if (linkIter1 == connections1.end() && linkIter2 == connections2.end()) { + // finally, link the two lines + depthmapX::addIfNotExists(m_links, link); + update = true; + } + } + } + + if (update) { + depthmapX::insert_sorted(m_connectors[size_t(index1)].m_connections, index2); + depthmapX::insert_sorted(m_connectors[size_t(index2)].m_connections, index1); + auto &row1 = getAttributeRowFromShapeIndex(index1); + auto &row2 = getAttributeRowFromShapeIndex(index2); + row1.incrValue(conn_col); + row2.incrValue(conn_col); + if (refresh && getDisplayedAttribute() == conn_col) { + invalidateDisplayedAttribute(); + setDisplayedAttribute(conn_col); // <- reflect changes to connectivity counts + } + } + + return update; } // this version is used to link segments in segment analysis // note it only links one way! -bool ShapeMap::linkShapes(int id1, int dir1, int id2, int dir2, float weight) -{ - int success = -1; - if (dir1 == 1) { - success = m_connectors[id1].m_forward_segconns.add(SegmentRef(dir2,id2),weight); - } - else { - success = m_connectors[id1].m_back_segconns.add(SegmentRef(dir2,id2),weight); - } - - // checking success != -1 avoids duplicate entries adding to connectivity - if (success != -1) { - int conn_col = m_attributes.getOrInsertLockedColumnIndex("Connectivity"); - m_attributes.incrValue(id1, conn_col); - int weight_col = m_attributes.getOrInsertLockedColumnIndex("Weighted Connectivity"); - m_attributes.incrValue(id1, weight_col, weight); - } - - return true; -} - -bool ShapeMap::unlinkShapes(const Point2f& p) -{ - if (m_selection_set.size() != 1) { - return false; - } - int index1 = m_selection_set[0]; - int index2 = pointInPoly(p); - if (index2 == -1) { - // try looking for a polyline instead - index2 = getClosestOpenGeom(p); - } - if (index2 == -1) { - return false; - } - clearSel(); - - unlinkShapes(index1,index2); - - return true; +bool ShapeMap::linkShapes(int id1, int dir1, int id2, int dir2, float weight) { + bool success = false; + Connector &connector = m_connectors[size_t(id1)]; + if (dir1 == 1) { + success = depthmapX::addIfNotExists(connector.m_forward_segconns, SegmentRef(dir2, id2), weight); + } else { + success = depthmapX::addIfNotExists(connector.m_back_segconns, SegmentRef(dir2, id2), weight); + } + + // checking success != -1 avoids duplicate entries adding to connectivity + if (success) { + int conn_col = m_attributes->getOrInsertLockedColumn("Connectivity"); + auto &row = getAttributeRowFromShapeIndex(id1); + row.incrValue(conn_col); + int weight_col = m_attributes->getOrInsertLockedColumn("Weighted Connectivity"); + row.incrValue(weight_col, weight); + } + + return true; +} + +bool ShapeMap::unlinkShapes(const Point2f &p) { + if (m_selection_set.size() != 1) { + return false; + } + int index1 = std::distance(m_shapes.begin(), m_shapes.find(*m_selection_set.begin())); + int index2 = pointInPoly(p); + if (index2 == -1) { + // try looking for a polyline instead + index2 = getClosestOpenGeom(p); + } + if (index2 == -1) { + return false; + } + clearSel(); + + unlinkShapes(index1, index2); + + return true; +} + +bool ShapeMap::unlinkShapesFromRefs(int ref1, int ref2, bool refresh) { + int index1 = depthmapX::findIndexFromKey(m_shapes, ref1); + int index2 = depthmapX::findIndexFromKey(m_shapes, ref2); + return unlinkShapes(index1, index2, refresh); } // note: uses rowids rather than shape key -bool ShapeMap::unlinkShapes(int index1, int index2, bool refresh) -{ - int conn_col = m_attributes.getColumnIndex("Connectivity"); - bool update = false; - - if (index1 != index2) { - // unlink these shapes... - // first look for explicit links and clear - OrderedIntPair unlink(index1,index2); - size_t linkindex = m_links.searchindex(unlink); - if (linkindex != paftl::npos) { - m_links.remove_at(linkindex); - update = true; - } - else { - // then check if linked already - size_t linkindex1 = m_connectors[index1].m_connections.searchindex(index2); - size_t linkindex2 = m_connectors[index2].m_connections.searchindex(index1); - if (linkindex1 != paftl::npos && linkindex2 != paftl::npos) { - // finally, unlink the two shapes - m_unlinks.add(unlink); +bool ShapeMap::unlinkShapes(int index1, int index2, bool refresh) { + int conn_col = m_attributes->getColumnIndex("Connectivity"); + bool update = false; + + if (index1 != index2) { + // unlink these shapes... + // first look for explicit links and clear + OrderedIntPair unlink(index1, index2); + auto linkiter = std::find(m_links.begin(), m_links.end(), unlink); + if (linkiter != m_links.end()) { + m_links.erase(linkiter); + update = true; + } else { + // then check if linked already + auto &connections1 = m_connectors[size_t(index1)].m_connections; + auto &connections2 = m_connectors[size_t(index2)].m_connections; + auto linkIter1 = std::find(connections1.begin(), connections1.end(), index2); + auto linkIter2 = std::find(connections2.begin(), connections2.end(), index1); + if (linkIter1 != connections1.end() && linkIter2 != connections2.end()) { + // finally, unlink the two shapes + depthmapX::addIfNotExists(m_unlinks, unlink); + update = true; + } + } + } + + if (update && conn_col != -1) { + depthmapX::findAndErase(m_connectors[size_t(index1)].m_connections, index2); + depthmapX::findAndErase(m_connectors[size_t(index2)].m_connections, index1); + auto &row1 = getAttributeRowFromShapeIndex(index1); + auto &row2 = getAttributeRowFromShapeIndex(index2); + row1.incrValue(conn_col, -1.0f); + row2.incrValue(conn_col, -1.0f); + if (refresh && getDisplayedAttribute() == conn_col) { + invalidateDisplayedAttribute(); + setDisplayedAttribute(conn_col); // <- reflect changes to connectivity counts + } + } + return update; +} + +bool ShapeMap::unlinkShapesByKey(int key1, int key2, bool refresh) { + int conn_col = m_attributes->getColumnIndex("Connectivity"); + bool update = false; + + int index1 = std::distance(m_shapes.begin(), m_shapes.find(key1)); + int index2 = std::distance(m_shapes.begin(), m_shapes.find(key2)); + + if (key1 != key2) { + // unlink these shapes... + // first look for explicit links and clear + OrderedIntPair unlink(index1, index2); + auto linkiter = std::find(m_links.begin(), m_links.end(), unlink); + if (linkiter != m_links.end()) { + m_links.erase(linkiter); update = true; - } - } - } - - if (update && conn_col != -1) { - m_connectors[index1].m_connections.remove(index2); - m_connectors[index2].m_connections.remove(index1); - m_attributes.decrValue(index1, conn_col); - m_attributes.decrValue(index2, conn_col); - if (refresh && getDisplayedAttribute() == conn_col) { - invalidateDisplayedAttribute(); - setDisplayedAttribute(conn_col); // <- reflect changes to connectivity counts - } - } - return update; + } else { + // then check if linked already + auto &connections1 = m_connectors[size_t(index1)].m_connections; + auto &connections2 = m_connectors[size_t(index2)].m_connections; + auto linkIter1 = std::find(connections1.begin(), connections1.end(), index2); + auto linkIter2 = std::find(connections2.begin(), connections2.end(), index1); + if (linkIter1 != connections1.end() && linkIter2 != connections2.end()) { + // finally, unlink the two shapes + depthmapX::addIfNotExists(m_unlinks, unlink); + update = true; + } + } + } + + if (update && conn_col != -1) { + depthmapX::findAndErase(m_connectors[size_t(index1)].m_connections, index2); + depthmapX::findAndErase(m_connectors[size_t(index2)].m_connections, index1); + auto &row1 = m_attributes->getRow(AttributeKey(key1)); + auto &row2 = m_attributes->getRow(AttributeKey(key1)); + row1.incrValue(conn_col, -1.0f); + row2.incrValue(conn_col, -1.0f); + if (refresh && getDisplayedAttribute() == conn_col) { + invalidateDisplayedAttribute(); + setDisplayedAttribute(conn_col); // <- reflect changes to connectivity counts + } + } + return update; +} + +bool ShapeMap::clearLinks() { + for (size_t i = 0; i < m_unlinks.size(); i++) { + OrderedIntPair link = m_unlinks[i]; + depthmapX::insert_sorted(m_connectors[size_t(link.a)].m_connections, link.b); + depthmapX::insert_sorted(m_connectors[size_t(link.b)].m_connections, link.a); + } + m_unlinks.clear(); + + for (size_t j = 0; j < m_links.size(); j++) { + OrderedIntPair link = m_links[j]; + depthmapX::findAndErase(m_connectors[size_t(link.a)].m_connections, link.b); + depthmapX::findAndErase(m_connectors[size_t(link.b)].m_connections, link.a); + } + m_links.clear(); + + return true; +} + +bool ShapeMap::unlinkShapeSet(std::istream &idset, int refcol) { + std::string line; + std::vector> unlinks; + do { + std::pair unlink; + dXstring::safeGetline(idset, line); + if (!line.empty()) { + auto tokens = dXstring::split(line, '\t'); + if (tokens.size() < 2) { + return false; + } + try { + unlink.first = stoi(tokens[0]); + unlink.second = stoi(tokens[1]); + unlinks.push_back(unlink); + } catch (const std::invalid_argument) { + ; + } catch (const std::out_of_range) { + ; + } // don't do anything if it can't parse the numbers, just ignore (e.g., first line) + } + } while (!idset.eof()); + + if (refcol != -1) { + // not using the standard "Ref", find the proper key + std::vector idx = + refcol != -1 ? makeAttributeIndex(*m_attributes, refcol) : std::vector(); + + AttributeKey dummykey(-1); + AttributeRowImpl dummyrow(*m_attributes); + + for (size_t i = 0; i < unlinks.size(); i++) { + auto iter = depthmapX::findBinary(idx, AttributeIndexItem(dummykey, unlinks[i].first, dummyrow)); + unlinks[i].first = (iter == idx.end()) ? -1 : iter->key.value; + iter = depthmapX::findBinary(idx, AttributeIndexItem(dummykey, unlinks[i].second, dummyrow)); + unlinks[i].second = (iter == idx.end()) ? -1 : iter->key.value; + } + } + for (size_t i = 0; i < unlinks.size(); i++) { + unlinkShapesByKey(unlinks[i].first, unlinks[i].second, false); + } + + int conn_col = m_attributes->getColumnIndex("Connectivity"); + if (getDisplayedAttribute() == conn_col) { + invalidateDisplayedAttribute(); + setDisplayedAttribute(conn_col); // <- reflect changes to connectivity counts + } + + return true; } -bool ShapeMap::clearLinks() -{ - for (size_t i = 0; i < m_unlinks.size(); i++) { - OrderedIntPair link = m_unlinks[i]; - m_connectors[link.a].m_connections.add(link.b); - m_connectors[link.b].m_connections.add(link.a); - } - m_unlinks.clear(); - - for (size_t j = 0; j < m_links.size(); j++) { - OrderedIntPair link = m_links[j]; - m_connectors[link.a].m_connections.remove(link.b); - m_connectors[link.b].m_connections.remove(link.a); - } - m_links.clear(); - - return true; -} +///////////////////////////////////////////////////////////////////////////////// -bool ShapeMap::unlinkShapeSet(istream& idset, int refcol) -{ - pstring line; - prefvec unlinks; - do { - IntPair unlink; - idset >> line; - if (!line.empty()) { - pvecstring tokens = line.tokenize('\t'); - if (tokens.size() < 2) { - return false; - } - try { - unlink.a = tokens[0].c_int(); - unlink.b = tokens[1].c_int(); - unlinks.push_back(unlink); - } - catch (pexception) {;} // don't do anything if it can't parse the numbers, just ignore (e.g., first line) - } - } while (!idset.eof()); - - AttributeIndex idx; - if (refcol != -1) { - idx.makeIndex(m_attributes,refcol,false); - } - - for (size_t i = 0; i < unlinks.size(); i++) { - if (refcol != -1) { - size_t x; - x = idx.searchindex(ValuePair(-1,unlinks[i].a)); - unlinks[i].a = (x == paftl::npos) ? -1 : idx[x].index; - x = idx.searchindex(ValuePair(-1,unlinks[i].b)); - unlinks[i].b = (x == paftl::npos) ? -1 : idx[x].index; - } - if (unlinks[i].a != paftl::npos && unlinks[i].b != paftl::npos) { - unlinkShapes(unlinks[i].a,unlinks[i].b,false); - } - } - - int conn_col = m_attributes.getColumnIndex("Connectivity"); - if (getDisplayedAttribute() == conn_col) { - invalidateDisplayedAttribute(); - setDisplayedAttribute(conn_col); // <- reflect changes to connectivity counts - } - - return true; +bool ShapeMap::findNextLinkLine() const { + if (m_curlinkline < (int)m_links.size()) { + m_curlinkline++; + } + return (m_curlinkline < (int)m_links.size()); } - - -///////////////////////////////////////////////////////////////////////////////// - -bool ShapeMap::findNextLinkLine() const -{ - if (m_curlinkline < (int)m_links.size()) { - m_curlinkline++; - } - return (m_curlinkline < (int)m_links.size()); +Line ShapeMap::getNextLinkLine() const { + // note, links are stored directly by rowid, not by key: + if (m_curlinkline < (int)m_links.size()) { + return Line(depthmapX::getMapAtIndex(m_shapes, m_links[m_curlinkline].a)->second.getCentroid(), + depthmapX::getMapAtIndex(m_shapes, m_links[m_curlinkline].b)->second.getCentroid()); + } + return Line(); } -Line ShapeMap::getNextLinkLine() const -{ - // note, links are stored directly by rowid, not by key: - if (m_curlinkline < (int)m_links.size()) { - return Line(m_shapes.value(m_links[m_curlinkline].a).getCentroid(), - m_shapes.value(m_links[m_curlinkline].b).getCentroid() ); - } - return Line(); +std::vector ShapeMap::getAllLinkLines() { + std::vector linkLines; + for (size_t i = 0; i < m_links.size(); i++) { + linkLines.push_back(SimpleLine(depthmapX::getMapAtIndex(m_shapes, m_links[i].a)->second.getCentroid(), + depthmapX::getMapAtIndex(m_shapes, m_links[i].b)->second.getCentroid())); + } + return linkLines; } // note: these functions would need slight work for arbitrary shape overlaps -bool ShapeMap::findNextUnlinkPoint() const -{ - if (m_curunlinkpoint < (int)m_unlinks.size()) { - m_curunlinkpoint++; - } - return (m_curunlinkpoint < (int)m_unlinks.size()); +bool ShapeMap::findNextUnlinkPoint() const { + if (m_curunlinkpoint < (int)m_unlinks.size()) { + m_curunlinkpoint++; + } + return (m_curunlinkpoint < (int)m_unlinks.size()); +} + +Point2f ShapeMap::getNextUnlinkPoint() const { + // note, links are stored directly by rowid, not by key: + if (m_curunlinkpoint < (int)m_unlinks.size()) { + return intersection_point(depthmapX::getMapAtIndex(m_shapes, m_unlinks[m_curunlinkpoint].a)->second.getLine(), + depthmapX::getMapAtIndex(m_shapes, m_unlinks[m_curunlinkpoint].b)->second.getLine(), + TOLERANCE_A); + } + return Point2f(); +} +std::vector ShapeMap::getAllUnlinkPoints() { + std::vector unlinkPoints; + for (size_t i = 0; i < m_unlinks.size(); i++) { + unlinkPoints.push_back(intersection_point(depthmapX::getMapAtIndex(m_shapes, m_unlinks[i].a)->second.getLine(), + depthmapX::getMapAtIndex(m_shapes, m_unlinks[i].b)->second.getLine(), + TOLERANCE_A)); + } + return unlinkPoints; +} + +void ShapeMap::outputUnlinkPoints(std::ofstream &stream, char delim) { + stream << "x" << delim << "y" << std::endl; + + stream.precision(12); + for (size_t i = 0; i < m_unlinks.size(); i++) { + // note, links are stored directly by rowid, not by key: + Point2f p = + intersection_point(depthmapX::getMapAtIndex(m_shapes, m_unlinks[i].a)->second.getLine(), + depthmapX::getMapAtIndex(m_shapes, m_unlinks[i].b)->second.getLine(), TOLERANCE_A); + stream << p.x << delim << p.y << std::endl; + } } -Point2f ShapeMap::getNextUnlinkPoint() const -{ - // note, links are stored directly by rowid, not by key: - if (m_curunlinkpoint < (int)m_unlinks.size()) { - return intersection_point(m_shapes.value(m_unlinks[m_curunlinkpoint].a).getLine(), - m_shapes.value(m_unlinks[m_curunlinkpoint].b).getLine(), TOLERANCE_A); - } - return Point2f(); -} +///////////////////////////////////////////////////////////////////////////////////////////////// -void ShapeMap::outputUnlinkPoints( ofstream& stream, char delim ) -{ - stream << "x" << delim << "y" << endl; - - stream.precision(12); - for (size_t i = 0; i < m_unlinks.size(); i++) { - // note, links are stored directly by rowid, not by key: - Point2f p = intersection_point(m_shapes.value(m_unlinks[i].a).getLine(), - m_shapes.value(m_unlinks[i].b).getLine(), TOLERANCE_A); - stream << p.x << delim << p.y << endl; - } -} +bool ShapeMap::makeBSPtree() const { + if (m_bsp_tree) { + return true; + } + std::vector partitionlines; + for (auto shape : m_shapes) { + if (shape.second.isLine()) { + partitionlines.push_back(TaggedLine(shape.second.getLine(), shape.first)); + } + } + if (partitionlines.size()) { + // + // Now we'll try the BSP tree: + // + if (m_bsp_root) { + delete m_bsp_root; + m_bsp_root = NULL; + } + m_bsp_root = new BSPNode(); -///////////////////////////////////////////////////////////////////////////////////////////////// + BSPTree::make(NULL, 0, partitionlines, m_bsp_root); + m_bsp_tree = true; + } -bool ShapeMap::makeBSPtree() const -{ - if (m_bsp_tree) { - return true; - } - - prefvec partitionlines; - for (size_t i = 0; i < m_shapes.size(); i++) { - if (m_shapes[i].isLine()) { - partitionlines.push_back(TaggedLine(m_shapes.value(i).getLine(),m_shapes.key(i))); - } - } - - if (partitionlines.size()) { - // - // Now we'll try the BSP tree: - // - if (m_bsp_root) { - delete m_bsp_root; - m_bsp_root = NULL; - } - m_bsp_root = new BSPNode(); - - m_bsp_root->make(NULL,0,partitionlines,NULL); - m_bsp_tree = true; - } - - partitionlines.clear(); - - return m_bsp_tree; + partitionlines.clear(); + + return m_bsp_tree; } ///////////////////////////////////////////////////////////////////////////////// @@ -3578,843 +3214,142 @@ bool ShapeMap::makeBSPtree() const //////////////////////////////////////////////////////////////////////////////////////////////// -int findwinner(double *bins, int bincount, int& difficult, int& impossible) -{ - difficult = 0; - impossible = 0; - // - double total = 0.0; - // - double maxvalue = -1.0; - int maxbin = -1; - int i; - for (i = 0; i < bincount; i++) { - if (i == 0 || bins[i] > maxvalue) { - maxvalue = bins[i]; - maxbin = i; - } - total += bins[i]; - } - if (maxvalue > total * 0.8) { - return maxbin; - } - int lastwinner = maxbin; - // no immediate clear winner, so see if across two adjacent bins: - double savebin = bins[bincount-1]; - double savebins0 = bins[0]; - for (i = 0; i < bincount - 1; i++) { - double lastbin = savebin; - savebin = bins[i]; - bins[i] += bins[i+1] + lastbin; - } - bins[bincount-1] += savebins0 + savebin; - - // now check again for a clear winner: - maxvalue = -1.0; - maxbin = -1; - for (i = 0; i < bincount; i++) { - if (i == 0 || bins[i] > maxvalue) { - maxvalue = bins[i]; - maxbin = i; - } - } - // if it's a tie, the last winner wins it: - if (maxbin != lastwinner && maxvalue == bins[lastwinner]) { - maxbin = lastwinner; - } - // - if (maxvalue > total * 0.8) { - return maxbin; - } - // - // now it's at least hard: - if (maxvalue > total * 0.6) { - difficult = 1; - return maxbin; - } - // - // if not even this is true, it's really a guess in the dark: - impossible = 1; - return maxbin; +int findwinner(double *bins, int bincount, int &difficult, int &impossible) { + difficult = 0; + impossible = 0; + // + double total = 0.0; + // + double maxvalue = -1.0; + int maxbin = -1; + int i; + for (i = 0; i < bincount; i++) { + if (i == 0 || bins[i] > maxvalue) { + maxvalue = bins[i]; + maxbin = i; + } + total += bins[i]; + } + if (maxvalue > total * 0.8) { + return maxbin; + } + int lastwinner = maxbin; + // no immediate clear winner, so see if across two adjacent bins: + double savebin = bins[bincount - 1]; + double savebins0 = bins[0]; + for (i = 0; i < bincount - 1; i++) { + double lastbin = savebin; + savebin = bins[i]; + bins[i] += bins[i + 1] + lastbin; + } + bins[bincount - 1] += savebins0 + savebin; + + // now check again for a clear winner: + maxvalue = -1.0; + maxbin = -1; + for (i = 0; i < bincount; i++) { + if (i == 0 || bins[i] > maxvalue) { + maxvalue = bins[i]; + maxbin = i; + } + } + // if it's a tie, the last winner wins it: + if (maxbin != lastwinner && maxvalue == bins[lastwinner]) { + maxbin = lastwinner; + } + // + if (maxvalue > total * 0.8) { + return maxbin; + } + // + // now it's at least hard: + if (maxvalue > total * 0.6) { + difficult = 1; + return maxbin; + } + // + // if not even this is true, it's really a guess in the dark: + impossible = 1; + return maxbin; } - // Quick mod - TV -#if defined(_WIN32) +#if defined(_MSC_VER) #include #endif -// this is similar to the ozlemSpecial version below, but puts axes into a shape layer rather than exporting -void ShapeMap::ozlemSpecial(ShapeMap& output) -{ - // output needs 4 lines per building, but this uses too much mem -- so just initialise as per buildings: - output.init(m_shapes.size(),QtRegion(m_region.bottom_left+Point2f(-50.0,-50.0),m_region.top_right+Point2f(50.0,50.0))); - - int inrefcol = m_attributes.getColumnIndex("PolyID"); - int exclcol = m_attributes.insertColumn("Poss problem"); - int outrefcol = output.m_attributes.insertColumn("BuildingPolyID"); - int outorientcol = output.m_attributes.insertColumn("Orientation"); - for (int i = 0; i < m_attributes.getRowCount(); i++) { - SalaShape& poly = m_shapes[i]; - if (!pointInPoly(poly.getCentroid(),m_shapes.key(i))) { - m_attributes.setValue(i,exclcol,1); - } - else { - m_attributes.setValue(i,exclcol,0); - } - // buildintid just used in output as key for MapInfo table - int buildintid = (int) m_attributes.getValue(i,inrefcol); - // - // put the poly edges into bins: - double bins64[16]; - size_t j; - for (j = 0; j < 16; j++) { - bins64[j] = 0; - } - Point2f start = poly[0]; - for (j = 1; j < poly.size() + 1; j++) { - Point2f end = (j != poly.size()) ? poly[j] : poly[0]; - { - Point2f vec = end - start; - double len = vec.length(); - vec.normalise(); - double ang = vec.angle(); // test angle okay - ang /= (M_PI * 0.5); - while (ang > 1) { - ang -= 1; - } - - bins64[(int)(round(ang * 16)) % 16] += len; - } - start = end; - } - int difficult = 0, impossible = 0; - int winner64 = findwinner(bins64,16,difficult,impossible); - double ang = M_PI * 0.5 * double(winner64) / 16; - Point2f axis(cos(ang),sin(ang)); - axis.scale(75.0); - for (j = 0; j < 4; j++) { - output.makeLineShape(Line(poly.getCentroid(),poly.getCentroid()+axis)); - // n.b., should be last one added, but this code is not strictly safe: - output.m_attributes.setValue(output.m_attributes.getRowCount()-1,outrefcol,(float)buildintid); - output.m_attributes.setValue(output.m_attributes.getRowCount()-1,outorientcol,(float)j); - - axis.rotate(M_PI * 0.5); - } - } - - output.invalidateDisplayedAttribute(); - output.setDisplayedAttribute(outrefcol); -} - -// expects to be the rays layer... check intersection of each ray with building polys -void ShapeMap::ozlemSpecial2(ShapeMap& buildings) -{ - int myrefcol = m_attributes.getColumnIndex("BuildingPolyID"); - int itsrefcol = buildings.m_attributes.getColumnIndex("PolyID"); - - pvecint removelist; - - size_t i; - for (i = 0; i < m_shapes.size(); i++) { - Line& li = m_shapes[i].m_region; - int buildingid = (int) m_attributes.getValue(i,myrefcol); - pvector cuts; - buildings.getShapeCuts(li, cuts); - Point2f mepoint; - bool meencountered = false, chopped = false; - if (li.width() > li.height()) { - // these are xaxis cuts - if (li.rightward()) { - // in the correct order: - for (size_t j = 0; j < cuts.size(); j++) { - int itsrowid = buildings.m_attributes.getRowid(cuts[j].index); - if (buildingid != buildings.m_attributes.getValue(itsrowid,itsrefcol)) { - Point2f newend = li.point_on_line(cuts[j].value + 0.1,XAXIS); // + 0.1 metres for tolerance later - if (!meencountered || dist(newend,mepoint) < 1.5) { - removelist.push_back(i); - } - else { - // section it here! - removePolyPixels(m_shapes.key(i)); - m_shapes[i].m_region = Line(mepoint,newend); - makePolyPixels(m_shapes.key(i)); - } - chopped = true; - break; - } - else { - mepoint = li.point_on_line(cuts[j].value - 0.1,XAXIS); // -0.1 metres for tolerance later - meencountered = true; - } - } - } - else { - // in reverse order: - for (size_t j = cuts.size() - 1; j != paftl::npos; j--) { - int itsrowid = buildings.m_attributes.getRowid(cuts[j].index); - if (buildingid != buildings.m_attributes.getValue(itsrowid,itsrefcol)) { - Point2f newend = li.point_on_line(cuts[j].value - 0.1,XAXIS); // -0.1 metres for tolerance later - if (!meencountered || dist(newend,mepoint) < 1.5) { - removelist.push_back(i); - } - else { - // section it here! - removePolyPixels(m_shapes.key(i)); - m_shapes[i].m_region = Line(mepoint,newend); - makePolyPixels(m_shapes.key(i)); - chopped = true; - } - chopped = true; - break; - } - else { - mepoint = li.point_on_line(cuts[j].value + 0.1,XAXIS); // +0.1 metres for tolerance later - meencountered = true; - } - } - } - } - else { - if (li.upward()) { - for (size_t j = 0; j < cuts.size(); j++) { - int itsrowid = buildings.m_attributes.getRowid(cuts[j].index); - if (buildingid != buildings.m_attributes.getValue(itsrowid,itsrefcol)) { - Point2f newend = li.point_on_line(cuts[j].value + 0.1,YAXIS); // +0.1 metres for tolerance later - if (!meencountered || dist(newend,mepoint) < 1.5) { - removelist.push_back(i); - } - else { - // section it here! - removePolyPixels(m_shapes.key(i)); - m_shapes[i].m_region = Line(mepoint,newend); - makePolyPixels(m_shapes.key(i)); - } - chopped = true; - break; - } - else { - mepoint = li.point_on_line(cuts[j].value - 0.1,YAXIS); // -0.1 metres for tolerance later - meencountered = true; - } - } - } - else { - // in reverse order: - for (size_t j = cuts.size() - 1; j != paftl::npos; j--) { - int itsrowid = buildings.m_attributes.getRowid(cuts[j].index); - if (buildingid != buildings.m_attributes.getValue(itsrowid,itsrefcol)) { - Point2f newend = li.point_on_line(cuts[j].value - 0.1,YAXIS); // -0.1 metres for tolerance later - if (!meencountered || dist(newend,mepoint) < 1.5) { - removelist.push_back(i); - } - else { - // section it here! - removePolyPixels(m_shapes.key(i)); - m_shapes[i].m_region = Line(mepoint,newend); - makePolyPixels(m_shapes.key(i)); - } - chopped = true; - break; - } - else { - mepoint = li.point_on_line(cuts[j].value + 0.1,YAXIS); // +0.1 metres for tolerance later - meencountered = true; - } - } - } - } - if (!chopped && meencountered) { - // section it here! - removePolyPixels(m_shapes.key(i)); - m_shapes[i].m_region = Line(mepoint,li.t_end()); - makePolyPixels(m_shapes.key(i)); - } - } - - for (i = 0; i < removelist.size(); i++) { - removePolyPixels(m_shapes.key(removelist[i])); - } - m_shapes.remove_at(removelist); - m_attributes.removeRowids(removelist); - - m_newshape = true; - m_displayed_attribute = -2; - setDisplayedAttribute(-1); -} - -// expects to be the rays layer... check intersection of each ray with *all* O.S. polys -void ShapeMap::ozlemSpecial3(ShapeMap& all) -{ - pvecint removelist; - - int intid = m_attributes.insertColumn("ExposurePolyID"); - int featcode = m_attributes.insertColumn("FeatureCode"); - - IntPair lookupcols; - lookupcols.a = all.m_attributes.getColumnIndex("PolyID"); - lookupcols.b = all.m_attributes.getColumnIndex("FeatureCode"); - - size_t i; - for (i = 0; i < m_shapes.size(); i++) { - Line& li = m_shapes[i].m_region; - pvector cuts; - all.getShapeCuts(li, cuts); - Point2f endpoint; - int state = 0; - IntPair previous; - if (li.width() > li.height()) { - // these are xaxis cuts - if (li.rightward()) { - // in the correct order: - for (size_t j = 0; j < cuts.size() && state < 2; j++) { - if (ozlemSpecial4(cuts[j],previous,state,all.m_attributes,lookupcols)) { // something of note encountered tag location: - endpoint = li.point_on_line(cuts[j].value,XAXIS); - } - } - } - else { - // in reverse order: - for (size_t j = cuts.size() - 1; j != paftl::npos && state < 2; j--) { - if (ozlemSpecial4(cuts[j],previous,state,all.m_attributes,lookupcols)) { // something of note encountered tag location: - endpoint = li.point_on_line(cuts[j].value,XAXIS); - } - } - } - } - else { - if (li.upward()) { - for (size_t j = 0; j < cuts.size() && state < 2; j++) { - if (ozlemSpecial4(cuts[j],previous,state,all.m_attributes,lookupcols)) { // something of note encountered tag location: - endpoint = li.point_on_line(cuts[j].value,YAXIS); - } - } - } - else { - // in reverse order: - for (size_t j = cuts.size() - 1; j != paftl::npos && state < 2; j--) { - if (ozlemSpecial4(cuts[j],previous,state,all.m_attributes,lookupcols)) { // something of note encountered tag location: - endpoint = li.point_on_line(cuts[j].value,YAXIS); - } - } - } - } - if (state != 0) { - // section it here! - removePolyPixels(m_shapes.key(i)); - m_shapes[i].m_region = Line(li.t_start(),endpoint); - makePolyPixels(m_shapes.key(i)); - m_attributes.setValue(i,intid,(float)previous.a); - m_attributes.setValue(i,featcode,(float)previous.b); - } - else { - // didn't encounter anything, remove it: - removelist.push_back(i); - } - } - - for (i = 0; i < removelist.size(); i++) { - removePolyPixels(m_shapes.key(removelist[i])); - } - m_shapes.remove_at(removelist); - m_attributes.removeRowids(removelist); - - m_newshape = true; - m_displayed_attribute = -2; - setDisplayedAttribute(-1); -} - -bool ShapeMap::ozlemSpecial4(ValuePair& cut, IntPair& previous, int& state, AttributeTable& table, IntPair& lookupcols) -{ - int rowid = table.getRowid(cut.index); - IntPair current; - current.a = (int)table.getValue(rowid,lookupcols.a); - current.b = (int)table.getValue(rowid,lookupcols.b); - if (current.b == 10021 || current.b == 10062 || current.b == 10185 || current.b == 10187) { - // building, glasshouse, or other building structures -- ignore, and don't alter the status: - return false; - } - if (current.b == 10053) { - if (previous.b == 10053) { - if (current.a != previous.a) { - // two adjacent parcels: finish up, and mark location: - state = 2; - return true; - } - // otherwise it's the same parcel: just ignore it - return false; - } - if (previous.b == -1) { - // first parcel cut, record and continue: - previous = current; - return false; - } - // otherwise there's been a previous feature:- only cut it if you have entered and exited the previous feature: - if (state == -1) { - state = 2; - return false; // <- cut at previous feature encounter, not this one - } - // otherwise continue as before - return false; - } - if (current.b == 10172 || current.b == 10167) { - // major feature type -- show this one, and cut here: - previous = current; - state = 2; - return true; - } - // any other code - if (previous.b == -1 || previous.b == 10053) { - // record if nothing in buffer or last was a land parcel and mark as found - previous = current; - state = 1; - return true; - } - else if (current.a == previous.a) { - state = -1; // exiting a feature: mark in case 10053 found - return false; - } - return false; -} - - - - -// expects to be the rays layer... check intersection of each ray with *all* O.S. polys -void ShapeMap::ozlemSpecial5(ShapeMap& buildings) -{ - pmap exposureranks; - exposureranks.add(10172,10); - exposureranks.add(10183,9); - exposureranks.add(10056,8); - exposureranks.add(10054,7); - exposureranks.add(10123,6); - exposureranks.add(10119,5); - exposureranks.add(10111,4); - exposureranks.add(10217,3); - exposureranks.add(10167,2); - exposureranks.add(10089,1); - exposureranks.add(10053,0); - exposureranks.add(-1,-1); - - int inorientcol = m_attributes.getColumnIndex("Orientation"); - int incodecol = m_attributes.getColumnIndex("FeatureCode"); - // - for (int ii = 0; ii < m_attributes.getRowCount(); ii++) { - int featcode = (int)m_attributes.getValue(ii,incodecol); - if (exposureranks.searchindex(featcode) == paftl::npos) { - pstring blah = pstringify(featcode,"Error: wasn't expecting feature code %d"); - // Quick mod - TV - // MessageBox(NULL,blah.c_str(),"Error: ozlemSpecial5",MB_OK|MB_ICONEXCLAMATION); - fprintf(stderr, "%s --- %s\n", blah.c_str(), "Error: ozlemSpecial5"); - return; - } - } - - int inbuildcol = m_attributes.getColumnIndex("BuildingPolyID"); - AttributeIndex idxlines; - if (inbuildcol != -1) { - idxlines.makeIndex(m_attributes,inbuildcol,false); - } - else { - // Quick mod - TV - // MessageBox(NULL,"Error: no PolyID column found in the lines table","Error: ozlemSpecial5",MB_OK|MB_ICONEXCLAMATION); - fprintf(stderr, "%s --- %s\n", "Error: no PolyID column found in the lines table", "Error: ozlemSpecial5"); - return; - } - // - int outtypecol = buildings.m_attributes.insertColumn("ExposureType"); - int outfacecol = buildings.m_attributes.insertColumn("FacesExposed"); - int outprimcol = buildings.m_attributes.insertColumn("PrimaryExposure"); - int outsecocol = buildings.m_attributes.insertColumn("SecondaryExposure"); - - int outbuildcol = buildings.m_attributes.getColumnIndex("PolyID"); - AttributeIndex idxbuildings; - if (outbuildcol != -1) { - idxbuildings.makeIndex(buildings.m_attributes,outbuildcol,false); - } - else { - // Quick mod - TV - // MessageBox(NULL,"Error: no PolyID column found in the buildings table","Error: ozlemSpecial5",MB_OK|MB_ICONEXCLAMATION); - fprintf(stderr, "%s --- %s\n", "Error: no PolyID column found in the buildings table","Error: ozlemSpecial5"); - return; - } - - - // Quick mod - TV - // MessageBox(NULL,"Message: about to start main loop","Message: ozlemSpecial5",MB_OK|MB_ICONINFORMATION); - fprintf(stderr, "%s --- %s\n", "Message: about to start main loop","Message: ozlemSpecial5"); - - int start = 0; - for (size_t i = 1; i <= idxlines.size(); i++) { - if (idxlines.size() == i || idxlines[i].value != idxlines[start].value) { - ValuePair buildinglkup; - buildinglkup.value = idxlines[start].value; - size_t idxb = idxbuildings.searchindex(buildinglkup); - if (idxb == paftl::npos) { - pstring blah = pstringify(idxlines[start].value,"Error: couldn't find PolyID %d in Buildings table"); - // Quick mod - TV - // MessageBox(NULL,blah.c_str(),"Error: ozlemSpecial5",MB_OK|MB_ICONEXCLAMATION); - fprintf(stderr, "%s --- %s\n",blah.c_str(),"Error: ozlemSpecial5"); - return; - } - int browid = idxbuildings[idxb].index; - // process: stage 1, orientation -- note orient is *ordered* - pvector exposurelist; - int risks = 0; - for (size_t j = start; j < i; j++) { - int feature = (int)m_attributes.getValue(idxlines[j].index,incodecol); - int orientation = (int)m_attributes.getValue(idxlines[j].index,inorientcol); - if (feature != 10053) { // don't count parcel boundaries towards exposure - exposurelist.add(IntPair(orientation,feature)); - } - } - if (exposurelist.size() == 0) { - buildings.m_attributes.setValue(browid,outfacecol,0); - buildings.m_attributes.setValue(browid,outtypecol,0); - } - else { - switch (exposurelist.size()) { - case 1: - buildings.m_attributes.setValue(browid,outfacecol,1); - buildings.m_attributes.setValue(browid,outtypecol,1); - buildings.m_attributes.setValue(browid,outprimcol,(float)exposurelist[0].b); - break; - case 2: - buildings.m_attributes.setValue(browid,outfacecol,2); - if ((exposurelist[0].a + 2) % 4 == exposurelist[1].a) { - buildings.m_attributes.setValue(browid,outtypecol,2); - } - else { - buildings.m_attributes.setValue(browid,outtypecol,3); - } - if (exposureranks.search(exposurelist[0].b) > exposureranks.search(exposurelist[1].b)) { - buildings.m_attributes.setValue(browid,outprimcol,(float)exposurelist[0].b); - buildings.m_attributes.setValue(browid,outsecocol,(float)exposurelist[1].b); - } - else { - buildings.m_attributes.setValue(browid,outprimcol,(float)exposurelist[1].b); - buildings.m_attributes.setValue(browid,outsecocol,(float)exposurelist[0].b); - } - break; - case 3: - { - buildings.m_attributes.setValue(browid,outfacecol,3); - bool rearexposed = false; - int prim = -1, seco = -1; - for (int i = 0; i < 3; i++) { - if (exposurelist[i].b == 10172) { - if (exposurelist[(i+1)%3].a == (exposurelist[i].a + 2) % 2 || - exposurelist[(i+2)%3].a == (exposurelist[i].a + 2) % 2) { - rearexposed = true; - } - } - if (exposureranks.search(exposurelist[i].b) > exposureranks.search(prim)) { - seco = prim; - prim = exposurelist[i].b; - } - else if (exposureranks.search(exposurelist[i].b) > exposureranks.search(seco)) { - seco = exposurelist[i].b; - } - } - buildings.m_attributes.setValue(browid,outtypecol,(float)(rearexposed?4:3)); - buildings.m_attributes.setValue(browid,outprimcol,(float)prim); - buildings.m_attributes.setValue(browid,outsecocol,(float)seco); - } - break; - case 4: - { - buildings.m_attributes.setValue(browid,outfacecol,4); - buildings.m_attributes.setValue(browid,outtypecol,4); - int prim = -1, seco = -1; - for (int i = 0; i < 4; i++) { - if (exposureranks.search(exposurelist[i].b) > exposureranks.search(prim)) { - seco = prim; - prim = exposurelist[i].b; - } - else if (exposureranks.search(exposurelist[i].b) > exposureranks.search(seco)) { - seco = exposurelist[i].b; - } - } - buildings.m_attributes.setValue(browid,outprimcol,(float)prim); - buildings.m_attributes.setValue(browid,outsecocol,(float)seco); - } - break; - } - } - start = i; - } - } - - // Quick mod - TV - // MessageBox(NULL,"Message: finished main loop","Message: ozlemSpecial5",MB_OK|MB_ICONINFORMATION); - fprintf(stderr, "%s --- %s\n","Message: finished main loop","Message: ozlemSpecial5"); - - buildings.m_displayed_attribute = -2; - buildings.setDisplayedAttribute(outtypecol); -} - -void ShapeMap::ozlemSpecial6() // ShapeMap& border) -{ - int count = 0; - int delcol = m_attributes.insertColumn("Delete"); - int dupcol = m_attributes.insertColumn("Duplicate"); - for (size_t i = 0; i < m_shapes.size(); i++) { - bool duplicate = false; - bool tag_delete = false; - PixelRef p = pixelate(m_shapes[i].getPoint()); - pqvector& sr = m_pixel_shapes[p.x][p.y]; - for (size_t j = 0; j < sr.size(); j++) { - if (sr[j].m_shape_ref != m_shapes.key(i)) { - if (m_shapes[i].getPoint() == m_shapes.search(sr[j].m_shape_ref).getPoint()) { - duplicate = true; - - // Quick mod - TV - if ((unsigned int)m_shapes.key(i) > sr[j].m_shape_ref) { - tag_delete = true; - } - } - } - } - if (duplicate) { - m_attributes.setValue(i,dupcol,1.0); - count++; - } - else { - m_attributes.setValue(i,dupcol,0.0); - } - if (tag_delete) { - m_attributes.setValue(i,delcol,1.0); - } - else { - m_attributes.setValue(i,delcol,0.0); - } - } - pstring blah; - blah = pstringify(count,"%d duplicates found"); - - // Quick mod - TV - // MessageBox(NULL,blah.c_str(),"Message: ozlemSpecial6",MB_OK|MB_ICONINFORMATION); - fprintf(stderr, "%s --- %s\n",blah.c_str(),"Message: ozlemSpecial6"); - - /* - pvecint removelist; - - for (i = 0; i < m_shapes.size(); i++) { - if (m_attributes.getValue(i,delcol) == 1.0) { - removelist.push_back(i); - } - else { - Point2f& p = m_shapes[i].getPoint(); - if (border.m_region.contains(p) && border.pointInPoly(p,0)) { - removelist.push_back(i); - } - } - } - - MessageBox(NULL,"Message: point in poly test complete","Message: ozlemSpecial6",MB_OK|MB_ICONINFORMATION); - - - for (i = 0; i < removelist.size(); i++) { - removePolyPixels(m_shapes.key(removelist[i])); - } - m_shapes.remove_at(removelist); - m_attributes.removeRowids(removelist); - */ -} - -/* -void ShapeMap::ozlemSpecial(ostream& file) -{ - int imposcount = 0; - int diffcount = 0; - int diffcol = m_attributes.insertColumn("Difficult"); - int imposcol = m_attributes.insertColumn("Impossible"); - int refcol = m_attributes.getColumnIndex("BuildIDInt"); - for (int i = 0; i < m_attributes.getRowCount(); i++) { - // buildintid just used in output as key for MapInfo table - int buildintid = m_attributes.getValue(i,refcol); - // put the poly edges into bins: - double bins32[8]; - double bins72[18]; - for (int j = 0; j < 8; j++) { - bins32[j] = 0; - } - for (j = 0; j < 18; j++) { - bins72[j] = 0; - } - SalaShape& poly = m_shapes[i]; - Point2f start = poly[0]; - for (j = 1; j < poly.size() + 1; j++) { - Point2f end = (j != poly.size()) ? poly[j] : poly[0]; - { - Point2f vec = end - start; - double len = vec.length(); - vec.normalise(); - double ang = vec.angle(); // test angle okay - ang /= (M_PI * 0.5); - while (ang > 1) { - ang -= 1; - } - bins32[round(ang * 8) % 8] += len; - bins72[round(ang * 18) % 18] += len; - } - start = end; - } - int difficult = 0, impossible = 0; - int winner72 = findwinner(bins72,18,difficult,impossible); - int winner32 = findwinner(bins32,8,difficult,impossible); - file << buildintid << "\t"; - double bearing = double((8 - winner32) % 8) * 11.25; - for (j = 0; j < 4; j++) { - file << bearing << "\t"; - bearing += 90; - } - bearing = double((18 - winner72) % 18) * 5; - for (j = 0; j < 4; j++) { - file << bearing << "\t"; - bearing += 90; - } - file << difficult << "\t" << impossible << endl; - if (difficult) { - m_attributes.setValue(i,diffcol,1); - diffcount += 1; - } - else { - m_attributes.setValue(i,diffcol,0); - } - if (impossible) { - m_attributes.setValue(i,imposcol,1); - imposcount += 1; - } - else { - m_attributes.setValue(i,imposcol,0); - } - } - - // let me know: - pstring di = pstringify(diffcount,"Difficult %d, "); - pstring im = pstringify(imposcount,"Impossible %d"); - pstring out = di + im; - MessageBox(NULL,out.c_str(),"Success: ozlemSpecial",MB_OK|MB_ICONINFORMATION); - - m_displayed_attribute = -2; - setDisplayedAttribute(imposcol); -} -*/ -/* -void ShapeMap::ozlemSpecial(ostream& file, ShapeMap& linemap) -{ - int refcol = m_attributes.getColumnIndex("BuildIDInt"); - AttributeIndex idxbuildings; - if (refcol != -1) { - idxbuildings.makeIndex(m_attributes,refcol,false); - } - else { - MessageBox(NULL,"Error: no BuildIDInt column found in the points table","Error: ozlemSpecial",MB_OK|MB_ICONEXCLAMATION); - return; - } - AttributeIndex idxlines; - int ref2col = linemap.m_attributes.getColumnIndex("Rdctr_id"); - if (ref2col != -1) { - idxlines.makeIndex(linemap.m_attributes,ref2col,false); - } - else { - MessageBox(NULL,"Error: no Rdctr_id column found in the line table","Error: ozlemSpecial",MB_OK|MB_ICONEXCLAMATION); - return; - } - int lookupcol = m_attributes.getColumnIndex("Rdctr_id"); - if (lookupcol == -1) { - MessageBox(NULL,"Error: no Rdctr_id column found in the building table","Error: ozlemSpecial",MB_OK|MB_ICONEXCLAMATION); - return; - } - - int errors = 0; - int curbuilding = idxbuildings[0].value; - int start = 0; - for (int i = 1; i <= idxbuildings.size(); i++) { - if (i == idxbuildings.size() || curbuilding != idxbuildings[i].value) { - { - if (curbuilding == 298613) { - cerr << "pause"; - } - // do intercheck here: - bool found = false, error = false; - IntPair couplet; - double ang; - for (int j = start; j < i && !found && !error; j++) { - for (int k = j + 1; k < i && !found && !error; k++) { - ValuePair linelkup1; - linelkup1.value = m_attributes.getValue(idxbuildings[j].index,lookupcol); - ValuePair linelkup2; - linelkup2.value = m_attributes.getValue(idxbuildings[k].index,lookupcol); - size_t lineref1ind = idxlines.searchindex(linelkup1); - size_t lineref2ind = idxlines.searchindex(linelkup2); - if (lineref1ind == paftl::npos || lineref2ind == paftl::npos) { - error = true; - break; - } - ValuePair lineref1 = idxlines.at(lineref1ind); - ValuePair lineref2 = idxlines.at(lineref2ind); - if ((lineref1.value == 213308 && lineref2.value == 213310) || (lineref2.value == 213308 && lineref1.value == 213310)) { - cerr << "pause 2"; - } - const Line& line1 = linemap.m_shapes[lineref1.index].getLine(); - const Line& line2 = linemap.m_shapes[lineref2.index].getLine(); - const Point2f& p1 = m_shapes[idxbuildings[j].index].getPoint(); - const Point2f& p2 = m_shapes[idxbuildings[k].index].getPoint(); - Point2f pn1 = line1.vector(); - pn1.normalise(); - Point2f pn2 = line2.vector(); - pn2.normalise(); - if (fabs(dot(pn1,pn2)) < 0.99) { // parallel lines confuse this script with their intersection points - Point2f p3 = intersection_point(line1,line2,1e-9); - ang = angle(p1,p3,p2); - if (ang < 2.35619449) { // 135 degrees - found = true; - couplet.a = linelkup1.value; - couplet.b = linelkup2.value; - } - } - } - } - if (found) { - file << curbuilding << "\t" << couplet.a << "\t" << couplet.b << "\t" << ang << endl; - } - else if (error) { - errors++; - } - } - if (i == idxbuildings.size()) { - break; - } - start = i; - curbuilding = idxbuildings[i].value; - } - } - if (errors) { - pstring errormsg = pstringify(errors,"There were %d cases where a point did not have an associated line"); - MessageBox(NULL,errormsg.c_str(),"Error: ozlemSpecial",MB_OK|MB_ICONEXCLAMATION); - return; - - } - else { - MessageBox(NULL,"Successfully completed ozlemSpecial function","Success: ozlemSpecial",MB_OK|MB_ICONINFORMATION); - } -} -*/ - -// expects to be the points layer... expects passed map to be lines layer -void ShapeMap::ozlemSpecial7(ShapeMap& linemap) -{ - int linerefcol = m_attributes.insertColumn("Line Ref"); - - for (size_t i = 0; i < m_shapes.size(); i++) { - Point2f p = m_shapes[i].getPoint(); - int index = linemap.getClosestLine(p); - m_attributes.setValue(i,linerefcol,(float)index); - } - - m_displayed_attribute = -2; - setDisplayedAttribute(linerefcol); +std::vector ShapeMap::getAllShapesAsLines() const { + std::vector lines; + const std::map &allShapes = getAllShapes(); + for (auto refShape : allShapes) { + SalaShape &shape = refShape.second; + if (shape.isLine()) { + lines.push_back(SimpleLine(shape.getLine())); + } else if (shape.isPolyLine() || shape.isPolygon()) { + for (size_t n = 0; n < shape.m_points.size() - 1; n++) { + lines.push_back(SimpleLine(shape.m_points[n], shape.m_points[n + 1])); + } + if (shape.isPolygon()) { + lines.push_back(SimpleLine(shape.m_points.back(), shape.m_points.front())); + } + } + } + return lines; +} + +std::vector> ShapeMap::getAllLinesWithColour() { + std::vector> colouredLines; + std::map &allShapes = getAllShapes(); + int k = -1; + for (auto &refShape : allShapes) { + k++; + SalaShape &shape = refShape.second; + PafColor colour(dXreimpl::getDisplayColor(AttributeKey(refShape.first), + m_attributes->getRow(AttributeKey(refShape.first)), + *m_attribHandle.get(), true)); + if (shape.isLine()) { + colouredLines.push_back(std::pair(SimpleLine(shape.getLine()), colour)); + } else if (shape.isPolyLine()) { + for (size_t n = 0; n < shape.m_points.size() - 1; n++) { + colouredLines.push_back( + std::pair(SimpleLine(shape.m_points[n], shape.m_points[n + 1]), colour)); + } + } + } + return colouredLines; +} + +std::map, PafColor> ShapeMap::getAllPolygonsWithColour() { + std::map, PafColor> colouredPolygons; + std::map &allShapes = getAllShapes(); + for (auto &refShape : allShapes) { + SalaShape &shape = refShape.second; + if (shape.isPolygon()) { + std::vector vertices; + for (size_t n = 0; n < shape.m_points.size(); n++) { + vertices.push_back(shape.m_points[n]); + } + vertices.push_back(shape.m_points.back()); + PafColor colour(dXreimpl::getDisplayColor(AttributeKey(refShape.first), + m_attributes->getRow(AttributeKey(refShape.first)), + *m_attribHandle.get(), true)); + colouredPolygons.insert(std::make_pair(vertices, colour)); + } + } + return colouredPolygons; +} + +std::vector> ShapeMap::getAllPointsWithColour() { + std::vector> colouredPoints; + std::map &allShapes = getAllShapes(); + for (auto &refShape : allShapes) { + SalaShape &shape = refShape.second; + if (shape.isPoint()) { + PafColor colour(dXreimpl::getDisplayColor(AttributeKey(refShape.first), + m_attributes->getRow(AttributeKey(refShape.first)), + *m_attribHandle.get(), true)); + colouredPoints.push_back(std::make_pair(shape.getCentroid(), colour)); + } + } + return colouredPoints; } diff --git a/salalib/shapemap.h b/salalib/shapemap.h index 9ef50a8b..f5b1ffb7 100644 --- a/salalib/shapemap.h +++ b/salalib/shapemap.h @@ -14,683 +14,617 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . - // This is my code to make a set of axial lines from a set of boundary lines -#ifndef __SHAPEMAP_H__ -#define __SHAPEMAP_H__ +#pragma once -///////////////////////////////////////////////////////////////////////////////////////////////// +#include "salalib/attributetable.h" +#include "salalib/attributetablehelpers.h" +#include "salalib/attributetableview.h" +#include "salalib/connector.h" +#include "salalib/importtypedefs.h" +#include "salalib/layermanagerimpl.h" +#include "salalib/parsers/mapinfodata.h" +#include "salalib/spacepix.h" + +#include "genlib/bsptree.h" +#include "genlib/containerutils.h" +#include "genlib/p2dpoly.h" +#include "genlib/readwritehelpers.h" +#include "genlib/stringutils.h" + +#include +#include +#include +#include // each pixel has various lists of information: -struct ShapeRef -{ - enum {SHAPE_REF_NULL = 0xFFFFFFFF}; - enum {SHAPE_L = 0x01, SHAPE_B = 0x02, SHAPE_R = 0x04, SHAPE_T = 0x08 }; - enum {SHAPE_EDGE = 0x0f, SHAPE_INTERNAL_EDGE = 0x10, SHAPE_CENTRE = 0x20, SHAPE_OPEN = 0x40 }; - unsigned char m_tags; - unsigned int m_shape_ref; - psubvec m_polyrefs; - ShapeRef( unsigned int sref = SHAPE_REF_NULL, unsigned char tags = 0x00 ) - { m_shape_ref = sref; m_tags = tags; } - friend bool operator == (const ShapeRef& a, const ShapeRef& b); - friend bool operator != (const ShapeRef& a, const ShapeRef& b); - friend bool operator < (const ShapeRef& a, const ShapeRef& b); - friend bool operator > (const ShapeRef& a, const ShapeRef& b); +struct ShapeRef { + enum { SHAPE_REF_NULL = 0xFFFFFFFF }; + enum { SHAPE_L = 0x01, SHAPE_B = 0x02, SHAPE_R = 0x04, SHAPE_T = 0x08 }; + enum { SHAPE_EDGE = 0x0f, SHAPE_INTERNAL_EDGE = 0x10, SHAPE_CENTRE = 0x20, SHAPE_OPEN = 0x40 }; + unsigned char m_tags; + unsigned int m_shape_ref; + std::vector m_polyrefs; + ShapeRef(unsigned int sref = SHAPE_REF_NULL, unsigned char tags = 0x00) { + m_shape_ref = sref; + m_tags = tags; + } + friend bool operator==(const ShapeRef &a, const ShapeRef &b); + friend bool operator!=(const ShapeRef &a, const ShapeRef &b); + friend bool operator<(const ShapeRef &a, const ShapeRef &b); + friend bool operator>(const ShapeRef &a, const ShapeRef &b); +}; +inline bool operator==(const ShapeRef &a, const ShapeRef &b) { return a.m_shape_ref == b.m_shape_ref; } +inline bool operator!=(const ShapeRef &a, const ShapeRef &b) { return a.m_shape_ref != b.m_shape_ref; } +inline bool operator<(const ShapeRef &a, const ShapeRef &b) { return a.m_shape_ref < b.m_shape_ref; } +inline bool operator>(const ShapeRef &a, const ShapeRef &b) { return a.m_shape_ref > b.m_shape_ref; } + +struct ShapeRefHash { + public: + size_t operator()(const ShapeRef &shapeRef) const { return shapeRef.m_shape_ref; } }; -inline bool operator == (const ShapeRef& a, const ShapeRef& b) -{ return a.m_shape_ref == b.m_shape_ref; } -inline bool operator != (const ShapeRef& a, const ShapeRef& b) -{ return a.m_shape_ref != b.m_shape_ref; } -inline bool operator < (const ShapeRef& a, const ShapeRef& b) -{ return a.m_shape_ref < b.m_shape_ref; } -inline bool operator > (const ShapeRef& a, const ShapeRef& b) -{ return a.m_shape_ref > b.m_shape_ref; } ///////////////////////////////////////////////////////////////////////////////////////////////// // this is a helper for cutting polygons to fit a viewport / cropping frame -struct SalaEdgeU : public EdgeU -{ - int index; - bool entry; // or exit - SalaEdgeU() : EdgeU() - { index = -1; entry = false; } - SalaEdgeU(int i, bool e, const EdgeU& eu) : EdgeU(eu) - { index = i; entry = e; } +struct SalaEdgeU : public EdgeU { + int index; + bool entry; // or exit + SalaEdgeU() : EdgeU() { + index = -1; + entry = false; + } + SalaEdgeU(int i, bool e, const EdgeU &eu) : EdgeU(eu) { + index = i; + entry = e; + } }; ///////////////////////////////////////////////////////////////////////////////////////////////// class PointMap; -class SalaShape : public pqvector -{ -public: - enum {SHAPE_POINT = 0x01, SHAPE_LINE = 0x02, SHAPE_POLY = 0x04, SHAPE_CIRCLE = 0x08, SHAPE_TYPE = 0x0f, SHAPE_CLOSED = 0x40, SHAPE_CCW = 0x80 }; - friend class ShapeMap; -protected: - unsigned char m_type; - Point2f m_centroid; // centre of mass, but also used as for point if object is a point - Line m_region; // bounding box, but also used as a line if object is a line, hence type - double m_area; - double m_perimeter; - // these are all temporary data which are recalculated on reload - mutable bool m_selected; - mutable float m_color; - mutable int m_draworder; -public: - SalaShape(unsigned char type = 0) - { m_type = type; m_draworder = -1; m_selected = false; m_area = 0.0; m_perimeter = 0.0; } - SalaShape(const Point2f& point) - { m_type = SHAPE_POINT; m_draworder = -1; m_selected = false; m_region = Line(point,point); m_centroid = point; m_area = 0.0; m_perimeter = 0.0; } - SalaShape(const Line& line) - { m_type = SHAPE_LINE; m_draworder = -1; m_selected = false; m_region = line; m_centroid = m_region.getCentre(); m_area = 0.0; m_perimeter = m_region.length(); } - // - bool isOpen() const - { return (m_type & SHAPE_CLOSED) == 0; } - bool isClosed() const - { return (m_type & SHAPE_CLOSED) == SHAPE_CLOSED; } - bool isPoint() const - { return (m_type == SHAPE_POINT); } - bool isLine() const - { return (m_type == SHAPE_LINE); } - bool isPolyLine() const - { return (m_type & (SHAPE_POLY | SHAPE_CLOSED)) == SHAPE_POLY; } - bool isPolygon() const - { return (m_type & (SHAPE_POLY | SHAPE_CLOSED)) == (SHAPE_POLY | SHAPE_CLOSED); } - bool isCCW() const - { return (m_type & SHAPE_CCW) == SHAPE_CCW; } - // - const Point2f& getPoint() const - { return m_centroid; } - const Line& getLine() const - { return m_region; } - const QtRegion& getBoundingBox() const - { return m_region; } - // - double getArea() const - { return m_area; } - double getPerimeter() const - { return m_perimeter; } - // duplicate function, but easier to understand naming convention - double getLength() const - { return m_perimeter; } - // - void setCentroidAreaPerim(); - void setCentroid(const Point2f& p); - // duplicate function, but easier to understand naming convention - const Point2f& getCentroid() const - { return m_centroid; } - // - double getAngDev() const; - // - pqvector getClippingSet(QtRegion& clipframe) const; - // - bool read(ifstream& stream, int version); - bool write(ofstream& stream); -}; +class SalaShape { + public: + std::vector m_points; + enum { + SHAPE_POINT = 0x01, + SHAPE_LINE = 0x02, + SHAPE_POLY = 0x04, + SHAPE_CIRCLE = 0x08, + SHAPE_TYPE = 0x0f, + SHAPE_CLOSED = 0x40, + SHAPE_CCW = 0x80 + }; + friend class ShapeMap; -///////////////////////////////////////////////////////////////////////////////////////////////// + protected: + unsigned char m_type; + Point2f m_centroid; // centre of mass, but also used as for point if object is a point + Line m_region; // bounding box, but also used as a line if object is a line, hence type + double m_area; + double m_perimeter; + // these are all temporary data which are recalculated on reload + mutable bool m_selected; + mutable float m_color; + mutable int m_draworder; -class SalaObject : public pvecint -{ - friend class ShapeMap; -protected: - Point2f m_centroid; -public: - SalaObject() {;} - // - bool read(ifstream& stream, int version); - bool write(ofstream& stream); -}; -inline bool SalaObject::read(ifstream& stream, int) -{ - stream.read((char *)&m_centroid,sizeof(m_centroid)); - pvecint::read(stream); - return true; -} -inline bool SalaObject::write(ofstream& stream) -{ - stream.write((char *)&m_centroid,sizeof(m_centroid)); - pvecint::write(stream); - return true; -} + public: + SalaShape(unsigned char type = 0) { + m_type = type; + m_draworder = -1; + m_selected = false; + m_area = 0.0; + m_perimeter = 0.0; + } + SalaShape(const Point2f &point) { + m_type = SHAPE_POINT; + m_draworder = -1; + m_selected = false; + m_region = Line(point, point); + m_centroid = point; + m_area = 0.0; + m_perimeter = 0.0; + } + SalaShape(const Line &line) { + m_type = SHAPE_LINE; + m_draworder = -1; + m_selected = false; + m_region = line; + m_centroid = m_region.getCentre(); + m_area = 0.0; + m_perimeter = m_region.length(); + } + // + bool isOpen() const { return (m_type & SHAPE_CLOSED) == 0; } + bool isClosed() const { return (m_type & SHAPE_CLOSED) == SHAPE_CLOSED; } + bool isPoint() const { return (m_type == SHAPE_POINT); } + bool isLine() const { return (m_type == SHAPE_LINE); } + bool isPolyLine() const { return (m_type & (SHAPE_POLY | SHAPE_CLOSED)) == SHAPE_POLY; } + bool isPolygon() const { return (m_type & (SHAPE_POLY | SHAPE_CLOSED)) == (SHAPE_POLY | SHAPE_CLOSED); } + bool isCCW() const { return (m_type & SHAPE_CCW) == SHAPE_CCW; } + // + const Point2f &getPoint() const { return m_centroid; } + const Line &getLine() const { return m_region; } + const QtRegion &getBoundingBox() const { return m_region; } + // + double getArea() const { return m_area; } + double getPerimeter() const { return m_perimeter; } + // duplicate function, but easier to understand naming convention + double getLength() const { return m_perimeter; } + // + void setCentroidAreaPerim(); + void setCentroid(const Point2f &p); + // duplicate function, but easier to understand naming convention + const Point2f &getCentroid() const { return m_centroid; } + // + double getAngDev() const; + // + std::vector getClippingSet(QtRegion &clipframe) const; + // + bool read(std::istream &stream); + bool write(std::ofstream &stream); -///////////////////////////////////////////////////////////////////////////////////////////////// - -struct Connector; + std::vector getAsLines() const { + std::vector lines; + if (isLine()) { + lines.push_back(getLine()); + } else if (isPolyLine() || isPolygon()) { + for (size_t j = 0; j < m_points.size() - 1; j++) { + lines.push_back(Line(m_points[j], m_points[j + 1])); + } + if (isClosed()) { + lines.push_back(Line(m_points[m_points.size() - 1], m_points[0])); + } + } + return lines; + } +}; ///////////////////////////////////////////////////////////////////////////////////////////////// -struct SalaEvent -{ - enum { SALA_NULL_EVENT, SALA_CREATED, SALA_DELETED, SALA_MOVED }; - int m_action; - int m_shape_ref; - SalaShape m_geometry; - SalaEvent(int action = SALA_NULL_EVENT, int shape_ref = -1) { m_action = action; m_shape_ref = shape_ref; } +struct SalaEvent { + enum { SALA_NULL_EVENT, SALA_CREATED, SALA_DELETED, SALA_MOVED }; + int m_action; + int m_shape_ref; + SalaShape m_geometry; + SalaEvent(int action = SALA_NULL_EVENT, int shape_ref = -1) { + m_action = action; + m_shape_ref = shape_ref; + } }; ///////////////////////////////////////////////////////////////////////////////////////////////// // Quick mod - TV class MapInfoData; -class ShapeMap : public PixelBase -{ - friend class AxialMaps; - friend class MapInfoData; -public: - // now shapemaps cover a multitude of different types, record here: - // (note, allline maps are automatically generated and have extra information recorded for line reduction) - // Do not change numeric values! They are saved to file. - // Note the Pesh map does auto-overlap of shape-shape (yet...), so can be used for an arbitrary shape map - enum { EMPTYMAP = 0x0000, DRAWINGMAP = 0x0001, DATAMAP = 0x0002, POINTMAP = 0x0004, CONVEXMAP = 0x0008, - ALLLINEMAP = 0x0010, AXIALMAP = 0x0020, SEGMENTMAP = 0x0040, PESHMAP = 0x0080, LINEMAP = 0x0070 }; - enum { COPY_NAME = 0x0001, COPY_GEOMETRY = 0x0002, COPY_ATTRIBUTES = 0x0004, COPY_GRAPH = 0x0008, COPY_ALL = 0x000f }; -protected: - pstring m_name; - int m_map_type; - bool m_hasgraph; - // counters - int m_obj_ref; - int m_shape_ref; - mutable bool m_newshape; // if a new shape has been added - // - // quick grab for shapes - pqvector **m_pixel_shapes; // i rows of j columns - // - // allow quick closest line test (note only works for a given layer, with many layers will be tricky) - mutable BSPNode *m_bsp_root; - mutable bool m_bsp_tree; - // - pqmap m_shapes; - pqmap m_objects; // THIS IS UNUSED! Meant for each object to have many shapes - // - prefvec m_undobuffer; - // - AttributeTable m_attributes; - // - // for graph functionality - // Note: this list is stored PACKED for optimal performance on graph analysis - // ALWAYS check it is in the same order as the shape list and attribute table - prefvec m_connectors; - // - // for geometric operations - double m_tolerance; - // for screen drawing - mutable int *m_display_shapes; - mutable int m_current; - mutable bool m_invalidate; - // -public: - ShapeMap(const pstring& name = pstring(),int type = EMPTYMAP); - virtual ~ShapeMap(); - void copy(const ShapeMap& shapemap, int copyflags = 0); - void clearAll(); - // - // num objects - const size_t getObjectCount() const - { return m_objects.size(); } - // num shapes total - const size_t getShapeCount() const - { return m_shapes.size(); } - // num shapes for this object (note, request by object rowid - // -- on interrogation, this is what you will usually receive) - const size_t getShapeCount(int rowid) const - { return m_shapes.value(rowid).size(); } - // - int getIndex(int rowid) const - { return m_shapes.key(rowid); } - // - // add shape tools - void makePolyPixels(int shaperef); - void shapePixelBorder(pmap& relations, int shaperef, int side, PixelRef currpix, PixelRef minpix, bool first); - // remove shape tools - void removePolyPixels(int shaperef); - // - // - void init(int size, const QtRegion& r); - // convert a single point into a shape - int makePointShape(const Point2f& point, bool tempshape = false); - // or a single line into a shape - int makeLineShape(const Line& line, bool through_ui = false, bool tempshape = false); - // or a polygon into a shape - int makePolyShape(const pvecpoint& points, bool open, bool tempshape = false); -public: - // or make a shape from a shape - int makeShape(const SalaShape& shape, int override_shape_ref = -1); - // convert points to polygons - bool convertPointsToPolys(double poly_radius, bool selected_only); - // convert a selected pixels to a layer object (note, uses selection attribute on pixel, you must select to make this work): - int makeShapeFromPointSet(const PointMap& pointmap); - // - // move a shape (currently only a line shape) -- in the future should use SalaShape - bool moveShape(int shaperef, const Line& line, bool undoing = false); - // delete selected shapes - void removeSelected(); - // delete a shape - void removeShape(int shaperef, bool undoing = false); - // - void setShapeAttributes(int rowid, const SalaShape& shape); - // - // some UI polygon creation tools: - int polyBegin(const Line& line); - bool polyAppend(const Point2f& point); - bool polyClose(); - bool polyCancel(); - // some shape creation tools for the scripting language or DLL interface -protected: - pvecpoint m_temppoints; -public: - // add a shape (does not commit to poly pixels) - void shapeBegin(); - void shapeVertex(const Point2f& p); - int shapeEnd(bool close); - // this simply adds all shapes to the poly pixels - void shapesCommit(); - // - bool canUndo() const - { return m_undobuffer.size() != 0; } - void undo(); - // - // helpers: - Point2f pointOffset(const PointMap& pointmap, int currpix, int side); - int moveDir(int side); - // - void pointPixelBorder(const PointMap& pointmap, pmap& relations, SalaShape& shape, int side, PixelRef currpix, PixelRef minpix, bool first); - // quick find of topmost poly from a point (bit too inaccurate!) - int quickPointInPoly(const Point2f& p) const; - // slower point in topmost poly test: - int pointInPoly(const Point2f& p) const; - // test if point is inside a particular shape - bool pointInPoly(const Point2f& p, int shaperef) const; - // retrieve lists of polys point intersects: - void pointInPolyList(const Point2f& p, pvecint& shapeindexlist) const; - void lineInPolyList(const Line& li, pvecint& shapeindexlist, int lineref = -1, double tolerance = 0.0) const; - void polyInPolyList(int polyref, pvecint& shapeindexlist, double tolerance = 0.0) const; - void shapeInPolyList(const SalaShape& shape, pvecint& shapeindexlist); - // helper to make actual test of point in shape: - int testPointInPoly(const Point2f& p, const ShapeRef& shape) const; - // also allow look for a close polyline: - int getClosestOpenGeom(const Point2f& p) const; - // this version uses a BSP tree to find closest line (currently only line shapes) - int getClosestLine(const Point2f& p) const; - // this version simply finds the closest vertex to the point - Point2f getClosestVertex(const Point2f& p) const; - // Find out which shapes a line cuts through: - void getShapeCuts(const Line& li_orig, pvector& cuts); - // Cut a line according to the first shape it cuts - void cutLine(Line& li);//, short dir); - // Find out which shapes are within a certain radius of a point: - int withinRadius(const Point2f& p, double radius, pvecint& bufferset); - // Connect a particular shape into the graph - int connectIntersected(int rowid, bool linegraph); - // Get the connections for a particular line - int getLineConnections(int lineref, pvecint& connections, double tolerance); - // Get arbitrary shape connections for a particular shape - int getShapeConnections(int polyref, pvecint& connections, double tolerance); - // Make all connections - void makeShapeConnections(); - // - bool makeBSPtree() const; - // - const prefvec& getConnections() const - { return m_connectors; } - // - bool isAllLineMap() const - { return m_map_type == ALLLINEMAP; } - bool isSegmentMap() const - { return m_map_type == SEGMENTMAP; } - bool isAxialMap() const - { return m_map_type == ALLLINEMAP || m_map_type == AXIALMAP; } - bool isPeshMap() const - { return m_map_type == PESHMAP; } - int getMapType() const - { return m_map_type; } - // Attribute functionality -protected: - // which attribute is currently displayed: - mutable int m_displayed_attribute; -public: - const pstring& getName() const - { return m_name; } - int addAttribute(const pstring& name) - { return m_attributes.insertColumn(name); } - void removeAttribute(int col) - { m_attributes.removeColumn(col); } - void setAttribute(int obj, const pstring& name, float val) - { m_attributes.setValue(m_attributes.getRowid(obj),name,val); } - void incrementAttribute(int obj, const pstring& name) - { m_attributes.incrValue(m_attributes.getRowid(obj),name); } - // I don't want to do this, but every so often you will need to update this table - // use const version by preference - AttributeTable& getAttributeTable() - { return m_attributes; } - const AttributeTable& getAttributeTable() const - { return m_attributes; } -public: - // layer functionality - bool isLayerVisible(int layerid) const - { return m_attributes.isLayerVisible(layerid); } - void setLayerVisible(int layerid, bool show) - { m_attributes.setLayerVisible(layerid,show); } - bool selectionToLayer(const pstring& name = pstring("Unnamed")); -public: - double getDisplayMinValue() const - { return (m_displayed_attribute != -1) ? m_attributes.getMinValue(m_displayed_attribute) : 0; } - double getDisplayMaxValue() const - { return (m_displayed_attribute != -1) ? m_attributes.getMaxValue(m_displayed_attribute) : m_shape_ref; } - // - mutable DisplayParams m_display_params; - const DisplayParams& getDisplayParams() const - { return m_attributes.getDisplayParams(m_displayed_attribute); } - // make a local copy of the display params for access speed: - void setDisplayParams(const DisplayParams& dp, bool apply_to_all = false) - { if (apply_to_all) - m_attributes.setDisplayParams(dp); - else - m_attributes.setDisplayParams(m_displayed_attribute, dp); - m_display_params = dp; } - // - mutable bool m_show_lines; - mutable bool m_show_fill; - mutable bool m_show_centroids; - void getPolygonDisplay(bool& show_lines, bool& show_fill, bool& show_centroids) - { show_lines = m_show_lines; show_fill = m_show_fill; show_centroids = m_show_centroids; } - void setPolygonDisplay(bool show_lines, bool show_fill, bool show_centroids) - { m_show_lines = show_lines; m_show_fill = show_fill; m_show_centroids = show_centroids; } - // -public: - void setDisplayedAttribute( int col ) const; - // use set displayed attribute instead unless you are deliberately changing the column order: - void overrideDisplayedAttribute(int attribute) - { m_displayed_attribute = attribute; } - // now, there is a slightly odd thing here: the displayed attribute can go out of step with the underlying - // attribute data if there is a delete of an attribute in idepthmap.h, so it just needs checking before returning! - int getDisplayedAttribute() const - { if (m_displayed_attribute == m_attributes.m_display_column) return m_displayed_attribute; - if (m_attributes.m_display_column != -2) { - m_displayed_attribute = m_attributes.m_display_column; - m_display_params = m_attributes.getDisplayParams(m_displayed_attribute); - } - return m_displayed_attribute; } - // - void invalidateDisplayedAttribute() - { m_invalidate = true; } - // - double getDisplayedAverage() - { return m_attributes.getAvgValue( m_displayed_attribute ); } - // -protected: - bool m_show; // used when shape map is a drawing layer - bool m_editable; - bool m_selection; - pvecint m_selection_set; // note: uses rowids not keys -public: - // Selection - bool isSelected() const - { return m_selection; } - bool setCurSel( QtRegion& r, bool add = false ); - bool setCurSel( const pvecint& selset, bool add = false ); - bool setCurSelDirect( const pvecint& selset, bool add = false ); - bool clearSel(); - pvecint& getSelSet() - { return m_selection_set; } - const pvecint& getSelSet() const - { return m_selection_set; } - size_t getSelCount() - { return m_selection_set.size(); } - QtRegion getSelBounds(); - // To showing - bool isShown() const - { return m_show; } - void setShow(bool on = true) - { m_show = on; } - // To all editing - bool isEditable() const - { return m_editable; } - void setEditable(bool on = true) - { m_editable = on; } -protected: - MapInfoData *m_mapinfodata; -public: - int loadMifMap(istream& miffile, istream& midfile); - bool outputMifMap(ostream& miffile, ostream& midfile) const; - const MapInfoData *getMapInfoData() const - { return m_mapinfodata; } -public: - // Screen - void makeViewportShapes( const QtRegion& viewport ) const; - bool findNextShape(bool& nextlayer) const; - const SalaShape& getNextShape() const; - const PafColor getShapeColor() const - { return m_attributes.getDisplayColor(m_display_shapes[m_current]); } - bool getShapeSelected() const - { return m_shapes[m_display_shapes[m_current]].m_selected; } - // - double getLocationValue(const Point2f& point) const; - - // Quick mod - TV -#if !defined(_WIN32) -#define __max(x,y) ((x& getAllShapes() const - { return m_shapes; } - pqmap& getAllShapes() - { return m_shapes; } - // required for PixelBase, have to implement your own version of pixelate - PixelRef pixelate( const Point2f& p, bool constrain = true, int = 1) const; - // -public: - // file - bool read( ifstream& stream, int version, bool drawinglayer = false ); - bool write( ofstream& stream, int version ); - // - bool output( ofstream& stream, char delimiter = '\t', bool updated_only = false ); - bool importTxt(istream& stream, bool csv); - // - // links and unlinks -protected: - pqvector m_links; - pqvector m_unlinks; - mutable int m_curlinkline; - mutable int m_curunlinkpoint; -public: - bool clearLinks(); - bool linkShapes(const Point2f& p); - bool linkShapes(int index1, int index2, bool refresh = true); - bool linkShapes(int id1, int dir1, int id2, int dir2, float weight); - bool unlinkShapes(const Point2f& p); - bool unlinkShapes(int index1, int index2, bool refresh = true); - bool unlinkShapeSet(istream& idset, int refcol); -public: - // generic for all types of graphs - bool findNextLinkLine() const; - Line getNextLinkLine() const; - // specific to axial line graphs - bool findNextUnlinkPoint() const; - Point2f getNextUnlinkPoint() const; - void outputUnlinkPoints( ofstream& stream, char delim ); -public: - void ozlemSpecial(ShapeMap& output); - void ozlemSpecial2(ShapeMap& buildings); - void ozlemSpecial3(ShapeMap& all); - bool ozlemSpecial4(ValuePair& cut, IntPair& previous, int& state, AttributeTable& table, IntPair& lookupcols); - void ozlemSpecial5(ShapeMap& buildings); - void ozlemSpecial6(); - void ozlemSpecial7(ShapeMap& linemap); -}; +class ShapeMap : public PixelBase { + friend class AxialMaps; + friend class MapInfoData; -///////////////////////////////////////////////////////////////////////////////////////////////// + public: + // now shapemaps cover a multitude of different types, record here: + // (note, allline maps are automatically generated and have extra information recorded for line reduction) + // Do not change numeric values! They are saved to file. + // Note the Pesh map does auto-overlap of shape-shape (yet...), so can be used for an arbitrary shape map + enum { + EMPTYMAP = 0x0000, + DRAWINGMAP = 0x0001, + DATAMAP = 0x0002, + POINTMAP = 0x0004, + CONVEXMAP = 0x0008, + ALLLINEMAP = 0x0010, + AXIALMAP = 0x0020, + SEGMENTMAP = 0x0040, + PESHMAP = 0x0080, + LINEMAP = 0x0070 + }; + enum { + COPY_NAME = 0x0001, + COPY_GEOMETRY = 0x0002, + COPY_ATTRIBUTES = 0x0004, + COPY_GRAPH = 0x0008, + COPY_ALL = 0x000f + }; -// Quick mod - TV -template -class ShapeMaps : public /*protected*/ prefvec -{ -protected: - size_t m_displayed_map; -public: - ShapeMaps() { m_displayed_map = paftl::npos;} - virtual ~ShapeMaps() {;} - // - size_t addMap(const pstring& name, int type); - void removeMap(size_t map); - - // - bool hasShapeMap() - { return pmemvec::size() != 0; } - // - // Simple display options - void setDisplayedMapRef(size_t map); - // - T& getDisplayedMap() - { return prefvec::at(m_displayed_map); } - const T& getDisplayedMap() const - { return prefvec::at(m_displayed_map); } - // - size_t getDisplayedMapRef() const - { return m_displayed_map; } - // Getting shape maps by name and reference - - // Quick mod - TV - T& getMap(size_t index) - { return prefvec::at(index); } - const T& getMap(size_t index) const - { return prefvec::at(index); } - const size_t getMapCount() - { return prefvec::size(); } - T& getLastMap() - { return prefvec::tail(); } - const T& getLastMap() const - { return prefvec::tail(); } - // - size_t getMapRef(const pstring& name) const; - // - size_t getObjectCount() const - { return prefvec::at(m_displayed_map).getObjectCount(); } - const size_t getShapeCount() const - { return prefvec::at(m_displayed_map).m_shapes.size(); } - // - bool read( ifstream& stream, int version ); - bool write( ofstream& stream, int version, bool displayedmaponly = false ); - // - const QtRegion& getBoundingBox() const - { return prefvec::at(m_displayed_map).getRegion(); } - // - // making links and unlinks - bool linkShapes(const Point2f& p) - { return prefvec::at(m_displayed_map).linkShapes(p); } - bool unlinkShapes(const Point2f& p) - { return prefvec::at(m_displayed_map).unlinkShapes(p); } - // for displaying links and unlinks - bool findNextLinkLine() const - { return prefvec::at(m_displayed_map).findNextLinkLine(); } - Line getNextLinkLine() const - { return prefvec::at(m_displayed_map).getNextLinkLine(); } - // unlinks are actually only used for special case of axial lines: - bool findNextUnlinkPoint() const - { return prefvec::at(m_displayed_map).findNextUnlinkPoint(); } - Point2f getNextUnlinkPoint() const - { return prefvec::at(m_displayed_map).getNextUnlinkPoint(); } -}; + protected: + std::string m_name; + int m_map_type; + bool m_hasgraph; + // counters + int m_obj_ref; + mutable bool m_newshape; // if a new shape has been added + // + // quick grab for shapes + depthmapX::ColumnMatrix> m_pixel_shapes; // i rows of j columns + // + // allow quick closest line test (note only works for a given layer, with many layers will be tricky) + mutable BSPNode *m_bsp_root = nullptr; + mutable bool m_bsp_tree = false; + // + std::map m_shapes; + // + std::vector m_undobuffer; + // + std::unique_ptr m_attributes; + std::unique_ptr m_attribHandle; + LayerManagerImpl m_layers; + // + // for graph functionality + // Note: this list is stored PACKED for optimal performance on graph analysis + // ALWAYS check it is in the same order as the shape list and attribute table + std::vector m_connectors; + // + // for geometric operations + double m_tolerance; + // for screen drawing + mutable std::vector m_display_shapes; + mutable int m_current; + mutable bool m_invalidate; + // +private: + void moveData(ShapeMap& other) { + m_show = other.isShown(); + m_shapes = std::move(other.m_shapes); + m_hasgraph = other.m_hasgraph; + m_connectors = std::move(other.m_connectors); + m_links = std::move(other.m_links); + m_unlinks = std::move(other.m_unlinks); + m_mapinfodata = std::move(other.m_mapinfodata); + m_hasMapInfoData = other.m_hasMapInfoData; + m_displayed_attribute = other.m_displayed_attribute; + m_display_shapes = std::move(other.m_display_shapes); + m_rows = other.m_rows; + m_cols = other.m_cols; + m_region = std::move(other.m_region); + m_map_type = other.m_map_type; + } -template -size_t ShapeMaps::addMap(const pstring& name, int type) -{ - ShapeMaps::push_back(T(name,type)); - setDisplayedMapRef(pmemvec::size()-1); - return (pmemvec::size()-1); -} -template -void ShapeMaps::removeMap(size_t map) -{ - // note: with the shape map name look up in the past, this was corrupting the - // lookup! Better just to go with a simple system: -// Quick mod - TV - prefvec::remove_at(map); - if (m_displayed_map > map || m_displayed_map >= pmemvec::size()) - m_displayed_map--; -} -template -size_t ShapeMaps::getMapRef(const pstring& name) const -{ - // note, only finds first map with this name - for (size_t i = 0; i < pmemvec::size(); i++) { - if (prefvec::at(i).getName() == name) - return i; - } - return -1; -} -template -void ShapeMaps::setDisplayedMapRef(size_t map) -{ - if (m_displayed_map != paftl::npos && m_displayed_map != map) - prefvec::at(m_displayed_map).clearSel(); - m_displayed_map = map; -} -template -bool ShapeMaps::read( ifstream& stream, int version ) -{ - prefvec::clear(); // empty existing data - // n.b. -- do not change to size_t as will cause 32-bit to 64-bit conversion problems - unsigned int displayed_map; - stream.read((char *)&displayed_map,sizeof(displayed_map)); - m_displayed_map = size_t(displayed_map); - // read maps - // n.b. -- do not change to size_t as will cause 32-bit to 64-bit conversion problems - unsigned int count = 0; - stream.read((char *) &count, sizeof(count)); - if (version < VERSION_NO_SHAPEMAP_NAME_LOOKUP) { - for (size_t i = 0; i < size_t(count); i++) { - // dummy name lookup (now simply creates on fly, as the name lookup may be corrupted in earlier versions) - pstring name; int number; - name.read(stream); - stream.read((char *)&number,sizeof(number)); - } - } - for (size_t j = 0; j < size_t(count); j++) { - ShapeMaps::push_back(T()); - prefvec::tail().read(stream,version); - } - return true; -} -template -bool ShapeMaps::write( ofstream& stream, int version, bool displayedmaponly ) -{ - if (!displayedmaponly) { - // n.b. -- do not change to size_t as will cause 32-bit to 64-bit conversion problems - unsigned int displayed_map = (unsigned int)(m_displayed_map); - stream.write((char *)&displayed_map,sizeof(displayed_map)); - // write maps - // n.b. -- do not change to size_t as will cause 32-bit to 64-bit conversion problems - unsigned int count = (unsigned int) pmemvec::size(); - stream.write((char *) &count, sizeof(count)); - for (size_t j = 0; j < count; j++) { - prefvec::at(j).write(stream,version); - } - } - else { - unsigned int dummy; - // displayed map is 0 - dummy = 0; - stream.write((char *)&dummy,sizeof(dummy)); - // count is 1 - dummy = 1; - stream.write((char *)&dummy,sizeof(dummy)); - // write map: - prefvec::at(m_displayed_map).write(stream,version); - } - return true; -} + public: + ShapeMap(const std::string &name = std::string(), int type = EMPTYMAP); + virtual ~ShapeMap(); + void copy(const ShapeMap &shapemap, int copyflags = 0); -///////////////////////////////////////////////////////////////////////////////////////////////// + ShapeMap(ShapeMap &&other) + : m_name(std::move(other.m_name)), m_pixel_shapes(std::move(other.m_pixel_shapes)), + m_attributes(std::move(other.m_attributes)), m_attribHandle(std::move(other.m_attribHandle)), + m_layers(std::move(other.m_layers)) { + moveData(other); + } + ShapeMap &operator=(ShapeMap &&other) { + m_name = std::move(other.m_name); + m_pixel_shapes = std::move(other.m_pixel_shapes); + m_attributes = std::move(other.m_attributes); + m_attribHandle = std::move(other.m_attribHandle); + m_layers = std::move(other.m_layers); + moveData(other); + return *this; + } + ShapeMap(const ShapeMap &) = delete; + ShapeMap &operator=(const ShapeMap &other) = delete; + + // TODO: These three functions should be refactored out of the code as much as possible + // they are only left here because they're being used by various components that still + // access the attribute table through indices. Once these are removed these functions + // should only appear sparingly or removed entirely. The bits of the application + // that still use them are the connections of the axial/segment maps and the point + // in polygon functions. + const std::map::const_iterator getShapeRefFromIndex(size_t index) const { + return depthmapX::getMapAtIndex(m_shapes, index); + } + AttributeRow &getAttributeRowFromShapeIndex(size_t index) { + return m_attributes->getRow(AttributeKey(getShapeRefFromIndex(index)->first)); + } + const AttributeRow &getAttributeRowFromShapeIndex(size_t index) const { + return m_attributes->getRow(AttributeKey(getShapeRefFromIndex(index)->first)); + } + + void clearAll(); + // num shapes total + size_t getShapeCount() const { return m_shapes.size(); } + // num shapes for this object (note, request by object rowid + // -- on interrogation, this is what you will usually receive) + size_t getShapeCount(int rowid) const { + return depthmapX::getMapAtIndex(m_shapes, rowid)->second.m_points.size(); + } + // + int getIndex(int rowid) const { return depthmapX::getMapAtIndex(m_shapes, rowid)->first; } + // + // add shape tools + void makePolyPixels(int shaperef); + void shapePixelBorder(std::map &relations, int shaperef, int side, PixelRef currpix, PixelRef minpix, + bool first); + // remove shape tools + void removePolyPixels(int shaperef); + // + // + void init(int size, const QtRegion &r); + int getNextShapeKey(); + // convert a single point into a shape + int makePointShapeWithRef(const Point2f &point, int shape_ref, bool tempshape = false, + const std::map &extraAttributes = std::map()); + int makePointShape(const Point2f &point, bool tempshape = false, + const std::map &extraAttributes = std::map()); + // or a single line into a shape + int makeLineShapeWithRef(const Line &line, int shape_ref, bool through_ui = false, bool tempshape = false, + const std::map &extraAttributes = std::map()); + int makeLineShape(const Line &line, bool through_ui = false, bool tempshape = false, + const std::map &extraAttributes = std::map()); + // or a polygon into a shape + int makePolyShapeWithRef(const std::vector &points, bool open, int shape_ref, bool tempshape = false, + const std::map &extraAttributes = std::map()); + int makePolyShape(const std::vector &points, bool open, bool tempshape = false, + const std::map &extraAttributes = std::map()); + + public: + // or make a shape from a shape + int makeShape(const SalaShape &shape, int override_shape_ref = -1, + const std::map &extraAttributes = std::map()); + // convert points to polygons + bool convertPointsToPolys(double poly_radius, bool selected_only); + // convert a selected pixels to a layer object (note, uses selection attribute on pixel, you must select to make + // this work): + int makeShapeFromPointSet(const PointMap &pointmap); + // + // move a shape (currently only a line shape) -- in the future should use SalaShape + bool moveShape(int shaperef, const Line &line, bool undoing = false); + // delete selected shapes + bool removeSelected(); + // delete a shape + void removeShape(int shaperef, bool undoing = false); + // + void setShapeAttributes(int rowid, const SalaShape &shape); + // + // some UI polygon creation tools: + int polyBegin(const Line &line); + bool polyAppend(int shape_ref, const Point2f &point); + bool polyClose(int shape_ref); + bool polyCancel(int shape_ref); + // some shape creation tools for the scripting language or DLL interface + public: + bool canUndo() const { return m_undobuffer.size() != 0; } + void undo(); + // + // helpers: + Point2f pointOffset(const PointMap &pointmap, int side); + int moveDir(int side); + // + void pointPixelBorder(const PointMap &pointmap, std::map &relations, SalaShape &shape, int side, + PixelRef currpix, PixelRef minpix, bool first); + // slower point in topmost poly test: + int pointInPoly(const Point2f &p) const; + // test if point is inside a particular shape + bool pointInPoly(const Point2f &p, int shaperef) const; + // retrieve lists of polys point intersects: + std::vector pointInPolyList(const Point2f &p) const; + std::vector lineInPolyList(const Line &li, size_t lineref = -1, double tolerance = 0.0) const; + std::vector polyInPolyList(int polyref, double tolerance = 0.0) const; + std::vector shapeInPolyList(const SalaShape &shape); + // helper to make actual test of point in shape: + int testPointInPoly(const Point2f &p, const ShapeRef &shape) const; + // also allow look for a close polyline: + int getClosestOpenGeom(const Point2f &p) const; + // this version uses a BSP tree to find closest line (currently only line shapes) + int getClosestLine(const Point2f &p) const; + // this version simply finds the closest vertex to the point + Point2f getClosestVertex(const Point2f &p) const; + // Connect a particular shape into the graph + int connectIntersected(int rowid, bool linegraph); + // Get the connections for a particular line + std::vector getLineConnections(int lineref, double tolerance); + // Get arbitrary shape connections for a particular shape + std::vector getShapeConnections(int polyref, double tolerance); + // Make all connections + void makeShapeConnections(); + // + bool makeBSPtree() const; + // + const std::vector &getConnections() const { return m_connectors; } + std::vector &getConnections() { return m_connectors; } + // + bool isAllLineMap() const { return m_map_type == ALLLINEMAP; } + bool isSegmentMap() const { return m_map_type == SEGMENTMAP; } + bool isAxialMap() const { return m_map_type == ALLLINEMAP || m_map_type == AXIALMAP; } + bool isPeshMap() const { return m_map_type == PESHMAP; } + int getMapType() const { return m_map_type; } + // Attribute functionality + protected: + // which attribute is currently displayed: + mutable int m_displayed_attribute; + + public: + const std::string &getName() const { return m_name; } + int addAttribute(const std::string &name) { return m_attributes->insertOrResetColumn(name); } + void removeAttribute(int col) { m_attributes->removeColumn(col); } + // I don't want to do this, but every so often you will need to update this table + // use const version by preference + AttributeTable &getAttributeTable() { return *m_attributes.get(); } + const AttributeTable &getAttributeTable() const { return *m_attributes.get(); } + LayerManagerImpl &getLayers() { return m_layers; } + const LayerManagerImpl &getLayers() const { return m_layers; } + AttributeTableHandle &getAttributeTableHandle() { return *m_attribHandle.get(); } + const AttributeTableHandle &getAttributeTableHandle() const { return *m_attribHandle.get(); } + + public: + // layer functionality + bool isLayerVisible(int layerid) const { return m_layers.isLayerVisible(layerid); } + void setLayerVisible(int layerid, bool show) { m_layers.setLayerVisible(layerid, show); } + bool selectionToLayer(const std::string &name = std::string("Unnamed")); + + public: + double getDisplayMinValue() const { + return (m_displayed_attribute != -1) ? m_attributes->getColumn(m_displayed_attribute).getStats().min : 0; + } + double getDisplayMaxValue() const { + return (m_displayed_attribute != -1) ? m_attributes->getColumn(m_displayed_attribute).getStats().max + : (m_shapes.size() > 0 ? m_shapes.rbegin()->first : 0); + } + + const DisplayParams &getDisplayParams() const { + return m_attributes->getColumn(m_displayed_attribute).getDisplayParams(); + } + // make a local copy of the display params for access speed: + void setDisplayParams(const DisplayParams &dp, bool apply_to_all = false) { + if (apply_to_all) + m_attributes->setDisplayParams(dp); + else + m_attributes->getColumn(m_displayed_attribute).setDisplayParams(dp); + } + // + mutable bool m_show_lines; + mutable bool m_show_fill; + mutable bool m_show_centroids; + void getPolygonDisplay(bool &show_lines, bool &show_fill, bool &show_centroids) { + show_lines = m_show_lines; + show_fill = m_show_fill; + show_centroids = m_show_centroids; + } + void setPolygonDisplay(bool show_lines, bool show_fill, bool show_centroids) { + m_show_lines = show_lines; + m_show_fill = show_fill; + m_show_centroids = show_centroids; + } + // + public: + void setDisplayedAttribute(int col); + // use set displayed attribute instead unless you are deliberately changing the column order: + void overrideDisplayedAttribute(int attribute) { m_displayed_attribute = attribute; } + // now, there is a slightly odd thing here: the displayed attribute can go out of step with the underlying + // attribute data if there is a delete of an attribute in idepthmap.h, so it just needs checking before returning! + int getDisplayedAttribute() const { + if (m_displayed_attribute == m_attribHandle->getDisplayColIndex()) + return m_displayed_attribute; + if (m_attribHandle->getDisplayColIndex() != -2) { + m_displayed_attribute = m_attribHandle->getDisplayColIndex(); + } + return m_displayed_attribute; + } + // + void invalidateDisplayedAttribute() { m_invalidate = true; } + // + double getDisplayedAverage() { + return m_attributes->getColumn(m_displayed_attribute).getStats().total / m_attributes->getNumRows(); + } + // + protected: + mutable bool m_show; // used when shape map is a drawing layer + bool m_editable; + bool m_selection; + std::set m_selection_set; // note: uses keys + public: + // Selection + bool isSelected() const { return m_selection; } + bool setCurSel(QtRegion &r, bool add = false); + bool setCurSel(const std::vector &selset, bool add = false); + bool setCurSelDirect(const std::vector &selset, bool add = false); + float getDisplayedSelectedAvg(); + bool clearSel(); + std::set &getSelSet() { return m_selection_set; } + const std::set &getSelSet() const { return m_selection_set; } + size_t getSelCount() { return m_selection_set.size(); } + QtRegion getSelBounds(); + // To showing + bool isShown() const { return m_show; } + void setShow(bool on = true) const { m_show = on; } + // To all editing + bool isEditable() const { return m_editable; } + void setEditable(bool on = true) { m_editable = on; } + protected: + bool m_hasMapInfoData = false; + MapInfoData m_mapinfodata; + + public: + bool hasMapInfoData() const { return m_hasMapInfoData; } + int loadMifMap(std::istream &miffile, std::istream &midfile); + bool outputMifMap(std::ostream &miffile, std::ostream &midfile); + const MapInfoData &getMapInfoData() const { return m_mapinfodata; } + + public: + // Screen + void makeViewportShapes(const QtRegion &viewport) const; + bool findNextShape(bool &nextlayer) const; + const SalaShape &getNextShape() const; + const PafColor getShapeColor() const { + AttributeKey key(m_display_shapes[m_current]); + const AttributeRow &row = m_attributes->getRow(key); + return dXreimpl::getDisplayColor(key, row, *m_attribHandle.get(), true); + ; + } + bool getShapeSelected() const { + return depthmapX::getMapAtIndex(m_shapes, m_display_shapes[m_current])->second.m_selected; + } + // + double getLocationValue(const Point2f &point) const; + + // Quick mod - TV +#if !defined(_MSC_VER) +#define __max(x, y) ((x < y) ? y : x) +#define __min(x, y) ((x < y) ? x : y) #endif + // + double getSpacing() { + return __max(m_region.width(), m_region.height()) / (10 * log((double)10 + m_shapes.size())); + } + // + // dangerous: accessor for the shapes themselves: + const std::map &getAllShapes() const { return m_shapes; } + std::map &getAllShapes() { return m_shapes; } + // required for PixelBase, have to implement your own version of pixelate + PixelRef pixelate(const Point2f &p, bool constrain = true, int = 1) const; + // + public: + // file + bool read(std::istream &stream); + bool write(std::ofstream &stream); + // + bool output(std::ofstream &stream, char delimiter = '\t'); + // + // links and unlinks + protected: + std::vector m_links; + std::vector m_unlinks; + mutable int m_curlinkline; + mutable int m_curunlinkpoint; + + public: + bool clearLinks(); + bool linkShapes(const Point2f &p); + bool linkShapesFromRefs(int ref1, int ref2, bool refresh = true); + bool linkShapes(int index1, int index2, bool refresh = true); + bool linkShapes(int id1, int dir1, int id2, int dir2, float weight); + bool unlinkShapes(const Point2f &p); + bool unlinkShapesFromRefs(int index1, int index2, bool refresh = true); + bool unlinkShapes(int index1, int index2, bool refresh = true); + bool unlinkShapesByKey(int key1, int key2, bool refresh = true); + bool unlinkShapeSet(std::istream &idset, int refcol); + + public: + // generic for all types of graphs + bool findNextLinkLine() const; + Line getNextLinkLine() const; + std::vector getAllLinkLines(); + // specific to axial line graphs + bool findNextUnlinkPoint() const; + Point2f getNextUnlinkPoint() const; + std::vector getAllUnlinkPoints(); + void outputUnlinkPoints(std::ofstream &stream, char delim); + + public: + std::vector getAllShapesAsLines() const; + std::vector> getAllLinesWithColour(); + std::map, PafColor> getAllPolygonsWithColour(); + std::vector> getAllPointsWithColour(); + bool importLines(const std::vector &lines, const depthmapX::Table &data); + bool importLinesWithRefs(const std::map &lines, const depthmapX::Table &data); + bool importPoints(const std::vector &points, const depthmapX::Table &data); + bool importPointsWithRefs(const std::map &points, const depthmapX::Table &data); + bool importPolylines(const std::vector &lines, const depthmapX::Table &data); + bool importPolylinesWithRefs(const std::map &lines, const depthmapX::Table &data); + void copyMapInfoBaseData(const ShapeMap &sourceMap); + + private: + bool importData(const depthmapX::Table &data, std::vector shape_refs); +}; diff --git a/salalib/spacepix.cpp b/salalib/spacepix.cpp index 36a817bb..3294eed2 100644 --- a/salalib/spacepix.cpp +++ b/salalib/spacepix.cpp @@ -14,17 +14,19 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . - - // This is my code to make a set of axial lines from a set of boundary lines // spatial data -#include -#include +#include "salalib/spacepix.h" -#include // purely for the version info --- as phased out should replace -#include +#include "genlib/stringutils.h" +#include "genlib/readwritehelpers.h" +#include "genlib/containerutils.h" + +#include +#include +#include #ifndef _WIN32 #define _finite finite @@ -53,1002 +55,739 @@ } */ -PixelRefList PixelBase::pixelateLine( Line l, int scalefactor ) const -{ - PixelRefList pixel_list; +PixelRefVector PixelBase::pixelateLine(Line l, int scalefactor) const { + PixelRefVector pixel_list; - // this is *not* correct for lines that are off the edge... - // should use non-constrained version (false), and find where line enters the region - PixelRef a = pixelate( l.start(), true, scalefactor ); - PixelRef b = pixelate( l.end(), true, scalefactor ); + // this is *not* correct for lines that are off the edge... + // should use non-constrained version (false), and find where line enters the region + PixelRef a = pixelate(l.start(), true, scalefactor); + PixelRef b = pixelate(l.end(), true, scalefactor); - l.normalScale( m_region ); + l.normalScale(m_region); - pixel_list.push_back( a ); + pixel_list.push_back(a); - int scaledcols = m_cols * scalefactor; - int scaledrows = m_rows * scalefactor; + int scaledcols = m_cols * scalefactor; + int scaledrows = m_rows * scalefactor; - int parity = 1; // Line goes upwards - if (a.y > b.y) { - parity = -1; // Line goes downwards - a.y *= -1; - b.y *= -1; // Set ay and by saves work on comparisons later on - } + int parity = 1; // Line goes upwards + if (a.y > b.y) { + parity = -1; // Line goes downwards + a.y *= -1; + b.y *= -1; // Set ay and by saves work on comparisons later on + } - // special case 1 - if (a.x == b.x) { - while (a.y < b.y ) { - a.y += 1; - pixel_list.push_back( PixelRef(a.x,parity * a.y) ); - } - } - else if (a.y == b.y) { - while ( a.x < b.x ) { - a.x += 1; - pixel_list.push_back( PixelRef(a.x,parity * a.y) ); // Lines always go left to right - } - } - else { - - double hw_ratio = l.height() / l.width(); // Working all of these out leaves less scope for floating point error - double wh_ratio = l.width() / l.height(); - double x0_const = l.ay() - double(parity) * hw_ratio * l.ax(); - double y0_const = l.ax() - double(parity) * wh_ratio * l.ay(); - - while (a.x < b.x || a.y < b.y) { - PixelRef e; - e.y = parity * int( double(scaledrows) * (x0_const + parity * hw_ratio * (double(a.x + 1) / double(scaledcols))) ); - // Note when decending 1.5 -> 1 and ascending 1.5 -> 2 - if (parity < 0) { - e.x = int( double(scaledcols) * (y0_const + wh_ratio * ( double(a.y) / double(scaledrows))) ); - } - else { - e.x = int( double(scaledcols) * (y0_const + wh_ratio * (double(a.y + 1) / double(scaledrows))) ); - } - - if (a.y < e.y) { - while (a.y < e.y && a.y < b.y) { - a.y += 1; - pixel_list.push_back( PixelRef(a.x,parity * a.y) ); - } - if (a.x < b.x) { - a.x += 1; - pixel_list.push_back( PixelRef(a.x,parity * a.y) ); - } - } - else if (a.x < e.x) { - while (a.x < e.x && a.x < b.x) { - a.x += 1; - pixel_list.push_back( PixelRef(a.x,parity * a.y) ); + // special case 1 + if (a.x == b.x) { + while (a.y < b.y) { + a.y += 1; + pixel_list.push_back(PixelRef(a.x, parity * a.y)); + } + } else if (a.y == b.y) { + while (a.x < b.x) { + a.x += 1; + pixel_list.push_back(PixelRef(a.x, parity * a.y)); // Lines always go left to right + } + } else { + + double hw_ratio = + l.height() / l.width(); // Working all of these out leaves less scope for floating point error + double wh_ratio = l.width() / l.height(); + double x0_const = l.ay() - double(parity) * hw_ratio * l.ax(); + double y0_const = l.ax() - double(parity) * wh_ratio * l.ay(); + + while (a.x < b.x || a.y < b.y) { + PixelRef e; + e.y = parity * + int(double(scaledrows) * (x0_const + parity * hw_ratio * (double(a.x + 1) / double(scaledcols)))); + // Note when decending 1.5 -> 1 and ascending 1.5 -> 2 + if (parity < 0) { + e.x = int(double(scaledcols) * (y0_const + wh_ratio * (double(a.y) / double(scaledrows)))); + } else { + e.x = int(double(scaledcols) * (y0_const + wh_ratio * (double(a.y + 1) / double(scaledrows)))); } - if (a.y < b.y) { - a.y += 1; - pixel_list.push_back( PixelRef(a.x,parity * a.y) ); + + if (a.y < e.y) { + while (a.y < e.y && a.y < b.y) { + a.y += 1; + pixel_list.push_back(PixelRef(a.x, parity * a.y)); + } + if (a.x < b.x) { + a.x += 1; + pixel_list.push_back(PixelRef(a.x, parity * a.y)); + } + } else if (a.x < e.x) { + while (a.x < e.x && a.x < b.x) { + a.x += 1; + pixel_list.push_back(PixelRef(a.x, parity * a.y)); + } + if (a.y < b.y) { + a.y += 1; + pixel_list.push_back(PixelRef(a.x, parity * a.y)); + } + } else { + // Special case: exactly diagonal step (should only require one step): + // (Should actually never happen) (Doesn't: checked with RFH) + if (a.x < b.x) { + a.x += 1; + pixel_list.push_back(PixelRef(a.x, parity * a.y)); + } + if (a.y < b.y) { + a.y += 1; + pixel_list.push_back(PixelRef(a.x, parity * a.y)); + } } - } - else { - // Special case: exactly diagonal step (should only require one step): - // (Should actually never happen) (Doesn't: checked with RFH) - a.x += 1; - pixel_list.push_back( PixelRef(a.x,parity * a.y) ); - a.y += 1; - pixel_list.push_back( PixelRef(a.x,parity * a.y) ); - } - } - } - return pixel_list; + } + } + return pixel_list; } // this version includes all pixels through which the line passes with touching // counting as both pixels. -PixelRefList PixelBase::pixelateLineTouching( Line l, double tolerance ) const -{ - PixelRefList pixel_list; - - // now assume that scaling to region then scaling up is going to give pixelation - // this is not necessarily the case! - l.normalScale( m_region ); - l.scale( Point2f(m_cols, m_rows) ); - - // but it does give us a nice line... - int dir; - double grad, constant; - - if (l.width() > l.height()) { - dir = XAXIS; - grad = l.grad(YAXIS); - constant = l.constant(YAXIS); - } - else { - dir = YAXIS; - grad = l.grad(XAXIS); - constant = l.constant(XAXIS); - } - PixelRef bounds( m_cols, m_rows ); - - if (dir == XAXIS) { - int first = (int) floor(l.ax() - tolerance); - int last = (int) floor(l.bx() + tolerance); - for (int i = first; i <= last ; i++) - { - int j1 = (int) floor((first == i ? l.ax() : double(i)) * grad + constant - l.sign() * tolerance); - int j2 = (int) floor((last == i ? l.bx() : double(i+1)) * grad + constant + l.sign() * tolerance); - if ( bounds.encloses( PixelRef( i, j1) )) { - pixel_list.push_back( PixelRef(i, j1) ); - } - if (j1 != j2) { - if ( bounds.encloses( PixelRef(i, j2) )) { - pixel_list.push_back( PixelRef(i, j2) ); +PixelRefVector PixelBase::pixelateLineTouching(Line l, double tolerance) const { + PixelRefVector pixel_list; + + // now assume that scaling to region then scaling up is going to give pixelation + // this is not necessarily the case! + l.normalScale(m_region); + l.scale(Point2f(m_cols, m_rows)); + + // but it does give us a nice line... + int dir; + double grad, constant; + + if (l.width() > l.height()) { + dir = XAXIS; + grad = l.grad(YAXIS); + constant = l.constant(YAXIS); + } else { + dir = YAXIS; + grad = l.grad(XAXIS); + constant = l.constant(XAXIS); + } + PixelRef bounds(m_cols, m_rows); + + if (dir == XAXIS) { + int first = (int)floor(l.ax() - tolerance); + int last = (int)floor(l.bx() + tolerance); + for (int i = first; i <= last; i++) { + int j1 = (int)floor((first == i ? l.ax() : double(i)) * grad + constant - l.sign() * tolerance); + int j2 = (int)floor((last == i ? l.bx() : double(i + 1)) * grad + constant + l.sign() * tolerance); + if (bounds.encloses(PixelRef(i, j1))) { + pixel_list.push_back(PixelRef(i, j1)); } - } - } - } - else { - int first = (int) floor(l.bottom_left.y - tolerance); - int last = (int) floor(l.top_right.y + tolerance); - for (int i = first; i <= last; i ++) - { - int j1 = (int) floor((first == i ? l.bottom_left.y : double(i)) * grad + constant - l.sign() * tolerance); - int j2 = (int) floor((last == i ? l.top_right.y : double(i+1)) * grad + constant + l.sign() * tolerance); - if ( bounds.encloses( PixelRef(j1, i) )) { - pixel_list.push_back( PixelRef(j1, i) ); - } - if (j1 != j2) { - if ( bounds.encloses( PixelRef(j2, i) )) { - pixel_list.push_back( PixelRef(j2, i) ); + if (j1 != j2) { + if (bounds.encloses(PixelRef(i, j2))) { + pixel_list.push_back(PixelRef(i, j2)); + } + if (abs(j2 - j1) == 2) { + // this rare event happens if lines are exactly diagonal + int j3 = (j1 + j2) / 2; + if (bounds.encloses(PixelRef(i, j3))) { + pixel_list.push_back(PixelRef(i, j3)); + } + } } - if (abs(j2 - j1) == 2) { - // this rare event happens if lines are exactly diagonal - int j3 = (j1 + j2) / 2; - if ( bounds.encloses( PixelRef(j3, i) )) { - pixel_list.push_back( PixelRef(j3, i) ); - } + } + } else { + int first = (int)floor(l.bottom_left.y - tolerance); + int last = (int)floor(l.top_right.y + tolerance); + for (int i = first; i <= last; i++) { + int j1 = (int)floor((first == i ? l.bottom_left.y : double(i)) * grad + constant - l.sign() * tolerance); + int j2 = (int)floor((last == i ? l.top_right.y : double(i + 1)) * grad + constant + l.sign() * tolerance); + if (bounds.encloses(PixelRef(j1, i))) { + pixel_list.push_back(PixelRef(j1, i)); } - } - } - } + if (j1 != j2) { + if (bounds.encloses(PixelRef(j2, i))) { + pixel_list.push_back(PixelRef(j2, i)); + } + if (abs(j2 - j1) == 2) { + // this rare event happens if lines are exactly diagonal + int j3 = (j1 + j2) / 2; + if (bounds.encloses(PixelRef(j3, i))) { + pixel_list.push_back(PixelRef(j3, i)); + } + } + } + } + } - return pixel_list; + return pixel_list; } // this version for a quick set of pixels -PixelRefList PixelBase::quickPixelateLine(PixelRef p, PixelRef q) -{ - PixelRefList list; - - double dx = q.x - p.x; - double dy = q.y - p.y; - int polarity = -1; - double t = 0; - // Quick mod - TV -#if defined(_WIN32) - if (abs(dx) == abs(dy)) { +PixelRefVector PixelBase::quickPixelateLine(PixelRef p, PixelRef q) { + PixelRefVector list; + + double dx = q.x - p.x; + double dy = q.y - p.y; + int polarity = -1; + double t = 0; + // Quick mod - TV +#if defined(_MSC_VER) + if (abs(dx) == abs(dy)) { #else - if (fabs(dx) == fabs(dy)) { -#endif - polarity = 0; - } -#if defined(_WIN32) - else if (abs(dx) > abs(dy)) { - t = abs(dx); + if (fabs(dx) == fabs(dy)) { +#endif + polarity = 0; + } +#if defined(_MSC_VER) + else if (abs(dx) > abs(dy)) { + t = abs(dx); #else - else if (fabs(dx) > fabs(dy)) { - t = fabs(dx); -#endif - polarity = 1; - } - else { -#if defined(_WIN32) - t = abs(dy); + else if (fabs(dx) > fabs(dy)) { + t = fabs(dx); +#endif + polarity = 1; + } else { +#if defined(_MSC_VER) + t = abs(dy); #else - t = fabs(dy); -#endif - polarity = 2; - } - - dx /= t; - dy /= t; - double ppx = p.x + 0.5; - double ppy = p.y + 0.5; - - for (int i = 0; i <= t; i++) { - if (polarity == 1 && fabs(floor(ppy)-ppy) < 1e-9) { - list.push_back(PixelRef((short)floor(ppx),(short)floor(ppy+0.5))); - list.push_back(PixelRef((short)floor(ppx),(short)floor(ppy-0.5))); - } - else if (polarity == 2 && fabs(floor(ppx)-ppx) < 1e-9) { - list.push_back(PixelRef((short)floor(ppx+0.5),(short)floor(ppy))); - list.push_back(PixelRef((short)floor(ppx-0.5),(short)floor(ppy))); - } - else { - list.push_back(PixelRef((short)floor(ppx),(short)floor(ppy))); - } - ppx += dx; ppy += dy; - } - - return list; + t = fabs(dy); +#endif + polarity = 2; + } + + dx /= t; + dy /= t; + double ppx = p.x + 0.5; + double ppy = p.y + 0.5; + + for (int i = 0; i <= t; i++) { + if (polarity == 1 && fabs(floor(ppy) - ppy) < 1e-9) { + list.push_back(PixelRef((short)floor(ppx), (short)floor(ppy + 0.5))); + list.push_back(PixelRef((short)floor(ppx), (short)floor(ppy - 0.5))); + } else if (polarity == 2 && fabs(floor(ppx) - ppx) < 1e-9) { + list.push_back(PixelRef((short)floor(ppx + 0.5), (short)floor(ppy))); + list.push_back(PixelRef((short)floor(ppx - 0.5), (short)floor(ppy))); + } else { + list.push_back(PixelRef((short)floor(ppx), (short)floor(ppy))); + } + ppx += dx; + ppy += dy; + } + + return list; } -SpacePixel::SpacePixel(const pstring& name) -{ - m_name = name; - m_show = true; - m_edit = false; +SpacePixel::SpacePixel(const std::string &name) : m_pixel_lines(0, 0) { + m_name = name; + m_show = true; + m_edit = false; - m_cols = 0; - m_rows = 0; + m_cols = 0; + m_rows = 0; - m_ref = -1; - m_test = 0; + m_ref = -1; + m_test = 0; - m_pixel_lines = NULL; - m_display_lines = NULL; - m_newline = false; + m_newline = false; - m_style = 0; - m_color = 0; -} - -SpacePixel::~SpacePixel() -{ - if (m_pixel_lines) { - for (int i = 0; i < m_cols; i++) { - delete [] m_pixel_lines[i]; - } - delete [] m_pixel_lines; - m_pixel_lines = NULL; - } - if (m_display_lines) { - delete [] m_display_lines; - m_display_lines = NULL; - } + m_style = 0; + m_color = 0; } -SpacePixel::SpacePixel(const SpacePixel& spacepixel) -{ - // n.b., not strictly allowed - construct(spacepixel); +SpacePixel::SpacePixel(const SpacePixel &spacepixel) + : m_pixel_lines(spacepixel.m_pixel_lines.rows(), spacepixel.m_pixel_lines.columns()) { + // n.b., not strictly allowed + construct(spacepixel); } -SpacePixel& SpacePixel::operator = (const SpacePixel& spacepixel) -{ - if (this != &spacepixel) { - if (m_pixel_lines) { - for (int i = 0; i < m_cols; i++) { - delete [] m_pixel_lines[i]; - } - delete [] m_pixel_lines; - m_pixel_lines = NULL; - } - if (m_display_lines) { - delete [] m_display_lines; - m_display_lines = NULL; - } - - construct(spacepixel); - } - return *this; +SpacePixel &SpacePixel::operator=(const SpacePixel &spacepixel) { + if (this != &spacepixel) { + construct(spacepixel); + } + return *this; } -void SpacePixel::construct(const SpacePixel& spacepixel) -{ - m_name = spacepixel.m_name; - m_show = spacepixel.m_show; - m_edit = spacepixel.m_edit; +void SpacePixel::construct(const SpacePixel &spacepixel) { + m_name = spacepixel.m_name; + m_show = spacepixel.m_show; + m_edit = spacepixel.m_edit; - m_rows = spacepixel.m_rows; - m_cols = spacepixel.m_cols; + m_rows = spacepixel.m_rows; + m_cols = spacepixel.m_cols; - m_region = spacepixel.m_region; + m_region = spacepixel.m_region; - m_ref = spacepixel.m_ref; - m_test = spacepixel.m_test; - m_lines = spacepixel.m_lines; - m_newline = true; + m_ref = spacepixel.m_ref; + m_test = spacepixel.m_test; + m_lines = spacepixel.m_lines; + m_newline = true; - if (!m_rows || !m_cols) { - m_pixel_lines = NULL; - m_display_lines = NULL; - return; - } + if (!m_rows || !m_cols) { + m_display_lines.clear(); + return; + } - m_pixel_lines = new pvecint *[m_cols]; - for (int i = 0; i < m_cols; i++) { - m_pixel_lines[i] = new pvecint[m_rows]; - for (int j = 0; j < m_rows; j++) { - m_pixel_lines[i][j] = spacepixel.m_pixel_lines[i][j]; - } - } + m_pixel_lines = spacepixel.m_pixel_lines; - m_color = spacepixel.m_color; - m_style = spacepixel.m_style; + m_color = spacepixel.m_color; + m_style = spacepixel.m_style; - //m_pixel_height = spacepixel.m_pixel_height; - //m_pixel_width = spacepixel.m_pixel_width; + // m_pixel_height = spacepixel.m_pixel_height; + // m_pixel_width = spacepixel.m_pixel_width; } -PixelRef SpacePixel::pixelate( const Point2f& p, bool constrain, int ) const -{ - PixelRef r; - - Point2f p1 = p; - p1.normalScale(m_region); - - r.x = short(p1.x * double(m_cols-1e-9)); - if (constrain) { - if (r.x >= m_cols) - r.x = m_cols - 1; - else if (r.x < 0) - r.x = 0; - } - r.y = short(p1.y * double(m_rows-1e-9)); - if (constrain) { - if (r.y >= m_rows) - r.y = m_rows - 1; - else if (r.y < 0) - r.y = 0; - } - - return r; +PixelRef SpacePixel::pixelate(const Point2f &p, bool constrain, int) const { + PixelRef r; + + Point2f p1 = p; + p1.normalScale(m_region); + + r.x = short(p1.x * double(m_cols - 1e-9)); + if (constrain) { + if (r.x >= static_cast(m_cols)) + r.x = m_cols - 1; + else if (r.x < 0) + r.x = 0; + } + r.y = short(p1.y * double(m_rows - 1e-9)); + if (constrain) { + if (r.y >= static_cast(m_rows)) + r.y = m_rows - 1; + else if (r.y < 0) + r.y = 0; + } + + return r; } -void SpacePixel::makeViewportLines( const QtRegion& viewport ) const -{ - if (!m_display_lines || m_newline) { - if (m_display_lines) - delete [] m_display_lines; - m_display_lines = new int [m_lines.size()]; - m_newline = false; - for (size_t i = 0; i < m_lines.size(); i++) { - m_display_lines[i] = 0; - } - } +void SpacePixel::makeViewportLines(const QtRegion &viewport) const { + if (m_display_lines.empty() || m_newline) { + m_display_lines = std::vector(m_lines.size()); + m_newline = false; + std::fill(m_display_lines.begin(), m_display_lines.end(), 0); + } - m_current = -1; // note: findNext expects first to be labelled -1 + m_current = -1; // note: findNext expects first to be labelled -1 - /* - // Fixing bounding rectangle: normalisation removed - QtRegion r_viewport = viewport; + /* + // Fixing bounding rectangle: normalisation removed + QtRegion r_viewport = viewport; - r_viewport.normalScale( m_region ); - */ + r_viewport.normalScale( m_region ); + */ - PixelRef bl = pixelate( viewport.bottom_left ); - PixelRef tr = pixelate( viewport.top_right ); + PixelRef bl = pixelate(viewport.bottom_left); + PixelRef tr = pixelate(viewport.top_right); - for (int i = bl.x; i <= tr.x; i++) { - for (int j = bl.y; j <= tr.y; j++) { - for (size_t k = 0; k < m_pixel_lines[i][j].size(); k++) { - m_display_lines[ m_lines.searchindex(m_pixel_lines[i][j][k]) ] = 1; - } - } - } + for (int i = bl.x; i <= tr.x; i++) { + for (int j = bl.y; j <= tr.y; j++) { + auto &pixel_lines = m_pixel_lines(static_cast(j), static_cast(i)); + for (int pixel_line : pixel_lines) { + m_display_lines[size_t(depthmapX::findIndexFromKey(m_lines, pixel_line))] = 1; + } + } + } } // expect to be used as: // -// if (findNext()) +// if (findNext()) // getNext(); -bool SpacePixel::findNextLine(bool& nextlayer) const -{ - if (m_newline) // after adding a line you must reinitialise the display lines - return false; +bool SpacePixel::findNextLine(bool &nextlayer) const { + if (m_newline) // after adding a line you must reinitialise the display lines + return false; - while (++m_current < (int)m_lines.size() && m_display_lines[m_current] == 0 ); - - if (m_current < (int)m_lines.size()) { - return true; - } - else { - m_current = (int)m_lines.size(); - nextlayer = true; - return false; - } + while (++m_current < (int)m_lines.size() && m_display_lines[m_current] == 0) + ; + + if (m_current < (int)m_lines.size()) { + return true; + } else { + m_current = (int)m_lines.size(); + nextlayer = true; + return false; + } } -const Line& SpacePixel::getNextLine() const -{ - m_display_lines[m_current] = 0; // You've drawn it - /* - // Fixing: removed rectangle scaling - l.denormalScale( m_region ); - */ - return m_lines[m_current].line; +const Line &SpacePixel::getNextLine() const { + m_display_lines[m_current] = 0; // You've drawn it + /* + // Fixing: removed rectangle scaling + l.denormalScale( m_region ); + */ + return m_lines.find(m_current)->second.line; } -void SpacePixel::initLines(int size, const Point2f& min, const Point2f& max, double density) -{ - if (m_pixel_lines) - { - for (int i = 0; i < m_cols; i++) { - delete [] m_pixel_lines[i]; - } - delete [] m_pixel_lines; - m_pixel_lines = NULL; - } - if (m_display_lines) { - delete [] m_display_lines; - m_display_lines = NULL; - } - m_lines.clear(); - m_ref = -1; - m_test = 0; +void SpacePixel::initLines(int size, const Point2f &min, const Point2f &max, double density) { + m_display_lines.clear(); + m_lines.clear(); + m_ref = -1; + m_test = 0; - // work out extents... - m_region = QtRegion(min, max); + // work out extents... + m_region = QtRegion(min, max); - double wh_ratio = m_region.width() / m_region.height(); - double hw_ratio = m_region.height() / m_region.width(); + double wh_ratio = m_region.width() / m_region.height(); + double hw_ratio = m_region.height() / m_region.width(); - m_rows = (int) sqrt(double(size) * wh_ratio * density); - m_cols = (int) sqrt(double(size) * hw_ratio * density); + m_rows = (int)sqrt(double(size) * wh_ratio * density); + m_cols = (int)sqrt(double(size) * hw_ratio * density); - if (m_rows < 1) - m_rows = 1; - if (m_cols < 1) - m_cols = 1; + if (m_rows < 1) + m_rows = 1; + if (m_cols < 1) + m_cols = 1; - // could work these two out on the fly, but it's easier to have them stored: - //m_pixel_height = m_region.height() / double(m_rows); - //m_pixel_width = m_region.width() / double(m_cols); + // could work these two out on the fly, but it's easier to have them stored: + // m_pixel_height = m_region.height() / double(m_rows); + // m_pixel_width = m_region.width() / double(m_cols); - m_pixel_lines = new pvecint *[m_cols]; - for (int i = 0; i < m_cols; i++) { - m_pixel_lines[i] = new pvecint[m_rows]; - } + m_pixel_lines = depthmapX::RowMatrix>(static_cast(m_rows), static_cast(m_cols)); } -void SpacePixel::reinitLines(double density) -{ - if (m_pixel_lines) - { - for (int i = 0; i < m_cols; i++) { - delete [] m_pixel_lines[i]; - } - delete [] m_pixel_lines; - m_pixel_lines = NULL; - } - if (m_display_lines) { - delete [] m_display_lines; - m_display_lines = NULL; - } +void SpacePixel::reinitLines(double density) { + m_display_lines.clear(); - double wh_ratio = m_region.width() / m_region.height(); - double hw_ratio = m_region.height() / m_region.width(); + double wh_ratio = m_region.width() / m_region.height(); + double hw_ratio = m_region.height() / m_region.width(); - m_rows = (int) sqrt(double(m_lines.size()) * wh_ratio * density); - m_cols = (int) sqrt(double(m_lines.size()) * hw_ratio * density); + m_rows = (int)sqrt(double(m_lines.size()) * wh_ratio * density); + m_cols = (int)sqrt(double(m_lines.size()) * hw_ratio * density); - if (m_rows < 1) - m_rows = 1; - if (m_cols < 1) - m_cols = 1; + if (m_rows < 1) + m_rows = 1; + if (m_cols < 1) + m_cols = 1; - m_pixel_lines = new pvecint *[m_cols]; - for (int i = 0; i < m_cols; i++) { - m_pixel_lines[i] = new pvecint[m_rows]; - } + m_pixel_lines = depthmapX::RowMatrix>(static_cast(m_rows), static_cast(m_cols)); - // now re-add the lines: - for (size_t i = 0; i < m_lines.size(); i++) { - PixelRefList list = pixelateLine( m_lines.value(i).line ); - for (size_t j = 0; j < list.size(); j++) { - // note: m_pixel_lines will be reordered by sortPixelLines - m_pixel_lines[list[j].x][list[j].y].push_back( m_lines.key(i) ); - } - } + // now re-add the lines: + for (auto line : m_lines) { + PixelRefVector list = pixelateLine(line.second.line); + for (size_t j = 0; j < list.size(); j++) { + // note: m_pixel_lines will be reordered by sortPixelLines + m_pixel_lines(static_cast(list[j].y), static_cast(list[j].x)).push_back(line.first); + } + } - // and finally sort: - sortPixelLines(); + // and finally sort: + sortPixelLines(); - // flag as newline just in case: - m_newline = true; + // flag as newline just in case: + m_newline = true; } // Add line: pixelate the line -void SpacePixel::addLine(const Line& line) -{ - // Fairly simple: just pixelates the line! - m_ref++; // need unique keys for the lines so they can be added / removed at any time - m_lines.add( m_ref, LineTest(line, 0) ); - m_newline = true; +void SpacePixel::addLine(const Line &line) { + // Fairly simple: just pixelates the line! + m_ref++; // need unique keys for the lines so they can be added / removed at any time + m_lines.insert(std::make_pair(m_ref, LineTest(line, 0))); + m_newline = true; - PixelRefList list = pixelateLine( line ); + PixelRefVector list = pixelateLine(line); - for (size_t i = 0; i < list.size(); i++) { - // note: m_pixel_lines will be reordered by sortPixelLines - m_pixel_lines[list[i].x][list[i].y].push_back( m_ref ); - } -} - -int SpacePixel::addLineDynamic(const Line& line) -{ - m_ref++; // need unique keys for the lines so they can be added / removed at any time - m_lines.add( m_ref, LineTest(line, 0) ); - m_newline = true; - - PixelRefList list = pixelateLine( line ); - - for (size_t i = 0; i < list.size(); i++) { - // note: dynamic lines could be dodgy... only pixelate bits that fall in range - if (list[i].x >= 0 && list[i].y >= 0 && list[i].x < m_cols && list[i].y < m_rows) { - // note, this probably won't be reordered on dynamic - m_pixel_lines[list[i].x][list[i].y].push_back( m_ref ); - } - } - - return m_ref; + for (size_t i = 0; i < list.size(); i++) { + // note: m_pixel_lines will be reordered by sortPixelLines + m_pixel_lines(static_cast(list[i].y), static_cast(list[i].x)).push_back(m_ref); + } } -bool SpacePixel::removeLineDynamic(int ref, Line& line) // fills in line if it finds it -{ - bool retvar = true; - - size_t lineref = m_lines.searchindex(ref); - - if (lineref == paftl::npos) { - return false; - } +int SpacePixel::addLineDynamic(const Line &line) { + m_ref++; // need unique keys for the lines so they can be added / removed at any time + m_lines.insert(std::make_pair(m_ref, LineTest(line, 0))); + m_newline = true; - line = m_lines[lineref].line; - PixelRefList list = pixelateLine( line ); - - for (size_t i = 0; i < list.size(); i++) { - // note: dynamic lines could be dodgy... only pixelate bits that fall in range - if (list[i].x >= 0 && list[i].y >= 0 && list[i].x < m_cols && list[i].y < m_rows) { - // note: m_pixel_lines will be reordered by sortPixelLines - size_t pixelsref = m_pixel_lines[list[i].x][list[i].y].findindex( ref ); - if (pixelsref != paftl::npos) { // <- just in case its been removed already for some reason - m_pixel_lines[list[i].x][list[i].y].remove_at(pixelsref); - } - } - } + PixelRefVector list = pixelateLine(line); - m_lines.remove_at(lineref); + for (size_t i = 0; i < list.size(); i++) { + // note: dynamic lines could be dodgy... only pixelate bits that fall in range + if (list[i].x >= 0 && list[i].y >= 0 && + static_cast(list[i].x) < m_cols && static_cast(list[i].y) < m_rows) { + // note, this probably won't be reordered on dynamic + m_pixel_lines(static_cast(list[i].y), static_cast(list[i].x)).push_back(m_ref); + } + } - // just flag up if true - m_newline = true; - - return retvar; + return m_ref; } -void SpacePixel::sortPixelLines() -{ - for (int i = 0; i < m_cols; i++) { - for (int j = 0; j < m_rows; j++) { - pvecint& pixel_lines = m_pixel_lines[i][j]; - // tidy up in case of removal - for (size_t n = pixel_lines.size() - 1; n != paftl::npos; n--) { - if (m_lines.searchindex(pixel_lines[n]) == paftl::npos) { - pixel_lines.remove_at(n); +void SpacePixel::sortPixelLines() { + for (size_t i = 0; i < static_cast(m_cols); i++) { + for (size_t j = 0; j < static_cast(m_rows); j++) { + std::vector &pixel_lines = m_pixel_lines(j, i); + // tidy up in case of removal + for (auto rev_iter = pixel_lines.rbegin(); rev_iter != pixel_lines.rend(); ++rev_iter) { + if (m_lines.find(*rev_iter) == m_lines.end()) { + pixel_lines.erase(std::next(rev_iter).base()); + } } - } - pixel_lines.sort(); - } - } + std::sort(pixel_lines.begin(), pixel_lines.end()); + } + } } -bool SpacePixel::intersect( const Line& l, double tolerance ) -{ - m_test++; // note loops! (but vary rarely: inevitabley, lines will have been marked before it loops) +bool SpacePixel::intersect(const Line &l, double tolerance) { + m_test++; // note loops! (but vary rarely: inevitabley, lines will have been marked before it loops) - PixelRefList list = pixelateLine( l ); + PixelRefVector list = pixelateLine(l); - for (size_t i = 0; i < list.size(); i++) { - for (size_t j = 0; j < m_pixel_lines[ list[i].x ][ list[i].y ].size(); j++) { - int lineref = m_pixel_lines[ list[i].x ][ list[i].y ][j]; - try { - LineTest& linetest = m_lines.search(lineref); + for (size_t i = 0; i < list.size(); i++) { + auto &pixel_lines = m_pixel_lines(static_cast(list[i].y), static_cast(list[i].x)); + for (int lineref : pixel_lines) { + LineTest &linetest = m_lines.find(lineref)->second; if (linetest.test != m_test) { - if ( intersect_region(linetest.line, l) ) { - if ( intersect_line(linetest.line, l, tolerance) ) { - return true; - } - } - linetest.test = m_test; + if (intersect_region(linetest.line, l)) { + if (intersect_line(linetest.line, l, tolerance)) { + return true; + } + } + linetest.test = m_test; } - } - catch (pexception) { - // the lineref may have been deleted -- this is supposed to be tidied up - // just ignore... - } - } - } + } + } - return false; + return false; } -bool SpacePixel::intersect_exclude( const Line& l, double tolerance ) -{ - m_test++; // note loops! (but vary rarely: inevitabley, lines will have been marked before it loops) +bool SpacePixel::intersect_exclude(const Line &l, double tolerance) { + m_test++; // note loops! (but vary rarely: inevitabley, lines will have been marked before it loops) - PixelRefList list = pixelateLine( l ); + PixelRefVector list = pixelateLine(l); - for (size_t i = 0; i < list.size(); i++) { - for (size_t j = 0; j < m_pixel_lines[ list[i].x ][ list[i].y ].size(); j++) { - int lineref = m_pixel_lines[ list[i].x ][ list[i].y ][j]; - try { - LineTest& linetest = m_lines.search(lineref); + for (size_t i = 0; i < list.size(); i++) { + auto &pixel_lines = m_pixel_lines(static_cast(list[i].y), static_cast(list[i].x)); + for (int lineref : pixel_lines) { + LineTest &linetest = m_lines.find(lineref)->second; if (linetest.test != m_test) { - if ( intersect_region(linetest.line, l) ) { - if ( intersect_line(linetest.line, l, tolerance) ) { - if ( linetest.line.start() != l.start() && linetest.line.start() != l.end() && - linetest.line.end() != l.start() && linetest.line.end() != l.end() ) { - return true; - } - } - } - linetest.test = m_test; + if (intersect_region(linetest.line, l)) { + if (intersect_line(linetest.line, l, tolerance)) { + if (linetest.line.start() != l.start() && linetest.line.start() != l.end() && + linetest.line.end() != l.start() && linetest.line.end() != l.end()) { + return true; + } + } + } + linetest.test = m_test; } - } - catch (pexception) { - // the lineref may have been deleted -- this is supposed to be tidied up - // just ignore... - } - } - } - - return false; -} - -/* -// get the first crossing point of lines with lines... -Point2f SpacePixel::getFirstCrossingPoint(const Line& l, int fromend, pvecint& ignorelist) -{ - Point2f point; - - int axis; - if (l.width() > l.height()) { - axis = XAXIS; - } - else { - axis = YAXIS; - } - - pvecdouble cross_list = getCrossingPoints(l, axis, ignorelist); - - if (fromend == Line::START) { - if (!cross_list.size()) { - point = l.end(); - } - else { - if (axis == XAXIS || l.sign() == 1) { - point = l.point_on_line(cross_list.head(),axis); - } - else { - point = l.point_on_line(cross_list.tail(),axis); - } - } - } - else { - if (!cross_list.size()) { - point = l.start(); - } - else { - if (axis == XAXIS || l.sign() == 1) { - point = l.point_on_line(cross_list.tail(),axis); - } - else { - point = l.point_on_line(cross_list.head(),axis); - } - } - } + } + } - return point; + return false; } -*/ - -void SpacePixel::cutLine(Line& l, short dir) -{ - m_test++; - double tolerance = l.length() * 1e-9; - - pvecdouble loc; - PixelRefList vec = pixelateLine(l); - - int axis; - if (l.width() >= l.height()) { - axis = XAXIS; - } - else { - axis = YAXIS; - } - Point2f truestart = (dir == l.direction()) ? l.start() : l.end(); - Point2f trueend = (dir == l.direction()) ? l.end() : l.start(); - - bool found = false; - prefvec touching_lines; - - for (size_t i = 0; i < vec.size() && !found; i++) { - // depending on direction of line either move head to tail or tail to head - PixelRef pix = (dir == l.direction()) ? vec[i] : vec[vec.size() - 1 - i]; - for (size_t j = 0; j < m_pixel_lines[ pix.x ][ pix.y ].size(); j++) { - int lineref = m_pixel_lines[ pix.x ][ pix.y ][j]; - //try { - LineTest& linetest = m_lines.search(lineref); +void SpacePixel::cutLine(Line &l, short dir) { + m_test++; + + double tolerance = l.length() * 1e-9; + + std::set loc; + PixelRefVector vec = pixelateLine(l); + + int axis; + if (l.width() >= l.height()) { + axis = XAXIS; + } else { + axis = YAXIS; + } + Point2f truestart = (dir == l.direction()) ? l.start() : l.end(); + Point2f trueend = (dir == l.direction()) ? l.end() : l.start(); + + bool found = false; + std::vector touching_lines; + + for (size_t i = 0; i < vec.size() && !found; i++) { + // depending on direction of line either move head to tail or tail to head + PixelRef pix = (dir == l.direction()) ? vec[i] : vec[vec.size() - 1 - i]; + auto &pixel_lines = m_pixel_lines(static_cast(pix.y), static_cast(pix.x)); + for (int lineref : pixel_lines) { + // try { + LineTest &linetest = m_lines.find(lineref)->second; if (linetest.test != m_test) { - if ( intersect_region(linetest.line, l, tolerance * linetest.line.length()) ) { - switch ( intersect_line_distinguish(linetest.line, l, tolerance * linetest.line.length() ) ) { - case 0: - break; - case 2: - { - loc.add( l.intersection_point(linetest.line, axis) ); - } - break; - case 1: - if (truestart != linetest.line.start() && truestart != linetest.line.end()) { - if (!touching_lines.size()) { - touching_lines.push_back(linetest.line); - } - else { - Point2f a,b; - int pair = -1; - // if there may be more than one touches in the same pixel, we have to build a list of possibles... - for (size_t k = 0; k < touching_lines.size() && pair == -1; k++) { - if (linetest.line.start() == touching_lines[k].start() || linetest.line.end() == touching_lines[k].end()) { - a = linetest.line.end() - linetest.line.start(); - pair = k; - } - else if (linetest.line.start() == touching_lines[k].end() || linetest.line.end() == touching_lines[k].start()) { - a = linetest.line.start() - linetest.line.end(); - pair = k; - } - if (pair != -1) { - b = touching_lines[pair].end() - touching_lines[pair].start(); - Point2f p = trueend - truestart; - double oa = det(p,a); - double ob = det(p,b); - if (sgn(oa) != sgn(ob) || fabs(oa) < tolerance * linetest.line.length() || fabs(ob) < tolerance * linetest.line.length()) { - // crossed - if (fabs(oa) > tolerance * linetest.line.length()) { // checks not parallel... - loc.add( l.intersection_point(linetest.line, axis) ); + if (intersect_region(linetest.line, l, tolerance * linetest.line.length())) { + switch (intersect_line_distinguish(linetest.line, l, tolerance * linetest.line.length())) { + case 0: + break; + case 2: { + loc.insert(l.intersection_point(linetest.line, axis)); + } break; + case 1: + if (truestart != linetest.line.start() && truestart != linetest.line.end()) { + if (!touching_lines.size()) { + touching_lines.push_back(linetest.line); + } else { + Point2f a, b; + int pair = -1; + // if there may be more than one touches in the same pixel, we have to build a list of + // possibles... + for (size_t k = 0; k < touching_lines.size() && pair == -1; k++) { + if (linetest.line.start() == touching_lines[k].start() || + linetest.line.end() == touching_lines[k].end()) { + a = linetest.line.end() - linetest.line.start(); + pair = k; + } else if (linetest.line.start() == touching_lines[k].end() || + linetest.line.end() == touching_lines[k].start()) { + a = linetest.line.start() - linetest.line.end(); + pair = k; } - else if (fabs(ob) > tolerance * linetest.line.length()) { - loc.add( l.intersection_point(touching_lines[pair], axis) ); + if (pair != -1) { + b = touching_lines[pair].end() - touching_lines[pair].start(); + Point2f p = trueend - truestart; + double oa = det(p, a); + double ob = det(p, b); + if (sgn(oa) != sgn(ob) || fabs(oa) < tolerance * linetest.line.length() || + fabs(ob) < tolerance * linetest.line.length()) { + // crossed + if (fabs(oa) > + tolerance * linetest.line.length()) { // checks not parallel... + loc.insert(l.intersection_point(linetest.line, axis)); + } else if (fabs(ob) > tolerance * linetest.line.length()) { + loc.insert(l.intersection_point(touching_lines[pair], axis)); + } else { + // parallel with both lines ... this shouldn't happen... + std::cerr << "couldn't chop at boundary" << std::endl; + } + } } - else { - // parallel with both lines ... this shouldn't happen... - cerr << "couldn't chop at boundary" << endl; - } - } - } - pair = -1; - } - touching_lines.push_back(linetest.line); + pair = -1; + } + touching_lines.push_back(linetest.line); + } } - } - break; - default: - break; - } - } - linetest.test = m_test; + break; + default: + break; + } + } + linetest.test = m_test; } - //} - //catch (pexception) { + //} + // catch (pexception) { // the lineref may have been deleted -- this is supposed to be tidied up // just ignore... - // cerr << "cut line exception -- missing line?" << endl; - //} - } - if (loc.size()) { - // there's no guarantee the loc actually happened in this pixel... - // check the first loc actually occurred in this pixel... - if ( (dir == l.direction() && (axis == XAXIS || l.sign() == 1)) || - (dir != l.direction() && (axis == YAXIS && l.sign() == -1)) ) { - if (pix == pixelate(l.point_on_line(loc.head(),axis))) { - found = true; + // cerr << "cut line exception -- missing line?" << endl; + //} + } + if (loc.size()) { + // there's no guarantee the loc actually happened in this pixel... + // check the first loc actually occurred in this pixel... + if ((dir == l.direction() && (axis == XAXIS || l.sign() == 1)) || + (dir != l.direction() && (axis == YAXIS && l.sign() == -1))) { + if (pix == pixelate(l.point_on_line(*loc.begin(), axis))) { + found = true; + } + } else { + if (pix == pixelate(l.point_on_line(*loc.rbegin(), axis))) { + found = true; + } } - } - else { - if (pix == pixelate(l.point_on_line(loc.tail(),axis))) { - found = true; + } + } + + if (loc.size()) { + // it intersected... + double pos; + if (dir == l.direction()) { + if (axis == XAXIS) { + pos = *loc.begin(); + l.by() = l.ay() + l.sign() * l.height() * (pos - l.ax()) / l.width(); + l.bx() = pos; + } else if (l.sign() == 1) { + pos = *loc.begin(); + l.bx() = l.ax() + l.width() * (pos - l.ay()) / l.height(); + l.by() = pos; + } else { + pos = *loc.rbegin(); + l.bx() = l.ax() + l.width() * (l.ay() - pos) / l.height(); + l.by() = pos; } - } - } - } - - if (loc.size()) { - // it intersected... - double pos; - if (dir == l.direction()) { - if (axis == XAXIS) { - pos = loc.head(); - l.by() = l.ay() + l.sign() * l.height() * (pos - l.ax()) / l.width(); - l.bx() = pos; - } - else if (l.sign() == 1) { - pos = loc.head(); - l.bx() = l.ax() + l.width() * (pos - l.ay()) / l.height(); - l.by() = pos; - } - else { - pos = loc.tail(); - l.bx() = l.ax() + l.width() * (l.ay() - pos) / l.height(); - l.by() = pos; - } - } - else { - if (axis == XAXIS) { - pos = loc.tail(); - l.ay() = l.by() - l.sign() * l.height() * (l.bx() - pos) / l.width(); - l.ax() = pos; - } - else if (l.sign() == 1) { - pos = loc.tail(); - l.ax() = l.bx() - l.width() * (l.by() - pos) / l.height(); - l.ay() = pos; - } - else { - pos = loc.head(); - l.ax() = l.bx() - l.width() * (pos - l.by()) / l.height(); - l.ay() = pos; - } - } - } -} - -pvecdouble SpacePixel::getCrossingPoints(const Line& l, int axis, pvecint& ignorelist ) -{ - pvecdouble cross_list; - pvecint checked_list = ignorelist; - - /* - // Regions no longer normalised - l.normalScale( m_region ); - - // Now it's me thats doing the squashing business... - // hmm... must correct pixelate function, not the DXF import... - - squash( l.bottom_left ); - squash( l.top_right ); - */ - - PixelRefList list = pixelateLine( l ); - - for (size_t i = 0; i < list.size(); i++) { - for (size_t j = 0; j < m_pixel_lines[ list[i].x ][ list[i].y ].size(); j++) { - int lineref = m_pixel_lines[ list[i].x ][ list[i].y ][j]; - if (checked_list.searchindex( lineref ) == paftl::npos) { - checked_list.add( lineref, paftl::ADD_HERE ); - if ( intersect_region(m_lines[lineref].line, l) ) { - double c; - if ( l.intersect_line(m_lines[lineref].line, axis, c) ) { - if (_finite(c)) { - cross_list.add( c ); - } - // if lines are coincident, just chuck on the start and the end - // of the crossing line: hope that there are no points actually on the - // line (otherwise these will be confused) - else if (axis == XAXIS) { - cross_list.add( m_lines[lineref].line.ax() ); - cross_list.add( m_lines[lineref].line.bx() ); - } - else /* if (axis == YAXIS) */ { - cross_list.add( m_lines[lineref].line.ay() ); - cross_list.add( m_lines[lineref].line.by() ); - } - } + } else { + if (axis == XAXIS) { + pos = *loc.rbegin(); + l.ay() = l.by() - l.sign() * l.height() * (l.bx() - pos) / l.width(); + l.ax() = pos; + } else if (l.sign() == 1) { + pos = *loc.rbegin(); + l.ax() = l.bx() - l.width() * (l.by() - pos) / l.height(); + l.ay() = pos; + } else { + pos = *loc.begin(); + l.ax() = l.bx() - l.width() * (pos - l.by()) / l.height(); + l.ay() = pos; } - } - } - } - return cross_list; + } + } } -bool SpacePixel::read( ifstream& stream, int version ) -{ - // clear anything that was there: - if (m_pixel_lines) - { - for (int i = 0; i < m_cols; i++) { - delete [] m_pixel_lines[i]; - } - delete [] m_pixel_lines; - m_pixel_lines = NULL; - } - if (m_display_lines) { - delete [] m_display_lines; - m_display_lines = NULL; - } - m_lines.clear(); +bool SpacePixel::read(std::istream &stream) { + // clear anything that was there: + m_display_lines.clear(); + m_lines.clear(); - // read name: - if (version >= VERSION_SPACEPIXELGROUPS) { - m_name.read( stream ); - stream.read( (char *) &m_show, sizeof(m_show) ); - } - else { - m_name = ""; - } - if (m_name.empty()) { - m_name = ""; - } + // read name: - m_edit = false; // <- just default to not editable on read + m_name = dXstring::readString(stream); + stream.read((char *)&m_show, sizeof(m_show)); - if (version >= VERSION_LAYERCOLORS) { - stream.read( (char *) &m_color, sizeof(m_color) ); - } + if (m_name.empty()) { + m_name = ""; + } - // read extents: - stream.read( (char *) &m_region, sizeof(m_region) ); + m_edit = false; // <- just default to not editable on read - // read rows / cols - stream.read( (char *) &m_rows, sizeof(m_rows) ); - stream.read( (char *) &m_cols, sizeof(m_cols) ); + stream.read((char *)&m_color, sizeof(m_color)); - // could work these two out on the fly, but it's easier to have them stored: - //m_pixel_height = m_region.height() / double(m_rows); - //m_pixel_width = m_region.width() / double(m_cols); + // read extents: + stream.read((char *)&m_region, sizeof(m_region)); - // prepare loader: - m_pixel_lines = new pvecint *[m_cols]; - for (int i = 0; i < m_cols; i++) { - m_pixel_lines[i] = new pvecint[m_rows]; - } + // read rows / cols + int rows, cols; + stream.read(reinterpret_cast(&rows), sizeof(rows)); + stream.read(reinterpret_cast(&cols), sizeof(cols)); + m_rows = static_cast(rows); + m_cols = static_cast(cols); - if (version < VERSION_DYNAMICLINES) { - // read lines as refvec... - prefvec lines; - lines.read( stream ); - // ... and transfer to new system: - m_ref = -1; - for (size_t i = 0; i < lines.size(); i++) { - m_lines.add(++m_ref, LineTest(lines[i],0)); - } - } - else { - stream.read((char *) &m_ref, sizeof(m_ref)); - m_lines.read( stream ); - } + // could work these two out on the fly, but it's easier to have them stored: + // m_pixel_height = m_region.height() / double(m_rows); + // m_pixel_width = m_region.width() / double(m_cols); - if (version < VERSION_SPACEPIXELGROUPS) { - // Scale up lines (should just work) - for (size_t i = 0; i < m_lines.size(); i++) { - m_lines[i].line.denormalScale(m_region); - } - } + // prepare loader: + m_pixel_lines = depthmapX::RowMatrix>(static_cast(m_rows), static_cast(m_cols)); - // now load into structure: - for (size_t n = 0; n < m_lines.size(); n++) { + stream.read((char *)&m_ref, sizeof(m_ref)); + dXreadwrite::readIntoMap(stream, m_lines); + // now load into structure: + int n = -1; + for (auto line : m_lines) { + n++; - PixelRefList list = pixelateLine( m_lines[n].line ); + PixelRefVector list = pixelateLine(line.second.line); - for (size_t m = 0; m < list.size(); m++) { - // note: m_pixel_lines is an *ordered* list! --- used by other ops. - m_pixel_lines[list[m].x][list[m].y].push_back( n ); - } - } + for (size_t m = 0; m < list.size(); m++) { + // note: m_pixel_lines is an *ordered* list! --- used by other ops. + m_pixel_lines(static_cast(list[m].y), static_cast(list[m].x)).push_back(n); + } + } - return true; + return true; } -bool SpacePixel::write( ofstream& stream ) -{ - // write name: - m_name.write( stream ); - stream.write( (char *) &m_show, sizeof(m_show) ); - stream.write( (char *) &m_color, sizeof(m_color) ); +bool SpacePixel::write(std::ofstream &stream) { + // write name: + dXstring::writeString(stream, m_name); + stream.write((char *)&m_show, sizeof(m_show)); + stream.write((char *)&m_color, sizeof(m_color)); - // write extents: - stream.write( (char *) &m_region, sizeof(m_region) ); + // write extents: + stream.write((char *)&m_region, sizeof(m_region)); - // write rows / cols - stream.write( (char *) &m_rows, sizeof(m_rows) ); - stream.write( (char *) &m_cols, sizeof(m_cols) ); + // write rows / cols + int rows = static_cast(m_rows); + int cols = static_cast(m_cols); + stream.write(reinterpret_cast(&rows), sizeof(rows)); + stream.write(reinterpret_cast(&cols), sizeof(cols)); - // write lines: - stream.write( (char *) &m_ref, sizeof(m_ref) ); - m_lines.write( stream ); + // write lines: + stream.write((char *)&m_ref, sizeof(m_ref)); - return true; -} + dXreadwrite::writeMap(stream, m_lines); + return true; +} diff --git a/salalib/spacepix.h b/salalib/spacepix.h index f75ec1bc..807f7dff 100644 --- a/salalib/spacepix.h +++ b/salalib/spacepix.h @@ -1,5 +1,6 @@ // sala - a component of the depthmapX - spatial network analysis platform // Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2018, Petros Koutsolampros // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -14,193 +15,41 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . - // This is my code to make a set of axial lines from a set of boundary lines -#ifndef __SPATIALDATA_H__ -#define __SPATIALDATA_H__ - -///////////////////////////////////////////////////////////////////////////////////////////////// - -class SalaShape; - -class PixelRef -{ -public: - short x; - short y; - PixelRef( short ax = -1, short ay = -1 ) - { x = ax; y = ay; } - PixelRef( int i ) - { x = short(i >> 16); y = short(i & 0xffff); } - bool empty() - { return x == -1 && y == -1; } - PixelRef up() const - { return PixelRef(x, y + 1); } - PixelRef left() const - { return PixelRef(x - 1, y); } - PixelRef right() const - { return PixelRef(x + 1, y); } - PixelRef down() const - { return PixelRef(x, y - 1); } - short& operator [] (int i) - { return (i == XAXIS) ? x : y; } - bool within( const PixelRef bl, const PixelRef tr ) const - { return (x >= bl.x && x <= tr.x && y >= bl.y && y <= tr.y); } - bool encloses( PixelRef testpoint ) const - { return (testpoint.x >= 0 && testpoint.x < x && testpoint.y >= 0 && testpoint.y < y);} - // directions for the ngraph: - enum {NODIR = 0x00, HORIZONTAL = 0x01, VERTICAL = 0x02, POSDIAGONAL = 0x04, NEGDIAGONAL = 0x08, DIAGONAL = 0x0c, NEGHORIZONTAL = 0x10, NEGVERTICAL = 0x20}; - short& row(char dir) - { return (dir & VERTICAL) ? x : y; } - short& col(char dir) - { return (dir & VERTICAL) ? y : x; } - const short& row(char dir) const - { return (dir & VERTICAL) ? x : y; } - const short& col(char dir) const - { return (dir & VERTICAL) ? y : x; } - PixelRef& move(char dir) - { switch (dir) - { - case POSDIAGONAL: x++; y++; break; - case NEGDIAGONAL: x++; y--; break; - case HORIZONTAL: x++; break; - case VERTICAL: y++; break; - case NEGHORIZONTAL: x--; break; - case NEGVERTICAL: y--; break; - } - return *this; } - bool isodd() - { return x % 2 == 1 && y % 2 == 1; } - bool iseven() - { return x % 2 == 0 && y % 2 == 0; } - friend bool operator == (const PixelRef a, const PixelRef b); - friend bool operator != (const PixelRef a, const PixelRef b); - friend bool operator < (const PixelRef a, const PixelRef b); - friend bool operator > (const PixelRef a, const PixelRef b); - friend PixelRef operator + (const PixelRef a, const PixelRef b); - friend PixelRef operator - (const PixelRef a, const PixelRef b); - friend PixelRef operator / (const PixelRef a, const int factor); - friend double dist(const PixelRef a, const PixelRef b); - friend double angle(const PixelRef a, const PixelRef b, const PixelRef c); - operator int() const - { return ((int(x) << 16) + (int(y) & 0xffff)); } -}; - -const PixelRef NoPixel( -1, -1 ); - -inline bool operator == (const PixelRef a, const PixelRef b) -{ - return (a.x == b.x) && (a.y == b.y); -} -inline bool operator != (const PixelRef a, const PixelRef b) -{ - return (a.x != b.x) || (a.y != b.y); -} -inline bool operator < (const PixelRef a, const PixelRef b) -{ - return (a.x < b.x) || (a.x == b.x && a.y < b.y); -} -inline bool operator > (const PixelRef a, const PixelRef b) -{ - return (a.x > b.x) || (a.x == b.x && a.y > b.y); -} -inline PixelRef operator + (const PixelRef a, const PixelRef b) -{ - return PixelRef(a.x + b.x, a.y + b.y); -} -inline PixelRef operator - (const PixelRef a, const PixelRef b) -{ - return PixelRef(a.x - b.x, a.y - b.y); -} -inline PixelRef operator / (const PixelRef a, const int factor) -{ - return PixelRef(a.x / factor, a.y / factor); -} +#pragma once -inline double dist(const PixelRef a, const PixelRef b) -{ - return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y)); -} +#include "salalib/pafcolor.h" +#include "salalib/pixelref.h" -inline double angle(const PixelRef a, const PixelRef b, const PixelRef c) -{ - if (c == NoPixel) { - return 0.0; - } - else { - // n.b. 1e-12 required for floating point error - return acos( double((a.x - b.x) * (b.x - c.x) + (a.y - b.y) * (b.y - c.y)) / - (sqrt(sqr(a.x - b.x) + sqr(a.y - b.y)) * sqrt(sqr(b.x - c.x) + sqr(b.y - c.y)) + 1e-12) ); - } -} +#include "genlib/p2dpoly.h" +#include "genlib/pafmath.h" +#include "genlib/simplematrix.h" +#include "genlib/stringutils.h" -// Now sizeof(PixelRef) == sizeof(int) better stored directly: -typedef pvector PixelRefList; +#include +#include -///////////////////////////////////////////////////////////////////////////////////////////////// - -struct PixelRefPair -{ - PixelRef a; - PixelRef b; - PixelRefPair(const PixelRef x = NoPixel, const PixelRef y = NoPixel) - { - a = x < y ? x : y; - b = x < y ? y : x; - } - friend bool operator == (const PixelRefPair& x, const PixelRefPair& y); - friend bool operator != (const PixelRefPair& x, const PixelRefPair& y); - friend bool operator < (const PixelRefPair& x, const PixelRefPair& y); - friend bool operator > (const PixelRefPair& x, const PixelRefPair& y); - -}; - -// note: these are made with a is always less than b -inline bool operator == (const PixelRefPair& x, const PixelRefPair& y) -{ - return (x.a == y.a && x.b == y.b); -} -inline bool operator != (const PixelRefPair& x, const PixelRefPair& y) -{ - return (x.a != y.a || x.b != y.b); -} -inline bool operator < (const PixelRefPair& x, const PixelRefPair& y) -{ - return ( (x.a == y.a) ? x.b < y.b : x.a < y.a ); -} -inline bool operator > (const PixelRefPair& x, const PixelRefPair& y) -{ - return ( (x.a == y.a) ? x.b > y.b : x.a > y.a ); -} - -///////////////////////////////////////////////////////////////////////////////////////////////// +class SalaShape; -class PixelBase -{ -protected: - int m_rows; - int m_cols; - QtRegion m_region; -public: - PixelBase() {;} - // constrain is constrain to bounding box (i.e., in row / col bounds) - virtual PixelRef pixelate(const Point2f&, bool constrain = true, int scalefactor = 1 ) const = 0; - PixelRefList pixelateLine( Line l, int scalefactor = 1 ) const; - PixelRefList pixelateLineTouching( Line l, double tolerance ) const; - PixelRefList quickPixelateLine(PixelRef p, PixelRef q); - bool includes(const PixelRef pix) const { - return (pix.x >= 0 && pix.x < m_cols && pix.y >= 0 && pix.y < m_rows); - } - int getCols() const { - return m_cols; - } - int getRows() const { - return m_rows; - } - const QtRegion& getRegion() const { - return m_region; - } +class PixelBase { + protected: + size_t m_rows; + size_t m_cols; + QtRegion m_region; + + public: + PixelBase() { ; } + // constrain is constrain to bounding box (i.e., in row / col bounds) + virtual PixelRef pixelate(const Point2f &, bool constrain = true, int scalefactor = 1) const = 0; + PixelRefVector pixelateLine(Line l, int scalefactor = 1) const; + PixelRefVector pixelateLineTouching(Line l, double tolerance) const; + PixelRefVector quickPixelateLine(PixelRef p, PixelRef q); + bool includes(const PixelRef pix) const { return (pix.x >= 0 && pix.x < static_cast(m_cols) && + pix.y >= 0 && pix.y < static_cast(m_rows)); } + size_t getCols() const { return m_cols; } + size_t getRows() const { return m_rows; } + const QtRegion &getRegion() const { return m_region; } }; ///////////////////////////////////////////// @@ -208,307 +57,107 @@ class PixelBase // couple of quick helpers struct LineTest { - Line line; - unsigned int test; - LineTest(const Line& l = Line(), int t = -1) - { line = l; test = t; } -// operator Line() {return line;} + Line line; + unsigned int test; + LineTest(const Line &l = Line(), int t = -1) { + line = l; + test = t; + } + // operator Line() {return line;} }; -/* -struct LineTest : public Line -{ -public: - // Inside / outside system... sides refer to the side hit when line runs from A to B - enum { NEITHER = 0, LEFT = 1, RIGHT = 2 }; - unsigned short inside; - // - unsigned int test; -public: - LineTest(const Line& l = Line(), int t = -1) : Line(l) - { test = t; inside = NEITHER; } -}; -*/ + struct LineKey { - unsigned int file : 4; - unsigned int layer : 6; - unsigned int lineref : 20; - operator int() { return *(int *)this; } - LineKey(int value = 0) { *(int *)this = value; } - friend bool operator < (LineKey a, LineKey b); - friend bool operator > (LineKey a, LineKey b); - friend bool operator == (LineKey a, LineKey b); + unsigned int file : 4; + unsigned int layer : 6; + unsigned int lineref : 20; + operator int() { return *(int *)this; } + LineKey(int value = 0) { *(int *)this = value; } + friend bool operator<(LineKey a, LineKey b); + friend bool operator>(LineKey a, LineKey b); + friend bool operator==(LineKey a, LineKey b); }; -inline bool operator < (LineKey a, LineKey b) -{ return int(a) < int(b); } -inline bool operator > (LineKey a, LineKey b) -{ return int(a) > int(b); } -inline bool operator == (LineKey a, LineKey b) -{ return int(a) == int(b); } +inline bool operator<(LineKey a, LineKey b) { return int(a) < int(b); } +inline bool operator>(LineKey a, LineKey b) { return int(a) > int(b); } +inline bool operator==(LineKey a, LineKey b) { return int(a) == int(b); } ///////////////////////////////////////////// -class SpacePixel : public PixelBase -{ - friend class PointMap; - friend class AxialMaps; - friend class AxialPolygons; - friend class ShapeMap; // for transfer to everything being ShapeMaps -protected: - bool m_lock; - mutable bool m_newline; -protected: - PafColor m_color; - int m_style; // allows for bold / dotted lines etc - pstring m_name; - bool m_show; - bool m_edit; - pvecint **m_pixel_lines; -// int m_rows; -// int m_cols; -// -// double m_pixel_height; -// double m_pixel_width; - // - int m_ref; - pmap m_lines; - // - // for screen drawing - mutable int *m_display_lines; - mutable int m_current; - // - // for line testing - mutable unsigned int m_test; - // -public: - SpacePixel(const pstring& name = pstring("Default")); - virtual ~SpacePixel(); - // - SpacePixel(const SpacePixel& spacepixel); - SpacePixel& operator = (const SpacePixel& spacepixel); - void construct(const SpacePixel& spacepixel); - // - PixelRef pixelate( const Point2f& p, bool constrain = true, int = 1 ) const; -// PixelRefList pixelate( const Line& l ) const; - // - void initLines(int size, const Point2f& min, const Point2f& max, double density = 1.0); - void reinitLines(double density); // just reinitialises pixel lines, keeps lines, current ref and test setting - // - void addLine(const Line& l); - void sortPixelLines(); - // - int addLineDynamic(const Line& l); - - // Quick mod - TV -#if defined(_WIN32) - bool removeLineDynamic(int ref, Line& line = Line() ); // fills in line if it finds it -#else - bool removeLineDynamic(int ref, Line& line); // fills in line if it finds it -#endif - // - virtual void makeViewportLines( const QtRegion& viewport ) const; - virtual bool findNextLine(bool&) const; - virtual const Line& getNextLine() const; - // - bool intersect(const Line& l, double tolerance = 0.0); - bool intersect_exclude(const Line& l, double tolerance = 0.0); - // - // Point2f getFirstCrossingPoint(const Line& l, int fromend, pvecint& ignorelist = pvecint()); - void cutLine(Line& l, short dir); - // Quick mod - TV -#if defined(_WIN32) - pvecdouble getCrossingPoints(const Line& l, int ignore1, pvecint& ignorelist = pvecint() ); -#else - pvecdouble getCrossingPoints(const Line& l, int ignore1, pvecint& ignorelist); -#endif - // - QtRegion& getRegion() const - { return (QtRegion&) m_region; } - // - const pmap& getAllLines() const // Danger! Use solely to look at the raw line data - { return m_lines; } - // - // For easy layer manipulation: - void setName(const pstring& name) - { m_name = name; } - pstring getName() - { return m_name; } - void setShow(bool show = true) - { m_show = show; } - bool isShown() const - { return m_show; } - void setEditable(bool edit = true) - { m_edit = edit; } - bool isEditable() const - { return m_edit; } -public: - // for screen drawing: - PafColor getLineColor(bool in_color = true) const - { return m_color; } - int getLineStyle() const - { return m_style; } - const bool getLineSelected() const - { return false; } // selection not enabled as yet for non-axial lines -- note: major change around when it happens - void setColor(const PafColor& color) - { m_color = color; } - void setStyle(const int style) - { m_style = style; } - // just to know... - int getLineCount() const - { return (int)m_lines.size(); } -public: - virtual bool read( ifstream& stream, int version ); - virtual bool write( ofstream& stream ); - friend bool operator == (const SpacePixel& a, const SpacePixel& b); +class SpacePixel : public PixelBase { + friend class PointMap; + friend class AxialMaps; + friend class AxialPolygons; + friend class ShapeMap; // for transfer to everything being ShapeMaps + protected: + bool m_lock; + mutable bool m_newline; + + protected: + PafColor m_color; + int m_style; // allows for bold / dotted lines etc + std::string m_name; + bool m_show; + bool m_edit; + depthmapX::RowMatrix> m_pixel_lines; + + int m_ref; + std::map m_lines; + // + // for screen drawing + mutable std::vector m_display_lines; + mutable int m_current; + // + // for line testing + mutable unsigned int m_test; + // + public: + SpacePixel(const std::string &name = std::string("Default")); + // + SpacePixel(const SpacePixel &spacepixel); + SpacePixel &operator=(const SpacePixel &spacepixel); + void construct(const SpacePixel &spacepixel); + // + PixelRef pixelate(const Point2f &p, bool constrain = true, int = 1) const; + // PixelRefVector pixelate( const Line& l ) const; + // + void initLines(int size, const Point2f &min, const Point2f &max, double density = 1.0); + void reinitLines(double density); // just reinitialises pixel lines, keeps lines, current ref and test setting + // + void addLine(const Line &l); + void sortPixelLines(); + // + int addLineDynamic(const Line &l); + + virtual void makeViewportLines(const QtRegion &viewport) const; + virtual bool findNextLine(bool &) const; + virtual const Line &getNextLine() const; + // + bool intersect(const Line &l, double tolerance = 0.0); + bool intersect_exclude(const Line &l, double tolerance = 0.0); + + void cutLine(Line &l, short dir); + + QtRegion &getRegion() const { return (QtRegion &)m_region; } + + void setRegion(QtRegion ®ion) { m_region = region; } + // + const std::map &getAllLines() const // Danger! Use solely to look at the raw line data + { + return m_lines; + } + // + // For easy layer manipulation: + void setName(const std::string &name) { m_name = name; } + std::string getName() { return m_name; } + void setShow(bool show = true) { m_show = show; } + bool isShown() const { return m_show; } + void setEditable(bool edit = true) { m_edit = edit; } + bool isEditable() const { return m_edit; } + + public: + virtual bool read(std::istream &stream); + virtual bool write(std::ofstream &stream); + friend bool operator==(const SpacePixel &a, const SpacePixel &b); }; // simply check they are the same name... useful for findindex from the group -inline bool operator == (const SpacePixel& a, const SpacePixel& b) -{ - return a.m_name == b.m_name; -} - -// Two levels of space pixel layering (file, and layers in files)... - -template -class SpacePixelGroup : public pqvector -{ -protected: - pstring m_name; // <- file name - mutable int m_current_layer; -public: - QtRegion m_region; // easier public for now - // - SpacePixelGroup(const pstring& name = pstring()) - { m_name = name; m_current_layer = -1; } - void setName(const pstring& name) - { m_name = name; } - const pstring& getName() const - { return m_name; } - // - QtRegion& getRegion() const - { return (QtRegion&) m_region; } - // - // Screen functionality: - void makeViewportShapes( const QtRegion& viewport = QtRegion() ) const; - bool findNextShape(bool& nextlayer) const; - - // Quick mod - TV -#if 0 -#if !defined(_WIN32) - size_t size() const - { return pmemvec::size(); } - - T& at(size_t pos) - { return prefvec::at(pos); } - - T& tail() - { return prefvec::tail(); } - -#endif -#endif - - const SalaShape& getNextShape() const - { return prefvec::at(m_current_layer).getNextShape(); } - const PafColor getLineColor() const - { return prefvec::at(m_current_layer).getLineColor(); } - const int getLineStyle() const - { return prefvec::at(m_current_layer).getLineStyle(); } - const bool getLineSelected() const - { return prefvec::at(m_current_layer).getLineSelected(); } - - // - void cutLine(Line& l);//, short dir); - // - // Is any one sublayer shown? - - bool isShown() const - { for (size_t i = 0; i < prefvec::size(); i++) if (prefvec::at(i).isShown()) return true; return false; } - // -public: - bool read( ifstream& stream, int version, bool drawinglayer = true ); - bool write( ofstream& stream, int version ); -}; - -template -void SpacePixelGroup::cutLine(Line& l)//, short dir) -{ - for (size_t i = 0; i < prefvec::size(); i++) { - if (prefvec::at(i).isShown()) { - prefvec::at(i).cutLine(l); //,dir); - } - } -} - -template -void SpacePixelGroup::makeViewportShapes( const QtRegion& viewport ) const -{ - m_current_layer = -1; - for (size_t i = prefvec::size() - 1; i != paftl::npos; i--) { - if (prefvec::at(i).isShown()) { - m_current_layer = (int) i; - prefvec::at(i).makeViewportShapes( (viewport.isNull() ? m_region : viewport) ); - } - } -} -template -bool SpacePixelGroup::findNextShape(bool& nextlayer) const -{ - if (m_current_layer == -1) - return false; - while (!prefvec::at(m_current_layer).findNextShape(nextlayer)) { - while (++m_current_layer < (int)prefvec::size() && !prefvec::at(m_current_layer).isShown()); - if (m_current_layer == prefvec::size()) { - m_current_layer = -1; - return false; - } - } - return true; -} -template -bool SpacePixelGroup::read( ifstream& stream, int version, bool drawinglayer ) -{ - if (version >= VERSION_SPACEPIXELGROUPS) { - m_name.read(stream); - stream.read( (char *) &m_region, sizeof(m_region) ); - int count; - stream.read( (char *) &count, sizeof(count) ); - for (int i = 0; i < count; i++) { - SpacePixelGroup::push_back(T()); - prefvec::tail().read(stream,version,true); - } - } - else { - m_name = ""; - SpacePixelGroup::push_back(T()); - prefvec::tail().read(stream,version,true); - m_region = prefvec::tail().getRegion(); - } - if (m_name.empty()) { - m_name = ""; - } - return true; -} -template -bool SpacePixelGroup::write( ofstream& stream, int version ) -{ - m_name.write(stream); - stream.write( (char *) &m_region, sizeof(m_region) ); - - // Quick mod - TV - int count = prefvec::size(); - stream.write( (char *) &count, sizeof(count) ); - for (int i = 0; i < count; i++) { - prefvec::at(i).write(stream,version); - } - return true; -} - -// (Currently) two layers of SpacePixeling, the file, and the whole lot (in SuperSpacePixel) -// (I aim to split this into a set of ShapeMaps with the version 9 layer system for each subset) -#include -#include -typedef SpacePixelGroup < ShapeMap> SpacePixelFile; -//typedef SpacePixelGroup SpacePixelFile; -typedef SpacePixelGroup SuperSpacePixel; - -#endif +inline bool operator==(const SpacePixel &a, const SpacePixel &b) { return a.m_name == b.m_name; } diff --git a/salalib/spacepixfile.cpp b/salalib/spacepixfile.cpp new file mode 100644 index 00000000..c8cf0830 --- /dev/null +++ b/salalib/spacepixfile.cpp @@ -0,0 +1,57 @@ +#include "salalib/spacepixfile.h" + +void SpacePixelFile::makeViewportShapes( const QtRegion& viewport ) const +{ + m_current_layer = -1; + for (size_t i = m_spacePixels.size() - 1; static_cast(i) != -1; i--) { + if (m_spacePixels[i].isShown()) { + m_current_layer = (int) i; + m_spacePixels[i].makeViewportShapes( (viewport.atZero() ? m_region : viewport) ); + } + } +} + +bool SpacePixelFile::findNextShape(bool& nextlayer) const +{ + if (m_current_layer == -1) + return false; + while (!m_spacePixels[m_current_layer].findNextShape(nextlayer)) { + while (++m_current_layer < (int)m_spacePixels.size() && !m_spacePixels[m_current_layer].isShown()); + if (m_current_layer == static_cast(m_spacePixels.size())) { + m_current_layer = -1; + return false; + } + } + return true; +} + +bool SpacePixelFile::read( std::istream& stream ) +{ + m_name = dXstring::readString(stream); + stream.read( (char *) &m_region, sizeof(m_region) ); + int count; + stream.read( (char *) &count, sizeof(count) ); + for (int i = 0; i < count; i++) { + m_spacePixels.emplace_back(); + m_spacePixels.back().read(stream); + } + + if (m_name.empty()) { + m_name = ""; + } + return true; +} + +bool SpacePixelFile::write( std::ofstream& stream ) +{ + dXstring::writeString(stream, m_name); + stream.write( (char *) &m_region, sizeof(m_region) ); + + // Quick mod - TV + int count = m_spacePixels.size(); + stream.write( (char *) &count, sizeof(count) ); + for (auto& spacePixel: m_spacePixels) { + spacePixel.write(stream); + } + return true; +} diff --git a/salalib/spacepixfile.h b/salalib/spacepixfile.h new file mode 100644 index 00000000..a4425730 --- /dev/null +++ b/salalib/spacepixfile.h @@ -0,0 +1,57 @@ +#pragma once + +#include "salalib/shapemap.h" +#include "genlib/p2dpoly.h" +#include +#include + +class SpacePixelFile +{ +protected: + std::string m_name; // <- file name + mutable int m_current_layer; +public: + std::deque m_spacePixels; + QtRegion m_region; // easier public for now + // + SpacePixelFile(const std::string& name = std::string()) + { m_name = name; m_current_layer = -1; } + SpacePixelFile(SpacePixelFile&& other): + m_name(other.m_name), + m_current_layer(other.m_current_layer), + m_spacePixels(std::move(other.m_spacePixels)), + m_region(std::move(other.m_region)) {} + SpacePixelFile& operator =(SpacePixelFile&& other) { + m_name = other.m_name; + m_current_layer = other.m_current_layer; + m_spacePixels = std::move(other.m_spacePixels); + m_region = std::move(other.m_region); + return *this; + } + SpacePixelFile(const SpacePixelFile&) = delete; + SpacePixelFile& operator =(const SpacePixelFile&) = delete; + + void setName(const std::string& name) + { m_name = name; } + const std::string& getName() const + { return m_name; } + // + QtRegion& getRegion() const + { return (QtRegion&) m_region; } + // + // Screen functionality: + void makeViewportShapes( const QtRegion& viewport = QtRegion() ) const; + bool findNextShape(bool& nextlayer) const; + + const SalaShape& getNextShape() const + { return m_spacePixels[m_current_layer].getNextShape(); } + + // Is any one sublayer shown? + + bool isShown() const + { for (size_t i = 0; i < m_spacePixels.size(); i++) if (m_spacePixels[i].isShown()) return true; return false; } + // +public: + bool read(std::istream &stream); + bool write(std::ofstream& stream); +}; diff --git a/salalib/sparksieve2.cpp b/salalib/sparksieve2.cpp index cf966502..c7657530 100644 --- a/salalib/sparksieve2.cpp +++ b/salalib/sparksieve2.cpp @@ -26,7 +26,6 @@ #include #include -#include #include #include "sparksieve2.h" @@ -43,7 +42,7 @@ sparkSieve2::~sparkSieve2() { } -bool sparkSieve2::testblock( const Point2f& point, const pqmap& lines, double tolerance ) +bool sparkSieve2::testblock( const Point2f& point, const std::vector& lines, double tolerance ) { Line l(m_centre, point); @@ -52,10 +51,10 @@ bool sparkSieve2::testblock( const Point2f& point, const pqmap& lines, return true; } - for (size_t i = 0; i < lines.size(); i++) + for (auto line: lines) { // Note: must check regions intersect before using this intersect_line test -- see notes on intersect_line - if (intersect_region(l,lines.value(i),tolerance) && intersect_line(l,lines.value(i),tolerance)) { + if (intersect_region(l,line,tolerance) && intersect_line(l,line,tolerance)) { return true; } } @@ -65,11 +64,11 @@ bool sparkSieve2::testblock( const Point2f& point, const pqmap& lines, // -void sparkSieve2::block( const pqmap& lines, int q ) +void sparkSieve2::block( const std::vector& lines, int q ) { - for (size_t i = 0; i < lines.size(); i++) { - double a = tanify(lines.value(i).start(), q); - double b = tanify(lines.value(i).end(), q); + for (auto line: lines) { + double a = tanify(line.start(), q); + double b = tanify(line.end(), q); sparkZone2 block; if (a < b) { @@ -81,61 +80,65 @@ void sparkSieve2::block( const pqmap& lines, int q ) block.end = a + 1e-10; } // this creates a list of blocks sorted by start location - m_blocks.add(block); + m_blocks.push_back(block); } + std::sort( m_blocks.begin(), m_blocks.end() ); + m_blocks.erase( std::unique( m_blocks.begin(), m_blocks.end() ), m_blocks.end() ); } void sparkSieve2::collectgarbage() { - m_gaps.first(); + auto iter = m_gaps.begin(); + auto blockIter = m_blocks.begin(); - for (size_t i = 0; i < m_blocks.size() && !m_gaps.is_tail(); i++) + for (; blockIter != m_blocks.end() && iter != m_gaps.end();) { - if (m_blocks[i].end < (*m_gaps).start) { + if (blockIter->end < iter->start) { + blockIter++; continue; } - sparkZone2& block = m_blocks[i]; bool create = true; - if (block.start <= (*m_gaps).start) { + if (blockIter->start <= iter->start) { create = false; - if (block.end > (*m_gaps).start) { + if (blockIter->end > iter->start) { // simply move the start in front of us - (*m_gaps).start = block.end; + iter->start = blockIter->end; } } - if (block.end >= (*m_gaps).end) { + if (blockIter->end >= iter->end) { create = false; - if (block.start < (*m_gaps).end) { + if (blockIter->start < iter->end) { // move the end behind us - (*m_gaps).end = block.start; + iter->end = blockIter->start; } } - if ((*m_gaps).end <= (*m_gaps).start + 1e-10) { // 1e-10 required for floating point error - i--; // on the next iteration, stay with this block - m_gaps.postdel(); + if (iter->end <= iter->start + 1e-10) { // 1e-10 required for floating point error + iter = m_gaps.erase(iter); + continue; // on the next iteration, stay with this block } - else if (block.end > (*m_gaps).end) { - i--; // on the next iteration, stay with this block - m_gaps++; + else if (blockIter->end > iter->end) { + ++iter; + continue; // on the next iteration, stay with this block } else if (create) { // add a new gap (has to be behind us), and move the start in front of us - m_gaps.preins( sparkZone2( (*m_gaps).start, block.start ) ); - (*m_gaps).start = block.end; + m_gaps.insert(iter, sparkZone2( iter->start, blockIter->start ) ); + iter->start = blockIter->end; } + blockIter++; } // reset blocks for next row: m_blocks.clear(); } -// q quadrants: -// -// \ 6 | 7 / -// 0 \ | / 1 -// - - - - -// 2 / | \ 3 -// / 4 | 5 \ -// +/* q quadrants: +* +* \ 6 | 7 / +* 0 \ | / 1 +* - - - - +* 2 / | \ 3 +* / 4 | 5 \ +*/ double sparkSieve2::tanify( const Point2f& point, int q ) { diff --git a/salalib/sparksieve2.h b/salalib/sparksieve2.h index c611e8bf..8e026097 100644 --- a/salalib/sparksieve2.h +++ b/salalib/sparksieve2.h @@ -22,6 +22,9 @@ #define __SPARKSIEVE2_H__ #include +#include "genlib/p2dpoly.h" +#include +#include class sparkSieve2 { @@ -38,16 +41,17 @@ class sparkSieve2 friend bool operator < (const sparkZone2& a, const sparkZone2& b); friend bool operator > (const sparkZone2& a, const sparkZone2& b); }; +private: Point2f m_centre; double m_maxdist; // for creating graphs that only see out a certain distance: set to -1.0 for infinite - pqvector m_blocks; + std::vector m_blocks; public: - plist m_gaps; + std::list m_gaps; public: sparkSieve2( const Point2f& centre, double maxdist = -1.0 ); ~sparkSieve2(); - bool testblock( const Point2f& point, const pqmap& lines, double tolerance ); - void block( const pqmap& lines, int q ); + bool testblock(const Point2f& point, const std::vector &lines, double tolerance ); + void block(const std::vector &lines, int q ); void collectgarbage(); double tanify( const Point2f& point, int q ); // diff --git a/salalib/tidylines.cpp b/salalib/tidylines.cpp new file mode 100644 index 00000000..fcf01265 --- /dev/null +++ b/salalib/tidylines.cpp @@ -0,0 +1,124 @@ +#include "salalib/tidylines.h" +#include "salalib/tolerances.h" + +// helper -- a little class to tidy up a set of lines + +void TidyLines::tidy(std::vector& lines, const QtRegion& region) +{ + m_region = region; + double maxdim = std::max(m_region.width(),m_region.height()); + + // simple first pass -- remove very short lines + lines.erase( + std::remove_if(lines.begin(), lines.end(), + [maxdim](const Line& line) + {return line.length() < maxdim * TOLERANCE_B;}), lines.end()); + + // now load up m_lines... + initLines(lines.size(),m_region.bottom_left,m_region.top_right); + for (auto& line: lines) { + addLine(line); + } + sortPixelLines(); + + std::vector removelist; + for (size_t i = 0; i < lines.size(); i++) { + // n.b., as m_lines have just been made, note that what's in m_lines matches whats in lines + // we will use this later! + m_test++; + m_lines[i].test = m_test; + PixelRefVector list = pixelateLine( m_lines[i].line ); + for (size_t a = 0; a < list.size(); a++) { + auto pixel_lines = m_pixel_lines(static_cast(list[a].y), static_cast(list[a].x)); + for (int j: pixel_lines) { + if (m_lines[j].test != m_test && j > (int)i && intersect_region(lines[i],lines[j],TOLERANCE_B * maxdim)) { + m_lines[j].test = m_test; + int axis_i = (lines[i].width() >= lines[i].height()) ? XAXIS : YAXIS; + int axis_j = (lines[j].width() >= lines[j].height()) ? XAXIS : YAXIS; + int axis_reverse = (axis_i == XAXIS) ? YAXIS : XAXIS; + if (axis_i == axis_j && fabs(lines[i].grad(axis_reverse) - lines[j].grad(axis_reverse)) < TOLERANCE_A + && fabs(lines[i].constant(axis_reverse) - lines[j].constant(axis_reverse)) < (TOLERANCE_B * maxdim)) { + // check for overlap and merge + int parity = (axis_i == XAXIS) ? 1 : lines[i].sign(); + if ((lines[i].start()[axis_i] * parity + TOLERANCE_B * maxdim) > (lines[j].start()[axis_j] * parity) && + (lines[i].start()[axis_i] * parity) < (lines[j].end()[axis_j] * parity + TOLERANCE_B * maxdim)) { + int end = ((lines[i].end()[axis_i] * parity) > (lines[j].end()[axis_j] * parity)) ? i : j; + lines[j].bx() = lines[end].bx(); + lines[j].by() = lines[end].by(); + removelist.push_back(i); + continue; // <- don't do this any more, we've zapped it and replaced it with the later line + } + if ((lines[j].start()[axis_j] * parity + TOLERANCE_B * maxdim) > (lines[i].start()[axis_i] * parity) && + (lines[j].start()[axis_j] * parity) < (lines[i].end()[axis_i] * parity + TOLERANCE_B * maxdim)) { + int end = ((lines[i].end()[axis_i] * parity) > (lines[j].end()[axis_j] * parity)) ? i : j; + lines[j].ax() = lines[i].ax(); + lines[j].ay() = lines[i].ay(); + lines[j].bx() = lines[end].bx(); + lines[j].by() = lines[end].by(); + removelist.push_back(i); + continue; // <- don't do this any more, we've zapped it and replaced it with the later line + } + } + } + } + } + } + + // comes out sorted, remove duplicates just in case + removelist.erase(std::unique(removelist.begin(), removelist.end()), removelist.end()); + + for(auto iter = removelist.rbegin(); iter != removelist.rend(); ++iter) + lines.erase(lines.begin() + *iter); + removelist.clear(); // always clear this list, it's reused +} + +void TidyLines::quicktidy(std::map& lines, const QtRegion& region) +{ + m_region = region; + + double avglen = 0.0; + + for (auto line: lines) { + avglen += line.second.length(); + } + avglen /= lines.size(); + + double tolerance = avglen * 10e-6; + + auto iter = lines.begin(), end = lines.end(); + for(; iter != end; ) { + if (iter->second.length() < tolerance) { + iter = lines.erase(iter); + } else { + ++iter; + } + } + + // now load up m_lines... + initLines(lines.size(),m_region.bottom_left,m_region.top_right); + for (auto line: lines) { + addLine(line.second); + } + sortPixelLines(); + + // and chop duplicate lines: + std::vector removelist; + int i = -1; + for (auto line: lines) { + i++; + PixelRef start = pixelate(line.second.start()); + auto& pixel_lines = m_pixel_lines(static_cast(start.y), static_cast(start.x)); + for (int k: pixel_lines) { + if (k > int(i) && approxeq(m_lines[i].line.start(),m_lines[k].line.start(),tolerance)) { + if (approxeq(m_lines[i].line.end(),m_lines[k].line.end(),tolerance)) { + removelist.push_back(line.first); + break; + } + } + } + } + for(int remove: removelist) { + lines.erase(remove); + } + removelist.clear(); // always clear this list, it's reused} +} diff --git a/salalib/tidylines.h b/salalib/tidylines.h new file mode 100644 index 00000000..8748e6ab --- /dev/null +++ b/salalib/tidylines.h @@ -0,0 +1,14 @@ +#pragma once + +#include "salalib/spacepix.h" + +#include "genlib/p2dpoly.h" + +// helpers... a class to tidy up ugly maps people may give me... + +class TidyLines : public SpacePixel +{ +public: + void tidy(std::vector &lines, const QtRegion& region); + void quicktidy(std::map &lines, const QtRegion& region); +}; diff --git a/salalib/tolerances.h b/salalib/tolerances.h new file mode 100644 index 00000000..ef09e349 --- /dev/null +++ b/salalib/tolerances.h @@ -0,0 +1,21 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2018 Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +static const double TOLERANCE_A = 1e-9; +static const double TOLERANCE_B = 1e-12; +static const double TOLERANCE_C = 1e-6; diff --git a/salalib/topomet.cpp b/salalib/topomet.cpp deleted file mode 100644 index 97989185..00000000 --- a/salalib/topomet.cpp +++ /dev/null @@ -1,363 +0,0 @@ -// sala - a component of the depthmapX - spatial network analysis platform -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - - - -#include -#include -#include -#include -#include // For communicator - -#include // purely for the version info --- as phased out should replace -#include - -#include "topomet.h" - -bool ShapeGraph::analyseTopoMet(Communicator *comm, int analysis_type, double radius, bool sel_only) -{ - bool retvar = true; - - // Quick mod - TV -#if defined(_WIN32) - __time64_t atime = 0; -#else - time_t atime = 0; -#endif - - if (comm) { - qtimer( atime, 0 ); - comm->CommPostMessage( Communicator::NUM_RECORDS, (sel_only ? m_selection_set.size() : m_connectors.size()) ); - } - int reccount = 0; - - // record axial line refs for topological analysis - pvecint axialrefs; - // quick through to find the longest seg length - pvecfloat seglengths; - float maxseglength = 0.0f; - for (size_t cursor = 0; cursor < getShapeCount(); cursor++) - { - axialrefs.push_back(m_attributes.getValue(cursor,"Axial Line Ref")); - seglengths.push_back(m_attributes.getValue(cursor,"Segment Length")); - if (seglengths.tail() > maxseglength) { - maxseglength = seglengths.tail(); - } - } - - pstring prefix, suffix; - int maxbin; - if (analysis_type == TOPOMET_METHOD_METRIC) { - prefix = pstring("Metric "); - maxbin = 512; - } - else { - prefix = pstring("Topological "); - maxbin = 2; - } - if (radius != -1.0) { - suffix = pstringify(radius," R%.f metric"); - } - pstring choicecol = prefix + pstring("Choice") + suffix; - pstring wchoicecol = prefix + pstring("Choice [SLW]") + suffix; - pstring meandepthcol = prefix + pstring("Mean Depth") + suffix; - pstring wmeandepthcol = prefix + pstring("Mean Depth [SLW]") + suffix; - pstring totaldcol = prefix + pstring("Total Depth") + suffix; - pstring totalcol = prefix + pstring("Total Nodes") + suffix; - pstring wtotalcol = prefix + pstring("Total Length") + suffix; - // - if (!sel_only) { - m_attributes.insertColumn(choicecol.c_str()); - m_attributes.insertColumn(wchoicecol.c_str()); - } - m_attributes.insertColumn(meandepthcol.c_str()); - m_attributes.insertColumn(wmeandepthcol.c_str()); - m_attributes.insertColumn(totaldcol.c_str()); - m_attributes.insertColumn(totalcol.c_str()); - m_attributes.insertColumn(wtotalcol.c_str()); - // - unsigned int *seen = new unsigned int[getShapeCount()]; - TopoMetSegmentRef *audittrail = new TopoMetSegmentRef[getShapeCount()]; - TopoMetSegmentChoice *choicevals = new TopoMetSegmentChoice[getShapeCount()]; - for (size_t cursor = 0; cursor < getShapeCount(); cursor++) - { - if (sel_only && !m_attributes.isSelected(cursor)) { - continue; - } - for (size_t i = 0; i < getShapeCount(); i++) { - seen[i] = 0xffffffff; - } - pvecint list[512]; // 512 bins! - int bin = 0; - list[bin].push_back(cursor); - double rootseglength = seglengths[cursor]; - audittrail[cursor] = TopoMetSegmentRef(cursor,Connector::SEG_CONN_ALL,rootseglength*0.5,-1); - int open = 1; - unsigned int segdepth = 0; - double metdepth = 0.0, total = 0.0, wtotal = 0.0, wtotaldepth = 0.0, totalsegdepth = 0.0, totalmetdepth = 0.0; - while (open != 0) { - while (list[bin].size() == 0) { - bin++; - segdepth += 1; - if (bin == maxbin) { - bin = 0; - } - } - // - TopoMetSegmentRef& here = audittrail[list[bin].tail()]; - list[bin].pop_back(); - open--; - // - if (here.done) { - continue; - } - else { - here.done = true; - } - // - double len = seglengths[here.ref]; - totalsegdepth += segdepth; - totalmetdepth += here.dist - len*0.5; // preloaded with length ahead - wtotal += len; - if (analysis_type == TOPOMET_METHOD_METRIC) { - wtotaldepth += len * (here.dist - len*0.5); - } - else { - wtotaldepth += len * segdepth; - } - total += 1; - // - Connector& axline = m_connectors.at(here.ref); - axline.first(); - int connected_cursor = -1; - connected_cursor = axline.cursor(here.dir); - while (connected_cursor != -1) { - if (seen[connected_cursor] > segdepth && connected_cursor != cursor) { - bool seenalready = (seen[connected_cursor] == 0xffffffff) ? false : true; - float length = seglengths[connected_cursor]; - int axialref = axialrefs[connected_cursor]; - audittrail[connected_cursor] = TopoMetSegmentRef(connected_cursor,here.dir,here.dist+length,here.ref); - seen[connected_cursor] = segdepth; - if (radius == -1 || here.dist + length < radius) { - // puts in a suitable bin ahead of us... - open++; - // - if (analysis_type == TOPOMET_METHOD_METRIC) { - // better to divide by 511 but have 512 bins... - list[(bin + int(floor(0.5+511*length/maxseglength)))%512].push_back(connected_cursor); - } - else { // topological - if (axialrefs[here.ref] == axialref) { - list[bin].push_back(connected_cursor); - } - else { - list[(bin+1)%2].push_back(connected_cursor); - seen[connected_cursor] = segdepth + 1; // this is so if another node is connected directly to this one but is found later it is still handled -- note it can result in the connected cursor being added twice - } - } - } - // not sure why this is outside the radius restriction - // (sel_only: with restricted selection set, not all lines will be labelled) - // (seenalready: need to check that we're not doing this twice, given the seen can go twice) - - // Quick mod - TV - if (!sel_only && connected_cursor > (int)cursor && !seenalready) { // only one way paths, saves doing this twice - int subcur = connected_cursor; - while (subcur != -1) { - // in this method of choice, start and end lines are included - choicevals[subcur].choice += 1; - choicevals[subcur].wchoice += (rootseglength * length); - subcur = audittrail[subcur].previous; - } - } - } - axline.next(); - connected_cursor = axline.cursor(here.dir); - } - } - // also put in mean depth: - // - if (analysis_type == TOPOMET_METHOD_METRIC) { - m_attributes.setValue(cursor,meandepthcol.c_str(),totalmetdepth/(total-1)); - m_attributes.setValue(cursor,totaldcol.c_str(),totalmetdepth); - } - else { - m_attributes.setValue(cursor,meandepthcol.c_str(),totalsegdepth/(total-1)); - m_attributes.setValue(cursor,totaldcol.c_str(),totalsegdepth); - } - m_attributes.setValue(cursor,wmeandepthcol.c_str(),wtotaldepth/(wtotal-rootseglength)); - m_attributes.setValue(cursor,totalcol.c_str(),total); - m_attributes.setValue(cursor,wtotalcol.c_str(),wtotal); - // - if (comm) { - if (qtimer( atime, 500 )) { - if (comm->IsCancelled()) { - delete [] seen; - delete [] audittrail; - delete [] choicevals; - throw Communicator::CancelledException(); - } - } - comm->CommPostMessage( Communicator::CURRENT_RECORD, reccount ); - } - reccount++; - } - if (!sel_only) { - // note, I've stopped sel only from calculating choice values: - for (size_t cursor = 0; cursor < getShapeCount(); cursor++) - { - m_attributes.setValue(cursor,choicecol.c_str(),choicevals[cursor].choice); - m_attributes.setValue(cursor,wchoicecol.c_str(),choicevals[cursor].wchoice); - } - } - delete [] seen; - delete [] audittrail; - delete [] choicevals; - - if (!sel_only) { - setDisplayedAttribute(m_attributes.getColumnIndex(choicecol.c_str())); - } - else { - setDisplayedAttribute(m_attributes.getColumnIndex(meandepthcol.c_str())); - } - - return retvar; -} - -bool ShapeGraph::analyseTopoMetPD(Communicator *comm, int analysis_type) -{ - bool retvar = true; - - // record axial line refs for topological analysis - pvecint axialrefs; - // quick through to find the longest seg length - pvecfloat seglengths; - float maxseglength = 0.0f; - for (size_t cursor = 0; cursor < getShapeCount(); cursor++) - { - axialrefs.push_back(m_attributes.getValue(cursor,"Axial Line Ref")); - seglengths.push_back(m_attributes.getValue(cursor,"Segment Length")); - if (seglengths.tail() > maxseglength) { - maxseglength = seglengths.tail(); - } - } - - int maxbin; - pstring prefix; - if (analysis_type == TOPOMET_METHOD_METRIC) { - prefix = pstring("Metric "); - maxbin = 512; - } - else { - prefix = pstring("Topological "); - maxbin = 2; - } - pstring depthcol = prefix + pstring("Step Depth"); - - m_attributes.insertColumn(depthcol.c_str()); - - unsigned int *seen = new unsigned int[getShapeCount()]; - TopoMetSegmentRef *audittrail = new TopoMetSegmentRef[getShapeCount()]; - pvecint list[512]; // 512 bins! - int open = 0; - - for (size_t i = 0; i < getShapeCount(); i++) - { - seen[i] = 0xffffffff; - } - for (size_t i = 0; i < getSelCount(); i++) - { - size_t cursor = getSelSet().at(i); - seen[cursor] = 0; - open++; - double length = seglengths[cursor]; - audittrail[cursor] = TopoMetSegmentRef(cursor,Connector::SEG_CONN_ALL,length*0.5,-1); - if (analysis_type == TOPOMET_METHOD_METRIC) { - // better to divide by 511 but have 512 bins... - list[(int(floor(0.5+511*length/maxseglength)))%512].push_back(cursor); - } - else { - list[0].push_back(cursor); - } - m_attributes.setValue(cursor,depthcol.c_str(),0); - } - - unsigned int segdepth = 0; - int bin = 0; - - while (open != 0) { - while (list[bin].size() == 0) { - bin++; - segdepth += 1; - if (bin == maxbin) { - bin = 0; - } - } - // - TopoMetSegmentRef& here = audittrail[list[bin].tail()]; - list[bin].pop_back(); - open--; - // this is necessary using unsigned ints for "seen", as it is possible to add a node twice - if (here.done) { - continue; - } - else { - here.done = true; - } - // - double len = seglengths[here.ref]; - Connector& axline = m_connectors.at(here.ref); - axline.first(); - int connected_cursor = -1; - connected_cursor = axline.cursor(here.dir); - while (connected_cursor != -1) { - if (seen[connected_cursor] > segdepth) { - float length = seglengths[connected_cursor]; - int axialref = axialrefs[connected_cursor]; - seen[connected_cursor] = segdepth; - audittrail[connected_cursor] = TopoMetSegmentRef(connected_cursor,here.dir,here.dist+length,here.ref); - // puts in a suitable bin ahead of us... - open++; - // - if (analysis_type == TOPOMET_METHOD_METRIC) { - // better to divide by 511 but have 512 bins... - list[(bin + int(floor(0.5+511*length/maxseglength)))%512].push_back(connected_cursor); - m_attributes.setValue(connected_cursor,depthcol.c_str(),here.dist+length*0.5); - } - else { // topological - if (axialrefs[here.ref] == axialref) { - list[bin].push_back(connected_cursor); - m_attributes.setValue(connected_cursor,depthcol.c_str(),segdepth); - } - else { - list[(bin+1)%2].push_back(connected_cursor); - seen[connected_cursor] = segdepth + 1; // this is so if another node is connected directly to this one but is found later it is still handled -- note it can result in the connected cursor being added twice - m_attributes.setValue(connected_cursor,depthcol.c_str(),segdepth+1); - } - } - } - axline.next(); - connected_cursor = axline.cursor(here.dir); - } - } - - delete [] seen; - delete [] audittrail; - - setDisplayedAttribute(m_attributes.getColumnIndex(depthcol.c_str())); - - return retvar; -} diff --git a/salalib/vgamodules/CMakeLists.txt b/salalib/vgamodules/CMakeLists.txt new file mode 100644 index 00000000..89b71734 --- /dev/null +++ b/salalib/vgamodules/CMakeLists.txt @@ -0,0 +1,21 @@ +target_sources(salalib + PRIVATE + vgaisovist.cpp + vgaangular.cpp + vgametric.cpp + vgathroughvision.cpp + vgavisuallocal.cpp + vgavisualglobal.cpp + vgaangulardepth.cpp + vgametricdepth.cpp + vgavisualglobaldepth.cpp + PUBLIC + vgaangular.h + vgametric.h + vgavisualglobal.h + vgaangulardepth.h + vgametricdepth.h + vgavisualglobaldepth.h + vgaisovist.h + vgathroughvision.h + vgavisuallocal.h) diff --git a/salalib/vgamodules/vgaangular.cpp b/salalib/vgamodules/vgaangular.cpp new file mode 100644 index 00000000..85005db8 --- /dev/null +++ b/salalib/vgamodules/vgaangular.cpp @@ -0,0 +1,133 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "salalib/vgamodules/vgaangular.h" + +#include "genlib/stringutils.h" + +bool VGAAngular::run(Communicator *comm, PointMap &map, bool) { + time_t atime = 0; + if (comm) { + qtimer(atime, 0); + comm->CommPostMessage(Communicator::NUM_RECORDS, map.getFilledPointCount()); + } + + std::string radius_text; + if (m_radius != -1.0) { + if (map.getRegion().width() > 100.0) { + radius_text = std::string(" R") + dXstring::formatString(m_radius, "%.f"); + } else if (map.getRegion().width() < 1.0) { + radius_text = std::string(" R") + dXstring::formatString(m_radius, "%.4f"); + } else { + radius_text = std::string(" R") + dXstring::formatString(m_radius, "%.2f"); + } + } + + AttributeTable &attributes = map.getAttributeTable(); + + // n.b. these must be entered in alphabetical order to preserve col indexing: + std::string mean_depth_col_text = std::string("Angular Mean Depth") + radius_text; + int mean_depth_col = attributes.getOrInsertColumn(mean_depth_col_text.c_str()); + std::string total_detph_col_text = std::string("Angular Total Depth") + radius_text; + int total_depth_col = attributes.getOrInsertColumn(total_detph_col_text.c_str()); + std::string count_col_text = std::string("Angular Node Count") + radius_text; + int count_col = attributes.getOrInsertColumn(count_col_text.c_str()); + + // TODO: Binary compatibility. Remove in re-examination + total_depth_col = attributes.getOrInsertColumn(total_detph_col_text.c_str()); + + int count = 0; + + for (size_t i = 0; i < map.getCols(); i++) { + for (size_t j = 0; j < map.getRows(); j++) { + PixelRef curs = PixelRef(static_cast(i), static_cast(j)); + + if (map.getPoint(curs).filled()) { + + if (m_gates_only) { + count++; + continue; + } + + // TODO: Break out miscs/dist/cumangle into local variables and remove from Point class + for (auto &point : map.getPoints()) { + point.m_misc = 0; + point.m_dist = 0.0f; + point.m_cumangle = -1.0f; + } + + float total_angle = 0.0f; + int total_nodes = 0; + + // note that m_misc is used in a different manner to analyseGraph / PointDepth + // here it marks the node as used in calculation only + + std::set search_list; + search_list.insert(AngularTriple(0.0f, curs, NoPixel)); + map.getPoint(curs).m_cumangle = 0.0f; + while (search_list.size()) { + std::set::iterator it = search_list.begin(); + AngularTriple here = *it; + search_list.erase(it); + if (m_radius != -1.0 && here.angle > m_radius) { + break; + } + Point &p = map.getPoint(here.pixel); + // nb, the filled check is necessary as diagonals seem to be stored with 'gaps' left in + if (p.filled() && p.m_misc != ~0) { + p.getNode().extractAngular(search_list, &map, here); + p.m_misc = ~0; + if (!p.getMergePixel().empty()) { + Point &p2 = map.getPoint(p.getMergePixel()); + if (p2.m_misc != ~0) { + p2.m_cumangle = p.m_cumangle; + p2.getNode().extractAngular(search_list, &map, + AngularTriple(here.angle, p.getMergePixel(), NoPixel)); + p2.m_misc = ~0; + } + } + total_angle += p.m_cumangle; + total_nodes += 1; + } + } + + AttributeRow &row = map.getAttributeTable().getRow(AttributeKey(curs)); + if (total_nodes > 0) { + row.setValue(mean_depth_col, float(double(total_angle) / double(total_nodes))); + } + row.setValue(total_depth_col, total_angle); + row.setValue(count_col, float(total_nodes)); + + count++; // <- increment count + } + if (comm) { + if (qtimer(atime, 500)) { + if (comm->IsCancelled()) { + throw Communicator::CancelledException(); + } + comm->CommPostMessage(Communicator::CURRENT_RECORD, count); + } + } + } + } + + map.setDisplayedAttribute(-2); + map.setDisplayedAttribute(mean_depth_col); + + return true; +} diff --git a/salalib/vgamodules/vgaangular.h b/salalib/vgamodules/vgaangular.h new file mode 100644 index 00000000..d4602264 --- /dev/null +++ b/salalib/vgamodules/vgaangular.h @@ -0,0 +1,34 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/ivga.h" +#include "salalib/pixelref.h" +#include "salalib/pointdata.h" + +class VGAAngular : IVGA { + private: + double m_radius; + bool m_gates_only; + + public: + std::string getAnalysisName() const override { return "Angular Analysis"; } + bool run(Communicator *, PointMap &map, bool) override; + VGAAngular(double radius, bool gates_only) : m_radius(radius), m_gates_only(gates_only) {} +}; diff --git a/salalib/vgamodules/vgaangulardepth.cpp b/salalib/vgamodules/vgaangulardepth.cpp new file mode 100644 index 00000000..3c6b1b60 --- /dev/null +++ b/salalib/vgamodules/vgaangulardepth.cpp @@ -0,0 +1,75 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "salalib/vgamodules/vgaangulardepth.h" + +#include "genlib/stringutils.h" + +bool VGAAngularDepth::run(Communicator *, PointMap &map, bool) { + + AttributeTable &attributes = map.getAttributeTable(); + + // n.b., insert columns sets values to -1 if the column already exists + int path_angle_col = attributes.insertOrResetColumn("Angular Step Depth"); + + for (auto iter = attributes.begin(); iter != attributes.end(); iter++) { + PixelRef pix = iter->getKey().value; + map.getPoint(pix).m_misc = 0; + map.getPoint(pix).m_dist = 0.0f; + map.getPoint(pix).m_cumangle = -1.0f; + } + + std::set search_list; // contains root point + + for (auto &sel : map.getSelSet()) { + search_list.insert(AngularTriple(0.0f, sel, NoPixel)); + map.getPoint(sel).m_cumangle = 0.0f; + } + + // note that m_misc is used in a different manner to analyseGraph / PointDepth + // here it marks the node as used in calculation only + while (search_list.size()) { + std::set::iterator it = search_list.begin(); + AngularTriple here = *it; + search_list.erase(it); + Point &p = map.getPoint(here.pixel); + // nb, the filled check is necessary as diagonals seem to be stored with 'gaps' left in + if (p.filled() && p.m_misc != ~0) { + p.getNode().extractAngular(search_list, &map, here); + p.m_misc = ~0; + AttributeRow &row = map.getAttributeTable().getRow(AttributeKey(here.pixel)); + row.setValue(path_angle_col, float(p.m_cumangle)); + if (!p.getMergePixel().empty()) { + Point &p2 = map.getPoint(p.getMergePixel()); + if (p2.m_misc != ~0) { + p2.m_cumangle = p.m_cumangle; + AttributeRow &mergePixelRow = map.getAttributeTable().getRow(AttributeKey(p.getMergePixel())); + mergePixelRow.setValue(path_angle_col, float(p2.m_cumangle)); + p2.getNode().extractAngular(search_list, &map, + AngularTriple(here.angle, p.getMergePixel(), NoPixel)); + p2.m_misc = ~0; + } + } + } + } + + map.setDisplayedAttribute(-2); + map.setDisplayedAttribute(path_angle_col); + + return true; +} diff --git a/salalib/vgamodules/vgaangulardepth.h b/salalib/vgamodules/vgaangulardepth.h new file mode 100644 index 00000000..9c9c24d2 --- /dev/null +++ b/salalib/vgamodules/vgaangulardepth.h @@ -0,0 +1,29 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/ivga.h" +#include "salalib/pixelref.h" +#include "salalib/pointdata.h" + +class VGAAngularDepth : IVGA { + public: + std::string getAnalysisName() const override { return "Angular Depth"; } + bool run(Communicator *comm, PointMap &map, bool) override; +}; diff --git a/salalib/vgamodules/vgaisovist.cpp b/salalib/vgamodules/vgaisovist.cpp new file mode 100644 index 00000000..b36b4966 --- /dev/null +++ b/salalib/vgamodules/vgaisovist.cpp @@ -0,0 +1,124 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "salalib/vgamodules/vgaisovist.h" +#include "salalib/isovist.h" + +#include "genlib/stringutils.h" + +bool VGAIsovist::run(Communicator *comm, PointMap &map, bool simple_version) { + map.m_hasIsovistAnalysis = false; + // note, BSP tree plays with comm counting... + comm->CommPostMessage(Communicator::NUM_STEPS, 2); + comm->CommPostMessage(Communicator::CURRENT_STEP, 1); + BSPNode bspRoot = makeBSPtree(comm, map.getDrawingFiles()); + + AttributeTable &attributes = map.getAttributeTable(); + + comm->CommPostMessage(Communicator::CURRENT_STEP, 2); + + time_t atime = 0; + if (comm) { + qtimer(atime, 0); + comm->CommPostMessage(Communicator::NUM_RECORDS, map.getFilledPointCount()); + } + int count = 0; + + for (size_t i = 0; i < map.getCols(); i++) { + for (size_t j = 0; j < map.getRows(); j++) { + PixelRef curs = PixelRef(static_cast(i), static_cast(j)); + if (map.getPoint(curs).filled()) { + count++; + if (map.getPoint(curs).contextfilled() && !curs.iseven()) { + continue; + } + Isovist isovist; + isovist.makeit(&bspRoot, map.depixelate(curs), map.getRegion(), 0, 0); + + AttributeRow &row = attributes.getRow(AttributeKey(curs)); + isovist.setData(attributes, row, simple_version); + Node &node = map.getPoint(curs).getNode(); + std::vector *occ = node.m_occlusion_bins; + for (size_t k = 0; k < 32; k++) { + occ[k].clear(); + node.bin(static_cast(k)).setOccDistance(0.0f); + } + for (size_t k = 0; k < isovist.getOcclusionPoints().size(); k++) { + const PointDist &pointdist = isovist.getOcclusionPoints().at(k); + int bin = whichbin(pointdist.m_point - map.depixelate(curs)); + // only occlusion bins with a certain distance recorded (arbitrary scale note!) + if (pointdist.m_dist > 1.5) { + PixelRef pix = map.pixelate(pointdist.m_point); + if (pix != curs) { + occ[bin].push_back(pix); + } + } + node.bin(bin).setOccDistance(static_cast(pointdist.m_dist)); + } + } + if (comm) { + if (qtimer(atime, 500)) { + if (comm->IsCancelled()) { + throw Communicator::CancelledException(); + } + comm->CommPostMessage(Communicator::CURRENT_RECORD, count); + } + } + } + } + map.m_hasIsovistAnalysis = true; + + return true; +} + +BSPNode VGAIsovist::makeBSPtree(Communicator *communicator, const std::vector& drawingFiles) { + std::vector partitionlines; + for (const auto &pixelGroup : drawingFiles) { + for (const auto &pixel : pixelGroup.m_spacePixels) { + // chooses the first editable layer it can find: + if (pixel.isShown()) { + auto refShapes = pixel.getAllShapes(); + int k = -1; + for (const auto &refShape : refShapes) { + k++; + std::vector newLines = refShape.second.getAsLines(); + // I'm not sure what the tagging was meant for any more, + // tagging at the moment tags the *polygon* it was original attached to + // must check it is not a zero length line: + for (const Line &line : newLines) { + if (line.length() > 0.0) { + partitionlines.push_back(TaggedLine(line, k)); + } + } + } + } + } + } + + BSPNode bspRoot; + if (partitionlines.size()) { + + time_t atime = 0; + communicator->CommPostMessage(Communicator::NUM_RECORDS, static_cast(partitionlines.size())); + qtimer(atime, 0); + + BSPTree::make(communicator, atime, partitionlines, &bspRoot); + } + + return bspRoot; +} diff --git a/salalib/vgamodules/vgaisovist.h b/salalib/vgamodules/vgaisovist.h new file mode 100644 index 00000000..9454632e --- /dev/null +++ b/salalib/vgamodules/vgaisovist.h @@ -0,0 +1,30 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/ivga.h" +#include "salalib/pixelref.h" +#include "salalib/pointdata.h" + +class VGAIsovist : IVGA { + public: + std::string getAnalysisName() const override { return "Isovist Analysis"; } + bool run(Communicator *comm, PointMap &map, bool simple_version) override; + BSPNode makeBSPtree(Communicator *communicator, const std::vector &drawingFiles); +}; diff --git a/salalib/vgamodules/vgametric.cpp b/salalib/vgamodules/vgametric.cpp new file mode 100644 index 00000000..3fc22b33 --- /dev/null +++ b/salalib/vgamodules/vgametric.cpp @@ -0,0 +1,136 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "salalib/vgamodules/vgametric.h" + +#include "genlib/stringutils.h" + +// This is a slow algorithm, but should give the correct answer +// for demonstrative purposes + +bool VGAMetric::run(Communicator *comm, PointMap &map, bool) { + time_t atime = 0; + if (comm) { + qtimer(atime, 0); + comm->CommPostMessage(Communicator::NUM_RECORDS, map.getFilledPointCount()); + } + + std::string radius_text; + if (m_radius != -1.0) { + if (m_radius > 100.0) { + radius_text = std::string(" R") + dXstring::formatString(m_radius, "%.f"); + } else if (map.getRegion().width() < 1.0) { + radius_text = std::string(" R") + dXstring::formatString(m_radius, "%.4f"); + } else { + radius_text = std::string(" R") + dXstring::formatString(m_radius, "%.2f"); + } + } + AttributeTable &attributes = map.getAttributeTable(); + + // n.b. these must be entered in alphabetical order to preserve col indexing: + std::string mspa_col_text = std::string("Metric Mean Shortest-Path Angle") + radius_text; + int mspa_col = attributes.insertOrResetColumn(mspa_col_text.c_str()); + std::string mspl_col_text = std::string("Metric Mean Shortest-Path Distance") + radius_text; + int mspl_col = attributes.insertOrResetColumn(mspl_col_text.c_str()); + std::string dist_col_text = std::string("Metric Mean Straight-Line Distance") + radius_text; + int dist_col = attributes.insertOrResetColumn(dist_col_text.c_str()); + std::string count_col_text = std::string("Metric Node Count") + radius_text; + int count_col = attributes.insertOrResetColumn(count_col_text.c_str()); + + int count = 0; + + for (size_t i = 0; i < map.getCols(); i++) { + for (size_t j = 0; j < map.getRows(); j++) { + PixelRef curs = PixelRef(static_cast(i), static_cast(j)); + + if (map.getPoint(curs).filled()) { + + if (m_gates_only) { + count++; + continue; + } + + // TODO: Break out miscs/dist/cumangle into local variables and remove from Point class + for (auto &point : map.getPoints()) { + point.m_misc = 0; + point.m_dist = -1.0f; + point.m_cumangle = 0.0f; + } + + float euclid_depth = 0.0f; + float total_depth = 0.0f; + float total_angle = 0.0f; + int total_nodes = 0; + + // note that m_misc is used in a different manner to analyseGraph / PointDepth + // here it marks the node as used in calculation only + + std::set search_list; + search_list.insert(MetricTriple(0.0f, curs, NoPixel)); + while (search_list.size()) { + std::set::iterator it = search_list.begin(); + MetricTriple here = *it; + search_list.erase(it); + if (m_radius != -1.0 && (here.dist * map.getSpacing()) > m_radius) { + break; + } + Point &p = map.getPoint(here.pixel); + // nb, the filled check is necessary as diagonals seem to be stored with 'gaps' left in + if (p.filled() && p.m_misc != ~0) { + p.getNode().extractMetric(search_list, &map, here); + p.m_misc = ~0; + if (!p.getMergePixel().empty()) { + Point &p2 = map.getPoint(p.getMergePixel()); + if (p2.m_misc != ~0) { + p2.m_cumangle = p.m_cumangle; + p2.getNode().extractMetric(search_list, &map, + MetricTriple(here.dist, p.getMergePixel(), NoPixel)); + p2.m_misc = ~0; + } + } + total_depth += float(here.dist * map.getSpacing()); + total_angle += p.m_cumangle; + euclid_depth += float(map.getSpacing() * dist(here.pixel, curs)); + total_nodes += 1; + } + } + + AttributeRow &row = attributes.getRow(AttributeKey(curs)); + row.setValue(mspa_col, float(double(total_angle) / double(total_nodes))); + row.setValue(mspl_col, float(double(total_depth) / double(total_nodes))); + row.setValue(dist_col, float(double(euclid_depth) / double(total_nodes))); + row.setValue(count_col, float(total_nodes)); + + count++; // <- increment count + } + if (comm) { + if (qtimer(atime, 500)) { + if (comm->IsCancelled()) { + throw Communicator::CancelledException(); + } + comm->CommPostMessage(Communicator::CURRENT_RECORD, count); + } + } + } + } + + map.overrideDisplayedAttribute(-2); + map.setDisplayedAttribute(mspl_col); + + return true; +} diff --git a/salalib/vgamodules/vgametric.h b/salalib/vgamodules/vgametric.h new file mode 100644 index 00000000..d9e5a349 --- /dev/null +++ b/salalib/vgamodules/vgametric.h @@ -0,0 +1,34 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/ivga.h" +#include "salalib/pixelref.h" +#include "salalib/pointdata.h" + +class VGAMetric : IVGA { + private: + double m_radius; + bool m_gates_only; + + public: + std::string getAnalysisName() const override { return "Metric Analysis"; } + bool run(Communicator *comm, PointMap &map, bool) override; + VGAMetric(double radius, bool gates_only) : m_radius(radius), m_gates_only(gates_only) {} +}; diff --git a/salalib/vgamodules/vgametricdepth.cpp b/salalib/vgamodules/vgametricdepth.cpp new file mode 100644 index 00000000..68b31360 --- /dev/null +++ b/salalib/vgamodules/vgametricdepth.cpp @@ -0,0 +1,92 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "salalib/vgamodules/vgametricdepth.h" + +#include "genlib/stringutils.h" + +bool VGAMetricDepth::run(Communicator *, PointMap &map, bool) { + + AttributeTable &attributes = map.getAttributeTable(); + + // n.b., insert columns sets values to -1 if the column already exists + int path_angle_col = attributes.insertOrResetColumn("Metric Step Shortest-Path Angle"); + int path_length_col = attributes.insertOrResetColumn("Metric Step Shortest-Path Length"); + int dist_col = -1; + if (map.getSelSet().size() == 1) { + // Note: Euclidean distance is currently only calculated from a single point + dist_col = attributes.insertOrResetColumn("Metric Straight-Line Distance"); + } + + for (auto iter = attributes.begin(); iter != attributes.end(); iter++) { + PixelRef pix = iter->getKey().value; + map.getPoint(pix).m_misc = 0; + map.getPoint(pix).m_dist = -1.0f; + map.getPoint(pix).m_cumangle = 0.0f; + } + + // in order to calculate Penn angle, the MetricPair becomes a metric triple... + std::set search_list; // contains root point + + for (auto &sel : map.getSelSet()) { + search_list.insert(MetricTriple(0.0f, sel, NoPixel)); + } + + // note that m_misc is used in a different manner to analyseGraph / PointDepth + // here it marks the node as used in calculation only + while (search_list.size()) { + std::set::iterator it = search_list.begin(); + MetricTriple here = *it; + search_list.erase(it); + Point &p = map.getPoint(here.pixel); + // nb, the filled check is necessary as diagonals seem to be stored with 'gaps' left in + if (p.filled() && p.m_misc != ~0) { + p.getNode().extractMetric(search_list, &map, here); + p.m_misc = ~0; + AttributeRow &row = map.getAttributeTable().getRow(AttributeKey(here.pixel)); + row.setValue(path_length_col, float(map.getSpacing() * here.dist)); + row.setValue(path_angle_col, float(p.m_cumangle)); + if (map.getSelSet().size() == 1) { + // Note: Euclidean distance is currently only calculated from a single point + row.setValue(dist_col, float(map.getSpacing() * dist(here.pixel, *map.getSelSet().begin()))); + } + if (!p.getMergePixel().empty()) { + Point &p2 = map.getPoint(p.getMergePixel()); + if (p2.m_misc != ~0) { + p2.m_cumangle = p.m_cumangle; + AttributeRow &mergePixelRow = + map.getAttributeTable().getRow(AttributeKey(p.getMergePixel())); + mergePixelRow.setValue(path_length_col, float(map.getSpacing() * here.dist)); + mergePixelRow.setValue(path_angle_col, float(p2.m_cumangle)); + if (map.getSelSet().size() == 1) { + // Note: Euclidean distance is currently only calculated from a single point + mergePixelRow.setValue( + dist_col, float(map.getSpacing() * dist(p.getMergePixel(), *map.getSelSet().begin()))); + } + p2.getNode().extractMetric(search_list, &map, MetricTriple(here.dist, p.getMergePixel(), NoPixel)); + p2.m_misc = ~0; + } + } + } + } + + map.setDisplayedAttribute(-2); + map.setDisplayedAttribute(path_length_col); + + return true; +} diff --git a/salalib/vgamodules/vgametricdepth.h b/salalib/vgamodules/vgametricdepth.h new file mode 100644 index 00000000..00bec86f --- /dev/null +++ b/salalib/vgamodules/vgametricdepth.h @@ -0,0 +1,29 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/ivga.h" +#include "salalib/pixelref.h" +#include "salalib/pointdata.h" + +class VGAMetricDepth : IVGA { + public: + std::string getAnalysisName() const override { return "Metric Depth"; } + bool run(Communicator *, PointMap &map, bool) override; +}; diff --git a/salalib/vgamodules/vgathroughvision.cpp b/salalib/vgamodules/vgathroughvision.cpp new file mode 100644 index 00000000..42ff110f --- /dev/null +++ b/salalib/vgamodules/vgathroughvision.cpp @@ -0,0 +1,104 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "salalib/vgamodules/vgathroughvision.h" +#include "salalib/agents/agenthelpers.h" + +#include "genlib/stringutils.h" + +// This is a slow algorithm, but should give the correct answer +// for demonstrative purposes + +bool VGAThroughVision::run(Communicator *comm, PointMap &map, bool) { + time_t atime = 0; + if (comm) { + qtimer(atime, 0); + comm->CommPostMessage(Communicator::NUM_RECORDS, map.getFilledPointCount()); + } + + AttributeTable &attributes = map.getAttributeTable(); + + // current version (not sure of differences!) + for (size_t i = 0; i < map.getCols(); i++) { + for (size_t j = 0; j < map.getRows(); j++) { + PixelRef curs = PixelRef(static_cast(i), static_cast(j)); + map.getPoint(curs).m_misc = 0; + } + } + + bool hasGateColumn = map.getAttributeTable().hasColumn(g_col_gate); + + int count = 0; + for (size_t i = 0; i < map.getCols(); i++) { + for (size_t j = 0; j < map.getRows(); j++) { + std::vector seengates; + PixelRef curs = PixelRef(static_cast(i), static_cast(j)); + Point &p = map.getPoint(curs); + if (map.getPoint(curs).filled()) { + p.getNode().first(); + while (!p.getNode().is_tail()) { + PixelRef x = p.getNode().cursor(); + PixelRefVector pixels = map.quickPixelateLine(x, curs); + for (size_t k = 1; k < pixels.size() - 1; k++) { + PixelRef key = pixels[k]; + map.getPoint(key).m_misc += 1; + + // TODO: Undocumented functionality. Shows how many times a gate is passed? + if (hasGateColumn) { + auto iter = attributes.find(AttributeKey(key)); + if (iter != attributes.end()) { + int gate = static_cast(iter->getRow().getValue(g_col_gate)); + if (gate != -1) { + auto gateIter = depthmapX::findBinary(seengates, gate); + if (gateIter == seengates.end()) { + iter->getRow().incrValue(g_col_gate_counts); + seengates.insert(gateIter, int(gate)); + } + } + } + } + } + p.getNode().next(); + } + // only increment count for actual filled points + count++; + } + if (comm) { + if (qtimer(atime, 500)) { + if (comm->IsCancelled()) { + throw Communicator::CancelledException(); + } + comm->CommPostMessage(Communicator::CURRENT_RECORD, count); + } + } + } + } + + int col = attributes.getOrInsertColumn("Through vision"); + + for (auto iter = attributes.begin(); iter != attributes.end(); iter++) { + PixelRef pix = iter->getKey().value; + iter->getRow().setValue(col, static_cast(map.getPoint(pix).m_misc)); + map.getPoint(pix).m_misc = 0; + } + + map.overrideDisplayedAttribute(-2); + map.setDisplayedAttribute(col); + + return true; +} diff --git a/salalib/vgamodules/vgathroughvision.h b/salalib/vgamodules/vgathroughvision.h new file mode 100644 index 00000000..5b101f44 --- /dev/null +++ b/salalib/vgamodules/vgathroughvision.h @@ -0,0 +1,29 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/ivga.h" +#include "salalib/pixelref.h" +#include "salalib/pointdata.h" + +class VGAThroughVision : IVGA { + public: + std::string getAnalysisName() const override { return "Through Vision Analysis"; } + bool run(Communicator *comm, PointMap &map, bool) override; +}; diff --git a/salalib/vgamodules/vgavisualglobal.cpp b/salalib/vgamodules/vgavisualglobal.cpp new file mode 100644 index 00000000..ed29f4dd --- /dev/null +++ b/salalib/vgamodules/vgavisualglobal.cpp @@ -0,0 +1,240 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "salalib/vgamodules/vgavisualglobal.h" + +#include "genlib/stringutils.h" + +bool VGAVisualGlobal::run(Communicator *comm, PointMap &map, bool simple_version) { + time_t atime = 0; + if (comm) { + qtimer(atime, 0); + comm->CommPostMessage(Communicator::NUM_RECORDS, map.getFilledPointCount()); + } + AttributeTable &attributes = map.getAttributeTable(); + + int entropy_col = -1, rel_entropy_col = -1, integ_dv_col = -1, integ_pv_col = -1, integ_tk_col = -1, + depth_col = -1, count_col = -1; + std::string radius_text; + if (m_radius != -1) { + radius_text = std::string(" R") + dXstring::formatString(int(m_radius), "%d"); + } + + // n.b. these must be entered in alphabetical order to preserve col indexing: + // dX simple version test // TV +#ifndef _COMPILE_dX_SIMPLE_VERSION + if (!simple_version) { + std::string entropy_col_text = std::string("Visual Entropy") + radius_text; + entropy_col = attributes.insertOrResetColumn(entropy_col_text.c_str()); + } +#endif + + std::string integ_dv_col_text = std::string("Visual Integration [HH]") + radius_text; + integ_dv_col = attributes.insertOrResetColumn(integ_dv_col_text.c_str()); + +#ifndef _COMPILE_dX_SIMPLE_VERSION + if (!simple_version) { + std::string integ_pv_col_text = std::string("Visual Integration [P-value]") + radius_text; + integ_pv_col = attributes.insertOrResetColumn(integ_pv_col_text.c_str()); + std::string integ_tk_col_text = std::string("Visual Integration [Tekl]") + radius_text; + integ_tk_col = attributes.insertOrResetColumn(integ_tk_col_text.c_str()); + std::string depth_col_text = std::string("Visual Mean Depth") + radius_text; + depth_col = attributes.insertOrResetColumn(depth_col_text.c_str()); + std::string count_col_text = std::string("Visual Node Count") + radius_text; + count_col = attributes.insertOrResetColumn(count_col_text.c_str()); + std::string rel_entropy_col_text = std::string("Visual Relativised Entropy") + radius_text; + rel_entropy_col = attributes.insertOrResetColumn(rel_entropy_col_text.c_str()); + } +#endif + + int count = 0; + + depthmapX::RowMatrix miscs(map.getRows(), map.getCols()); + depthmapX::RowMatrix extents(map.getRows(), map.getCols()); + + for (size_t i = 0; i < map.getCols(); i++) { + for (size_t j = 0; j < map.getRows(); j++) { + PixelRef curs = PixelRef(i, j); + if (map.getPoint(curs).filled()) { + + if ((map.getPoint(curs).contextfilled() && !curs.iseven()) || (m_gates_only)) { + count++; + continue; + } + + for (size_t ii = 0; ii < map.getCols(); ii++) { + for (size_t jj = 0; jj < map.getRows(); jj++) { + miscs(jj, ii) = 0; + extents(jj, ii) = PixelRef(ii, jj); + } + } + + int total_depth = 0; + int total_nodes = 0; + + std::vector distribution; + std::vector search_tree; + search_tree.push_back(PixelRefVector()); + search_tree.back().push_back(curs); + + int level = 0; + while (search_tree[level].size()) { + search_tree.push_back(PixelRefVector()); + const PixelRefVector &searchTreeAtLevel = search_tree[level]; + distribution.push_back(0); + for (auto currLvlIter = searchTreeAtLevel.rbegin(); currLvlIter != searchTreeAtLevel.rend(); + currLvlIter++) { + int &pmisc = miscs(currLvlIter->y, currLvlIter->x); + Point &p = map.getPoint(*currLvlIter); + if (p.filled() && pmisc != ~0) { + total_depth += level; + total_nodes += 1; + distribution.back() += 1; + if ((int)m_radius == -1 || + (level < (int)m_radius && + (!p.contextfilled() || currLvlIter->iseven()))) { + extractUnseen(p.getNode(), search_tree[level + 1], miscs, extents); + pmisc = ~0; + if (!p.getMergePixel().empty()) { + PixelRef mergePixel = p.getMergePixel(); + int &p2misc = miscs(mergePixel.y, mergePixel.x); + Point &p2 = map.getPoint(mergePixel); + if (p2misc != ~0) { + extractUnseen(p2.getNode(), search_tree[level + 1], miscs, + extents); // did say p.misc + p2misc = ~0; + } + } + } else { + pmisc = ~0; + } + } + search_tree[level].pop_back(); + } + level++; + } + AttributeRow &row = attributes.getRow(AttributeKey(curs)); + // only set to single float precision after divide + // note -- total_nodes includes this one -- mean depth as per p.108 Social Logic of Space + if (!simple_version) { + row.setValue(count_col, float(total_nodes)); // note: total nodes includes this one + } + // ERROR !!!!!! + if (total_nodes > 1) { + double mean_depth = double(total_depth) / double(total_nodes - 1); + if (!simple_version) { + row.setValue(depth_col, float(mean_depth)); + } + // total nodes > 2 to avoid divide by 0 (was > 3) + if (total_nodes > 2 && mean_depth > 1.0) { + double ra = 2.0 * (mean_depth - 1.0) / double(total_nodes - 2); + // d-value / p-values from Depthmap 4 manual, note: node_count includes this one + double rra_d = ra / dvalue(total_nodes); + double rra_p = ra / pvalue(total_nodes); + double integ_tk = teklinteg(total_nodes, total_depth); + row.setValue(integ_dv_col, float(1.0 / rra_d)); + if (!simple_version) { + row.setValue(integ_pv_col, float(1.0 / rra_p)); + } + if (total_depth - total_nodes + 1 > 1) { + if (!simple_version) { + row.setValue(integ_tk_col, float(integ_tk)); + } + } else { + if (!simple_version) { + row.setValue(integ_tk_col, -1.0f); + } + } + } else { + row.setValue(integ_dv_col, (float)-1); + if (!simple_version) { + row.setValue(integ_pv_col, (float)-1); + row.setValue(integ_tk_col, (float)-1); + } + } + double entropy = 0.0, rel_entropy = 0.0, factorial = 1.0; + // n.b., this distribution contains the root node itself in distribution[0] + // -> chopped from entropy to avoid divide by zero if only one node + for (size_t k = 1; k < distribution.size(); k++) { + if (distribution[k] > 0) { + double prob = double(distribution[k]) / double(total_nodes - 1); + entropy -= prob * log2(prob); + // Formula from Turner 2001, "Depthmap" + factorial *= double(k + 1); + double q = (pow(mean_depth, double(k)) / double(factorial)) * exp(-mean_depth); + rel_entropy += (float)prob * log2(prob / q); + } + } + if (!simple_version) { + row.setValue(entropy_col, float(entropy)); + row.setValue(rel_entropy_col, float(rel_entropy)); + } + } else { + if (!simple_version) { + row.setValue(depth_col, (float)-1); + row.setValue(entropy_col, (float)-1); + row.setValue(rel_entropy_col, (float)-1); + } + } + count++; // <- increment count + if (comm) { + if (qtimer(atime, 500)) { + if (comm->IsCancelled()) { + throw Communicator::CancelledException(); + } + comm->CommPostMessage(Communicator::CURRENT_RECORD, count); + } + } + } + } + } + for (size_t i = 0; i < map.getCols(); i++) { + for (size_t j = 0; j < map.getRows(); j++) { + PixelRef curs = PixelRef(static_cast(i), static_cast(j)); + map.getPoint(curs).m_misc = miscs(j, i); + map.getPoint(curs).m_extent = extents(j, i); + } + } + map.setDisplayedAttribute(integ_dv_col); + + return true; +} + +void VGAVisualGlobal::extractUnseen(Node &node, PixelRefVector &pixels, depthmapX::RowMatrix &miscs, + depthmapX::RowMatrix &extents) { + for (int i = 0; i < 32; i++) { + Bin &bin = node.bin(i); + for (auto pixVec : bin.m_pixel_vecs) { + for (PixelRef pix = pixVec.start(); pix.col(bin.m_dir) <= pixVec.end().col(bin.m_dir);) { + int &misc = miscs(pix.y, pix.x); + PixelRef &extent = extents(pix.y, pix.x); + if (misc == 0) { + pixels.push_back(pix); + misc |= (1 << i); + } + // 10.2.02 revised --- diagonal was breaking this as it was extent in diagonal or horizontal + if (!(bin.m_dir & PixelRef::DIAGONAL)) { + if (extent.col(bin.m_dir) >= pixVec.end().col(bin.m_dir)) + break; + extent.col(bin.m_dir) = pixVec.end().col(bin.m_dir); + } + pix.move(bin.m_dir); + } + } + } +} diff --git a/salalib/vgamodules/vgavisualglobal.h b/salalib/vgamodules/vgavisualglobal.h new file mode 100644 index 00000000..7f6e89dc --- /dev/null +++ b/salalib/vgamodules/vgavisualglobal.h @@ -0,0 +1,38 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/ivga.h" +#include "salalib/pixelref.h" +#include "salalib/pointdata.h" + +#include "genlib/simplematrix.h" + +class VGAVisualGlobal : IVGA { + private: + double m_radius; + bool m_gates_only; + + public: + std::string getAnalysisName() const override { return "Global Visibility Analysis"; } + bool run(Communicator *comm, PointMap &map, bool simple_version) override; + void extractUnseen(Node &node, PixelRefVector &pixels, depthmapX::RowMatrix &miscs, + depthmapX::RowMatrix &extents); + VGAVisualGlobal(double radius, bool gates_only) : m_radius(radius), m_gates_only(gates_only) {} +}; diff --git a/salalib/vgamodules/vgavisualglobaldepth.cpp b/salalib/vgamodules/vgavisualglobaldepth.cpp new file mode 100644 index 00000000..88bb865c --- /dev/null +++ b/salalib/vgamodules/vgavisualglobaldepth.cpp @@ -0,0 +1,101 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "salalib/vgamodules/vgavisualglobaldepth.h" + +#include "genlib/stringutils.h" + +bool VGAVisualGlobalDepth::run(Communicator *, PointMap &map, bool) { + + AttributeTable &attributes = map.getAttributeTable(); + + // n.b., insert columns sets values to -1 if the column already exists + int col = attributes.insertOrResetColumn("Visual Step Depth"); + + for (auto iter = attributes.begin(); iter != attributes.end(); iter++) { + PixelRef pix = iter->getKey().value; + map.getPoint(pix).m_misc = 0; + map.getPoint(pix).m_extent = pix; + } + + std::vector search_tree; + search_tree.push_back(PixelRefVector()); + for (auto &sel : map.getSelSet()) { + // need to convert from ints (m_selection_set) to pixelrefs for this op: + search_tree.back().push_back(sel); + } + + size_t level = 0; + while (search_tree[level].size()) { + search_tree.push_back(PixelRefVector()); + const PixelRefVector& searchTreeAtLevel = search_tree[level]; + for (auto currLvlIter = searchTreeAtLevel.rbegin(); currLvlIter != searchTreeAtLevel.rend(); currLvlIter++) { + Point &p = map.getPoint(*currLvlIter); + if (p.filled() && p.m_misc != ~0) { + AttributeRow &row = attributes.getRow(AttributeKey(*currLvlIter)); + row.setValue(col, float(level)); + if (!p.contextfilled() || currLvlIter->iseven() || level == 0) { + p.getNode().extractUnseen(search_tree[level + 1], &map); + p.m_misc = ~0; + if (!p.getMergePixel().empty()) { + Point &p2 = map.getPoint(p.getMergePixel()); + if (p2.m_misc != ~0) { + AttributeRow &mergePixelRow = attributes.getRow(AttributeKey(p.getMergePixel())); + mergePixelRow.setValue(col, float(level)); + p2.getNode().extractUnseen(search_tree[level + 1], &map); // did say p.misc + p2.m_misc = ~0; + } + } + } else { + p.m_misc = ~0; + } + } + } + level++; + } + + // force redisplay: + map.setDisplayedAttribute(-2); + map.setDisplayedAttribute(col); + + return true; +} + +void VGAVisualGlobalDepth::extractUnseen(Node &node, PixelRefVector &pixels, depthmapX::RowMatrix &miscs, + depthmapX::RowMatrix &extents) { + for (int i = 0; i < 32; i++) { + Bin &bin = node.bin(i); + for (auto pixVec : bin.m_pixel_vecs) { + for (PixelRef pix = pixVec.start(); pix.col(bin.m_dir) <= pixVec.end().col(bin.m_dir);) { + int &misc = miscs(pix.y, pix.x); + PixelRef &extent = extents(pix.y, pix.x); + if (misc == 0) { + pixels.push_back(pix); + misc |= (1 << i); + } + // 10.2.02 revised --- diagonal was breaking this as it was extent in diagonal or horizontal + if (!(bin.m_dir & PixelRef::DIAGONAL)) { + if (extent.col(bin.m_dir) >= pixVec.end().col(bin.m_dir)) + break; + extent.col(bin.m_dir) = pixVec.end().col(bin.m_dir); + } + pix.move(bin.m_dir); + } + } + } +} diff --git a/salalib/vgamodules/vgavisualglobaldepth.h b/salalib/vgamodules/vgavisualglobaldepth.h new file mode 100644 index 00000000..53926ce9 --- /dev/null +++ b/salalib/vgamodules/vgavisualglobaldepth.h @@ -0,0 +1,33 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/ivga.h" +#include "salalib/pixelref.h" +#include "salalib/pointdata.h" + +#include "genlib/simplematrix.h" + +class VGAVisualGlobalDepth : IVGA { + public: + std::string getAnalysisName() const override { return "Global Visibility Depth"; } + bool run(Communicator *comm, PointMap &map, bool simple_version) override; + void extractUnseen(Node &node, PixelRefVector &pixels, depthmapX::RowMatrix &miscs, + depthmapX::RowMatrix &extents); +}; diff --git a/salalib/vgamodules/vgavisuallocal.cpp b/salalib/vgamodules/vgavisuallocal.cpp new file mode 100644 index 00000000..c167c4d3 --- /dev/null +++ b/salalib/vgamodules/vgavisuallocal.cpp @@ -0,0 +1,117 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "salalib/vgamodules/vgavisuallocal.h" + +#include "genlib/stringutils.h" + +bool VGAVisualLocal::run(Communicator *comm, PointMap &map, bool simple_version) { + time_t atime = 0; + if (comm) { + qtimer(atime, 0); + comm->CommPostMessage(Communicator::NUM_RECORDS, map.getFilledPointCount()); + } + + int cluster_col = -1, control_col = -1, controllability_col = -1; + if (!simple_version) { + cluster_col = map.getAttributeTable().insertOrResetColumn("Visual Clustering Coefficient"); + control_col = map.getAttributeTable().insertOrResetColumn("Visual Control"); + controllability_col = map.getAttributeTable().insertOrResetColumn("Visual Controllability"); + } + + int count = 0; + + for (size_t i = 0; i < map.getCols(); i++) { + for (size_t j = 0; j < map.getRows(); j++) { + PixelRef curs = PixelRef(static_cast(i), static_cast(j)); + if (map.getPoint(curs).filled()) { + if ((map.getPoint(curs).contextfilled() && !curs.iseven()) || (m_gates_only)) { + count++; + continue; + } + AttributeRow &row = map.getAttributeTable().getRow(AttributeKey(curs)); + + // This is much easier to do with a straight forward list: + PixelRefVector neighbourhood; + PixelRefVector totalneighbourhood; + map.getPoint(curs).getNode().contents(neighbourhood); + + // only required to match previous non-stl output. Without this + // the output differs by the last digit of the float + std::sort(neighbourhood.begin(), neighbourhood.end()); + + int cluster = 0; + float control = 0.0f; + + for (size_t i = 0; i < neighbourhood.size(); i++) { + int intersect_size = 0, retro_size = 0; + Point &retpt = map.getPoint(neighbourhood[i]); + if (retpt.filled() && retpt.hasNode()) { + retpt.getNode().first(); + while (!retpt.getNode().is_tail()) { + retro_size++; + if (std::find(neighbourhood.begin(), neighbourhood.end(), retpt.getNode().cursor()) != + neighbourhood.end()) { + intersect_size++; + } + if (std::find(totalneighbourhood.begin(), totalneighbourhood.end(), + retpt.getNode().cursor()) == totalneighbourhood.end()) { + totalneighbourhood.push_back( + retpt.getNode().cursor()); // <- note add does nothing if member already exists + } + retpt.getNode().next(); + } + control += 1.0f / float(retro_size); + cluster += intersect_size; + } + } +#ifndef _COMPILE_dX_SIMPLE_VERSION + if (!simple_version) { + if (neighbourhood.size() > 1) { + row.setValue(cluster_col, + float(cluster / double(neighbourhood.size() * (neighbourhood.size() - 1.0)))); + row.setValue(control_col, float(control)); + row.setValue(controllability_col, + float(double(neighbourhood.size()) / double(totalneighbourhood.size()))); + } else { + row.setValue(cluster_col, -1); + row.setValue(control_col, -1); + row.setValue(controllability_col, -1); + } + } +#endif + count++; // <- increment count + } + if (comm) { + if (qtimer(atime, 500)) { + if (comm->IsCancelled()) { + throw Communicator::CancelledException(); + } + comm->CommPostMessage(Communicator::CURRENT_RECORD, count); + } + } + } + } + +#ifndef _COMPILE_dX_SIMPLE_VERSION + if (!simple_version) + map.setDisplayedAttribute(cluster_col); +#endif + + return true; +} diff --git a/salalib/vgamodules/vgavisuallocal.h b/salalib/vgamodules/vgavisuallocal.h new file mode 100644 index 00000000..ddd6e565 --- /dev/null +++ b/salalib/vgamodules/vgavisuallocal.h @@ -0,0 +1,33 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "salalib/ivga.h" +#include "salalib/pixelref.h" +#include "salalib/pointdata.h" + +class VGAVisualLocal : IVGA { + private: + bool m_gates_only; + + public: + std::string getAnalysisName() const override { return "Local Visibility Analysis"; } + bool run(Communicator *comm, PointMap &map, bool simple_version) override; + VGAVisualLocal(bool gates_only) : m_gates_only(gates_only) {} +}; diff --git a/support-files/windows/InstallOnWindows.txt b/support-files/windows/InstallOnWindows.txt deleted file mode 100644 index 6c80e4f8..00000000 --- a/support-files/windows/InstallOnWindows.txt +++ /dev/null @@ -1,17 +0,0 @@ -Visual C++ 2005 Redistributable Package for (X86) - http://www.microsoft.com/downloads/en/details.aspx?FamilyId=32BC1BEE-A3F9-4C13-9C99-220B62A191EE&displaylang=en - -Visual C++ 2005 Redistributable Packager for (x64) - http://www.microsoft.com/downloads/en/details.aspx?FamilyID=eb4ebe2d-33c0-4a47-9dd4-b9a6d7bd44da&displaylang=en - -Microsoft Visual C++ 2008 Redistributable Package (x86) -http://www.microsoft.com/downloads/en/details.aspx?FamilyID=9B2DA534-3E03-4391-8A4D-074B9F2BC1BF&displaylang=en - -Microsoft Visual C++ 2008 SP1 Redistributable Package for (x64) - http://www.microsoft.com/downloads/en/details.aspx?familyid=BA9257CA-337F-4B40-8C14-157CFDFFEE4E&displaylang=en - -Microsoft Visual C++ 2010 Redistributable Package (x86) -http://www.microsoft.com/download/en/details.aspx?id=5555 - -Microsoft Visual C++ 2010 Redistributable Package (x64) -http://www.microsoft.com/download/en/details.aspx?id=14632 \ No newline at end of file diff --git a/support-files/windows/Windows32Bit/Microsoft Visual C++ 2005 Redistributable Package (x86).exe b/support-files/windows/Windows32Bit/Microsoft Visual C++ 2005 Redistributable Package (x86).exe deleted file mode 100644 index 1421c29c..00000000 Binary files a/support-files/windows/Windows32Bit/Microsoft Visual C++ 2005 Redistributable Package (x86).exe and /dev/null differ diff --git a/support-files/windows/Windows32Bit/Microsoft Visual C++ 2008 Redistributable Package (x86).exe b/support-files/windows/Windows32Bit/Microsoft Visual C++ 2008 Redistributable Package (x86).exe deleted file mode 100644 index b8a3da8d..00000000 Binary files a/support-files/windows/Windows32Bit/Microsoft Visual C++ 2008 Redistributable Package (x86).exe and /dev/null differ diff --git a/support-files/windows/Windows32Bit/Microsoft Visual C++ 2010 Redistributable Package (x86).exe b/support-files/windows/Windows32Bit/Microsoft Visual C++ 2010 Redistributable Package (x86).exe deleted file mode 100644 index 57e15c0b..00000000 Binary files a/support-files/windows/Windows32Bit/Microsoft Visual C++ 2010 Redistributable Package (x86).exe and /dev/null differ diff --git a/support-files/windows/Windows64Bit/Microsoft Visual C++ 2005 SP1 Redistributable Package (x64).exe b/support-files/windows/Windows64Bit/Microsoft Visual C++ 2005 SP1 Redistributable Package (x64).exe deleted file mode 100644 index 0e062ac1..00000000 Binary files a/support-files/windows/Windows64Bit/Microsoft Visual C++ 2005 SP1 Redistributable Package (x64).exe and /dev/null differ diff --git a/support-files/windows/Windows64Bit/Microsoft Visual C++ 2008 SP1 Redistributable Package (x64).exe b/support-files/windows/Windows64Bit/Microsoft Visual C++ 2008 SP1 Redistributable Package (x64).exe deleted file mode 100644 index 906f785b..00000000 Binary files a/support-files/windows/Windows64Bit/Microsoft Visual C++ 2008 SP1 Redistributable Package (x64).exe and /dev/null differ diff --git a/support-files/windows/Windows64Bit/Microsoft Visual C++ 2010 Redistributable Package (x64).exe b/support-files/windows/Windows64Bit/Microsoft Visual C++ 2010 Redistributable Package (x64).exe deleted file mode 100644 index 6ae64fb4..00000000 Binary files a/support-files/windows/Windows64Bit/Microsoft Visual C++ 2010 Redistributable Package (x64).exe and /dev/null differ diff --git a/testdata/all_line_noncont_keys.graph b/testdata/all_line_noncont_keys.graph new file mode 100644 index 00000000..2196ef27 Binary files /dev/null and b/testdata/all_line_noncont_keys.graph differ diff --git a/testdata/axmap_noncont_keys.graph b/testdata/axmap_noncont_keys.graph new file mode 100644 index 00000000..aad76a8f Binary files /dev/null and b/testdata/axmap_noncont_keys.graph differ diff --git a/testdata/barnsbury_axial.RT1 b/testdata/barnsbury_axial.RT1 new file mode 100644 index 00000000..635392d4 --- /dev/null +++ b/testdata/barnsbury_axial.RT1 @@ -0,0 +1,61 @@ +DUMMY TEXT A00 00005306350001844680000530732000183731 +DUMMY TEXT A01 00005306550001842670000531386000184568 +DUMMY TEXT A02 00005307810001843220000530814000184178 +DUMMY TEXT A03 00005306670001842030000531124000184392 +DUMMY TEXT A04 00005307980001842070000530856000184149 +DUMMY TEXT A05 00005307470001841450000530810000184207 +DUMMY TEXT A06 00005307530001841640000530781000183967 +DUMMY TEXT A07 00005306380001841230000531070000184116 +DUMMY TEXT A08 00005308370001839670000530855000184153 +DUMMY TEXT A09 00005307760001839700000530838000183968 +DUMMY TEXT A10 00005308030001836730000530817000183970 +DUMMY TEXT A11 00005308030001837420000530916000183745 +DUMMY TEXT A12 00005309120001836630000530932000184418 +DUMMY TEXT A13 00005309950001841910000531426000184272 +DUMMY TEXT A14 00005309920001842600000531006000184067 +DUMMY TEXT A15 00005310650001842640000531069000184200 +DUMMY TEXT A16 00005310140001842820000531076000184252 +DUMMY TEXT A17 00005310550001842540000531446000184352 +DUMMY TEXT A18 00005311010001844550000531227000184068 +DUMMY TEXT A19 00005312140001840670000531445000184127 +DUMMY TEXT A20 00005311660001838830000531225000184081 +DUMMY TEXT A21 00005311030001839440000531189000183939 +DUMMY TEXT A22 00005312740001845280000531297000184441 +DUMMY TEXT A23 00005313320001845830000531443000184125 +DUMMY TEXT A24 00005310260001841140000531441000184200 +DUMMY TEXT A25 00005313790001837260000531438000184206 +DUMMY TEXT A26 00005313700001835110000531409000184011 +DUMMY TEXT A27 00005312870001837160000531396000183759 +DUMMY TEXT A28 00005312940001837770000531391000183726 +DUMMY TEXT A29 00005313030001839670000531311000183765 +DUMMY TEXT A30 00005310690001838800000531403000183913 +DUMMY TEXT A31 00005310550001839730000531081000183854 +DUMMY TEXT A32 00005309790001838530000531006000183971 +DUMMY TEXT A33 00005310020001839650000531057000183972 +DUMMY TEXT A34 00005306750001838810000531237000183892 +DUMMY TEXT A35 00005312460001839010000531247000183877 +DUMMY TEXT A36 00005313780001840390000531423000184035 +DUMMY TEXT A37 00005313650001840480000531385000184035 +DUMMY TEXT A38 00005313600001841120000531368000184041 +DUMMY TEXT A39 00005311760001839320000531212000183499 +DUMMY TEXT A40 00005311910001835230000531385000183575 +DUMMY TEXT A41 00005309040001836810000531226000183515 +DUMMY TEXT A42 00005310870001835040000531157000183893 +DUMMY TEXT A43 00005310290001838910000531030000183855 +DUMMY TEXT A44 00005311820001837480000531275000183743 +DUMMY TEXT A45 00005312400001837410000531312000183782 +DUMMY TEXT A46 00005312380001837540000531308000183714 +DUMMY TEXT A47 00005312930001835470000531303000183726 +DUMMY TEXT A48 00005307070001835750000530731000183750 +DUMMY TEXT A49 00005307110001836900000530973000183658 +DUMMY TEXT A50 00005311390001841420000531154000184098 +DUMMY TEXT A51 00005310910001840890000531155000184099 +DUMMY TEXT A52 00005310600001841270000531065000184023 +DUMMY TEXT A53 00005309150001840350000531213000184017 +DUMMY TEXT A54 00005312810001840880000531294000184020 +DUMMY TEXT A55 00005312630001840150000531322000184027 +DUMMY TEXT A56 00005312670001840230000531279000183953 +DUMMY TEXT A57 00005312760001839540000531332000183964 +DUMMY TEXT A58 00005313150001840330000531330000183957 +DUMMY TEXT A59 00005308050001838140000530917000183816 +DUMMY TEXT A60 00005311370001843380000531389000184417 \ No newline at end of file diff --git a/testdata/barnsbury_axial.graph b/testdata/barnsbury_axial.graph new file mode 100644 index 00000000..f4711cd5 Binary files /dev/null and b/testdata/barnsbury_axial.graph differ diff --git a/testdata/barnsbury_drawing.graph b/testdata/barnsbury_drawing.graph new file mode 100644 index 00000000..aa403a43 Binary files /dev/null and b/testdata/barnsbury_drawing.graph differ diff --git a/testdata/barnsbury_extended1.dxf b/testdata/barnsbury_extended1.dxf new file mode 100644 index 00000000..5703a5f5 --- /dev/null +++ b/testdata/barnsbury_extended1.dxf @@ -0,0 +1,40614 @@ + 0 +SECTION + 2 +HEADER + 9 +$ACADVER + 1 +AC1032 + 9 +$ACADMAINTVER + 90 + 29 + 9 +$DWGCODEPAGE + 3 +ANSI_1252 + 9 +$LASTSAVEDBY + 1 +petros + 9 +$REQUIREDVERSIONS +160 + 0 + 9 +$INSBASE + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$EXTMIN + 10 +529323.2560585713 + 20 +181958.3850119969 + 30 +0.0 + 9 +$EXTMAX + 10 +537745.3426184553 + 20 +188578.5076793431 + 30 +0.0 + 9 +$LIMMIN + 10 +0.0 + 20 +0.0 + 9 +$LIMMAX + 10 +12.0 + 20 +9.0 + 9 +$ORTHOMODE + 70 + 0 + 9 +$REGENMODE + 70 + 1 + 9 +$FILLMODE + 70 + 1 + 9 +$QTEXTMODE + 70 + 0 + 9 +$MIRRTEXT + 70 + 0 + 9 +$LTSCALE + 40 +1.0 + 9 +$ATTMODE + 70 + 1 + 9 +$TEXTSIZE + 40 +0.2 + 9 +$TRACEWID + 40 +0.05 + 9 +$TEXTSTYLE + 7 +Standard + 9 +$CLAYER + 8 +0 + 9 +$CELTYPE + 6 +ByLayer + 9 +$CECOLOR + 62 + 256 + 9 +$CELTSCALE + 40 +1.0 + 9 +$DISPSILH + 70 + 0 + 9 +$DIMSCALE + 40 +1.0 + 9 +$DIMASZ + 40 +0.18 + 9 +$DIMEXO + 40 +0.0625 + 9 +$DIMDLI + 40 +0.38 + 9 +$DIMRND + 40 +0.0 + 9 +$DIMDLE + 40 +0.0 + 9 +$DIMEXE + 40 +0.18 + 9 +$DIMTP + 40 +0.0 + 9 +$DIMTM + 40 +0.0 + 9 +$DIMTXT + 40 +0.18 + 9 +$DIMCEN + 40 +0.09 + 9 +$DIMTSZ + 40 +0.0 + 9 +$DIMTOL + 70 + 0 + 9 +$DIMLIM + 70 + 0 + 9 +$DIMTIH + 70 + 1 + 9 +$DIMTOH + 70 + 1 + 9 +$DIMSE1 + 70 + 0 + 9 +$DIMSE2 + 70 + 0 + 9 +$DIMTAD + 70 + 0 + 9 +$DIMZIN + 70 + 0 + 9 +$DIMBLK + 1 + + 9 +$DIMASO + 70 + 1 + 9 +$DIMSHO + 70 + 1 + 9 +$DIMPOST + 1 + + 9 +$DIMAPOST + 1 + + 9 +$DIMALT + 70 + 0 + 9 +$DIMALTD + 70 + 2 + 9 +$DIMALTF + 40 +25.4 + 9 +$DIMLFAC + 40 +1.0 + 9 +$DIMTOFL + 70 + 0 + 9 +$DIMTVP + 40 +0.0 + 9 +$DIMTIX + 70 + 0 + 9 +$DIMSOXD + 70 + 0 + 9 +$DIMSAH + 70 + 0 + 9 +$DIMBLK1 + 1 + + 9 +$DIMBLK2 + 1 + + 9 +$DIMSTYLE + 2 +Standard + 9 +$DIMCLRD + 70 + 0 + 9 +$DIMCLRE + 70 + 0 + 9 +$DIMCLRT + 70 + 0 + 9 +$DIMTFAC + 40 +1.0 + 9 +$DIMGAP + 40 +0.09 + 9 +$DIMJUST + 70 + 0 + 9 +$DIMSD1 + 70 + 0 + 9 +$DIMSD2 + 70 + 0 + 9 +$DIMTOLJ + 70 + 1 + 9 +$DIMTZIN + 70 + 0 + 9 +$DIMALTZ + 70 + 0 + 9 +$DIMALTTZ + 70 + 0 + 9 +$DIMUPT + 70 + 0 + 9 +$DIMDEC + 70 + 4 + 9 +$DIMTDEC + 70 + 4 + 9 +$DIMALTU + 70 + 2 + 9 +$DIMALTTD + 70 + 2 + 9 +$DIMTXSTY + 7 +Standard + 9 +$DIMAUNIT + 70 + 0 + 9 +$DIMADEC + 70 + 0 + 9 +$DIMALTRND + 40 +0.0 + 9 +$DIMAZIN + 70 + 0 + 9 +$DIMDSEP + 70 + 46 + 9 +$DIMATFIT + 70 + 3 + 9 +$DIMFRAC + 70 + 0 + 9 +$DIMLDRBLK + 1 + + 9 +$DIMLUNIT + 70 + 2 + 9 +$DIMLWD + 70 + -2 + 9 +$DIMLWE + 70 + -2 + 9 +$DIMTMOVE + 70 + 0 + 9 +$DIMFXL + 40 +1.0 + 9 +$DIMFXLON + 70 + 0 + 9 +$DIMJOGANG + 40 +0.7853981633974483 + 9 +$DIMTFILL + 70 + 0 + 9 +$DIMTFILLCLR + 70 + 0 + 9 +$DIMARCSYM + 70 + 0 + 9 +$DIMLTYPE + 6 + + 9 +$DIMLTEX1 + 6 + + 9 +$DIMLTEX2 + 6 + + 9 +$DIMTXTDIRECTION + 70 + 0 + 9 +$LUNITS + 70 + 2 + 9 +$LUPREC + 70 + 4 + 9 +$SKETCHINC + 40 +0.1 + 9 +$FILLETRAD + 40 +0.0 + 9 +$AUNITS + 70 + 0 + 9 +$AUPREC + 70 + 0 + 9 +$MENU + 1 +. + 9 +$ELEVATION + 40 +0.0 + 9 +$PELEVATION + 40 +0.0 + 9 +$THICKNESS + 40 +0.0 + 9 +$LIMCHECK + 70 + 0 + 9 +$CHAMFERA + 40 +0.0 + 9 +$CHAMFERB + 40 +0.0 + 9 +$CHAMFERC + 40 +0.0 + 9 +$CHAMFERD + 40 +0.0 + 9 +$SKPOLY + 70 + 0 + 9 +$TDCREATE + 40 +2458404.565312500 + 9 +$TDUCREATE + 40 +2458404.523645833 + 9 +$TDUPDATE + 40 +2458404.623425926 + 9 +$TDUUPDATE + 40 +2458404.581759259 + 9 +$TDINDWG + 40 +0.0581134259 + 9 +$TDUSRTIMER + 40 +0.0581134259 + 9 +$USRTIMER + 70 + 1 + 9 +$ANGBASE + 50 +0.0 + 9 +$ANGDIR + 70 + 0 + 9 +$PDMODE + 70 + 0 + 9 +$PDSIZE + 40 +0.0 + 9 +$PLINEWID + 40 +0.0 + 9 +$SPLFRAME + 70 + 0 + 9 +$SPLINETYPE + 70 + 6 + 9 +$SPLINESEGS + 70 + 8 + 9 +$HANDSEED + 5 +659 + 9 +$SURFTAB1 + 70 + 6 + 9 +$SURFTAB2 + 70 + 6 + 9 +$SURFTYPE + 70 + 6 + 9 +$SURFU + 70 + 6 + 9 +$SURFV + 70 + 6 + 9 +$UCSBASE + 2 + + 9 +$UCSNAME + 2 + + 9 +$UCSORG + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSXDIR + 10 +1.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSYDIR + 10 +0.0 + 20 +1.0 + 30 +0.0 + 9 +$UCSORTHOREF + 2 + + 9 +$UCSORTHOVIEW + 70 + 0 + 9 +$UCSORGTOP + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGBOTTOM + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGLEFT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGRIGHT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGFRONT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGBACK + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSBASE + 2 + + 9 +$PUCSNAME + 2 + + 9 +$PUCSORG + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSXDIR + 10 +1.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSYDIR + 10 +0.0 + 20 +1.0 + 30 +0.0 + 9 +$PUCSORTHOREF + 2 + + 9 +$PUCSORTHOVIEW + 70 + 0 + 9 +$PUCSORGTOP + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGBOTTOM + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGLEFT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGRIGHT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGFRONT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGBACK + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$USERI1 + 70 + 0 + 9 +$USERI2 + 70 + 0 + 9 +$USERI3 + 70 + 0 + 9 +$USERI4 + 70 + 0 + 9 +$USERI5 + 70 + 0 + 9 +$USERR1 + 40 +0.0 + 9 +$USERR2 + 40 +0.0 + 9 +$USERR3 + 40 +0.0 + 9 +$USERR4 + 40 +0.0 + 9 +$USERR5 + 40 +0.0 + 9 +$WORLDVIEW + 70 + 1 + 9 +$SHADEDGE + 70 + 3 + 9 +$SHADEDIF + 70 + 70 + 9 +$TILEMODE + 70 + 1 + 9 +$MAXACTVP + 70 + 64 + 9 +$PINSBASE + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PLIMCHECK + 70 + 0 + 9 +$PEXTMIN + 10 +1.000000000000000E+20 + 20 +1.000000000000000E+20 + 30 +1.000000000000000E+20 + 9 +$PEXTMAX + 10 +-1.000000000000000E+20 + 20 +-1.000000000000000E+20 + 30 +-1.000000000000000E+20 + 9 +$PLIMMIN + 10 +0.0 + 20 +0.0 + 9 +$PLIMMAX + 10 +12.0 + 20 +9.0 + 9 +$UNITMODE + 70 + 0 + 9 +$VISRETAIN + 70 + 1 + 9 +$PLINEGEN + 70 + 0 + 9 +$PSLTSCALE + 70 + 1 + 9 +$TREEDEPTH + 70 + 3020 + 9 +$CMLSTYLE + 2 +Standard + 9 +$CMLJUST + 70 + 0 + 9 +$CMLSCALE + 40 +1.0 + 9 +$PROXYGRAPHICS + 70 + 1 + 9 +$MEASUREMENT + 70 + 0 + 9 +$CELWEIGHT +370 + -1 + 9 +$ENDCAPS +280 + 0 + 9 +$JOINSTYLE +280 + 0 + 9 +$LWDISPLAY +290 + 0 + 9 +$INSUNITS + 70 + 0 + 9 +$HYPERLINKBASE + 1 + + 9 +$STYLESHEET + 1 + + 9 +$XEDIT +290 + 1 + 9 +$CEPSNTYPE +380 + 0 + 9 +$PSTYLEMODE +290 + 1 + 9 +$FINGERPRINTGUID + 2 +{2B8CF25F-82C1-5146-94DB-BDE3530BDA2A} + 9 +$VERSIONGUID + 2 +{0C0159B8-69B3-CE49-BF34-83025D685E03} + 9 +$EXTNAMES +290 + 1 + 9 +$PSVPSCALE + 40 +0.0 + 9 +$OLESTARTUP +290 + 0 + 9 +$SORTENTS +280 + 127 + 9 +$INDEXCTL +280 + 0 + 9 +$HIDETEXT +280 + 0 + 9 +$XCLIPFRAME +280 + 2 + 9 +$HALOGAP +280 + 0 + 9 +$OBSCOLOR + 70 + 257 + 9 +$OBSLTYPE +280 + 0 + 9 +$INTERSECTIONDISPLAY +280 + 0 + 9 +$INTERSECTIONCOLOR + 70 + 257 + 9 +$DIMASSOC +280 + 1 + 9 +$PROJECTNAME + 1 + + 9 +$CAMERADISPLAY +290 + 0 + 9 +$LENSLENGTH + 40 +50.0 + 9 +$CAMERAHEIGHT + 40 +0.0 + 9 +$STEPSPERSEC + 40 +2.0 + 9 +$STEPSIZE + 40 +6.0 + 9 +$3DDWFPREC + 40 +2.0 + 9 +$PSOLWIDTH + 40 +0.25 + 9 +$PSOLHEIGHT + 40 +4.0 + 9 +$LOFTANG1 + 40 +1.570796326794896 + 9 +$LOFTANG2 + 40 +1.570796326794896 + 9 +$LOFTMAG1 + 40 +0.0 + 9 +$LOFTMAG2 + 40 +0.0 + 9 +$LOFTPARAM + 70 + 7 + 9 +$LOFTNORMALS +280 + 1 + 9 +$LATITUDE + 40 +37.795 + 9 +$LONGITUDE + 40 +-122.394 + 9 +$NORTHDIRECTION + 40 +0.0 + 9 +$TIMEZONE + 70 + -8000 + 9 +$LIGHTGLYPHDISPLAY +280 + 1 + 9 +$TILEMODELIGHTSYNCH +280 + 1 + 9 +$CMATERIAL +347 +11 + 9 +$SOLIDHIST +280 + 0 + 9 +$SHOWHIST +280 + 1 + 9 +$DWFFRAME +280 + 2 + 9 +$DGNFRAME +280 + 0 + 9 +$REALWORLDSCALE +290 + 1 + 9 +$INTERFERECOLOR + 62 + 1 + 9 +$INTERFEREOBJVS +345 +33 + 9 +$INTERFEREVPVS +346 +30 + 9 +$CSHADOW +280 + 0 + 9 +$SHADOWPLANELOCATION + 40 +0.0 + 0 +ENDSEC + 0 +SECTION + 2 +CLASSES + 0 +CLASS + 1 +ACDBDICTIONARYWDFLT + 2 +AcDbDictionaryWithDefault + 3 +ObjectDBX Classes + 90 + 0 + 91 + 1 +280 + 0 +281 + 0 + 0 +CLASS + 1 +MATERIAL + 2 +AcDbMaterial + 3 +ObjectDBX Classes + 90 + 1153 + 91 + 3 +280 + 0 +281 + 0 + 0 +CLASS + 1 +VISUALSTYLE + 2 +AcDbVisualStyle + 3 +ObjectDBX Classes + 90 + 4095 + 91 + 24 +280 + 0 +281 + 0 + 0 +CLASS + 1 +SCALE + 2 +AcDbScale + 3 +ObjectDBX Classes + 90 + 1153 + 91 + 17 +280 + 0 +281 + 0 + 0 +CLASS + 1 +TABLESTYLE + 2 +AcDbTableStyle + 3 +ObjectDBX Classes + 90 + 4095 + 91 + 1 +280 + 0 +281 + 0 + 0 +CLASS + 1 +MLEADERSTYLE + 2 +AcDbMLeaderStyle + 3 +ACDB_MLEADERSTYLE_CLASS + 90 + 4095 + 91 + 1 +280 + 0 +281 + 0 + 0 +CLASS + 1 +ACDBSECTIONVIEWSTYLE + 2 +AcDbSectionViewStyle + 3 +ObjectDBX Classes + 90 + 1025 + 91 + 1 +280 + 0 +281 + 0 + 0 +CLASS + 1 +ACDBDETAILVIEWSTYLE + 2 +AcDbDetailViewStyle + 3 +ObjectDBX Classes + 90 + 1025 + 91 + 1 +280 + 0 +281 + 0 + 0 +CLASS + 1 +SORTENTSTABLE + 2 +AcDbSortentsTable + 3 +ObjectDBX Classes + 90 + 0 + 91 + 1 +280 + 0 +281 + 0 + 0 +CLASS + 1 +DICTIONARYVAR + 2 +AcDbDictionaryVar + 3 +ObjectDBX Classes + 90 + 0 + 91 + 27 +280 + 0 +281 + 0 + 0 +CLASS + 1 +CELLSTYLEMAP + 2 +AcDbCellStyleMap + 3 +ObjectDBX Classes + 90 + 1152 + 91 + 3 +280 + 0 +281 + 0 + 0 +ENDSEC + 0 +SECTION + 2 +TABLES + 0 +TABLE + 2 +VPORT + 5 +8 +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +VPORT + 5 +B3 +330 +8 +100 +AcDbSymbolTableRecord +100 +AcDbViewportTableRecord + 2 +*Active + 70 + 0 + 10 +0.0 + 20 +0.0 + 11 +1.0 + 21 +1.0 + 12 +532607.1185847557 + 22 +184421.2568788754 + 13 +0.0 + 23 +0.0 + 14 +1.0 + 24 +1.0 + 15 +0.0 + 25 +0.0 + 16 +0.0 + 26 +0.0 + 36 +1.0 + 17 +0.0 + 27 +0.0 + 37 +0.0 + 40 +5191.861925766842 + 41 +1.549218031278748 + 42 +50.0 + 43 +0.0 + 44 +0.0 + 50 +0.0 + 51 +0.0 + 71 + 0 + 72 + 1000 + 73 + 1 + 74 + 3 + 75 + 0 + 76 + 0 + 77 + 0 + 78 + 0 +281 + 0 + 65 + 1 +110 +0.0 +120 +0.0 +130 +0.0 +111 +1.0 +121 +0.0 +131 +0.0 +112 +0.0 +122 +1.0 +132 +0.0 + 79 + 0 +146 +0.0 +348 +2F + 60 + 3 + 61 + 5 +292 + 1 +282 + 1 +141 +0.0 +142 +0.0 + 63 + 250 +421 + 3355443 +1001 +ACAD_NAV_VCDISPLAY +1070 + 1 + 0 +ENDTAB + 0 +TABLE + 2 +LTYPE + 5 +5 +330 +0 +100 +AcDbSymbolTable + 70 + 2 + 0 +LTYPE + 5 +5A +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByBlock + 70 + 0 + 3 + + 72 + 65 + 73 + 0 + 40 +0.0 + 0 +LTYPE + 5 +5B +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByLayer + 70 + 0 + 3 + + 72 + 65 + 73 + 0 + 40 +0.0 + 0 +LTYPE + 5 +5C +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +Continuous + 70 + 0 + 3 +Solid line + 72 + 65 + 73 + 0 + 40 +0.0 + 0 +ENDTAB + 0 +TABLE + 2 +LAYER + 5 +2 +102 +{ACAD_XDICTIONARY +360 +345 +102 +} +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +LAYER + 5 +54 +102 +{ACAD_XDICTIONARY +360 +340 +102 +} +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +0 + 70 + 0 + 62 + 7 + 6 +Continuous +370 + -3 +390 +F +347 +21 +348 +0 + 0 +ENDTAB + 0 +TABLE + 2 +STYLE + 5 +3 +330 +0 +100 +AcDbSymbolTable + 70 + 2 + 0 +STYLE + 5 +55 +330 +3 +100 +AcDbSymbolTableRecord +100 +AcDbTextStyleTableRecord + 2 +Standard + 70 + 0 + 40 +0.0 + 41 +1.0 + 50 +0.0 + 71 + 0 + 42 +0.2 + 3 +txt + 4 + + 0 +STYLE + 5 +59 +330 +3 +100 +AcDbSymbolTableRecord +100 +AcDbTextStyleTableRecord + 2 +Annotative + 70 + 0 + 40 +0.0 + 41 +1.0 + 50 +0.0 + 71 + 0 + 42 +0.2 + 3 +txt + 4 + +1001 +AcadAnnotative +1000 +AnnotativeData +1002 +{ +1070 + 1 +1070 + 1 +1002 +} + 0 +ENDTAB + 0 +TABLE + 2 +VIEW + 5 +6 +330 +0 +100 +AcDbSymbolTable + 70 + 3 + 0 +ENDTAB + 0 +TABLE + 2 +UCS + 5 +7 +330 +0 +100 +AcDbSymbolTable + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +APPID + 5 +9 +330 +0 +100 +AcDbSymbolTable + 70 + 4 + 0 +APPID + 5 +56 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD + 70 + 0 + 0 +APPID + 5 +5D +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +AcadAnnotative + 70 + 0 + 0 +APPID + 5 +B2 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD_NAV_VCDISPLAY + 70 + 0 + 0 +APPID + 5 +F2 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD_EXEMPT_FROM_CAD_STANDARDS + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +DIMSTYLE + 5 +A +330 +0 +100 +AcDbSymbolTable + 70 + 3 +100 +AcDbDimStyleTable + 71 + 1 +340 +57 + 0 +DIMSTYLE +105 +57 +330 +A +100 +AcDbSymbolTableRecord +100 +AcDbDimStyleTableRecord + 2 +Standard + 70 + 0 +340 +55 + 0 +DIMSTYLE +105 +58 +330 +A +100 +AcDbSymbolTableRecord +100 +AcDbDimStyleTableRecord + 2 +Annotative + 70 + 0 +340 +55 +1001 +AcadAnnotative +1000 +AnnotativeData +1002 +{ +1070 + 1 +1070 + 1 +1002 +} + 0 +ENDTAB + 0 +TABLE + 2 +BLOCK_RECORD + 5 +1 +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +BLOCK_RECORD + 5 +6F +102 +{ACAD_XDICTIONARY +360 +135 +102 +} +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Model_Space +340 +72 + 70 + 0 +280 + 1 +281 + 0 + 0 +BLOCK_RECORD + 5 +6B +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Paper_Space +340 +6E + 70 + 0 +280 + 1 +281 + 0 + 0 +ENDTAB + 0 +ENDSEC + 0 +SECTION + 2 +BLOCKS + 0 +BLOCK + 5 +70 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbBlockBegin + 2 +*Model_Space + 70 + 0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +*Model_Space + 1 + + 0 +ENDBLK + 5 +71 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbBlockEnd + 0 +BLOCK + 5 +6C +330 +6B +100 +AcDbEntity + 67 + 1 + 8 +0 +100 +AcDbBlockBegin + 2 +*Paper_Space + 70 + 0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +*Paper_Space + 1 + + 0 +ENDBLK + 5 +6D +330 +6B +100 +AcDbEntity + 67 + 1 + 8 +0 +100 +AcDbBlockEnd + 0 +ENDSEC + 0 +SECTION + 2 +ENTITIES + 0 +LINE + 5 +73 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530635.6962680001 + 20 +184468.675646 + 30 +0.0 + 11 +530732.3778539999 + 21 +183731.866556 + 31 +0.0 + 0 +LINE + 5 +74 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530655.0804069999 + 20 +184267.843134 + 30 +0.0 + 11 +531386.6646780001 + 21 +184568.766995 + 31 +0.0 + 0 +LINE + 5 +75 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530781.419478 + 20 +184322.997346 + 30 +0.0 + 11 +530814.78724 + 21 +184178.968574 + 31 +0.0 + 0 +LINE + 5 +76 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530667.7613100001 + 20 +184203.901437 + 30 +0.0 + 11 +531124.6861069999 + 21 +184392.857349 + 31 +0.0 + 0 +LINE + 5 +77 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530798.725861 + 20 +184207.390438 + 30 +0.0 + 11 +530856.762846 + 21 +184149.487013 + 31 +0.0 + 0 +LINE + 5 +78 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530747.8703240001 + 20 +184145.998012 + 30 +0.0 + 11 +530810.7554050001 + 21 +184207.340453 + 31 +0.0 + 0 +LINE + 5 +79 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530753.9386890001 + 20 +184164.022852 + 30 +0.0 + 11 +530781.427723 + 21 +183967.049235 + 31 +0.0 + 0 +LINE + 5 +7A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530638.0708449999 + 20 +184123.954322 + 30 +0.0 + 11 +531070.9777789999 + 21 +184116.826362 + 31 +0.0 + 0 +LINE + 5 +7B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530837.4941380001 + 20 +183967.908989 + 30 +0.0 + 11 +530855.6744979999 + 21 +184153.675814 + 31 +0.0 + 0 +LINE + 5 +7C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530776.9259189999 + 20 +183970.168342 + 30 +0.0 + 11 +530838.1125180001 + 21 +183968.488823 + 31 +0.0 + 0 +LINE + 5 +7D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530803.8790240001 + 20 +183673.983124 + 30 +0.0 + 11 +530817.351454 + 21 +183970.908131 + 31 +0.0 + 0 +LINE + 5 +7E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530803.31836 + 20 +183742.403539 + 30 +0.0 + 11 +530916.415863 + 21 +183745.002795 + 31 +0.0 + 0 +LINE + 5 +7F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530912.1861470001 + 20 +183663.646083 + 30 +0.0 + 11 +530932.996681 + 21 +184479.6069563149 + 31 +0.0 + 0 +LINE + 5 +80 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530995.2139119999 + 20 +184191.1051 + 30 +0.0 + 11 +531426.867596 + 21 +184272.091918 + 31 +0.0 + 0 +LINE + 5 +81 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530992.995991 + 20 +184260.565217 + 30 +0.0 + 11 +531006.3035189999 + 21 +184067.090599 + 31 +0.0 + 0 +LINE + 5 +82 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531065.5030580001 + 20 +184264.454104 + 30 +0.0 + 11 +531069.386482 + 21 +184200.262479 + 31 +0.0 + 0 +LINE + 5 +83 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531014.2600029999 + 20 +184282.658893 + 30 +0.0 + 11 +531076.262863 + 21 +184252.777446 + 31 +0.0 + 0 +LINE + 5 +84 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531055.8563370001 + 20 +184254.05708 + 30 +0.0 + 11 +531446.820644 + 21 +184352.768824 + 31 +0.0 + 0 +LINE + 5 +85 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531101.674141 + 20 +184455.949289 + 30 +0.0 + 11 +531227.444303 + 21 +184068.530187 + 31 +0.0 + 0 +LINE + 5 +86 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531214.16151 + 20 +184067.600453 + 30 +0.0 + 11 +531445.270572 + 21 +184127.80322 + 31 +0.0 + 0 +LINE + 5 +87 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531166.2824399999 + 20 +183883.173244 + 30 +0.0 + 11 +531225.605654 + 21 +184081.636435 + 31 +0.0 + 0 +LINE + 5 +88 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531103.958023 + 20 +183944.145791 + 30 +0.0 + 11 +531189.2449350001 + 21 +183939.966987 + 31 +0.0 + 0 +LINE + 5 +89 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531199.1268957056 + 20 +184509.5863229855 + 30 +0.0 + 11 +531222.4027027056 + 21 +184422.5212449855 + 31 +0.0 + 0 +LINE + 5 +8A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531332.5770770001 + 20 +184583.962646 + 30 +0.0 + 11 +531443.794706 + 21 +184125.074001 + 31 +0.0 + 0 +LINE + 5 +8B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531026.4544489999 + 20 +184114.297086 + 30 +0.0 + 11 +531441.626255 + 21 +184200.71235 + 31 +0.0 + 0 +LINE + 5 +8C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531379.0874670001 + 20 +183726.907975 + 30 +0.0 + 11 +531438.2045550001 + 21 +184206.79061 + 31 +0.0 + 0 +LINE + 5 +8D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531367.365093476 + 20 +183473.8360188434 + 30 +0.0 + 11 +531409.569458 + 21 +184011.596484 + 31 +0.0 + 0 +LINE + 5 +8E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531287.1303 + 20 +183716.111065 + 30 +0.0 + 11 +531396.253684 + 21 +183759.488649 + 31 +0.0 + 0 +LINE + 5 +8F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531294.394199 + 20 +183777.773415 + 30 +0.0 + 11 +531391.413833 + 21 +183726.268158 + 31 +0.0 + 0 +LINE + 5 +90 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531303.999695 + 20 +183967.539095 + 30 +0.0 + 11 +531311.931444 + 21 +183765.686875 + 31 +0.0 + 0 +LINE + 5 +91 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531069.774 + 20 +183880.95388 + 30 +0.0 + 11 +531403.294966 + 21 +183913.414588 + 31 +0.0 + 0 +LINE + 5 +92 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531055.773886 + 20 +183973.477395 + 30 +0.0 + 11 +531081.1604290001 + 21 +183854.721389 + 31 +0.0 + 0 +LINE + 5 +93 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530979.070082 + 20 +183853.471746 + 30 +0.0 + 11 +531006.056167 + 21 +183971.198048 + 31 +0.0 + 0 +LINE + 5 +94 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531002.3706249999 + 20 +183965.559662 + 30 +0.0 + 11 +531057.7609460001 + 21 +183972.597647 + 31 +0.0 + 0 +LINE + 5 +95 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530675.0499439999 + 20 +183881.16382 + 30 +0.0 + 11 +531237.536258 + 21 +183892.420597 + 31 +0.0 + 0 +LINE + 5 +96 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531246.803707 + 20 +183901.647956 + 30 +0.0 + 11 +531247.100529 + 21 +183877.364907 + 31 +0.0 + 0 +LINE + 5 +97 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531378.13104 + 20 +184039.148597 + 30 +0.0 + 11 +531423.297484 + 21 +184035.389673 + 31 +0.0 + 0 +LINE + 5 +98 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531365.8376540001 + 20 +184048.645878 + 30 +0.0 + 11 +531385.9885830001 + 21 +184035.489644 + 31 +0.0 + 0 +LINE + 5 +99 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531360.008395 + 20 +184112.477607 + 30 +0.0 + 11 +531368.607994 + 21 +184041.148025 + 31 +0.0 + 0 +LINE + 5 +9A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531176.638237 + 20 +183932.709065 + 30 +0.0 + 11 +531212.5949479999 + 21 +183499.852969 + 31 +0.0 + 0 +LINE + 5 +9B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531191.28971 + 20 +183523.406227 + 30 +0.0 + 11 +531385.782456 + 21 +183575.241389 + 31 +0.0 + 0 +LINE + 5 +9C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530904.180192 + 20 +183681.79089 + 30 +0.0 + 11 +531226.595062 + 21 +183515.558473 + 31 +0.0 + 0 +LINE + 5 +9D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531087.294754 + 20 +183504.461649 + 30 +0.0 + 11 +531157.6993310001 + 21 +183893.960157 + 31 +0.0 + 0 +LINE + 5 +9E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531029.2082989999 + 20 +183891.140964 + 30 +0.0 + 11 +531030.2306869999 + 21 +183855.631128 + 31 +0.0 + 0 +LINE + 5 +9F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531182.681866 + 20 +183748.751722 + 30 +0.0 + 11 +531275.851057 + 21 +183743.153325 + 31 +0.0 + 0 +LINE + 5 +A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531240.7600770001 + 20 +183741.113908 + 30 +0.0 + 11 +531312.920852 + 21 +183782.89195 + 31 +0.0 + 0 +LINE + 5 +A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531238.3195390001 + 20 +183754.010217 + 30 +0.0 + 11 +531308.0562649999 + 21 +183714.501526 + 31 +0.0 + 0 +LINE + 5 +A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531293.948966 + 20 +183547.909213 + 30 +0.0 + 11 +531303.2823749999 + 21 +183726.188181 + 31 +0.0 + 0 +LINE + 5 +A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530707.321114 + 20 +183575.611283 + 30 +0.0 + 11 +530731.6605340001 + 21 +183750.551207 + 31 +0.0 + 0 +LINE + 5 +A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530711.864142 + 20 +183690.118506 + 30 +0.0 + 11 +530973.265559 + 21 +183658.367594 + 31 +0.0 + 0 +LINE + 5 +A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531139.131454 + 20 +184142.888902 + 30 +0.0 + 11 +531154.5332279999 + 21 +184098.471616 + 31 +0.0 + 0 +LINE + 5 +A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531091.4007950001 + 20 +184089.16428 + 30 +0.0 + 11 +531155.7864770001 + 21 +184099.901207 + 31 +0.0 + 0 +LINE + 5 +A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531060.2262189999 + 20 +184127.683254 + 30 +0.0 + 11 +531065.6514689999 + 21 +184023.503075 + 31 +0.0 + 0 +LINE + 5 +A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530915.1048979999 + 20 +184035.689587 + 30 +0.0 + 11 +531213.1391220001 + 21 +184017.404821 + 31 +0.0 + 0 +LINE + 5 +A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531281.4989239999 + 20 +184088.374506 + 30 +0.0 + 11 +531294.732247 + 21 +184020.813845 + 31 +0.0 + 0 +LINE + 5 +AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531263.3103189999 + 20 +184015.655322 + 30 +0.0 + 11 +531322.3284660001 + 21 +184027.032065 + 31 +0.0 + 0 +LINE + 5 +AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531267.276193 + 20 +184023.293136 + 30 +0.0 + 11 +531279.9983229999 + 21 +183953.103227 + 31 +0.0 + 0 +LINE + 5 +AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531276.7909939999 + 20 +183954.982689 + 30 +0.0 + 11 +531332.164824 + 21 +183964.220045 + 31 +0.0 + 0 +LINE + 5 +AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531315.9385439999 + 20 +184033.420237 + 30 +0.0 + 11 +531330.6065079999 + 21 +183957.32202 + 31 +0.0 + 0 +LINE + 5 +AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530805.297175 + 20 +183814.47291 + 30 +0.0 + 11 +530917.998915 + 21 +183816.172423 + 31 +0.0 + 0 +LINE + 5 +AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531137.2515800001 + 20 +184338.103022 + 30 +0.0 + 11 +531389.731841 + 21 +184417.270361 + 31 +0.0 + 0 +LINE + 5 +B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531482.3151479505 + 20 +184748.9871594448 + 30 +0.0 + 11 +531515.6829099504 + 21 +184604.9583874448 + 31 +0.0 + 0 +LINE + 5 +B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531368.6569799505 + 20 +184629.8912504447 + 30 +0.0 + 11 +531825.5817769504 + 21 +184818.8471624447 + 31 +0.0 + 0 +LINE + 5 +B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531499.6215309505 + 20 +184633.3802514448 + 30 +0.0 + 11 +531557.6585159504 + 21 +184575.4768264448 + 31 +0.0 + 0 +LINE + 5 +BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531448.7659939505 + 20 +184571.9878254447 + 30 +0.0 + 11 +531511.6510749504 + 21 +184633.3302664447 + 31 +0.0 + 0 +LINE + 5 +BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531455.263586 + 20 +184588.2416564698 + 30 +0.0 + 11 +531482.7526199998 + 21 +184391.2680394698 + 31 +0.0 + 0 +LINE + 5 +BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531253.86750234 + 20 +184551.3453196492 + 30 +0.0 + 11 +531771.8734489504 + 21 +184542.8161754447 + 31 +0.0 + 0 +LINE + 5 +BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531538.3898079505 + 20 +184393.8988024447 + 30 +0.0 + 11 +531556.5701679504 + 21 +184579.6656274448 + 31 +0.0 + 0 +LINE + 5 +BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531477.8215889504 + 20 +184396.1581554448 + 30 +0.0 + 11 +531539.0081879505 + 21 +184394.4786364447 + 31 +0.0 + 0 +LINE + 5 +BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531504.7746939504 + 20 +184099.9729374447 + 30 +0.0 + 11 +531518.2471239504 + 21 +184396.8979444447 + 31 +0.0 + 0 +LINE + 5 +C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531504.2140299504 + 20 +184168.3933524448 + 30 +0.0 + 11 +531617.3115329505 + 21 +184170.9926084448 + 31 +0.0 + 0 +LINE + 5 +C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531613.0818169504 + 20 +184089.6358964447 + 30 +0.0 + 11 +531633.8923509504 + 21 +184844.9097024448 + 31 +0.0 + 0 +LINE + 5 +C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531696.1095819504 + 20 +184617.0949134447 + 30 +0.0 + 11 +532336.8255974543 + 21 +184713.6317642464 + 31 +0.0 + 0 +LINE + 5 +C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531693.8916609504 + 20 +184686.5550304448 + 30 +0.0 + 11 +531707.1991889504 + 21 +184493.0804124447 + 31 +0.0 + 0 +LINE + 5 +C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531766.3987279504 + 20 +184690.4439174447 + 30 +0.0 + 11 +531770.2821519504 + 21 +184626.2522924448 + 31 +0.0 + 0 +LINE + 5 +C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531715.1556729503 + 20 +184708.6487064448 + 30 +0.0 + 11 +531777.1585329505 + 21 +184678.7672594447 + 31 +0.0 + 0 +LINE + 5 +C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531756.7520069505 + 20 +184680.0468934447 + 30 +0.0 + 11 +531893.0496688435 + 21 +184714.4597021531 + 31 +0.0 + 0 +LINE + 5 +C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531802.5698109504 + 20 +184881.9391024447 + 30 +0.0 + 11 +531928.3399729504 + 21 +184494.5200004447 + 31 +0.0 + 0 +LINE + 5 +C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531915.0571799504 + 20 +184493.5902664447 + 30 +0.0 + 11 +532146.1662419505 + 21 +184553.7930334447 + 31 +0.0 + 0 +LINE + 5 +C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531867.1781099504 + 20 +184309.1630574448 + 30 +0.0 + 11 +531926.5013239504 + 21 +184507.6262484447 + 31 +0.0 + 0 +LINE + 5 +CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531804.8536929503 + 20 +184370.1356044448 + 30 +0.0 + 11 +531890.1406049505 + 21 +184365.9568004447 + 31 +0.0 + 0 +LINE + 5 +CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531914.954988917 + 20 +184937.2488970258 + 30 +0.0 + 11 +531938.230795917 + 21 +184850.1838190259 + 31 +0.0 + 0 +LINE + 5 +CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531727.3501189504 + 20 +184540.2868994447 + 30 +0.0 + 11 +532142.5219249505 + 21 +184626.7021634447 + 31 +0.0 + 0 +LINE + 5 +D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531988.0259699504 + 20 +184142.1008784448 + 30 +0.0 + 11 +532097.1493539504 + 21 +184185.4784624447 + 31 +0.0 + 0 +LINE + 5 +D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531995.2898689503 + 20 +184203.7632284447 + 30 +0.0 + 11 +532092.3095029504 + 21 +184152.2579714447 + 31 +0.0 + 0 +LINE + 5 +D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532004.8953649504 + 20 +184393.5289084448 + 30 +0.0 + 11 +532012.8271139505 + 21 +184191.6766884448 + 31 +0.0 + 0 +LINE + 5 +D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531770.6696699504 + 20 +184306.9436934447 + 30 +0.0 + 11 +532197.7006858273 + 21 +184339.4044014448 + 31 +0.0 + 0 +LINE + 5 +D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531756.6695559503 + 20 +184399.4672084447 + 30 +0.0 + 11 +531782.0560989504 + 21 +184280.7112024448 + 31 +0.0 + 0 +LINE + 5 +D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531679.9657519504 + 20 +184279.4615594447 + 30 +0.0 + 11 +531706.9518369503 + 21 +184397.1878614447 + 31 +0.0 + 0 +LINE + 5 +D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531703.2662949504 + 20 +184391.5494754448 + 30 +0.0 + 11 +531758.6566159504 + 21 +184398.5874604448 + 31 +0.0 + 0 +LINE + 5 +D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531375.9456139504 + 20 +184307.1536334448 + 30 +0.0 + 11 +531938.4319279503 + 21 +184318.4104104447 + 31 +0.0 + 0 +LINE + 5 +D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531947.6993769504 + 20 +184327.6377694447 + 30 +0.0 + 11 +531947.9961989505 + 21 +184303.3547204447 + 31 +0.0 + 0 +LINE + 5 +D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532079.0267099504 + 20 +184465.1384104447 + 30 +0.0 + 11 +532156.3508382652 + 21 +184461.3794864448 + 31 +0.0 + 0 +LINE + 5 +DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532066.7333239505 + 20 +184474.6356914448 + 30 +0.0 + 11 +532086.8842529504 + 21 +184461.4794574448 + 31 +0.0 + 0 +LINE + 5 +DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532060.9040649504 + 20 +184538.4674204447 + 30 +0.0 + 11 +532069.5036639504 + 21 +184467.1378384447 + 31 +0.0 + 0 +LINE + 5 +DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531877.5339069504 + 20 +184358.6988784447 + 30 +0.0 + 11 +531913.4906179503 + 21 +184005.4836986493 + 31 +0.0 + 0 +LINE + 5 +DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531605.0758619504 + 20 +184107.7807034448 + 30 +0.0 + 11 +531784.3258864618 + 21 +184010.3328863243 + 31 +0.0 + 0 +LINE + 5 +DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531761.9190629788 + 20 +183988.7626476783 + 30 +0.0 + 11 +531858.5950009506 + 21 +184319.9499704448 + 31 +0.0 + 0 +LINE + 5 +E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531730.1039689503 + 20 +184317.1307774448 + 30 +0.0 + 11 +531731.1263569504 + 21 +184281.6209414447 + 31 +0.0 + 0 +LINE + 5 +E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531883.5775359503 + 20 +184174.7415354448 + 30 +0.0 + 11 +531976.7467269504 + 21 +184169.1431384447 + 31 +0.0 + 0 +LINE + 5 +E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531941.6557469504 + 20 +184167.1037214447 + 30 +0.0 + 11 +532013.8165219504 + 21 +184208.8817634447 + 31 +0.0 + 0 +LINE + 5 +E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531939.2152089505 + 20 +184180.0000304447 + 30 +0.0 + 11 +532008.9519349504 + 21 +184140.4913394448 + 31 +0.0 + 0 +LINE + 5 +E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531994.8446359504 + 20 +184026.5398393117 + 30 +0.0 + 11 +532004.1780449503 + 21 +184152.1779944448 + 31 +0.0 + 0 +LINE + 5 +E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531409.1658425192 + 20 +184133.617550475 + 30 +0.0 + 11 +531674.1612289504 + 21 +184084.3574074447 + 31 +0.0 + 0 +LINE + 5 +E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531840.0271239504 + 20 +184568.8787154448 + 30 +0.0 + 11 +531855.4288979504 + 21 +184524.4614294448 + 31 +0.0 + 0 +LINE + 5 +E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531792.2964649504 + 20 +184515.1540934448 + 30 +0.0 + 11 +531856.6821469506 + 21 +184525.8910204447 + 31 +0.0 + 0 +LINE + 5 +E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531761.1218889504 + 20 +184553.6730674448 + 30 +0.0 + 11 +531766.5471389503 + 21 +184449.4928884447 + 31 +0.0 + 0 +LINE + 5 +EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531616.0005679503 + 20 +184461.6794004447 + 30 +0.0 + 11 +531914.0347919505 + 21 +184443.3946344448 + 31 +0.0 + 0 +LINE + 5 +EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531982.3945939504 + 20 +184514.3643194447 + 30 +0.0 + 11 +531995.6279169504 + 21 +184446.8036584448 + 31 +0.0 + 0 +LINE + 5 +EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531964.2059889504 + 20 +184441.6451354448 + 30 +0.0 + 11 +532023.2241359505 + 21 +184453.0218784447 + 31 +0.0 + 0 +LINE + 5 +ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531968.1718629504 + 20 +184449.2829494447 + 30 +0.0 + 11 +531980.8939929504 + 21 +184379.0930404447 + 31 +0.0 + 0 +LINE + 5 +EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531977.6866639504 + 20 +184380.9725024447 + 30 +0.0 + 11 +532033.0604939504 + 21 +184390.2098584447 + 31 +0.0 + 0 +LINE + 5 +EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532016.8342139503 + 20 +184459.4100504447 + 30 +0.0 + 11 +532031.5021779503 + 21 +184383.3118334448 + 31 +0.0 + 0 +LINE + 5 +F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531506.1928449503 + 20 +184240.4627234447 + 30 +0.0 + 11 +531618.8945849504 + 21 +184242.1622364448 + 31 +0.0 + 0 +LINE + 5 +F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531838.1472499504 + 20 +184764.0928354447 + 30 +0.0 + 11 +532090.6275109504 + 21 +184843.2601744448 + 31 +0.0 + 0 +LINE + 5 +F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531898.1410099429 + 20 +185489.5773460393 + 30 +0.0 + 11 +532384.9456462926 + 21 +183588.3773949871 + 31 +0.0 + 0 +LINE + 5 +FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532034.5704961169 + 20 +184072.7659341317 + 30 +0.0 + 11 +532153.81876062 + 21 +183879.2475727824 + 31 +0.0 + 0 +LINE + 5 +FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531848.4441497004 + 20 +184056.3091599104 + 30 +0.0 + 11 +531872.7555329125 + 21 +183888.2560305589 + 31 +0.0 + 0 +LINE + 5 +104 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531400.0540388189 + 20 +183972.7571852804 + 30 +0.0 + 11 +532184.2443917333 + 21 +184077.3429025231 + 31 +0.0 + 0 +LINE + 5 +105 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531934.003528394 + 20 +183974.8942294735 + 30 +0.0 + 11 +532082.7807717206 + 21 +183561.6762489006 + 31 +0.0 + 0 +LINE + 5 +106 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532002.2213451149 + 20 +183988.1590894068 + 30 +0.0 + 11 +531813.3438607319 + 21 +183944.1725686889 + 31 +0.0 + 0 +LINE + 5 +107 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532017.6216248512 + 20 +183917.199737725 + 30 +0.0 + 11 +531954.8704583398 + 21 +183903.1307362112 + 31 +0.0 + 0 +LINE + 5 +108 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532027.4228756862 + 20 +183970.6899285112 + 30 +0.0 + 11 +532007.8099904357 + 21 +183904.7157649685 + 31 +0.0 + 0 +LINE + 5 +109 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532005.8194622598 + 20 +183925.0652505675 + 30 +0.0 + 11 +532165.6070012576 + 21 +183554.8422905387 + 31 +0.0 + 0 +LINE + 5 +10A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532215.3406327096 + 20 +183914.506790095 + 30 +0.0 + 11 +531850.025606886 + 21 +183726.0905468235 + 31 +0.0 + 0 +LINE + 5 +10B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531846.9898456826 + 20 +183739.0551582372 + 30 +0.0 + 11 +531943.2723962861 + 21 +183520.502093417 + 31 +0.0 + 0 +LINE + 5 +10C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531657.2879060011 + 20 +183756.915025109 + 30 +0.0 + 11 +531862.6710068011 + 21 +183729.9954447442 + 31 +0.0 + 0 +LINE + 5 +10D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531707.542847412 + 20 +183828.1640623365 + 30 +0.0 + 11 +531717.0163799135 + 21 +183743.3019863348 + 31 +0.0 + 0 +LINE + 5 +10F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532612.061878647 + 20 +183803.7866919309 + 30 +0.0 + 11 +531940.3427695725 + 21 +183521.5239075487 + 31 +0.0 + 0 +LINE + 5 +110 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531863.1594357444 + 20 +183931.8064504249 + 30 +0.0 + 11 +532014.6676634007 + 21 +183535.7250404825 + 31 +0.0 + 0 +LINE + 5 +111 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531536.9533087979 + 20 +183521.91630484 + 30 +0.0 + 11 +532020.1225745254 + 21 +183540.0721337803 + 31 +0.0 + 0 +LINE + 5 +112 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531322.8230960096 + 20 +183496.2175151871 + 30 +0.0 + 11 +531822.8598906507 + 21 +183537.2174611747 + 31 +0.0 + 0 +LINE + 5 +113 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531511.6320955302 + 20 +183610.9754424221 + 30 +0.0 + 11 +531571.8542817987 + 21 +183510.1646492979 + 31 +0.0 + 0 +LINE + 5 +114 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531573.6637703916 + 20 +183613.6364478867 + 30 +0.0 + 11 +531538.2870985667 + 21 +183509.6456215089 + 31 +0.0 + 0 +LINE + 5 +115 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531762.5332163358 + 20 +183634.4117035529 + 30 +0.0 + 11 +531564.5281508437 + 21 +183594.3963889772 + 31 +0.0 + 0 +LINE + 5 +116 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531647.8000830325 + 20 +183818.5796003908 + 30 +0.0 + 11 +531724.9336515695 + 21 +183527.7567185295 + 31 +0.0 + 0 +LINE + 5 +117 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531562.2020126962 + 20 +183850.0654772609 + 30 +0.0 + 11 +531683.6345265603 + 21 +183848.7965788212 + 31 +0.0 + 0 +LINE + 5 +118 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531664.5618179023 + 20 +183949.0972884033 + 30 +0.0 + 11 +531554.5510755348 + 21 +183899.2438278418 + 31 +0.0 + 0 +LINE + 5 +119 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531559.3441468586 + 20 +183903.9768061644 + 30 +0.0 + 11 +531563.459261181 + 21 +183848.292995883 + 31 +0.0 + 0 +LINE + 5 +11A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531576.9778841278 + 20 +184241.5424111468 + 30 +0.0 + 11 +531576.9801121507 + 21 +184241.5301770692 + 31 +0.0 + 0 +LINE + 5 +11B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531688.3652557219 + 20 +183680.3696937222 + 30 +0.0 + 11 +531664.4402060374 + 21 +183676.2047723989 + 31 +0.0 + 0 +LINE + 5 +11C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531845.0466985964 + 20 +183572.6468079129 + 30 +0.0 + 11 +531848.5375890713 + 21 +183527.4588575618 + 31 +0.0 + 0 +LINE + 5 +11D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531852.4623111796 + 20 +183586.2972429151 + 30 +0.0 + 11 +531842.6874311459 + 21 +183564.3063776991 + 31 +0.0 + 0 +LINE + 5 +11E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531914.5479255571 + 20 +183602.2297999917 + 30 +0.0 + 11 +531845.5021105826 + 21 +183582.3668242385 + 31 +0.0 + 0 +LINE + 5 +11F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531707.8411943863 + 20 +183754.5901321862 + 30 +0.0 + 11 +531365.7560113711 + 21 +183674.7938172478 + 31 +0.0 + 0 +LINE + 5 +122 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531374.0607747642 + 20 +183774.5071494866 + 30 +0.0 + 11 +531666.5682496065 + 21 +183767.1082814454 + 31 +0.0 + 0 +LINE + 5 +123 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531643.2974167897 + 20 +183893.5059139139 + 30 +0.0 + 11 +531608.4049033558 + 21 +183886.834614473 + 31 +0.0 + 0 +LINE + 5 +124 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531527.2010051643 + 20 +183719.29209353 + 30 +0.0 + 11 +531536.5299245022 + 21 +183626.4222304713 + 31 +0.0 + 0 +LINE + 5 +125 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531528.9213936644 + 20 +183660.7390828553 + 30 +0.0 + 11 +531581.6708679228 + 21 +183596.1629633728 + 31 +0.0 + 0 +LINE + 5 +126 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531541.263570164 + 20 +183665.2046948853 + 30 +0.0 + 11 +531513.379763223 + 21 +183590.0605605288 + 31 +0.0 + 0 +LINE + 5 +127 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531346.6694038719 + 20 +183577.4244724932 + 30 +0.0 + 11 +531524.155712167 + 21 +183596.6367946471 + 31 +0.0 + 0 +LINE + 5 +129 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531909.3516392598 + 20 +183825.1299313012 + 30 +0.0 + 11 +531867.9584077485 + 21 +183802.8429323334 + 31 +0.0 + 0 +LINE + 5 +12A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531848.70377308 + 20 +183863.6836230238 + 30 +0.0 + 11 +531869.5695376331 + 21 +183801.8336633017 + 31 +0.0 + 0 +LINE + 5 +12B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531881.7592038701 + 20 +183900.6011533052 + 30 +0.0 + 11 +531779.7769291967 + 21 +183878.6339348538 + 31 +0.0 + 0 +LINE + 5 +12C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531767.8030984371 + 20 +184029.1975708737 + 30 +0.0 + 11 +531797.2733862307 + 21 +183732.0608456437 + 31 +0.0 + 0 +LINE + 5 +12D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531878.2349730312 + 20 +183675.8916353841 + 30 +0.0 + 11 +531813.6487009317 + 21 +183652.0551673432 + 31 +0.0 + 0 +LINE + 5 +12E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531803.5459941819 + 20 +183682.2525717864 + 30 +0.0 + 11 +531824.1875434457 + 21 +183625.8034938436 + 31 +0.0 + 0 +LINE + 5 +12F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531811.718444662 + 20 +183679.5552745401 + 30 +0.0 + 11 +531744.4550535487 + 21 +183655.8042296553 + 31 +0.0 + 0 +LINE + 5 +130 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531745.7990662274 + 20 +183659.270202339 + 30 +0.0 + 11 +531763.7475182558 + 21 +183606.0776947413 + 31 +0.0 + 0 +LINE + 5 +131 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531829.4751229565 + 20 +183633.1302494412 + 30 +0.0 + 11 +531756.6892737099 + 21 +183606.5161939831 + 31 +0.0 + 0 +LINE + 5 +133 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532101.7684936581 + 20 +183858.112361732 + 30 +0.0 + 11 +532220.1805946465 + 21 +183621.4853892659 + 31 +0.0 + 0 +LINE + 5 +134 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531603.2015619726 + 20 +184097.5481402789 + 30 +0.0 + 11 +531677.7782680863 + 21 +183688.04728826 + 31 +0.0 + 0 +LINE + 5 +137 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530735.9131272892 + 20 +184226.3356863664 + 30 +0.0 + 11 +530283.9544628965 + 21 +184816.224090947 + 31 +0.0 + 0 +LINE + 5 +138 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530031.1888274785 + 20 +184139.9555640059 + 30 +0.0 + 11 +532155.7272385915 + 21 +185032.5284892478 + 31 +0.0 + 0 +LINE + 5 +139 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530736.1824591328 + 20 +184432.3874965597 + 30 +0.0 + 11 +530658.0779895487 + 21 +184557.9159257529 + 31 +0.0 + 0 +LINE + 5 +13A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530571.6050156501 + 20 +184436.4223187819 + 30 +0.0 + 11 +531028.5298126501 + 21 +184625.3782307819 + 31 +0.0 + 0 +LINE + 5 +13B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530666.7818999167 + 20 +184526.4514665502 + 30 +0.0 + 11 +530666.9708656795 + 21 +184608.4335532921 + 31 +0.0 + 0 +LINE + 5 +13C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530587.4192474452 + 20 +184533.9936815043 + 30 +0.0 + 11 +530675.262569967 + 21 +184534.9832109703 + 31 +0.0 + 0 +LINE + 5 +13D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530604.4459568053 + 20 +184525.5195397091 + 30 +0.0 + 11 +530484.7853398737 + 21 +184684.3766753369 + 31 +0.0 + 0 +LINE + 5 +13E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530494.1205644549 + 20 +184472.0484992076 + 30 +0.0 + 11 +530795.5503186188 + 21 +184782.8528180704 + 31 +0.0 + 0 +LINE + 5 +13F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530525.0832024871 + 20 +184723.3672426156 + 30 +0.0 + 11 +530669.1589131753 + 21 +184604.6995201719 + 31 +0.0 + 0 +LINE + 5 +140 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530483.8014128733 + 20 +184678.989008366 + 30 +0.0 + 11 +530525.9304985947 + 21 +184723.3935218478 + 31 +0.0 + 0 +LINE + 5 +141 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530293.6891368917 + 20 +184907.7016572334 + 30 +0.0 + 11 +530512.942028526 + 21 +184707.017488296 + 31 +0.0 + 0 +LINE + 5 +142 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530341.6169557605 + 20 +184858.8693757858 + 30 +0.0 + 11 +530423.5169519545 + 21 +184936.9090576151 + 31 +0.0 + 0 +LINE + 5 +143 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530363.0611291584 + 20 +184991.515820703 + 30 +0.0 + 11 +530950.6381382885 + 21 +184434.1646856795 + 31 +0.0 + 0 +LINE + 5 +144 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530794.3778468289 + 20 +184676.7579559348 + 30 +0.0 + 11 +531157.1550750989 + 21 +184924.2987611555 + 31 +0.0 + 0 +LINE + 5 +145 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530841.8667898658 + 20 +184626.0191412416 + 30 +0.0 + 11 +530714.6380901394 + 21 +184772.3829895024 + 31 +0.0 + 0 +LINE + 5 +146 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530895.9427945592 + 20 +184674.477204796 + 30 +0.0 + 11 +530853.3539856806 + 21 +184722.662670036 + 31 +0.0 + 0 +LINE + 5 +147 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530872.5246082747 + 20 +184625.397131656 + 30 +0.0 + 11 +530895.3127741604 + 21 +184690.3429168817 + 31 +0.0 + 0 +LINE + 5 +148 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530881.7703476819 + 20 +184675.0240901761 + 30 +0.0 + 11 +531228.261643328 + 21 +184881.2784956878 + 31 +0.0 + 0 +LINE + 5 +149 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531056.8004158705 + 20 +184564.4609387729 + 30 +0.0 + 11 +530872.2051953306 + 21 +184927.5536250086 + 31 +0.0 + 0 +LINE + 5 +14A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530862.1453565096 + 20 +184918.8302863079 + 30 +0.0 + 11 +531068.2731269009 + 21 +185039.441703539 + 31 +0.0 + 0 +LINE + 5 +14B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530697.9914463482 + 20 +185015.5737333332 + 30 +0.0 + 11 +530880.1604013233 + 21 +184916.9768076993 + 31 +0.0 + 0 +LINE + 5 +14C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530696.9350081967 + 20 +184928.3907741009 + 30 +0.0 + 11 +530754.3600034362 + 21 +184991.5864201783 + 31 +0.0 + 0 +LINE + 5 +14D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531230.2997171692 + 20 +184634.8808927253 + 30 +0.0 + 11 +531185.2838804869 + 21 +184712.9556354173 + 31 +0.0 + 0 +LINE + 5 +14E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531310.6762763139 + 20 +184636.9221898522 + 30 +0.0 + 11 +531065.3007066001 + 21 +185040.3313857042 + 31 +0.0 + 0 +LINE + 5 +14F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530762.244886776 + 20 +184753.1969188066 + 30 +0.0 + 11 +531117.1883003287 + 21 +184985.2538073602 + 31 +0.0 + 0 +LINE + 5 +150 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530857.7930969276 + 20 +185213.7272284981 + 30 +0.0 + 11 +531119.0590254821 + 21 +184978.5341598309 + 31 +0.0 + 0 +LINE + 5 +151 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530551.2309914298 + 20 +185447.3752691109 + 30 +0.0 + 11 +530733.9839065221 + 21 +185290.855504596 + 31 +0.0 + 0 +LINE + 5 +159 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530348.8181148427 + 20 +184670.0431449962 + 30 +0.0 + 11 +530754.9648854495 + 21 +185059.3532645555 + 31 +0.0 + 0 +LINE + 5 +15A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530768.0427135953 + 20 +185059.3665338815 + 30 +0.0 + 11 +530751.1019407378 + 21 +185076.7666714392 + 31 +0.0 + 0 +LINE + 5 +15B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530958.1276376176 + 20 +185054.7821770324 + 30 +0.0 + 11 +530999.5616859051 + 21 +185101.4584959087 + 31 +0.0 + 0 +LINE + 5 +15C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530956.1327284902 + 20 +185039.3761384984 + 30 +0.0 + 11 +530961.1058763477 + 21 +185062.9221409832 + 31 +0.0 + 0 +LINE + 5 +15D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530997.0898474322 + 20 +184990.0711256135 + 30 +0.0 + 11 +530952.7982457301 + 21 +185046.6406968503 + 31 +0.0 + 0 +LINE + 5 +15E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530292.8641702958 + 20 +185138.907267058 + 30 +0.0 + 11 +530369.4465080707 + 21 +185353.2161854958 + 31 +0.0 + 0 +LINE + 5 +160 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530370.209055034 + 20 +184973.0161857821 + 30 +0.0 + 11 +530279.2606443146 + 21 +185168.0844213306 + 31 +0.0 + 0 +LINE + 5 +167 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530155.8545585965 + 20 +184909.1432228739 + 30 +0.0 + 11 +530296.6434578779 + 21 +184802.4901862823 + 31 +0.0 + 0 +LINE + 5 +168 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530239.946090109 + 20 +184831.2897865306 + 30 +0.0 + 11 +530402.572414678 + 21 +185038.3924175608 + 31 +0.0 + 0 +LINE + 5 +169 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530862.2055151921 + 20 +184812.5389120712 + 30 +0.0 + 11 +530841.7372332032 + 21 +184854.8610028793 + 31 +0.0 + 0 +LINE + 5 +16A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530790.4707324915 + 20 +184816.8599962522 + 30 +0.0 + 11 +530843.6341425299 + 21 +184854.7341230553 + 31 +0.0 + 0 +LINE + 5 +16B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530795.6071824628 + 20 +184767.5732594106 + 30 +0.0 + 11 +530725.8663087268 + 21 +184845.1564635503 + 31 +0.0 + 0 +LINE + 5 +16C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530627.8983637173 + 20 +184730.1996766032 + 30 +0.0 + 11 +530825.9688616006 + 21 +184953.6427548386 + 31 +0.0 + 0 +LINE + 5 +16D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530924.4874933892 + 20 +184951.6836966566 + 30 +0.0 + 11 +530886.1381600594 + 21 +185008.8579249901 + 31 +0.0 + 0 +LINE + 5 +16E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530860.2504800935 + 20 +184990.3167291071 + 30 +0.0 + 11 +530910.0659924778 + 21 +185023.9468745498 + 31 +0.0 + 0 +LINE + 5 +16F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530868.4525274285 + 20 +184987.7108168294 + 30 +0.0 + 11 +530827.8842952691 + 21 +185046.3852955798 + 31 +0.0 + 0 +LINE + 5 +170 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530826.9412049412 + 20 +185042.789476152 + 30 +0.0 + 11 +530872.6657967761 + 21 +185075.3601914692 + 31 +0.0 + 0 +LINE + 5 +171 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530910.0543372351 + 20 +185014.9114050643 + 30 +0.0 + 11 +530866.6906180778 + 21 +185079.1428277431 + 31 +0.0 + 0 +LINE + 5 +179 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531418.7837954784 + 20 +184696.3400722527 + 30 +0.0 + 11 +531280.8903155291 + 21 +184879.4025017154 + 31 +0.0 + 0 +LINE + 5 +17A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531365.823685466 + 20 +184738.3257753346 + 30 +0.0 + 11 +531592.6022829192 + 21 +184976.3217497332 + 31 +0.0 + 0 +LINE + 5 +17B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531322.1351667875 + 20 +184916.8361742784 + 30 +0.0 + 11 +531466.2108774758 + 21 +184798.1684518348 + 31 +0.0 + 0 +LINE + 5 +17C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531280.8533771736 + 20 +184872.4579400288 + 30 +0.0 + 11 +531322.982462895 + 21 +184916.8624535107 + 31 +0.0 + 0 +LINE + 5 +17D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531090.7411011921 + 20 +185101.1705888962 + 30 +0.0 + 11 +531309.9939928264 + 21 +184900.4864199589 + 31 +0.0 + 0 +LINE + 5 +17F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531234.6183701311 + 20 +185110.4794756935 + 30 +0.0 + 11 +531708.2884303343 + 21 +184665.0084063687 + 31 +0.0 + 0 +LINE + 5 +180 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531591.4298111294 + 20 +184870.2268875977 + 30 +0.0 + 11 +531810.6718730136 + 21 +185019.8265656036 + 31 +0.0 + 0 +LINE + 5 +181 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531638.9187541661 + 20 +184819.4880729046 + 30 +0.0 + 11 +531511.6900544397 + 21 +184965.8519211652 + 31 +0.0 + 0 +LINE + 5 +182 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531692.9947588596 + 20 +184867.9461364589 + 30 +0.0 + 11 +531650.4059499809 + 21 +184916.131601699 + 31 +0.0 + 0 +LINE + 5 +183 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531669.5765725752 + 20 +184818.8660633189 + 30 +0.0 + 11 +531692.3647384609 + 21 +184883.8118485445 + 31 +0.0 + 0 +LINE + 5 +184 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531678.8223119822 + 20 +184868.493021839 + 30 +0.0 + 11 +532025.3136076283 + 21 +185074.7474273507 + 31 +0.0 + 0 +LINE + 5 +185 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531803.886242807 + 20 +184855.9649338027 + 30 +0.0 + 11 +531669.257159631 + 21 +185121.0225566715 + 31 +0.0 + 0 +LINE + 5 +186 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531659.1973208101 + 20 +185112.2992179708 + 30 +0.0 + 11 +531865.3250912014 + 21 +185232.9106352019 + 31 +0.0 + 0 +LINE + 5 +187 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531525.0175778789 + 20 +185192.8194795596 + 30 +0.0 + 11 +531677.2123656238 + 21 +185110.4457393622 + 31 +0.0 + 0 +LINE + 5 +188 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531361.9808639693 + 20 +184957.7832641063 + 30 +0.0 + 11 +531551.4119677366 + 21 +185185.0553518411 + 31 +0.0 + 0 +LINE + 5 +18B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531559.2968510764 + 20 +184946.6658504695 + 30 +0.0 + 11 +531914.240264629 + 21 +185178.722739023 + 31 +0.0 + 0 +LINE + 5 +18C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531495.5870839868 + 20 +185514.328262188 + 30 +0.0 + 11 +531683.1901243598 + 21 +185202.3268566529 + 31 +0.0 + 0 +LINE + 5 +18D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531462.5997031672 + 20 +185412.663348532 + 30 +0.0 + 11 +531570.4877017599 + 21 +185459.0282866746 + 31 +0.0 + 0 +LINE + 5 +18E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531511.2935385215 + 20 +185374.1416658756 + 30 +0.0 + 11 +531543.5981320771 + 21 +185479.1274464145 + 31 +0.0 + 0 +LINE + 5 +194 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531145.8700791432 + 20 +184863.5120766591 + 30 +0.0 + 11 +531379.5250384659 + 21 +185080.3303849344 + 31 +0.0 + 0 +LINE + 5 +199 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531364.8828980397 + 20 +185058.1671364388 + 30 +0.0 + 11 +531313.3430297857 + 21 +185456.7339505713 + 31 +0.0 + 0 +LINE + 5 +19D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531306.0542879552 + 20 +185343.6943371587 + 30 +0.0 + 11 +531471.2618974371 + 21 +185366.875736194 + 31 +0.0 + 0 +LINE + 5 +19E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531447.4325044233 + 20 +185362.2124236505 + 30 +0.0 + 11 +531528.0241316422 + 21 +185383.6033531333 + 31 +0.0 + 0 +LINE + 5 +19F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531454.8133421622 + 20 +185351.359117895 + 30 +0.0 + 11 +531476.2768427921 + 21 +185428.5825972159 + 31 +0.0 + 0 +LINE + 5 +1A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531385.8070593463 + 20 +185499.2874665739 + 30 +0.0 + 11 +531481.1514824921 + 21 +185416.9376060774 + 31 +0.0 + 0 +LINE + 5 +1A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531046.8204185548 + 20 +185009.8251670371 + 30 +0.0 + 11 +531131.4314460383 + 21 +185132.7716499767 + 31 +0.0 + 0 +LINE + 5 +1A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531659.2574794926 + 20 +185006.0078437341 + 30 +0.0 + 11 +531638.7891975036 + 21 +185048.3299345422 + 31 +0.0 + 0 +LINE + 5 +1A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531587.5226967918 + 20 +185010.328927915 + 30 +0.0 + 11 +531640.6861068304 + 21 +185048.2030547182 + 31 +0.0 + 0 +LINE + 5 +1A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531592.6591467632 + 20 +184961.0421910735 + 30 +0.0 + 11 +531522.9182730272 + 21 +185038.6253952131 + 31 +0.0 + 0 +LINE + 5 +1A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531424.9503280177 + 20 +184923.6686082661 + 30 +0.0 + 11 +531623.020825901 + 21 +185147.1116865014 + 31 +0.0 + 0 +LINE + 5 +1A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531721.5394576896 + 20 +185145.1526283194 + 30 +0.0 + 11 +531683.1901243598 + 21 +185202.3268566529 + 31 +0.0 + 0 +LINE + 5 +1A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531522.4751258036 + 20 +185175.0126803835 + 30 +0.0 + 11 +531707.1179567783 + 21 +185217.4158062127 + 31 +0.0 + 0 +LINE + 5 +1AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531190.971715833 + 20 +185002.7164624653 + 30 +0.0 + 11 +531271.9560624464 + 21 +185081.1135679418 + 31 +0.0 + 0 +LINE + 5 +1AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531510.9794785422 + 20 +185470.5053524346 + 30 +0.0 + 11 +531383.9700559601 + 21 +186031.2293542523 + 31 +0.0 + 0 +LINE + 5 +1AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531446.5789296222 + 20 +185494.6210341629 + 30 +0.0 + 11 +531394.3170697989 + 21 +185715.8408406318 + 31 +0.0 + 0 +LINE + 5 +1AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531303.1927971798 + 20 +185374.8117721197 + 30 +0.0 + 11 +531201.7089334832 + 21 +185510.9511236965 + 31 +0.0 + 0 +LINE + 5 +1B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531179.1304861695 + 20 +185309.1540542189 + 30 +0.0 + 11 +531945.5235833686 + 21 +185894.4094584342 + 31 +0.0 + 0 +LINE + 5 +1B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531306.2594945883 + 20 +185492.8769809982 + 30 +0.0 + 11 +531119.7299674333 + 21 +185890.4829456162 + 31 +0.0 + 0 +LINE + 5 +1B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531363.9212119025 + 20 +185531.6681318393 + 30 +0.0 + 11 +531199.1434766117 + 21 +185429.4046678644 + 31 +0.0 + 0 +LINE + 5 +1B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531324.7054493229 + 20 +185592.7788688038 + 30 +0.0 + 11 +531270.3457337778 + 21 +185558.4180331335 + 31 +0.0 + 0 +LINE + 5 +1B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531369.4236081366 + 20 +185561.8345429817 + 30 +0.0 + 11 +531308.9422635012 + 21 +185594.6866734165 + 31 +0.0 + 0 +LINE + 5 +1B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531321.9057846517 + 20 +185578.8749408755 + 30 +0.0 + 11 +531173.5376807172 + 21 +185953.8202748729 + 31 +0.0 + 0 +LINE + 5 +1B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531458.9627071512 + 20 +185734.036583085 + 30 +0.0 + 11 +531071.0819022518 + 21 +185609.6976292752 + 31 +0.0 + 0 +LINE + 5 +1B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531078.0896100116 + 20 +185598.3755699595 + 30 +0.0 + 11 +530991.8880389454 + 21 +185821.0975061012 + 31 +0.0 + 0 +LINE + 5 +1B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530956.4097734758 + 20 +185451.7474070975 + 30 +0.0 + 11 +531082.7918483163 + 21 +185615.8646001648 + 31 +0.0 + 0 +LINE + 5 +1B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531042.3088874028 + 20 +185436.8032889021 + 30 +0.0 + 11 +530989.0780830456 + 21 +185503.5700563008 + 31 +0.0 + 0 +LINE + 5 +1BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531427.9086440181 + 20 +185996.2182578582 + 30 +0.0 + 11 +530990.5357910721 + 21 +185818.3049727551 + 31 +0.0 + 0 +LINE + 5 +1BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531225.67491972 + 20 +185473.3432035857 + 30 +0.0 + 11 +531053.182121386 + 21 +185860.7466894662 + 31 +0.0 + 0 +LINE + 5 +1BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530705.244826224 + 20 +185533.1168306179 + 30 +0.0 + 11 +531060.1140837642 + 21 +185861.5220430019 + 31 +0.0 + 0 +LINE + 5 +1BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530750.2210620191 + 20 +185452.1857979919 + 30 +0.0 + 11 +530721.6518899537 + 21 +185566.0863253691 + 31 +0.0 + 0 +LINE + 5 +1C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530796.0140686663 + 20 +185494.1144299564 + 30 +0.0 + 11 +530697.5223713036 + 21 +185542.7455561081 + 31 +0.0 + 0 +LINE + 5 +1C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530944.3922051937 + 20 +185612.8039722922 + 30 +0.0 + 11 +530775.9576853574 + 21 +185501.2824771057 + 31 +0.0 + 0 +LINE + 5 +1C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530993.2462747479 + 20 +185401.3925582406 + 30 +0.0 + 11 +530842.445202569 + 21 +185661.7511045552 + 31 +0.0 + 0 +LINE + 5 +1C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530910.7632248174 + 20 +185339.3410325321 + 30 +0.0 + 11 +530866.5377199338 + 21 +185054.4967921601 + 31 +0.0 + 0 +LINE + 5 +1C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531241.8445475884 + 20 +185051.9469660791 + 30 +0.0 + 11 +531241.8374840348 + 21 +185051.9572004795 + 31 +0.0 + 0 +LINE + 5 +1C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531058.6997013602 + 20 +185297.1334434182 + 30 +0.0 + 11 +530922.2746789083 + 21 +185514.9725242263 + 31 +0.0 + 0 +LINE + 5 +1C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530924.3468199957 + 20 +185527.8851535635 + 30 +0.0 + 11 +530904.4681140505 + 21 +185513.935543462 + 31 +0.0 + 0 +LINE + 5 +1C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530959.1812899459 + 20 +185714.807207831 + 30 +0.0 + 11 +530929.7367229487 + 21 +185749.2623184473 + 31 +0.0 + 0 +LINE + 5 +1CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530974.0721419792 + 20 +185710.3813506865 + 30 +0.0 + 11 +530951.6203425609 + 21 +185719.0452490875 + 31 +0.0 + 0 +LINE + 5 +1CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531029.2769113626 + 20 +185742.952861627 + 30 +0.0 + 11 +530966.368846218 + 21 +185708.2478517434 + 31 +0.0 + 0 +LINE + 5 +1CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530990.5554871495 + 20 +185489.0985828673 + 30 +0.0 + 11 +530692.0265768201 + 21 +185303.9764231624 + 31 +0.0 + 0 +LINE + 5 +1CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530835.9437799745 + 20 +185306.8642317253 + 30 +0.0 + 11 +530970.1789346107 + 21 +185451.086004182 + 31 +0.0 + 0 +LINE + 5 +1CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531368.1091655744 + 20 +185350.5718122836 + 30 +0.0 + 11 +530668.7795996761 + 21 +185311.5128716326 + 31 +0.0 + 0 +LINE + 5 +1CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530837.7457079078 + 20 +185386.5022824307 + 30 +0.0 + 11 +530778.7567006423 + 21 +185458.8357962565 + 31 +0.0 + 0 +LINE + 5 +1D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530797.6081421722 + 20 +185429.1683182495 + 30 +0.0 + 11 +530789.3411006597 + 21 +185512.1396281498 + 31 +0.0 + 0 +LINE + 5 +1D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530809.4994571749 + 20 +185434.7241835344 + 30 +0.0 + 11 +530736.6862803595 + 21 +185468.2262566015 + 31 +0.0 + 0 +LINE + 5 +1D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530609.7436608612 + 20 +185359.4255856905 + 30 +0.0 + 11 +530748.9595424861 + 21 +185471.1817544603 + 31 +0.0 + 0 +LINE + 5 +1D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531183.0307102225 + 20 +185581.4869541878 + 30 +0.0 + 11 +531137.9864403011 + 21 +185568.0287342017 + 31 +0.0 + 0 +LINE + 5 +1D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531167.3269023387 + 20 +185511.358919597 + 30 +0.0 + 11 +531138.4141562844 + 21 +185569.8811441243 + 31 +0.0 + 0 +LINE + 5 +1D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531226.956583333 + 20 +185337.0486008117 + 30 +0.0 + 11 +531037.9542343994 + 21 +185568.2127058122 + 31 +0.0 + 0 +LINE + 5 +1D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531055.5968811997 + 20 +185665.1585449819 + 30 +0.0 + 11 +530905.7031021065 + 21 +185592.1718504262 + 31 +0.0 + 0 +LINE + 5 +1DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531342.5419517839 + 20 +185694.0402766141 + 30 +0.0 + 11 +531259.2409286286 + 21 +185945.1870251501 + 31 +0.0 + 0 +LINE + 5 +1DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530564.9552335094 + 20 +184893.4794901465 + 30 +0.0 + 11 +530687.4949689912 + 21 +184780.9839569827 + 31 +0.0 + 0 +LINE + 5 +1DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530476.7429703214 + 20 +184939.4505193447 + 30 +0.0 + 11 +530406.7340426724 + 21 +184768.7171604471 + 31 +0.0 + 0 +LINE + 5 +1E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531173.3663268639 + 20 +185528.1064924517 + 30 +0.0 + 11 +531070.7327473466 + 21 +185471.5685231011 + 31 +0.0 + 0 +LINE + 5 +1E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531054.9475551248 + 20 +184568.1054545053 + 30 +0.0 + 11 +531230.7725863385 + 21 +184476.7284847849 + 31 +0.0 + 0 +LINE + 5 +1E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533270.7018874835 + 20 +183269.704674172 + 30 +0.0 + 11 +533995.2261483039 + 21 +183104.4788902862 + 31 +0.0 + 0 +LINE + 5 +1E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533457.9214482086 + 20 +183355.7642878445 + 30 +0.0 + 11 +533604.5737555198 + 21 +183337.0347532795 + 31 +0.0 + 0 +LINE + 5 +1E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533530.1315517867 + 20 +183207.8193128204 + 30 +0.0 + 11 +533511.6243141418 + 21 +183701.9266786306 + 31 +0.0 + 0 +LINE + 5 +1E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533572.3429516997 + 20 +183331.8438445227 + 30 +0.0 + 11 +533646.7981581808 + 21 +183366.1588628451 + 31 +0.0 + 0 +LINE + 5 +1E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533612.2522464815 + 20 +183262.8325135418 + 30 +0.0 + 11 +533576.567616609 + 21 +183343.107264685 + 31 +0.0 + 0 +LINE + 5 +1E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533597.4568488472 + 20 +183274.7830833879 + 30 +0.0 + 11 +533791.7168653863 + 21 +183232.1532961663 + 31 +0.0 + 0 +LINE + 5 +1E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533594.7911288029 + 20 +183152.2117233308 + 30 +0.0 + 11 +533751.8214958982 + 21 +183555.6973923812 + 31 +0.0 + 0 +LINE + 5 +1EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533810.3821678945 + 20 +183285.0285129525 + 30 +0.0 + 11 +533642.492107029 + 21 +183366.5930041412 + 31 +0.0 + 0 +LINE + 5 +1EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533787.2284528752 + 20 +183229.0149493306 + 30 +0.0 + 11 +533810.0531847598 + 21 +183285.8097756414 + 31 +0.0 + 0 +LINE + 5 +1EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534074.3386399248 + 20 +183151.4269752421 + 30 +0.0 + 11 +533800.5742660043 + 21 +183267.181170518 + 31 +0.0 + 0 +LINE + 5 +1ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534009.9822550737 + 20 +183174.6632241171 + 30 +0.0 + 11 +534046.8228962966 + 21 +183281.6238171917 + 31 +0.0 + 0 +LINE + 5 +1EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534121.646702763 + 20 +183249.4026584481 + 30 +0.0 + 11 +533363.7016999166 + 21 +183552.296365491 + 31 +0.0 + 0 +LINE + 5 +1EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533655.8537941067 + 20 +183510.4459319125 + 30 +0.0 + 11 +533729.8187339051 + 21 +183943.3581115531 + 31 +0.0 + 0 +LINE + 5 +1F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533589.946866456 + 20 +183532.4891602347 + 30 +0.0 + 11 +533776.0005197917 + 21 +183477.7757597539 + 31 +0.0 + 0 +LINE + 5 +1F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533611.4813241646 + 20 +183601.8337010309 + 30 +0.0 + 11 +533673.0261102665 + 21 +183583.1820253481 + 31 +0.0 + 0 +LINE + 5 +1F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533576.6132530237 + 20 +183560.1026257608 + 30 +0.0 + 11 +533626.1680009311 + 21 +183607.8685391599 + 31 +0.0 + 0 +LINE + 5 +1F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533617.8809475537 + 20 +183589.176602051 + 30 +0.0 + 11 +533661.0930421482 + 21 +183990.087829921 + 31 +0.0 + 0 +LINE + 5 +1F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533444.4675323084 + 20 +183702.2585308958 + 30 +0.0 + 11 +533851.4514544708 + 21 +183685.6518652057 + 31 +0.0 + 0 +LINE + 5 +1F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533847.7102810031 + 20 +183672.8729522521 + 30 +0.0 + 11 +533871.5176046772 + 21 +183910.5049850937 + 31 +0.0 + 0 +LINE + 5 +1F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534004.0299181535 + 20 +183563.9235520484 + 30 +0.0 + 11 +533838.5224367574 + 21 +183688.479384923 + 31 +0.0 + 0 +LINE + 5 +1F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533925.2076230635 + 20 +183526.6538560638 + 30 +0.0 + 11 +533958.7459745272 + 21 +183605.1809134549 + 31 +0.0 + 0 +LINE + 5 +1F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533207.3255747524 + 20 +183960.3049635265 + 30 +0.0 + 11 +533517.743220695 + 21 +183803.8631234574 + 31 +0.0 + 0 +LINE + 5 +1F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533404.6134673158 + 20 +183963.2474941249 + 30 +0.0 + 11 +533873.5643870205 + 21 +183908.1731405794 + 31 +0.0 + 0 +LINE + 5 +1FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533738.7306447869 + 20 +183513.0669599583 + 30 +0.0 + 11 +533801.8809645519 + 21 +183932.4084239981 + 31 +0.0 + 0 +LINE + 5 +1FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534224.47460254 + 20 +183709.2127634093 + 30 +0.0 + 11 +533794.9927018023 + 21 +183931.3106481514 + 31 +0.0 + 0 +LINE + 5 +1FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534457.7232899407 + 20 +183610.3296057948 + 30 +0.0 + 11 +533968.0924029948 + 21 +183836.668115154 + 31 +0.0 + 0 +LINE + 5 +1FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534202.6632789288 + 20 +183619.2296539358 + 30 +0.0 + 11 +534199.8836010037 + 21 +183736.6255700483 + 31 +0.0 + 0 +LINE + 5 +1FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534147.3617370868 + 20 +183647.456398454 + 30 +0.0 + 11 +534229.3554706404 + 21 +183720.5496849997 + 31 +0.0 + 0 +LINE + 5 +1FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533972.7437243368 + 20 +183722.3685368734 + 30 +0.0 + 11 +534164.7865490214 + 21 +183659.7044734213 + 31 +0.0 + 0 +LINE + 5 +200 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533972.5943166301 + 20 +183472.651390221 + 30 +0.0 + 11 +534057.9839914489 + 21 +183796.6861657618 + 31 +0.0 + 0 +LINE + 5 +201 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533880.9676565471 + 20 +183491.6555787594 + 30 +0.0 + 11 +534001.1484391712 + 21 +183474.2186921551 + 31 +0.0 + 0 +LINE + 5 +202 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533966.8649116843 + 20 +183378.0488408435 + 30 +0.0 + 11 +533865.8384516585 + 21 +183444.2408746609 + 31 +0.0 + 0 +LINE + 5 +203 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533869.8459157255 + 20 +183438.8265558422 + 30 +0.0 + 11 +533882.4827401662 + 21 +183493.2134252263 + 31 +0.0 + 0 +LINE + 5 +204 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533835.3120588305 + 20 +183102.5693639709 + 30 +0.0 + 11 +534020.1041949207 + 21 +183633.953815103 + 31 +0.0 + 0 +LINE + 5 +205 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534014.6697131808 + 20 +183645.8490315072 + 30 +0.0 + 11 +534037.5443778956 + 21 +183637.6940154909 + 31 +0.0 + 0 +LINE + 5 +206 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533931.3368567337 + 20 +183816.7552329881 + 30 +0.0 + 11 +533950.5478562621 + 21 +183857.8048940144 + 31 +0.0 + 0 +LINE + 5 +207 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533918.161300471 + 20 +183808.5253846964 + 30 +0.0 + 11 +533937.4969419636 + 21 +183822.8529595328 + 31 +0.0 + 0 +LINE + 5 +208 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533856.2782318213 + 20 +183825.2273517097 + 30 +0.0 + 11 +533926.1545818143 + 21 +183808.5193272029 + 31 +0.0 + 0 +LINE + 5 +209 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533961.1739025831 + 20 +183590.8382696407 + 30 +0.0 + 11 +534379.5749554227 + 21 +183474.2284763425 + 31 +0.0 + 0 +LINE + 5 +20A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534350.0885551939 + 20 +183462.4292674622 + 30 +0.0 + 11 +534369.0260173707 + 21 +183662.8181014637 + 31 +0.0 + 0 +LINE + 5 +20B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534101.8508752668 + 20 +183248.1966110715 + 30 +0.0 + 11 +534369.7091801646 + 21 +183492.8116011192 + 31 +0.0 + 0 +LINE + 5 +20C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534331.7371032914 + 20 +183358.3280084779 + 30 +0.0 + 11 +533990.9335592428 + 21 +183559.6209208238 + 31 +0.0 + 0 +LINE + 5 +20D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533948.953081579 + 20 +183438.1485673899 + 30 +0.0 + 11 +533982.607720473 + 21 +183426.774957106 + 31 +0.0 + 0 +LINE + 5 +20E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534135.7799619498 + 20 +183532.6183973673 + 30 +0.0 + 11 +534173.3870155533 + 21 +183618.0440944372 + 31 +0.0 + 0 +LINE + 5 +20F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534163.1125968062 + 20 +183584.4290320622 + 30 +0.0 + 11 +534148.9959986748 + 21 +183666.607520118 + 31 +0.0 + 0 +LINE + 5 +210 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534150.1714181212 + 20 +183586.619216026 + 30 +0.0 + 11 +534211.4401009357 + 21 +183638.2941240943 + 31 +0.0 + 0 +LINE + 5 +211 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534362.7636945454 + 20 +183567.208368469 + 30 +0.0 + 11 +534198.8229231334 + 21 +183637.8760868667 + 31 +0.0 + 0 +LINE + 5 +212 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534133.0534407664 + 20 +183026.7152225984 + 30 +0.0 + 11 +533977.4553795874 + 21 +183110.2952903923 + 31 +0.0 + 0 +LINE + 5 +213 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534027.2513479877 + 20 +183070.7431726557 + 30 +0.0 + 11 +534147.8091657108 + 21 +183304.8470679847 + 31 +0.0 + 0 +LINE + 5 +214 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533751.0505647677 + 20 +183628.6602944098 + 30 +0.0 + 11 +533798.0520979916 + 21 +183627.6775367849 + 31 +0.0 + 0 +LINE + 5 +215 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533784.854580768 + 20 +183565.2423212487 + 30 +0.0 + 11 +533797.1467362854 + 21 +183629.3492675242 + 31 +0.0 + 0 +LINE + 5 +216 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533737.9064232348 + 20 +183549.3855860542 + 30 +0.0 + 11 +533837.4861916935 + 21 +183518.2919734023 + 31 +0.0 + 0 +LINE + 5 +217 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533773.7742595558 + 20 +183381.3482958636 + 30 +0.0 + 11 +533894.426477489 + 21 +183654.4815484178 + 31 +0.0 + 0 +LINE + 5 +218 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533851.6151786993 + 20 +183743.2337394579 + 30 +0.0 + 11 +533919.5664651833 + 21 +183732.1799429354 + 31 +0.0 + 0 +LINE + 5 +219 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533913.4912480489 + 20 +183700.922309379 + 30 +0.0 + 11 +533923.3192982251 + 21 +183760.2180207445 + 31 +0.0 + 0 +LINE + 5 +21A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533907.7061656309 + 20 +183707.2939010718 + 30 +0.0 + 11 +533977.9455113938 + 21 +183694.8476074883 + 31 +0.0 + 0 +LINE + 5 +21B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533975.0691473797 + 20 +183692.4926410805 + 30 +0.0 + 11 +533985.6377707644 + 21 +183747.6278747745 + 31 +0.0 + 0 +LINE + 5 +21C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533915.1095672107 + 20 +183756.444406914 + 30 +0.0 + 11 +533991.5652424396 + 21 +183743.7709100099 + 31 +0.0 + 0 +LINE + 5 +21D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533943.085985443 + 20 +183201.5481465576 + 30 +0.0 + 11 +533980.6329200526 + 21 +183307.8251348707 + 31 +0.0 + 0 +LINE + 5 +21E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533567.3344408619 + 20 +183694.6941674654 + 30 +0.0 + 11 +533580.779713257 + 21 +183958.953461359 + 31 +0.0 + 0 +LINE + 5 +21F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533299.3400004697 + 20 +184222.45492858 + 30 +0.0 + 11 +533281.5900181469 + 21 +184813.9041900183 + 31 +0.0 + 0 +LINE + 5 +220 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533203.5044763441 + 20 +184131.5129678913 + 30 +0.0 + 11 +533448.5161786756 + 21 +184142.2478269584 + 31 +0.0 + 0 +LINE + 5 +221 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533425.5537299617 + 20 +183189.4530703633 + 30 +0.0 + 11 +533355.5667372975 + 21 +184507.1397523095 + 31 +0.0 + 0 +LINE + 5 +222 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533416.2853748554 + 20 +184137.0569182016 + 30 +0.0 + 11 +533490.7405813366 + 21 +184171.371936524 + 31 +0.0 + 0 +LINE + 5 +223 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533456.1946696371 + 20 +184068.0455872208 + 30 +0.0 + 11 +533420.5100397649 + 21 +184148.3203383639 + 31 +0.0 + 0 +LINE + 5 +224 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533443.2091147538 + 20 +184079.7836062105 + 30 +0.0 + 11 +533637.4691312929 + 21 +184037.1538189889 + 31 +0.0 + 0 +LINE + 5 +225 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533407.8651870973 + 20 +183878.1092921243 + 30 +0.0 + 11 +533595.7639190539 + 21 +184360.9104660599 + 31 +0.0 + 0 +LINE + 5 +226 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533654.3245910503 + 20 +184090.2415866314 + 30 +0.0 + 11 +533486.4345301848 + 21 +184171.8060778201 + 31 +0.0 + 0 +LINE + 5 +227 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533631.1708760309 + 20 +184034.2280230095 + 30 +0.0 + 11 +533653.9956079154 + 21 +184091.0228493203 + 31 +0.0 + 0 +LINE + 5 +228 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533918.2810630806 + 20 +183956.640048921 + 30 +0.0 + 11 +533644.51668916 + 21 +184072.3942441969 + 31 +0.0 + 0 +LINE + 5 +229 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533853.9246782293 + 20 +183979.876297796 + 30 +0.0 + 11 +533890.7653194523 + 21 +184086.8368908706 + 31 +0.0 + 0 +LINE + 5 +22A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533965.5891259187 + 20 +184054.615732127 + 30 +0.0 + 11 +533264.55379769 + 21 +184336.4331711375 + 31 +0.0 + 0 +LINE + 5 +22B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533499.7962172624 + 20 +184315.6590055914 + 30 +0.0 + 11 +533573.7611570609 + 21 +184748.571185232 + 31 +0.0 + 0 +LINE + 5 +22C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533433.8892896117 + 20 +184337.7022339136 + 30 +0.0 + 11 +533619.9429429473 + 21 +184282.9888334328 + 31 +0.0 + 0 +LINE + 5 +22D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533455.4237473202 + 20 +184407.0467747098 + 30 +0.0 + 11 +533516.9685334222 + 21 +184388.3950990269 + 31 +0.0 + 0 +LINE + 5 +22E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533420.5556761794 + 20 +184365.3156994397 + 30 +0.0 + 11 +533470.1104240868 + 21 +184413.0816128387 + 31 +0.0 + 0 +LINE + 5 +22F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533461.8233707093 + 20 +184394.3896757299 + 30 +0.0 + 11 +533505.0354653038 + 21 +184795.3009035999 + 31 +0.0 + 0 +LINE + 5 +230 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533288.409955464 + 20 +184507.4716045747 + 30 +0.0 + 11 +533695.3938776265 + 21 +184490.8649388846 + 31 +0.0 + 0 +LINE + 5 +231 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533691.6527041588 + 20 +184478.0860259309 + 30 +0.0 + 11 +533715.4600278328 + 21 +184715.7180587726 + 31 +0.0 + 0 +LINE + 5 +232 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533847.9723413094 + 20 +184369.1366257273 + 30 +0.0 + 11 +533682.4648599131 + 21 +184493.6924586019 + 31 +0.0 + 0 +LINE + 5 +233 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533769.1500462192 + 20 +184331.8669297427 + 30 +0.0 + 11 +533802.6883976829 + 21 +184410.3939871337 + 31 +0.0 + 0 +LINE + 5 +234 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533280.1746114135 + 20 +184638.1115223118 + 30 +0.0 + 11 +533369.9039828841 + 21 +184629.7013561934 + 31 +0.0 + 0 +LINE + 5 +235 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533248.5558904716 + 20 +184768.4605678038 + 30 +0.0 + 11 +533717.5068101762 + 21 +184713.3862142584 + 31 +0.0 + 0 +LINE + 5 +236 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533582.6730679426 + 20 +184318.2800336372 + 30 +0.0 + 11 +533645.8233877078 + 21 +184737.6214976771 + 31 +0.0 + 0 +LINE + 5 +237 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534121.0039373072 + 20 +184485.2255270968 + 30 +0.0 + 11 +533638.9351249581 + 21 +184736.5237218303 + 31 +0.0 + 0 +LINE + 5 +238 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534046.6057020844 + 20 +184424.4427276146 + 30 +0.0 + 11 +534043.8260241595 + 21 +184541.8386437273 + 31 +0.0 + 0 +LINE + 5 +239 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533991.3041602425 + 20 +184452.6694721329 + 30 +0.0 + 11 +534073.2978937962 + 21 +184525.7627586786 + 31 +0.0 + 0 +LINE + 5 +23A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533816.6861474925 + 20 +184527.5816105521 + 30 +0.0 + 11 +534008.728972177 + 21 +184464.9175471002 + 31 +0.0 + 0 +LINE + 5 +23B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533816.5367397858 + 20 +184277.8644638999 + 30 +0.0 + 11 +533901.9264146046 + 21 +184601.8992394407 + 31 +0.0 + 0 +LINE + 5 +23C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533724.9100797029 + 20 +184296.8686524383 + 30 +0.0 + 11 +533845.0908623268 + 21 +184279.431765834 + 31 +0.0 + 0 +LINE + 5 +23D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533810.80733484 + 20 +184183.2619145225 + 30 +0.0 + 11 +533709.7808748142 + 21 +184249.4539483398 + 31 +0.0 + 0 +LINE + 5 +23E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533713.7883388812 + 20 +184244.0396295211 + 30 +0.0 + 11 +533726.4251633219 + 21 +184298.4264989052 + 31 +0.0 + 0 +LINE + 5 +23F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533679.2544819863 + 20 +183907.7824376498 + 30 +0.0 + 11 +533864.0466180764 + 21 +184439.1668887819 + 31 +0.0 + 0 +LINE + 5 +240 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533858.6121363364 + 20 +184451.062105186 + 30 +0.0 + 11 +533881.4868010512 + 21 +184442.9070891699 + 31 +0.0 + 0 +LINE + 5 +241 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533775.2792798894 + 20 +184621.968306667 + 30 +0.0 + 11 +533794.4902794179 + 21 +184663.0179676933 + 31 +0.0 + 0 +LINE + 5 +242 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533762.1037236266 + 20 +184613.7384583753 + 30 +0.0 + 11 +533781.4393651193 + 21 +184628.0660332116 + 31 +0.0 + 0 +LINE + 5 +243 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533700.2206549769 + 20 +184630.4404253886 + 30 +0.0 + 11 +533770.0970049699 + 21 +184613.7324008818 + 31 +0.0 + 0 +LINE + 5 +244 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533805.1163257388 + 20 +184396.0513433196 + 30 +0.0 + 11 +534148.8336143433 + 21 +184307.1003803216 + 31 +0.0 + 0 +LINE + 5 +245 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533945.7932984225 + 20 +184053.4096847504 + 30 +0.0 + 11 +534099.4280930914 + 21 +184187.6594453309 + 31 +0.0 + 0 +LINE + 5 +246 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534111.8739580623 + 20 +184159.1560880029 + 30 +0.0 + 11 +533834.8759823985 + 21 +184364.8339945026 + 31 +0.0 + 0 +LINE + 5 +247 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533792.8955047349 + 20 +184243.3616410688 + 30 +0.0 + 11 +533826.5501436287 + 21 +184231.9880307849 + 31 +0.0 + 0 +LINE + 5 +248 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533979.7223851056 + 20 +184337.8314710463 + 30 +0.0 + 11 +534017.3294387088 + 21 +184423.2571681159 + 31 +0.0 + 0 +LINE + 5 +249 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534007.0550199618 + 20 +184389.6421057411 + 30 +0.0 + 11 +533992.9384218304 + 21 +184471.8205937969 + 31 +0.0 + 0 +LINE + 5 +24A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533994.1138412768 + 20 +184391.8322897049 + 30 +0.0 + 11 +534055.3825240914 + 21 +184443.5071977732 + 31 +0.0 + 0 +LINE + 5 +24B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534157.3418682092 + 20 +184390.7032924748 + 30 +0.0 + 11 +534042.765346289 + 21 +184443.0891605456 + 31 +0.0 + 0 +LINE + 5 +24C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533853.5262160742 + 20 +183878.666833987 + 30 +0.0 + 11 +533991.7515888664 + 21 +184110.0601416636 + 31 +0.0 + 0 +LINE + 5 +24D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533594.9929879234 + 20 +184433.8733680887 + 30 +0.0 + 11 +533641.9945211472 + 21 +184432.8906104638 + 31 +0.0 + 0 +LINE + 5 +24E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533628.7970039238 + 20 +184370.4553949276 + 30 +0.0 + 11 +533641.0891594411 + 21 +184434.5623412031 + 31 +0.0 + 0 +LINE + 5 +24F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533581.8488463905 + 20 +184354.5986597329 + 30 +0.0 + 11 +533681.4286148493 + 21 +184323.5050470813 + 31 +0.0 + 0 +LINE + 5 +250 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533617.7166827114 + 20 +184186.5613695425 + 30 +0.0 + 11 +533738.3689006447 + 21 +184459.6946220967 + 31 +0.0 + 0 +LINE + 5 +251 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533695.5576018551 + 20 +184548.4468131368 + 30 +0.0 + 11 +533763.508888339 + 21 +184537.3930166142 + 31 +0.0 + 0 +LINE + 5 +252 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533757.4336712046 + 20 +184506.1353830579 + 30 +0.0 + 11 +533767.2617213808 + 21 +184565.4310944234 + 31 +0.0 + 0 +LINE + 5 +253 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533751.6485887866 + 20 +184512.5069747506 + 30 +0.0 + 11 +533821.8879345495 + 21 +184500.0606811671 + 31 +0.0 + 0 +LINE + 5 +254 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533819.0115705354 + 20 +184497.7057147594 + 30 +0.0 + 11 +533829.5801939202 + 21 +184552.8409484534 + 31 +0.0 + 0 +LINE + 5 +255 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533759.0519903664 + 20 +184561.6574805929 + 30 +0.0 + 11 +533835.5076655954 + 21 +184548.9839836887 + 31 +0.0 + 0 +LINE + 5 +256 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533787.0284085987 + 20 +184006.7612202365 + 30 +0.0 + 11 +533824.5753432083 + 21 +184113.0382085496 + 31 +0.0 + 0 +LINE + 5 +257 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533411.2768640178 + 20 +184499.9072411442 + 30 +0.0 + 11 +533424.7221364126 + 21 +184764.1665350379 + 31 +0.0 + 0 +LINE + 5 +258 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534079.0438751079 + 20 +184492.5166948246 + 30 +0.0 + 11 +534641.721189493 + 21 +184610.5719340789 + 31 +0.0 + 0 +LINE + 5 +25A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534078.581459301 + 20 +184263.7540395752 + 30 +0.0 + 11 +534244.6175290031 + 21 +184228.1883089295 + 31 +0.0 + 0 +LINE + 5 +25B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534001.2095466687 + 20 +183814.2563075048 + 30 +0.0 + 11 +534167.6424192837 + 21 +184551.2581387564 + 31 +0.0 + 0 +LINE + 5 +25C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534184.6430945557 + 20 +184315.7129436011 + 30 +0.0 + 11 +534623.810301958 + 21 +184321.8368213024 + 31 +0.0 + 0 +LINE + 5 +25D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534195.8955435099 + 20 +184384.2914345422 + 30 +0.0 + 11 +534171.5481171157 + 21 +184191.8941348217 + 31 +0.0 + 0 +LINE + 5 +25E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534267.7865448688 + 20 +184374.0893695216 + 30 +0.0 + 11 +534259.1867207302 + 21 +184310.3579900692 + 31 +0.0 + 0 +LINE + 5 +25F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534221.0297037694 + 20 +184401.8573877923 + 30 +0.0 + 11 +534276.0859439502 + 21 +184360.5528367094 + 31 +0.0 + 0 +LINE + 5 +260 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534256.3117883924 + 20 +184365.7534653767 + 30 +0.0 + 11 +534658.9839601197 + 21 +184387.0189272303 + 31 +0.0 + 0 +LINE + 5 +261 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534340.2964578094 + 20 +184554.9790199963 + 30 +0.0 + 11 +534388.795247378 + 21 +184150.5540434503 + 31 +0.0 + 0 +LINE + 5 +262 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534375.5833000987 + 20 +184152.2097741889 + 30 +0.0 + 11 +534613.971169032 + 21 +184166.5971171824 + 31 +0.0 + 0 +LINE + 5 +263 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534292.9527107281 + 20 +183980.5182296566 + 30 +0.0 + 11 +534389.5250794471 + 21 +184163.7684943256 + 31 +0.0 + 0 +LINE + 5 +264 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534243.591734117 + 20 +184052.3894925513 + 30 +0.0 + 11 +534326.4617765393 + 21 +184031.8012475966 + 31 +0.0 + 0 +LINE + 5 +265 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534523.6546636549 + 20 +184592.9361776223 + 30 +0.0 + 11 +534529.6593127575 + 21 +184503.01379338 + 31 +0.0 + 0 +LINE + 5 +267 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534200.4451829229 + 20 +184234.3143184903 + 30 +0.0 + 11 +534624.4909197793 + 21 +184238.8353143359 + 31 +0.0 + 0 +LINE + 5 +268 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534471.5327107409 + 20 +183786.0600145884 + 30 +0.0 + 11 +534606.9904846774 + 21 +184209.2224334297 + 31 +0.0 + 0 +LINE + 5 +269 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534421.2657241103 + 20 +183576.3330352236 + 30 +0.0 + 11 +534556.4776611428 + 21 +184059.4846922112 + 31 +0.0 + 0 +LINE + 5 +26A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534379.2230397164 + 20 +183793.2446136424 + 30 +0.0 + 11 +534494.6738051587 + 21 +183814.7073368633 + 31 +0.0 + 0 +LINE + 5 +26B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534398.2709077693 + 20 +183852.3393541769 + 30 +0.0 + 11 +534483.5028377962 + 21 +183783.049246773 + 31 +0.0 + 0 +LINE + 5 +26C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534444.3820505485 + 20 +184036.6679774855 + 30 +0.0 + 11 +534413.1406446979 + 21 +183837.0904088021 + 31 +0.0 + 0 +LINE + 5 +26D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534231.8313058096 + 20 +183993.0367155942 + 30 +0.0 + 11 +534531.3403140241 + 21 +183964.3680914949 + 31 +0.0 + 0 +LINE + 5 +26E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534172.5775135222 + 20 +183923.7014562585 + 30 +0.0 + 11 +534215.9402417578 + 21 +184037.1348698833 + 31 +0.0 + 0 +LINE + 5 +26F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534115.2587862785 + 20 +184054.0831760169 + 30 +0.0 + 11 +534123.8030832675 + 21 +183933.6060995451 + 31 +0.0 + 0 +LINE + 5 +270 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534121.0293094167 + 20 +183939.744568014 + 30 +0.0 + 11 +534174.6763040911 + 21 +183924.2648762933 + 31 +0.0 + 0 +LINE + 5 +271 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533810.5991600926 + 20 +184073.5153000436 + 30 +0.0 + 11 +533810.6114064545 + 21 +184073.5131405614 + 31 +0.0 + 0 +LINE + 5 +272 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533954.7380145801 + 20 +184048.098338197 + 30 +0.0 + 11 +534364.6500434818 + 21 +183975.815826753 + 31 +0.0 + 0 +LINE + 5 +273 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534375.5265551551 + 20 +183983.0774559717 + 30 +0.0 + 11 +534371.123204419 + 21 +183959.1951387822 + 31 +0.0 + 0 +LINE + 5 +274 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534530.9589212817 + 20 +184092.5949168104 + 30 +0.0 + 11 +534574.5465687242 + 21 +184080.1750068405 + 31 +0.0 + 0 +LINE + 5 +275 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534520.7335404321 + 20 +184104.2896708572 + 30 +0.0 + 11 +534537.9608515989 + 21 +184087.4859158428 + 31 +0.0 + 0 +LINE + 5 +276 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534527.3546613447 + 20 +184168.0441267445 + 30 +0.0 + 11 +534522.0020775037 + 21 +184096.3976877718 + 31 +0.0 + 0 +LINE + 5 +277 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534312.6897586476 + 20 +184027.1174682027 + 30 +0.0 + 11 +534268.715040369 + 21 +183678.6121619755 + 31 +0.0 + 0 +LINE + 5 +278 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534178.0924395927 + 20 +183721.0298699493 + 30 +0.0 + 11 +534286.6169309787 + 21 +183992.7609886244 + 31 +0.0 + 0 +LINE + 5 +279 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534160.0049395611 + 20 +184014.8357883496 + 30 +0.0 + 11 +534154.1430236581 + 21 +183979.7982132065 + 31 +0.0 + 0 +LINE + 5 +27A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534283.0554192325 + 20 +183845.4622028715 + 30 +0.0 + 11 +534373.3845904289 + 21 +183821.9572878209 + 31 +0.0 + 0 +LINE + 5 +27B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534338.5613499616 + 20 +183826.740385397 + 30 +0.0 + 11 +534417.4375952255 + 21 +183853.7796193919 + 31 +0.0 + 0 +LINE + 5 +27C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534338.6600611481 + 20 +183839.8652194019 + 30 +0.0 + 11 +534399.4430551205 + 21 +183787.6198821797 + 31 +0.0 + 0 +LINE + 5 +27D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534353.3950801142 + 20 +183626.8977659865 + 30 +0.0 + 11 +534397.018575538 + 21 +183800.0089834212 + 31 +0.0 + 0 +LINE + 5 +27E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534316.5240373919 + 20 +184240.583205404 + 30 +0.0 + 11 +534323.0481789416 + 21 +184194.0262992032 + 31 +0.0 + 0 +LINE + 5 +27F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534259.3074196166 + 20 +184197.0997663956 + 30 +0.0 + 11 +534324.5541633551 + 21 +184195.1866329612 + 31 +0.0 + 0 +LINE + 5 +280 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534236.1677363386 + 20 +184240.9189471798 + 30 +0.0 + 11 +534221.3497769108 + 21 +184137.6553470467 + 31 +0.0 + 0 +LINE + 5 +281 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534075.9993490205 + 20 +184178.7166941591 + 30 +0.0 + 11 +534364.8760209383 + 21 +184103.158770916 + 31 +0.0 + 0 +LINE + 5 +282 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534445.6665385903 + 20 +184159.5737598459 + 30 +0.0 + 11 +534445.5888953305 + 21 +184090.7293139994 + 31 +0.0 + 0 +LINE + 5 +283 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534413.7624798858 + 20 +184091.7428221283 + 30 +0.0 + 11 +534473.8666444875 + 21 +184091.4951244661 + 31 +0.0 + 0 +LINE + 5 +284 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534419.1301320043 + 20 +184098.4698326099 + 30 +0.0 + 11 +534418.0426346745 + 21 +184027.1445687356 + 31 +0.0 + 0 +LINE + 5 +285 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534415.2591650874 + 20 +184029.6086372781 + 30 +0.0 + 11 +534471.3741634863 + 21 +184027.9664590178 + 31 +0.0 + 0 +LINE + 5 +286 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534468.8322797114 + 20 +184098.9981249308 + 30 +0.0 + 11 +534468.5116705245 + 21 +184021.4998345739 + 31 +0.0 + 0 +LINE + 5 +287 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534352.4198206242 + 20 +184432.4779143455 + 30 +0.0 + 11 +534615.4420738622 + 21 +184461.3404170194 + 31 +0.0 + 0 +LINE + 5 +288 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533532.7624275796 + 20 +183279.5203883841 + 30 +0.0 + 11 +532822.6282750719 + 21 +183060.5581778998 + 31 +0.0 + 0 +LINE + 5 +289 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533342.1028701529 + 20 +183213.5023917251 + 30 +0.0 + 11 +533311.0032423039 + 21 +183772.1392497893 + 31 +0.0 + 0 +LINE + 5 +28A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533339.6295991045 + 20 +183351.3335597998 + 30 +0.0 + 11 +533194.7893030568 + 21 +183321.6859065113 + 31 +0.0 + 0 +LINE + 5 +28B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533278.6891237384 + 20 +183198.401309585 + 30 +0.0 + 11 +533234.487352922 + 21 +184185.8116573112 + 31 +0.0 + 0 +LINE + 5 +28C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533227.3181130724 + 20 +183318.9206275791 + 30 +0.0 + 11 +533150.504528331 + 21 +183347.5697367062 + 31 +0.0 + 0 +LINE + 5 +28D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533192.6831632028 + 20 +183247.1171745893 + 30 +0.0 + 11 +533222.2627044432 + 21 +183329.8364542056 + 31 +0.0 + 0 +LINE + 5 +28E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533206.543120186 + 20 +183260.1410566229 + 30 +0.0 + 11 +533016.016412499 + 21 +183203.0987351212 + 31 +0.0 + 0 +LINE + 5 +28F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533218.3705491292 + 20 +183138.1125505508 + 30 +0.0 + 11 +533031.596680065 + 21 +183528.7207214253 + 31 +0.0 + 0 +LINE + 5 +290 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532993.44798064 + 20 +183254.429505146 + 30 +0.0 + 11 +533154.7660373612 + 21 +183348.3247837068 + 31 +0.0 + 0 +LINE + 5 +291 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533020.7270185264 + 20 +183200.3049458331 + 30 +0.0 + 11 +532993.7175981719 + 21 +183255.2331889633 + 31 +0.0 + 0 +LINE + 5 +292 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532740.2254147077 + 20 +183101.4565594727 + 30 +0.0 + 11 +533004.5635047808 + 21 +183237.3658685307 + 31 +0.0 + 0 +LINE + 5 +293 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532802.6632449139 + 20 +183129.4420001883 + 30 +0.0 + 11 +532757.924443903 + 21 +183233.3469615745 + 31 +0.0 + 0 +LINE + 5 +294 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532685.720654224 + 20 +183195.6187514277 + 30 +0.0 + 11 +533412.4422479266 + 21 +183553.0579135474 + 31 +0.0 + 0 +LINE + 5 +295 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533130.6806038581 + 20 +183490.7750957559 + 30 +0.0 + 11 +533024.5381114682 + 21 +183916.9411888579 + 31 +0.0 + 0 +LINE + 5 +296 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533194.7538784246 + 20 +183517.6868499452 + 30 +0.0 + 11 +533013.3144771753 + 21 +183449.2086651994 + 31 +0.0 + 0 +LINE + 5 +297 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533168.0923122618 + 20 +183585.2261651385 + 30 +0.0 + 11 +533108.1152453137 + 21 +183562.0227786959 + 31 +0.0 + 0 +LINE + 5 +298 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533205.9844550757 + 20 +183546.2203893963 + 30 +0.0 + 11 +533152.9953396826 + 21 +183590.1454297818 + 31 +0.0 + 0 +LINE + 5 +299 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533162.6574581374 + 20 +183572.125795115 + 30 +0.0 + 11 +533089.5755333646 + 21 +183968.6811254574 + 31 +0.0 + 0 +LINE + 5 +29A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533327.1256725953 + 20 +183697.8633855617 + 30 +0.0 + 11 +532922.5243948965 + 21 +183650.8580632188 + 31 +0.0 + 0 +LINE + 5 +29B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532927.2110360585 + 20 +183638.3948216737 + 30 +0.0 + 11 +532885.6939141481 + 21 +183873.5800684076 + 31 +0.0 + 0 +LINE + 5 +29C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532779.4795621642 + 20 +183518.0569124989 + 30 +0.0 + 11 +532935.2056681788 + 21 +183654.6448395154 + 31 +0.0 + 0 +LINE + 5 +29D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532860.8690292618 + 20 +183486.7880927641 + 30 +0.0 + 11 +532821.5502885538 + 21 +183562.5862219661 + 31 +0.0 + 0 +LINE + 5 +29F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533293.6322814212 + 20 +183952.7605173787 + 30 +0.0 + 11 +532883.8273047613 + 21 +183871.1016442716 + 31 +0.0 + 0 +LINE + 5 +2A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533047.8398997946 + 20 +183487.189023119 + 30 +0.0 + 11 +532953.4969078967 + 21 +183900.6314329289 + 31 +0.0 + 0 +LINE + 5 +2A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532548.7839254298 + 20 +183646.44825568 + 30 +0.0 + 11 +532960.4479911811 + 21 +183900.052022287 + 31 +0.0 + 0 +LINE + 5 +2A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532323.5859293173 + 20 +183530.3935634832 + 30 +0.0 + 11 +532794.9132185243 + 21 +183792.7256292301 + 31 +0.0 + 0 +LINE + 5 +2A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532577.2654881728 + 20 +183558.3489116874 + 30 +0.0 + 11 +532571.2553581126 + 21 +183675.6238282977 + 31 +0.0 + 0 +LINE + 5 +2A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532630.3005233718 + 20 +183590.633500544 + 30 +0.0 + 11 +532543.0686538527 + 21 +183657.3882892886 + 31 +0.0 + 0 +LINE + 5 +2A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532798.8253221348 + 20 +183678.3983628817 + 30 +0.0 + 11 +532612.008295049 + 21 +183601.5437615102 + 31 +0.0 + 0 +LINE + 5 +2A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532817.6548659477 + 20 +183429.3920899996 + 30 +0.0 + 11 +532708.2644265074 + 21 +183746.131200443 + 31 +0.0 + 0 +LINE + 5 +2A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532982.2371375846 + 20 +183070.6166723318 + 30 +0.0 + 11 +532758.2115810167 + 21 +183586.6884875571 + 31 +0.0 + 0 +LINE + 5 +2A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532762.7409918191 + 20 +183598.9569105556 + 30 +0.0 + 11 +532740.5404720749 + 21 +183589.1135627954 + 31 +0.0 + 0 +LINE + 5 +2A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532833.0553973926 + 20 +183775.6181090037 + 30 +0.0 + 11 +532810.8274301857 + 21 +183815.1156361047 + 31 +0.0 + 0 +LINE + 5 +2AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532846.8096853747 + 20 +183768.3969423502 + 30 +0.0 + 11 +532826.4564207106 + 21 +183781.2379333611 + 31 +0.0 + 0 +LINE + 5 +2AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532907.2699385936 + 20 +183789.6813889798 + 30 +0.0 + 11 +532838.8392540151 + 21 +183767.7929495795 + 31 +0.0 + 0 +LINE + 5 +2AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532820.202091548 + 20 +183548.1021399771 + 30 +0.0 + 11 +532411.6965931075 + 21 +183400.5198149712 + 31 +0.0 + 0 +LINE + 5 +2AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532705.5512352485 + 20 +183195.8969469713 + 30 +0.0 + 11 +532420.1445797267 + 21 +183419.7888982393 + 31 +0.0 + 0 +LINE + 5 +2AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532468.0705552294 + 20 +183288.5226947296 + 30 +0.0 + 11 +532792.8610919387 + 21 +183514.7460345087 + 31 +0.0 + 0 +LINE + 5 +2B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532650.440516718 + 20 +183476.9836669457 + 30 +0.0 + 11 +532606.5484086562 + 21 +183559.3567393084 + 31 +0.0 + 0 +LINE + 5 +2B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532619.308676055 + 20 +183526.6044619072 + 30 +0.0 + 11 +532627.2382057076 + 21 +183609.6087075904 + 31 +0.0 + 0 +LINE + 5 +2B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532632.0497533188 + 20 +183529.7565979628 + 30 +0.0 + 11 +532567.0871053734 + 21 +183576.7033975304 + 31 +0.0 + 0 +LINE + 5 +2B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532319.1054598828 + 20 +183440.943242896 + 30 +0.0 + 11 +532579.7002024197 + 21 +183577.2303830341 + 31 +0.0 + 0 +LINE + 5 +2B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532691.0044244704 + 20 +182972.7019742909 + 30 +0.0 + 11 +532839.9141442266 + 21 +183067.6876560392 + 31 +0.0 + 0 +LINE + 5 +2B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532793.2164716504 + 20 +183024.5212818305 + 30 +0.0 + 11 +532655.4838754236 + 21 +183248.9506764272 + 31 +0.0 + 0 +LINE + 5 +2B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533026.9073257411 + 20 +183601.5368553743 + 30 +0.0 + 11 +532980.1110058652 + 21 +183597.0408144468 + 31 +0.0 + 0 +LINE + 5 +2B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532997.9421264003 + 20 +183535.767804562 + 30 +0.0 + 11 +532980.888773864 + 21 +183598.7755883294 + 31 +0.0 + 0 +LINE + 5 +2B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533045.9449296638 + 20 +183523.46754336 + 30 +0.0 + 11 +532948.9701949887 + 21 +183485.011804273 + 31 +0.0 + 0 +LINE + 5 +2B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533022.747934971 + 20 +183353.2179265787 + 30 +0.0 + 11 +532882.0015395169 + 21 +183616.5602579835 + 31 +0.0 + 0 +LINE + 5 +2BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532918.0536104154 + 20 +183708.2663477616 + 30 +0.0 + 11 +532851.1196203771 + 21 +183692.1603013838 + 31 +0.0 + 0 +LINE + 5 +2BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532859.5161003121 + 20 +183661.4447183113 + 30 +0.0 + 11 +532845.2798621558 + 21 +183719.8390800234 + 31 +0.0 + 0 +LINE + 5 +2BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532864.808334425 + 20 +183668.2312208995 + 30 +0.0 + 11 +532795.6968644821 + 21 +183650.5654166575 + 31 +0.0 + 0 +LINE + 5 +2BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532798.7413366781 + 20 +183648.4322205175 + 30 +0.0 + 11 +532784.0778326244 + 21 +183702.6223620896 + 31 +0.0 + 0 +LINE + 5 +2BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532853.7488820336 + 20 +183716.6901838713 + 30 +0.0 + 11 +532778.4554968875 + 21 +183698.3327888569 + 31 +0.0 + 0 +LINE + 5 +2C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533236.9410300952 + 20 +184128.2527506047 + 30 +0.0 + 11 +533126.981531269 + 21 +184343.3517983396 + 31 +0.0 + 0 +LINE + 5 +2C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532835.6102659117 + 20 +183916.0876363871 + 30 +0.0 + 11 +533298.5518772549 + 21 +184154.1088557825 + 31 +0.0 + 0 +LINE + 5 +2C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532781.1055054279 + 20 +184010.2498283422 + 30 +0.0 + 11 +533459.0946851481 + 21 +184343.719875779 + 31 +0.0 + 0 +LINE + 5 +2C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533226.0654550621 + 20 +184305.4061726703 + 30 +0.0 + 11 +533119.9229626722 + 21 +184731.5722657724 + 31 +0.0 + 0 +LINE + 5 +2C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533290.1387296285 + 20 +184332.3179268596 + 30 +0.0 + 11 +533108.6993283793 + 21 +184263.8397421138 + 31 +0.0 + 0 +LINE + 5 +2C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533263.4771634658 + 20 +184399.8572420528 + 30 +0.0 + 11 +533203.5000965176 + 21 +184376.6538556104 + 31 +0.0 + 0 +LINE + 5 +2CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533301.3693062795 + 20 +184360.8514663108 + 30 +0.0 + 11 +533248.3801908866 + 21 +184404.7765066962 + 31 +0.0 + 0 +LINE + 5 +2CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533258.0423093414 + 20 +184386.7568720294 + 30 +0.0 + 11 +533184.9603845684 + 21 +184783.3122023718 + 31 +0.0 + 0 +LINE + 5 +2CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533313.2245827507 + 20 +184499.6854179535 + 30 +0.0 + 11 +533017.9092461005 + 21 +184465.4891401333 + 31 +0.0 + 0 +LINE + 5 +2CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533022.5958872625 + 20 +184453.0258985883 + 30 +0.0 + 11 +532981.0787653521 + 21 +184688.211145322 + 31 +0.0 + 0 +LINE + 5 +2CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532874.8644133681 + 20 +184332.6879894133 + 30 +0.0 + 11 +533030.5905193828 + 21 +184469.2759164299 + 31 +0.0 + 0 +LINE + 5 +2CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532956.2538804658 + 20 +184301.4191696784 + 30 +0.0 + 11 +532916.9351397578 + 21 +184377.2172988805 + 31 +0.0 + 0 +LINE + 5 +2D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533312.5190293062 + 20 +184749.7419374041 + 30 +0.0 + 11 +532979.2121559653 + 21 +184685.7327211861 + 31 +0.0 + 0 +LINE + 5 +2D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533143.2247509987 + 20 +184301.8201000335 + 30 +0.0 + 11 +533048.8817591007 + 21 +184715.2625098432 + 31 +0.0 + 0 +LINE + 5 +2D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532593.9135947571 + 20 +184428.0269791083 + 30 +0.0 + 11 +533055.8328423851 + 21 +184714.6830992013 + 31 +0.0 + 0 +LINE + 5 +2D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532672.6503393768 + 20 +184372.9799886018 + 30 +0.0 + 11 +532666.6402093166 + 21 +184490.254905212 + 31 +0.0 + 0 +LINE + 5 +2D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532725.6853745756 + 20 +184405.2645774584 + 30 +0.0 + 11 +532638.4535050566 + 21 +184472.0193662031 + 31 +0.0 + 0 +LINE + 5 +2D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532894.2101733388 + 20 +184493.0294397962 + 30 +0.0 + 11 +532707.3931462529 + 21 +184416.1748384246 + 31 +0.0 + 0 +LINE + 5 +2D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532913.0397171517 + 20 +184244.0231669139 + 30 +0.0 + 11 +532803.6492777113 + 21 +184560.7622773574 + 31 +0.0 + 0 +LINE + 5 +2D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533002.9879995437 + 20 +184269.8284089141 + 30 +0.0 + 11 +532884.4483571425 + 21 +184243.4500331875 + 31 +0.0 + 0 +LINE + 5 +2D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533018.0305508438 + 20 +184217.9793931889 + 30 +0.0 + 11 +533001.3606235288 + 21 +184271.2685517172 + 31 +0.0 + 0 +LINE + 5 +2D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533077.6219887886 + 20 +183885.2477492463 + 30 +0.0 + 11 +532853.5964322206 + 21 +184401.3195644716 + 31 +0.0 + 0 +LINE + 5 +2DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532858.125843023 + 20 +184413.5879874701 + 30 +0.0 + 11 +532835.9253232789 + 21 +184403.7446397097 + 31 +0.0 + 0 +LINE + 5 +2DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532928.4402485964 + 20 +184590.2491859182 + 30 +0.0 + 11 +532906.2122813897 + 21 +184629.7467130191 + 31 +0.0 + 0 +LINE + 5 +2DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532942.1945365787 + 20 +184583.0280192646 + 30 +0.0 + 11 +532921.8412719146 + 21 +184595.8690102754 + 31 +0.0 + 0 +LINE + 5 +2DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533002.6547897976 + 20 +184604.3124658941 + 30 +0.0 + 11 +532934.2241052192 + 21 +184582.424026494 + 31 +0.0 + 0 +LINE + 5 +2DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532915.586942752 + 20 +184362.7332168916 + 30 +0.0 + 11 +532579.4868776007 + 21 +184248.3190809244 + 31 +0.0 + 0 +LINE + 5 +2DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532800.9360864524 + 20 +184010.5280238858 + 30 +0.0 + 11 +532637.6889675159 + 21 +184132.908686197 + 31 +0.0 + 0 +LINE + 5 +2E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532627.4102219 + 20 +184103.5541580553 + 30 +0.0 + 11 +532888.2459431427 + 21 +184329.3771114232 + 31 +0.0 + 0 +LINE + 5 +2E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532939.1957581605 + 20 +184211.3855460326 + 30 +0.0 + 11 +532906.4862421954 + 21 +184197.5262063909 + 31 +0.0 + 0 +LINE + 5 +2E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532745.825367922 + 20 +184291.6147438601 + 30 +0.0 + 11 +532701.9332598602 + 21 +184373.9878162229 + 31 +0.0 + 0 +LINE + 5 +2E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532714.693527259 + 20 +184341.2355388216 + 30 +0.0 + 11 +532722.6230569117 + 21 +184424.2397845048 + 31 +0.0 + 0 +LINE + 5 +2E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532727.4346045227 + 20 +184344.3876748772 + 30 +0.0 + 11 +532662.4719565772 + 21 +184391.3344744447 + 31 +0.0 + 0 +LINE + 5 +2E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532564.7483924605 + 20 +184331.0512654725 + 30 +0.0 + 11 +532675.0850536236 + 21 +184391.8614599485 + 31 +0.0 + 0 +LINE + 5 +2E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532906.0166036281 + 20 +183843.1770056994 + 30 +0.0 + 11 +532750.8687266275 + 21 +184063.5817533417 + 31 +0.0 + 0 +LINE + 5 +2E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533122.292176945 + 20 +184416.1679322887 + 30 +0.0 + 11 +533075.4958570691 + 21 +184411.6718913614 + 31 +0.0 + 0 +LINE + 5 +2E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533093.3269776042 + 20 +184350.3988814763 + 30 +0.0 + 11 +533076.273625068 + 21 +184413.4066652438 + 31 +0.0 + 0 +LINE + 5 +2E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533141.3297808676 + 20 +184338.0986202742 + 30 +0.0 + 11 +533044.3550461925 + 21 +184299.6428811874 + 31 +0.0 + 0 +LINE + 5 +2EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533118.132786175 + 20 +184167.8490034932 + 30 +0.0 + 11 +532977.3863907207 + 21 +184431.1913348979 + 31 +0.0 + 0 +LINE + 5 +2EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533013.4384616195 + 20 +184522.897424676 + 30 +0.0 + 11 +532946.5044715811 + 21 +184506.7913782983 + 31 +0.0 + 0 +LINE + 5 +2EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532954.9009515162 + 20 +184476.0757952258 + 30 +0.0 + 11 +532940.6647133597 + 21 +184534.470156938 + 31 +0.0 + 0 +LINE + 5 +2ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532960.1931856289 + 20 +184482.8622978139 + 30 +0.0 + 11 +532891.0817156861 + 21 +184465.196493572 + 31 +0.0 + 0 +LINE + 5 +2EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532894.1261878821 + 20 +184463.0632974319 + 30 +0.0 + 11 +532879.4626838282 + 21 +184517.2534390039 + 31 +0.0 + 0 +LINE + 5 +2EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532949.1337332375 + 20 +184531.3212607857 + 30 +0.0 + 11 +532873.8403480914 + 21 +184512.9638657713 + 31 +0.0 + 0 +LINE + 5 +2F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532962.7457486525 + 20 +183975.8869687485 + 30 +0.0 + 11 +532917.3537715828 + 21 +184079.0574052173 + 31 +0.0 + 0 +LINE + 5 +2F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532635.2106572713 + 20 +184438.4366176368 + 30 +0.0 + 11 +532065.2785999623 + 21 +184514.0689499459 + 31 +0.0 + 0 +LINE + 5 +2F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532590.2300880724 + 20 +184386.4198395649 + 30 +0.0 + 11 +532364.6295972854 + 21 +184414.239316967 + 31 +0.0 + 0 +LINE + 5 +2F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532652.7847925186 + 20 +184210.3495376971 + 30 +0.0 + 11 +532489.8745094784 + 21 +184162.4628243181 + 31 +0.0 + 0 +LINE + 5 +2F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532763.5654245859 + 20 +183767.8992291204 + 30 +0.0 + 11 +532542.4660997646 + 21 +184490.3856919131 + 31 +0.0 + 0 +LINE + 5 +2F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532543.1334552761 + 20 +184254.2287175145 + 30 +0.0 + 11 +532030.3823403245 + 21 +184165.1226977185 + 31 +0.0 + 0 +LINE + 5 +2F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532526.7823938887 + 20 +184321.7732940453 + 30 +0.0 + 11 +532565.4542369875 + 21 +184131.7364379803 + 31 +0.0 + 0 +LINE + 5 +2F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532455.8560125364 + 20 +184306.2218749684 + 30 +0.0 + 11 +532469.1992844791 + 21 +184243.3123939978 + 31 +0.0 + 0 +LINE + 5 +2F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532500.404604757 + 20 +184337.4098207074 + 30 +0.0 + 11 +532448.5924934925 + 21 +184292.102419002 + 31 +0.0 + 0 +LINE + 5 +2F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532467.9222000074 + 20 +184298.7677181402 + 30 +0.0 + 11 +532151.5594281791 + 21 +184344.7377033163 + 31 +0.0 + 0 +LINE + 5 +2FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532546.3727587354 + 20 +184062.6106464354 + 30 +0.0 + 11 +532126.1632264118 + 21 +184073.4140238009 + 31 +0.0 + 0 +LINE + 5 +307 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532584.4903761105 + 20 +183864.2182182287 + 30 +0.0 + 11 +532532.7635513458 + 21 +183974.0899667647 + 31 +0.0 + 0 +LINE + 5 +308 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532631.8950520743 + 20 +183998.5224476362 + 30 +0.0 + 11 +532632.3872072136 + 21 +183877.743770919 + 31 +0.0 + 0 +LINE + 5 +309 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532634.6940095361 + 20 +183884.0725369571 + 30 +0.0 + 11 +532582.3553185839 + 21 +183864.6230556592 + 31 +0.0 + 0 +LINE + 5 +30A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532934.2473785581 + 20 +184040.6907525797 + 30 +0.0 + 11 +532934.235328054 + 21 +184040.6876830364 + 31 +0.0 + 0 +LINE + 5 +30B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532792.4137581562 + 20 +184004.5624334069 + 30 +0.0 + 11 +532167.9345982127 + 21 +183901.8182242516 + 31 +0.0 + 0 +LINE + 5 +310 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532368.508547977 + 20 +184092.6775787239 + 30 +0.0 + 11 +532506.9565822644 + 21 +183612.623907776 + 31 +0.0 + 0 +LINE + 5 +311 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532594.1521268948 + 20 +183661.7019549843 + 30 +0.0 + 11 +532478.1241977714 + 21 +183964.5209857737 + 31 +0.0 + 0 +LINE + 5 +312 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532590.2102493452 + 20 +183956.0377104505 + 30 +0.0 + 11 +532598.6767912577 + 21 +183921.5368206355 + 31 +0.0 + 0 +LINE + 5 +317 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532306.0587504182 + 20 +184266.992331815 + 30 +0.0 + 11 +532414.2191715132 + 21 +184122.5293847503 + 31 +0.0 + 0 +LINE + 5 +318 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532477.551415465 + 20 +184130.3624860479 + 30 +0.0 + 11 +532412.6306058845 + 21 +184123.5738093414 + 31 +0.0 + 0 +LINE + 5 +319 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532661.721044324 + 20 +184125.7436229359 + 30 +0.0 + 11 +532439.6824280089 + 21 +184049.5153294456 + 31 +0.0 + 0 +LINE + 5 +31C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532847.7714891928 + 20 +183350.8987513204 + 30 +0.0 + 11 +532995.8222172223 + 21 +183426.7421009539 + 31 +0.0 + 0 +LINE + 5 +31D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532774.0262611856 + 20 +183284.1426261447 + 30 +0.0 + 11 +532909.8188335092 + 21 +183159.1966094306 + 31 +0.0 + 0 +LINE + 5 +31E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532709.4902750977 + 20 +183812.8863756505 + 30 +0.0 + 11 +532835.4314276548 + 21 +183979.9680373762 + 31 +0.0 + 0 +LINE + 5 +31F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532463.9437321764 + 20 +184141.8423292799 + 30 +0.0 + 11 +532481.318514892 + 21 +184025.9617418272 + 31 +0.0 + 0 +LINE + 5 +320 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533323.0645174747 + 20 +183697.3915731477 + 30 +0.0 + 11 +533469.8168568623 + 21 +183830.5378952181 + 31 +0.0 + 0 +LINE + 5 +322 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529846.7918439317 + 20 +185094.6275250928 + 30 +0.0 + 11 +532736.3514167985 + 21 +185388.7767557458 + 31 +0.0 + 0 +LINE + 5 +323 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530632.5473901829 + 20 +185377.7313809267 + 30 +0.0 + 11 +530347.847156352 + 21 +185292.772304566 + 31 +0.0 + 0 +LINE + 5 +324 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530537.8475188888 + 20 +185421.3935488612 + 30 +0.0 + 11 +530918.4513398055 + 21 +185724.2180642567 + 31 +0.0 + 0 +LINE + 5 +325 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530524.4682282156 + 20 +184838.4117535552 + 30 +0.0 + 11 +530539.0027126899 + 21 +185369.0524173398 + 31 +0.0 + 0 +LINE + 5 +326 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530335.1690853607 + 20 +184982.8667579243 + 30 +0.0 + 11 +530559.2802786548 + 21 +185043.4543895813 + 31 +0.0 + 0 +LINE + 5 +327 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530707.0247008471 + 20 +184994.505863614 + 30 +0.0 + 11 +530707.477024887 + 21 +185313.5574728215 + 31 +0.0 + 0 +LINE + 5 +332 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531131.4314460383 + 20 +185132.7716499767 + 30 +0.0 + 11 +531131.4314460383 + 21 +185359.3560314326 + 31 +0.0 + 0 +LINE + 5 +333 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530501.6760625543 + 20 +185036.5091148205 + 30 +0.0 + 11 +530743.4035747344 + 21 +185005.6828851596 + 31 +0.0 + 0 +LINE + 5 +334 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530485.4823504736 + 20 +185236.4996961124 + 30 +0.0 + 11 +530775.1816292018 + 21 +185251.6757933341 + 31 +0.0 + 0 +LINE + 5 +335 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532544.9929155681 + 20 +185376.4324141973 + 30 +0.0 + 11 +536042.6124124007 + 21 +185481.9872221566 + 31 +0.0 + 0 +LINE + 5 +358 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532320.5649707108 + 20 +184501.5680036159 + 30 +0.0 + 11 +532310.185466446 + 21 +184245.5571047196 + 31 +0.0 + 0 +LINE + 5 +366 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532121.1286102474 + 20 +185156.5429902478 + 30 +0.0 + 11 +532552.7822942475 + 21 +185237.5298082478 + 31 +0.0 + 0 +LINE + 5 +367 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532107.1836522989 + 20 +185396.4993852853 + 30 +0.0 + 11 +532132.2182172474 + 21 +185032.5284892478 + 31 +0.0 + 0 +LINE + 5 +368 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532191.4177562475 + 20 +185229.8919942478 + 30 +0.0 + 11 +532195.3011802475 + 21 +185165.7003692478 + 31 +0.0 + 0 +LINE + 5 +36B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532227.5888392475 + 20 +185421.3871792478 + 30 +0.0 + 11 +532353.3590012474 + 21 +185033.9680772478 + 31 +0.0 + 0 +LINE + 5 +36C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532340.0762082474 + 20 +185033.0383432478 + 30 +0.0 + 11 +532571.1852702475 + 21 +185093.2411102478 + 31 +0.0 + 0 +LINE + 5 +36D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532292.1971382474 + 20 +184848.6111342478 + 30 +0.0 + 11 +532351.5203522474 + 21 +185047.0743252478 + 31 +0.0 + 0 +LINE + 5 +36E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532229.8727212474 + 20 +184909.5836812478 + 30 +0.0 + 11 +532315.1596332476 + 21 +184905.4048772478 + 31 +0.0 + 0 +LINE + 5 +36F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532325.041593953 + 20 +185475.0242132333 + 30 +0.0 + 11 +532348.3174009531 + 21 +185387.9591352333 + 31 +0.0 + 0 +LINE + 5 +370 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532458.4917752475 + 20 +185549.4005362478 + 30 +0.0 + 11 +532569.7094042475 + 21 +185090.5118912478 + 31 +0.0 + 0 +LINE + 5 +371 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532152.3691472474 + 20 +185079.7349762478 + 30 +0.0 + 11 +532567.5409532475 + 21 +185166.1502402478 + 31 +0.0 + 0 +LINE + 5 +372 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532505.0021652475 + 20 +184692.3458652478 + 30 +0.0 + 11 +532564.1192532476 + 21 +185172.2285002478 + 31 +0.0 + 0 +LINE + 5 +373 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532493.2797917234 + 20 +184439.2739090913 + 30 +0.0 + 11 +532535.4841562475 + 21 +184977.0343742478 + 31 +0.0 + 0 +LINE + 5 +374 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532413.0449982474 + 20 +184681.5489552478 + 30 +0.0 + 11 +532522.1683822475 + 21 +184724.9265392478 + 31 +0.0 + 0 +LINE + 5 +375 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532420.3088972474 + 20 +184743.2113052478 + 30 +0.0 + 11 +532517.3285312475 + 21 +184691.7060482478 + 31 +0.0 + 0 +LINE + 5 +376 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532429.9143932474 + 20 +184932.9769852478 + 30 +0.0 + 11 +532437.8461422474 + 21 +184731.1247652478 + 31 +0.0 + 0 +LINE + 5 +377 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532009.6784914184 + 20 +184830.2079244615 + 30 +0.0 + 11 +532529.2096642474 + 21 +184878.8524782478 + 31 +0.0 + 0 +LINE + 5 +37C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532372.7184052475 + 20 +184867.0858462478 + 30 +0.0 + 11 +532373.0152272474 + 21 +184842.8027972478 + 31 +0.0 + 0 +LINE + 5 +37D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532504.0457382474 + 20 +185004.5864872478 + 30 +0.0 + 11 +532549.2121822474 + 21 +185000.8275632478 + 31 +0.0 + 0 +LINE + 5 +37E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532491.7523522475 + 20 +185014.0837682478 + 30 +0.0 + 11 +532511.9032812475 + 21 +185000.9275342478 + 31 +0.0 + 0 +LINE + 5 +37F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532485.9230932474 + 20 +185077.9154972478 + 30 +0.0 + 11 +532494.5226922474 + 21 +185006.5859152478 + 31 +0.0 + 0 +LINE + 5 +380 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532302.5529352474 + 20 +184898.1469552478 + 30 +0.0 + 11 +532338.5096462474 + 21 +184465.2908592478 + 31 +0.0 + 0 +LINE + 5 +381 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532317.2044082475 + 20 +184488.8441172478 + 30 +0.0 + 11 +532511.6971542474 + 21 +184540.6792792478 + 31 +0.0 + 0 +LINE + 5 +383 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532213.2094522475 + 20 +184469.8995392478 + 30 +0.0 + 11 +532283.6140292475 + 21 +184859.3980472478 + 31 +0.0 + 0 +LINE + 5 +385 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532308.5965642474 + 20 +184714.1896122478 + 30 +0.0 + 11 +532401.7657552475 + 21 +184708.5912152478 + 31 +0.0 + 0 +LINE + 5 +386 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532366.6747752475 + 20 +184706.5517982478 + 30 +0.0 + 11 +532438.8355502475 + 21 +184748.3298402478 + 31 +0.0 + 0 +LINE + 5 +387 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532364.2342372475 + 20 +184719.4481072478 + 30 +0.0 + 11 +532433.9709632473 + 21 +184679.9394162478 + 31 +0.0 + 0 +LINE + 5 +388 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532419.8636642474 + 20 +184513.3471032478 + 30 +0.0 + 11 +532429.1970732474 + 21 +184691.6260712478 + 31 +0.0 + 0 +LINE + 5 +38B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532265.0461522474 + 20 +185108.3267922478 + 30 +0.0 + 11 +532280.4479262474 + 21 +185063.9095062478 + 31 +0.0 + 0 +LINE + 5 +38C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532217.3154932475 + 20 +185054.6021702478 + 30 +0.0 + 11 +532281.7011752476 + 21 +185065.3390972478 + 31 +0.0 + 0 +LINE + 5 +38D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532186.1409172473 + 20 +185093.1211442478 + 30 +0.0 + 11 +532191.5661672473 + 21 +184988.9409652478 + 31 +0.0 + 0 +LINE + 5 +38E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532041.0195962473 + 20 +185001.1274772478 + 30 +0.0 + 11 +532339.0538202476 + 21 +184982.8427112478 + 31 +0.0 + 0 +LINE + 5 +38F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532407.4136222474 + 20 +185053.8123962478 + 30 +0.0 + 11 +532420.6469452474 + 21 +184986.2517352478 + 31 +0.0 + 0 +LINE + 5 +390 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532389.2250172473 + 20 +184981.0932122478 + 30 +0.0 + 11 +532448.2431642476 + 21 +184992.4699552478 + 31 +0.0 + 0 +LINE + 5 +391 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532393.1908912475 + 20 +184988.7310262478 + 30 +0.0 + 11 +532405.9130212474 + 21 +184918.5411172478 + 31 +0.0 + 0 +LINE + 5 +392 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532402.7056922474 + 20 +184920.4205792478 + 30 +0.0 + 11 +532458.0795222474 + 21 +184929.6579352478 + 31 +0.0 + 0 +LINE + 5 +393 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532441.8532422473 + 20 +184998.8581272478 + 30 +0.0 + 11 +532456.5212062474 + 21 +184922.7599102478 + 31 +0.0 + 0 +LINE + 5 +396 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532481.8907751978 + 20 +185659.2708376926 + 30 +0.0 + 11 +533213.4750461979 + 21 +185960.1946986926 + 31 +0.0 + 0 +LINE + 5 +397 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532608.229846198 + 20 +185714.4250496926 + 30 +0.0 + 11 +532641.5976081978 + 21 +185570.3962776926 + 31 +0.0 + 0 +LINE + 5 +398 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532494.571678198 + 20 +185595.3291406926 + 30 +0.0 + 11 +532951.4964751979 + 21 +185784.2850526926 + 31 +0.0 + 0 +LINE + 5 +399 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532625.5362291979 + 20 +185598.8181416926 + 30 +0.0 + 11 +532683.5732141979 + 21 +185540.9147166926 + 31 +0.0 + 0 +LINE + 5 +39A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532574.6806921979 + 20 +185537.4257156926 + 30 +0.0 + 11 +532637.5657731979 + 21 +185598.7681566926 + 31 +0.0 + 0 +LINE + 5 +39C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532379.7822005875 + 20 +185516.783209897 + 30 +0.0 + 11 +532897.7881471978 + 21 +185508.2540656925 + 31 +0.0 + 0 +LINE + 5 +3A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532630.1287281979 + 20 +185133.8312426926 + 30 +0.0 + 11 +532743.2262311979 + 21 +185136.4304986926 + 31 +0.0 + 0 +LINE + 5 +3A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532738.9965151979 + 20 +185055.0737866926 + 30 +0.0 + 11 +532759.8070491979 + 21 +185810.3475926926 + 31 +0.0 + 0 +LINE + 5 +3A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532822.0242801978 + 20 +185582.5328036926 + 30 +0.0 + 11 +533308.048428696 + 21 +185701.9470633644 + 31 +0.0 + 0 +LINE + 5 +3A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532819.8063591979 + 20 +185651.9929206926 + 30 +0.0 + 11 +532833.1138871978 + 21 +185458.5183026926 + 31 +0.0 + 0 +LINE + 5 +3A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532892.3134261978 + 20 +185655.8818076926 + 30 +0.0 + 11 +532896.1968501978 + 21 +185591.6901826926 + 31 +0.0 + 0 +LINE + 5 +3A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532841.0703711978 + 20 +185674.0865966926 + 30 +0.0 + 11 +532903.0732311979 + 21 +185644.2051496926 + 31 +0.0 + 0 +LINE + 5 +3A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532882.6667051979 + 20 +185645.4847836926 + 30 +0.0 + 11 +533018.964367091 + 21 +185679.8975924009 + 31 +0.0 + 0 +LINE + 5 +3A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532928.4845091979 + 20 +185847.3769926925 + 30 +0.0 + 11 +533171.7912461943 + 21 +185088.6905515849 + 31 +0.0 + 0 +LINE + 5 +3A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533040.9718781979 + 20 +185459.0281566926 + 30 +0.0 + 11 +533342.0861666041 + 21 +185539.2294065369 + 31 +0.0 + 0 +LINE + 5 +3AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533040.8696871645 + 20 +185902.6867872737 + 30 +0.0 + 11 +533064.1454941645 + 21 +185815.6217092737 + 31 +0.0 + 0 +LINE + 5 +3AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532853.2648171979 + 20 +185505.7247896926 + 30 +0.0 + 11 +533314.949234796 + 21 +185601.8213459973 + 31 +0.0 + 0 +LINE + 5 +3B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532896.5843681978 + 20 +185272.3815836926 + 30 +0.0 + 11 +533323.6153840747 + 21 +185304.8422916926 + 31 +0.0 + 0 +LINE + 5 +3B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532501.8603121979 + 20 +185272.5915236926 + 30 +0.0 + 11 +533064.3466261978 + 21 +185283.8483006926 + 31 +0.0 + 0 +LINE + 5 +3B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533003.4486051978 + 20 +185324.1367686926 + 30 +0.0 + 11 +533056.9763947938 + 21 +184798.3148205676 + 31 +0.0 + 0 +LINE + 5 +3BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532730.9905601978 + 20 +185073.2185936926 + 30 +0.0 + 11 +532910.2405847092 + 21 +184975.7707765721 + 31 +0.0 + 0 +LINE + 5 +3BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532887.8337612262 + 20 +184954.2005379262 + 30 +0.0 + 11 +532984.509699198 + 21 +185285.3878606926 + 31 +0.0 + 0 +LINE + 5 +3BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533009.4922341978 + 20 +185140.1794256926 + 30 +0.0 + 11 +533223.8406176101 + 21 +185128.4247817856 + 31 +0.0 + 0 +LINE + 5 +3C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533120.7593341979 + 20 +184991.9777295595 + 30 +0.0 + 11 +533164.6698493871 + 21 +185152.1929908819 + 31 +0.0 + 0 +LINE + 5 +3C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532535.0805407667 + 20 +185099.0554407228 + 30 +0.0 + 11 +532800.0759271978 + 21 +185049.7952976926 + 31 +0.0 + 0 +LINE + 5 +3C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532965.9418221979 + 20 +185534.3166056926 + 30 +0.0 + 11 +532981.3435961978 + 21 +185489.8993196926 + 31 +0.0 + 0 +LINE + 5 +3C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532918.2111631979 + 20 +185480.5919836926 + 30 +0.0 + 11 +532982.596845198 + 21 +185491.3289106925 + 31 +0.0 + 0 +LINE + 5 +3C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532887.0365871978 + 20 +185519.1109576926 + 30 +0.0 + 11 +532892.4618371978 + 21 +185414.9307786926 + 31 +0.0 + 0 +LINE + 5 +3CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532632.1075431978 + 20 +185205.9006136926 + 30 +0.0 + 11 +532744.8092831978 + 21 +185207.6001266926 + 31 +0.0 + 0 +LINE + 5 +3CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532964.0619481979 + 20 +185729.5307256926 + 30 +0.0 + 11 +533287.3999608604 + 21 +185848.0166997513 + 31 +0.0 + 0 +LINE + 5 +3CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533160.4851943644 + 20 +185038.2038243795 + 30 +0.0 + 11 +533312.3771077996 + 21 +184720.5496568575 + 31 +0.0 + 0 +LINE + 5 +3D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532525.9687370664 + 20 +184938.1950755283 + 30 +0.0 + 11 +533310.1590899808 + 21 +185042.7807927709 + 31 +0.0 + 0 +LINE + 5 +3D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532783.2026042486 + 20 +184722.3529153568 + 30 +0.0 + 11 +533016.3547312031 + 21 +184679.6358716281 + 31 +0.0 + 0 +LINE + 5 +3D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532833.4575456594 + 20 +184793.6019525844 + 30 +0.0 + 11 +532842.931078161 + 21 +184708.7398765826 + 31 +0.0 + 0 +LINE + 5 +3DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532637.5467937776 + 20 +184576.4133326699 + 30 +0.0 + 11 +532697.7689800461 + 21 +184475.6025395458 + 31 +0.0 + 0 +LINE + 5 +3DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532699.5784686391 + 20 +184579.0743381345 + 30 +0.0 + 11 +532664.2017968141 + 21 +184475.0835117567 + 31 +0.0 + 0 +LINE + 5 +3E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532790.6590954802 + 20 +184784.0174906387 + 30 +0.0 + 11 +532807.618670413 + 21 +184536.4242881813 + 31 +0.0 + 0 +LINE + 5 +3E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532688.1167109437 + 20 +184815.5033675087 + 30 +0.0 + 11 +532809.5492248077 + 21 +184814.234469069 + 31 +0.0 + 0 +LINE + 5 +3E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532790.4765161498 + 20 +184914.5351786511 + 30 +0.0 + 11 +532680.4657737823 + 21 +184864.6817180896 + 31 +0.0 + 0 +LINE + 5 +3E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532685.2588451061 + 20 +184869.4146964122 + 30 +0.0 + 11 +532689.3739594284 + 21 +184813.7308861308 + 31 +0.0 + 0 +LINE + 5 +3E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532702.8925823753 + 20 +185206.9803013947 + 30 +0.0 + 11 +532702.8948103981 + 21 +185206.968067317 + 31 +0.0 + 0 +LINE + 5 +3E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532729.11626022 + 20 +185062.9860305268 + 30 +0.0 + 11 +532803.6929663337 + 21 +184653.4851785078 + 31 +0.0 + 0 +LINE + 5 +3EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532833.7558926337 + 20 +184720.028022434 + 30 +0.0 + 11 +532491.6707096186 + 21 +184640.2317074956 + 31 +0.0 + 0 +LINE + 5 +3EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532499.9754730116 + 20 +184739.9450397345 + 30 +0.0 + 11 +532792.482947854 + 21 +184732.5461716932 + 31 +0.0 + 0 +LINE + 5 +3ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532769.2121150372 + 20 +184858.9438041617 + 30 +0.0 + 11 +532734.3196016032 + 21 +184852.2725047208 + 31 +0.0 + 0 +LINE + 5 +3EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532653.1157034118 + 20 +184684.7299837778 + 30 +0.0 + 11 +532662.4446227496 + 21 +184591.8601207191 + 31 +0.0 + 0 +LINE + 5 +3EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532654.8360919118 + 20 +184626.1769731031 + 30 +0.0 + 11 +532707.5855661702 + 21 +184561.6008536206 + 31 +0.0 + 0 +LINE + 5 +3F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532667.1782684115 + 20 +184630.6425851331 + 30 +0.0 + 11 +532639.2944614704 + 21 +184555.4984507766 + 31 +0.0 + 0 +LINE + 5 +3F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532472.5841021194 + 20 +184542.862362741 + 30 +0.0 + 11 +532650.0704104144 + 21 +184562.0746848949 + 31 +0.0 + 0 +LINE + 5 +3F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532893.7177966846 + 20 +184994.6354611215 + 30 +0.0 + 11 +532923.1880844782 + 21 +184697.4987358915 + 31 +0.0 + 0 +LINE + 5 +3FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531861.8278255367 + 20 +185191.7735766143 + 30 +0.0 + 11 +531538.5384386285 + 21 +185607.8478836246 + 31 +0.0 + 0 +LINE + 5 +3FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531733.7040754842 + 20 +185347.6380927605 + 30 +0.0 + 11 +532464.1482035561 + 21 +185651.3189967688 + 31 +0.0 + 0 +LINE + 5 +3FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531862.0971573802 + 20 +185397.8253868076 + 30 +0.0 + 11 +531783.9926877962 + 21 +185523.3538160008 + 31 +0.0 + 0 +LINE + 5 +3FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531697.5197138976 + 20 +185401.8602090297 + 30 +0.0 + 11 +532154.4445108975 + 21 +185590.8161210297 + 31 +0.0 + 0 +LINE + 5 +400 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531792.6965981642 + 20 +185491.8893567981 + 30 +0.0 + 11 +531792.885563927 + 21 +185573.87144354 + 31 +0.0 + 0 +LINE + 5 +401 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531713.3339456926 + 20 +185499.4315717521 + 30 +0.0 + 11 +531801.1772682144 + 21 +185500.4211012181 + 31 +0.0 + 0 +LINE + 5 +402 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531730.3606550528 + 20 +185490.9574299569 + 30 +0.0 + 11 +531610.7000381212 + 21 +185649.8145655847 + 31 +0.0 + 0 +LINE + 5 +403 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531620.0352627024 + 20 +185437.4863894554 + 30 +0.0 + 11 +531921.4650168662 + 21 +185748.2907083182 + 31 +0.0 + 0 +LINE + 5 +404 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531650.9979007346 + 20 +185688.8051328634 + 30 +0.0 + 11 +531795.0736114228 + 21 +185570.1374104197 + 31 +0.0 + 0 +LINE + 5 +405 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531609.7161111208 + 20 +185644.4268986138 + 30 +0.0 + 11 +531651.8451968421 + 21 +185688.8314120956 + 31 +0.0 + 0 +LINE + 5 +406 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531419.6038351391 + 20 +185873.1395474812 + 30 +0.0 + 11 +531638.8567267734 + 21 +185672.4553785438 + 31 +0.0 + 0 +LINE + 5 +407 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531467.5316540079 + 20 +185824.3072660336 + 30 +0.0 + 11 +531549.4316502019 + 21 +185902.346947863 + 31 +0.0 + 0 +LINE + 5 +408 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531488.9758274058 + 20 +185956.9537109508 + 30 +0.0 + 11 +532119.1862890298 + 21 +185356.9691234335 + 31 +0.0 + 0 +LINE + 5 +409 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531920.2925450763 + 20 +185642.1958461826 + 30 +0.0 + 11 +532283.0697733463 + 21 +185889.7366514033 + 31 +0.0 + 0 +LINE + 5 +40A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531967.7814881132 + 20 +185591.4570314894 + 30 +0.0 + 11 +531840.5527883868 + 21 +185737.8208797502 + 31 +0.0 + 0 +LINE + 5 +40B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532021.8574928066 + 20 +185639.9150950438 + 30 +0.0 + 11 +531979.268683928 + 21 +185688.1005602838 + 31 +0.0 + 0 +LINE + 5 +40C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531998.4393065221 + 20 +185590.8350219038 + 30 +0.0 + 11 +532021.2274724078 + 21 +185655.7808071295 + 31 +0.0 + 0 +LINE + 5 +40D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532007.6850459294 + 20 +185640.4619804239 + 30 +0.0 + 11 +532354.1763415755 + 21 +185846.7163859356 + 31 +0.0 + 0 +LINE + 5 +40E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532182.715114118 + 20 +185529.8988290208 + 30 +0.0 + 11 +531998.1198935781 + 21 +185892.9915152565 + 31 +0.0 + 0 +LINE + 5 +40F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531988.0600547571 + 20 +185884.2681765558 + 30 +0.0 + 11 +532194.1878251483 + 21 +186004.8795937868 + 31 +0.0 + 0 +LINE + 5 +410 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531823.9061445957 + 20 +185981.011623581 + 30 +0.0 + 11 +532006.0750995708 + 21 +185882.4146979472 + 31 +0.0 + 0 +LINE + 5 +411 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531822.8497064442 + 20 +185893.8286643487 + 30 +0.0 + 11 +531880.2747016837 + 21 +185957.0243104261 + 31 +0.0 + 0 +LINE + 5 +412 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532356.2144154167 + 20 +185600.3187829731 + 30 +0.0 + 11 +532311.1985787343 + 21 +185678.3935256651 + 31 +0.0 + 0 +LINE + 5 +413 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532436.5909745613 + 20 +185602.3600801 + 30 +0.0 + 11 +532191.2154048476 + 21 +186005.769275952 + 31 +0.0 + 0 +LINE + 5 +414 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531888.1595850235 + 20 +185718.6348090544 + 30 +0.0 + 11 +532243.1029985761 + 21 +185950.691697608 + 31 +0.0 + 0 +LINE + 5 +415 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531983.707795175 + 20 +186179.1651187459 + 30 +0.0 + 11 +532196.6318225811 + 21 +185988.747421823 + 31 +0.0 + 0 +LINE + 5 +416 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531651.9676286941 + 20 +186274.3789995667 + 30 +0.0 + 11 +531834.7205437863 + 21 +186117.8592350517 + 31 +0.0 + 0 +LINE + 5 +417 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531474.7328130902 + 20 +185635.481035244 + 30 +0.0 + 11 +531880.879583697 + 21 +186024.7911548033 + 31 +0.0 + 0 +LINE + 5 +419 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532084.0423358651 + 20 +186020.2200672802 + 30 +0.0 + 11 +532125.4763841526 + 21 +186066.8963861565 + 31 +0.0 + 0 +LINE + 5 +41A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532082.0474267376 + 20 +186004.8140287462 + 30 +0.0 + 11 +532087.0205745952 + 21 +186028.360031231 + 31 +0.0 + 0 +LINE + 5 +41B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532123.0045456797 + 20 +185955.5090158614 + 30 +0.0 + 11 +532078.7129439776 + 21 +186012.0785870981 + 31 +0.0 + 0 +LINE + 5 +41C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531418.7788685433 + 20 +186104.3451573058 + 30 +0.0 + 11 +531495.3612063181 + 21 +186318.6540757437 + 31 +0.0 + 0 +LINE + 5 +41D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531496.1237532815 + 20 +185938.45407603 + 30 +0.0 + 11 +531405.175342562 + 21 +186133.5223115784 + 31 +0.0 + 0 +LINE + 5 +41F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531988.1202134396 + 20 +185777.976802319 + 30 +0.0 + 11 +531967.6519314506 + 21 +185820.2988931271 + 31 +0.0 + 0 +LINE + 5 +420 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531916.3854307389 + 20 +185782.2978865 + 30 +0.0 + 11 +531969.5488407774 + 21 +185820.1720133031 + 31 +0.0 + 0 +LINE + 5 +421 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531921.5218807102 + 20 +185733.0111496584 + 30 +0.0 + 11 +531851.7810069742 + 21 +185810.5943537981 + 31 +0.0 + 0 +LINE + 5 +422 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531753.8130619647 + 20 +185695.637566851 + 30 +0.0 + 11 +531951.8835598481 + 21 +185919.0806450864 + 31 +0.0 + 0 +LINE + 5 +423 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532050.4021916367 + 20 +185917.1215869044 + 30 +0.0 + 11 +532012.0528583068 + 21 +185974.2958152379 + 31 +0.0 + 0 +LINE + 5 +424 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531986.1651783409 + 20 +185955.7546193549 + 30 +0.0 + 11 +532035.9806907252 + 21 +185989.3847647976 + 31 +0.0 + 0 +LINE + 5 +425 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531994.3672256759 + 20 +185953.1487070773 + 30 +0.0 + 11 +531953.7989935165 + 21 +186011.8231858276 + 31 +0.0 + 0 +LINE + 5 +426 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531952.8559031887 + 20 +186008.2273663998 + 30 +0.0 + 11 +531998.5804950235 + 21 +186040.7980817171 + 31 +0.0 + 0 +LINE + 5 +427 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532035.9690354825 + 20 +185980.3492953121 + 30 +0.0 + 11 +531992.6053163253 + 21 +186044.5807179909 + 31 +0.0 + 0 +LINE + 5 +428 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532589.7485624646 + 20 +185685.3582884609 + 30 +0.0 + 11 +532589.9375282275 + 21 +185767.3403752028 + 31 +0.0 + 0 +LINE + 5 +429 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532510.3859099931 + 20 +185692.900503415 + 30 +0.0 + 11 +532598.2292325149 + 21 +185693.8900328809 + 31 +0.0 + 0 +LINE + 5 +42A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532526.4656307082 + 20 +185685.9832563354 + 30 +0.0 + 11 +532406.8050137765 + 21 +185844.8403919632 + 31 +0.0 + 0 +LINE + 5 +42B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532357.8334418678 + 20 +185569.8587237367 + 30 +0.0 + 11 +532718.5169811667 + 21 +185941.7596399811 + 31 +0.0 + 0 +LINE + 5 +42C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532448.049865035 + 20 +185882.2740645263 + 30 +0.0 + 11 +532592.1255757233 + 21 +185763.6063420826 + 31 +0.0 + 0 +LINE + 5 +42D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532406.7680754211 + 20 +185837.8958302767 + 30 +0.0 + 11 +532448.8971611424 + 21 +185882.3003437585 + 31 +0.0 + 0 +LINE + 5 +42E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532216.6557994395 + 20 +186066.608479144 + 30 +0.0 + 11 +532435.9086910738 + 21 +185865.9243102067 + 31 +0.0 + 0 +LINE + 5 +42F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532360.5330683786 + 20 +186075.9173659413 + 30 +0.0 + 11 +532834.2031285817 + 21 +185630.4462966165 + 31 +0.0 + 0 +LINE + 5 +430 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532717.3445093768 + 20 +185835.6647778455 + 30 +0.0 + 11 +532936.5865712611 + 21 +185985.2644558515 + 31 +0.0 + 0 +LINE + 5 +431 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532764.8334524136 + 20 +185784.9259631524 + 30 +0.0 + 11 +532637.6047526871 + 21 +185931.289811413 + 31 +0.0 + 0 +LINE + 5 +432 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532818.909457107 + 20 +185833.3840267067 + 30 +0.0 + 11 +532776.3206482284 + 21 +185881.5694919468 + 31 +0.0 + 0 +LINE + 5 +433 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532795.4912708226 + 20 +185784.3039535667 + 30 +0.0 + 11 +532818.2794367084 + 21 +185849.2497387923 + 31 +0.0 + 0 +LINE + 5 +434 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532804.7370102297 + 20 +185833.9309120868 + 30 +0.0 + 11 +533151.2283058758 + 21 +186040.1853175985 + 31 +0.0 + 0 +LINE + 5 +435 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532929.8009410545 + 20 +185821.4028240506 + 30 +0.0 + 11 +532795.1718578784 + 21 +186086.4604469193 + 31 +0.0 + 0 +LINE + 5 +436 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532785.1120190575 + 20 +186077.7371082186 + 30 +0.0 + 11 +532991.2397894489 + 21 +186198.3485254497 + 31 +0.0 + 0 +LINE + 5 +437 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532620.9581088962 + 20 +186174.4805552439 + 30 +0.0 + 11 +532803.1270638713 + 21 +186075.88362961 + 31 +0.0 + 0 +LINE + 5 +438 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532487.8955622168 + 20 +185923.2211543541 + 30 +0.0 + 11 +532677.3266659841 + 21 +186150.4932420889 + 31 +0.0 + 0 +LINE + 5 +439 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532685.2115493238 + 20 +185912.1037407173 + 30 +0.0 + 11 +533069.5807117685 + 21 +186166.970324897 + 31 +0.0 + 0 +LINE + 5 +43A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532596.3237212511 + 20 +186341.3319926437 + 30 +0.0 + 11 +532783.9267616241 + 21 +186029.3305871086 + 31 +0.0 + 0 +LINE + 5 +43B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532563.3363404315 + 20 +186239.6670789878 + 30 +0.0 + 11 +532671.2243390242 + 21 +186286.0320171303 + 31 +0.0 + 0 +LINE + 5 +43C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532612.0301757858 + 20 +186201.1453963313 + 30 +0.0 + 11 +532644.3347693412 + 21 +186306.1311768702 + 31 +0.0 + 0 +LINE + 5 +43D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532271.7847773906 + 20 +185828.9499669069 + 30 +0.0 + 11 +532505.4397367133 + 21 +186045.7682751822 + 31 +0.0 + 0 +LINE + 5 +43E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532456.1709398957 + 20 +185958.2385074901 + 30 +0.0 + 11 +532414.07966705 + 21 +186283.737681027 + 31 +0.0 + 0 +LINE + 5 +43F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532406.7909252194 + 20 +186170.6980676144 + 30 +0.0 + 11 +532571.9985347014 + 21 +186193.8794666497 + 31 +0.0 + 0 +LINE + 5 +440 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532548.1691416875 + 20 +186189.2161541062 + 30 +0.0 + 11 +532628.7607689065 + 21 +186210.607083589 + 31 +0.0 + 0 +LINE + 5 +441 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532555.5499794265 + 20 +186178.3628483507 + 30 +0.0 + 11 +532577.0134800563 + 21 +186255.5863276716 + 31 +0.0 + 0 +LINE + 5 +442 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532486.5436966105 + 20 +186326.2911970296 + 30 +0.0 + 11 +532581.8881197563 + 21 +186243.9413365331 + 31 +0.0 + 0 +LINE + 5 +443 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532172.7351168023 + 20 +185975.263057285 + 30 +0.0 + 11 +532257.3461442857 + 21 +186098.2095402245 + 31 +0.0 + 0 +LINE + 5 +444 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532785.17217774 + 20 +185971.4457339819 + 30 +0.0 + 11 +532764.7038957511 + 21 +186013.76782479 + 31 +0.0 + 0 +LINE + 5 +445 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532713.4373950393 + 20 +185975.7668181629 + 30 +0.0 + 11 +532766.6008050778 + 21 +186013.640944966 + 31 +0.0 + 0 +LINE + 5 +446 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532718.5738450106 + 20 +185926.4800813213 + 30 +0.0 + 11 +532648.8329712746 + 21 +186004.063285461 + 31 +0.0 + 0 +LINE + 5 +447 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532550.8650262651 + 20 +185889.1064985139 + 30 +0.0 + 11 +532748.9355241485 + 21 +186112.5495767493 + 31 +0.0 + 0 +LINE + 5 +448 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532847.4541559371 + 20 +186110.5905185672 + 30 +0.0 + 11 +532809.1048226073 + 21 +186167.7647469007 + 31 +0.0 + 0 +LINE + 5 +449 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532783.2171426415 + 20 +186149.2235510178 + 30 +0.0 + 11 +532833.0326550258 + 21 +186182.8536964605 + 31 +0.0 + 0 +LINE + 5 +44A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532316.8864140805 + 20 +185968.1543527131 + 30 +0.0 + 11 +532397.8707606938 + 21 +186046.5514581896 + 31 +0.0 + 0 +LINE + 5 +44B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532611.7161158065 + 20 +186297.5090828903 + 30 +0.0 + 11 +532484.7066932243 + 21 +186858.233084708 + 31 +0.0 + 0 +LINE + 5 +44C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532547.3155668865 + 20 +186321.6247646187 + 30 +0.0 + 11 +532495.053707063 + 21 +186542.8445710875 + 31 +0.0 + 0 +LINE + 5 +44D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532403.9294344441 + 20 +186201.8155025754 + 30 +0.0 + 11 +532302.4455707475 + 21 +186337.9548541522 + 31 +0.0 + 0 +LINE + 5 +44E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532279.8671234338 + 20 +186136.1577846746 + 30 +0.0 + 11 +533301.9646360159 + 21 +186916.6816373291 + 31 +0.0 + 0 +LINE + 5 +44F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532406.9961318524 + 20 +186319.8807114539 + 30 +0.0 + 11 +532220.4666046975 + 21 +186717.4866760719 + 31 +0.0 + 0 +LINE + 5 +450 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532464.6578491668 + 20 +186358.671862295 + 30 +0.0 + 11 +532299.8801138759 + 21 +186256.40839832 + 31 +0.0 + 0 +LINE + 5 +451 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532425.4420865872 + 20 +186419.7825992595 + 30 +0.0 + 11 +532371.082371042 + 21 +186385.4217635892 + 31 +0.0 + 0 +LINE + 5 +452 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532470.1602454009 + 20 +186388.8382734374 + 30 +0.0 + 11 +532409.6789007655 + 21 +186421.6904038722 + 31 +0.0 + 0 +LINE + 5 +453 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532422.6424219159 + 20 +186405.8786713312 + 30 +0.0 + 11 +532274.2743179815 + 21 +186780.8240053286 + 31 +0.0 + 0 +LINE + 5 +454 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532559.6993444154 + 20 +186561.0403135408 + 30 +0.0 + 11 +532171.8185395161 + 21 +186436.7013597309 + 31 +0.0 + 0 +LINE + 5 +455 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532178.8262472758 + 20 +186425.3793004152 + 30 +0.0 + 11 +532092.6246762097 + 21 +186648.1012365569 + 31 +0.0 + 0 +LINE + 5 +456 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532057.1464107401 + 20 +186278.7511375533 + 30 +0.0 + 11 +532183.5284855804 + 21 +186442.8683306205 + 31 +0.0 + 0 +LINE + 5 +457 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532143.045524667 + 20 +186263.8070193578 + 30 +0.0 + 11 +532089.8147203099 + 21 +186330.5737867565 + 31 +0.0 + 0 +LINE + 5 +458 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532517.844537266 + 20 +186743.5482656535 + 30 +0.0 + 11 +532433.5909544371 + 21 +186711.5572547416 + 31 +0.0 + 0 +LINE + 5 +459 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532528.6452812824 + 20 +186823.2219883138 + 30 +0.0 + 11 +532091.2724283363 + 21 +186645.3087032108 + 31 +0.0 + 0 +LINE + 5 +45A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532326.4115569843 + 20 +186300.3469340414 + 30 +0.0 + 11 +532153.9187586503 + 21 +186687.7504199219 + 31 +0.0 + 0 +LINE + 5 +45B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531805.9814634882 + 20 +186360.1205610736 + 30 +0.0 + 11 +532160.8507210284 + 21 +186688.5257734576 + 31 +0.0 + 0 +LINE + 5 +45C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531638.584156153 + 20 +186248.3972793169 + 30 +0.0 + 11 +532019.1879770698 + 21 +186551.2217947124 + 31 +0.0 + 0 +LINE + 5 +45D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531850.9576992834 + 20 +186279.1895284476 + 30 +0.0 + 11 +531822.388527218 + 21 +186393.0900558247 + 31 +0.0 + 0 +LINE + 5 +45E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531896.7507059305 + 20 +186321.1181604121 + 30 +0.0 + 11 +531798.2590085679 + 21 +186369.7492865638 + 31 +0.0 + 0 +LINE + 5 +45F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532045.128842458 + 20 +186439.807702748 + 30 +0.0 + 11 +531876.6943226217 + 21 +186328.2862075614 + 31 +0.0 + 0 +LINE + 5 +460 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532093.9829120121 + 20 +186228.3962886964 + 30 +0.0 + 11 +531943.1818398332 + 21 +186488.7548350109 + 31 +0.0 + 0 +LINE + 5 +461 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532011.4998620817 + 20 +186166.3447629878 + 30 +0.0 + 11 +531995.1789584217 + 21 +186015.2308868018 + 31 +0.0 + 0 +LINE + 5 +462 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532367.7592458358 + 20 +186017.384856327 + 30 +0.0 + 11 +532367.7521822822 + 21 +186017.3950907273 + 31 +0.0 + 0 +LINE + 5 +463 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532159.4363386244 + 20 +186124.1371738739 + 30 +0.0 + 11 +532023.0113161725 + 21 +186341.976254682 + 31 +0.0 + 0 +LINE + 5 +464 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532025.08345726 + 20 +186354.8888840192 + 30 +0.0 + 11 +532005.2047513148 + 21 +186340.9392739177 + 31 +0.0 + 0 +LINE + 5 +465 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532059.9179272102 + 20 +186541.8109382867 + 30 +0.0 + 11 +532030.473360213 + 21 +186576.266048903 + 31 +0.0 + 0 +LINE + 5 +466 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532074.8087792434 + 20 +186537.3850811423 + 30 +0.0 + 11 +532052.356979825 + 21 +186546.0489795433 + 31 +0.0 + 0 +LINE + 5 +467 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532130.0135486268 + 20 +186569.9565920827 + 30 +0.0 + 11 +532067.1054834822 + 21 +186535.2515821992 + 31 +0.0 + 0 +LINE + 5 +468 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532091.2921244136 + 20 +186316.102313323 + 30 +0.0 + 11 +531792.7632140843 + 21 +186130.9801536181 + 31 +0.0 + 0 +LINE + 5 +469 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531936.6804172387 + 20 +186133.8679621811 + 30 +0.0 + 11 +532070.9155718749 + 21 +186278.0897346377 + 31 +0.0 + 0 +LINE + 5 +46A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532468.8458028386 + 20 +186177.5755427393 + 30 +0.0 + 11 +531769.5162369404 + 21 +186138.5166020882 + 31 +0.0 + 0 +LINE + 5 +46B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531938.4823451721 + 20 +186213.5060128864 + 30 +0.0 + 11 +531879.4933379066 + 21 +186285.8395267122 + 31 +0.0 + 0 +LINE + 5 +46C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531898.3447794365 + 20 +186256.1720487052 + 30 +0.0 + 11 +531890.077737924 + 21 +186339.1433586055 + 31 +0.0 + 0 +LINE + 5 +46D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531910.2360944391 + 20 +186261.7279139901 + 30 +0.0 + 11 +531837.4229176238 + 21 +186295.2299870572 + 31 +0.0 + 0 +LINE + 5 +46E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531710.4802981255 + 20 +186186.4293161462 + 30 +0.0 + 11 +531849.6961797504 + 21 +186298.185484916 + 31 +0.0 + 0 +LINE + 5 +46F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532283.7673474868 + 20 +186408.4906846435 + 30 +0.0 + 11 +532238.7230775654 + 21 +186395.0324646574 + 31 +0.0 + 0 +LINE + 5 +470 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532268.0635396029 + 20 +186338.3626500527 + 30 +0.0 + 11 +532239.1507935487 + 21 +186396.88487458 + 31 +0.0 + 0 +LINE + 5 +471 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532327.6932205972 + 20 +186164.0523312674 + 30 +0.0 + 11 +532138.6908716636 + 21 +186395.2164362678 + 31 +0.0 + 0 +LINE + 5 +472 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532156.333518464 + 20 +186492.1622754376 + 30 +0.0 + 11 +532006.4397393707 + 21 +186419.1755808819 + 31 +0.0 + 0 +LINE + 5 +473 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532443.2785890483 + 20 +186521.0440070698 + 30 +0.0 + 11 +532359.9775658928 + 21 +186772.1907556058 + 31 +0.0 + 0 +LINE + 5 +474 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531690.8699317568 + 20 +185858.9173803943 + 30 +0.0 + 11 +531813.4096672386 + 21 +185746.4218472305 + 31 +0.0 + 0 +LINE + 5 +475 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531602.6576685688 + 20 +185904.8884095925 + 30 +0.0 + 11 +531532.6487409198 + 21 +185734.1550506949 + 31 +0.0 + 0 +LINE + 5 +476 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532274.1029641282 + 20 +186355.1102229073 + 30 +0.0 + 11 +532171.4693846109 + 21 +186298.5722535568 + 31 +0.0 + 0 +LINE + 5 +477 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532180.8622533723 + 20 +185533.5433447531 + 30 +0.0 + 11 +532356.6872845859 + 21 +185442.1663750327 + 31 +0.0 + 0 +LINE + 5 +478 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534574.6571852977 + 20 +184195.4021252921 + 30 +0.0 + 11 +535121.1408465514 + 21 +184069.916780534 + 31 +0.0 + 0 +LINE + 5 +479 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534591.6805218133 + 20 +184183.5721895806 + 30 +0.0 + 11 +534563.5622932388 + 21 +184974.1290065872 + 31 +0.0 + 0 +LINE + 5 +47A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534583.8361464561 + 20 +184321.2021780923 + 30 +0.0 + 11 +534730.4884537673 + 21 +184302.4726435274 + 31 +0.0 + 0 +LINE + 5 +47C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534698.2576499472 + 20 +184297.2817347705 + 30 +0.0 + 11 +534772.7128564283 + 21 +184331.596753093 + 31 +0.0 + 0 +LINE + 5 +47D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534738.1669447289 + 20 +184228.2704037896 + 30 +0.0 + 11 +534702.4823148565 + 21 +184308.5451549328 + 31 +0.0 + 0 +LINE + 5 +47E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534723.3715470947 + 20 +184240.2209736357 + 30 +0.0 + 11 +534917.6315636337 + 21 +184197.5911864141 + 31 +0.0 + 0 +LINE + 5 +47F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534720.7058270503 + 20 +184117.6496135786 + 30 +0.0 + 11 +534877.7361941457 + 21 +184521.135282629 + 31 +0.0 + 0 +LINE + 5 +480 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534936.296866142 + 20 +184250.4664032003 + 30 +0.0 + 11 +534768.4068052764 + 21 +184332.030894389 + 31 +0.0 + 0 +LINE + 5 +481 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534913.1431511226 + 20 +184194.4528395784 + 30 +0.0 + 11 +534935.9678830072 + 21 +184251.2476658892 + 31 +0.0 + 0 +LINE + 5 +482 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535200.2533381722 + 20 +184116.8648654899 + 30 +0.0 + 11 +534926.4889642517 + 21 +184232.6190607658 + 31 +0.0 + 0 +LINE + 5 +483 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535135.8969533211 + 20 +184140.101114365 + 30 +0.0 + 11 +535172.7375945441 + 21 +184247.0617074395 + 31 +0.0 + 0 +LINE + 5 +484 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535247.5614010104 + 20 +184214.8405486959 + 30 +0.0 + 11 +534562.2605079586 + 21 +184461.1649807091 + 31 +0.0 + 0 +LINE + 5 +485 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534781.7684923542 + 20 +184475.8838221603 + 30 +0.0 + 11 +534855.7334321526 + 21 +184908.796001801 + 31 +0.0 + 0 +LINE + 5 +486 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534715.8615647035 + 20 +184497.9270504825 + 30 +0.0 + 11 +534901.9152180392 + 21 +184443.2136500017 + 31 +0.0 + 0 +LINE + 5 +487 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534737.396022412 + 20 +184567.2715912787 + 30 +0.0 + 11 +534798.940808514 + 21 +184548.6199155959 + 31 +0.0 + 0 +LINE + 5 +488 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534702.5279512712 + 20 +184525.5405160086 + 30 +0.0 + 11 +534752.0826991785 + 21 +184573.3064294077 + 31 +0.0 + 0 +LINE + 5 +489 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534743.7956458011 + 20 +184554.6144922988 + 30 +0.0 + 11 +534787.0077403957 + 21 +184955.5257201689 + 31 +0.0 + 0 +LINE + 5 +48A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534570.3822305559 + 20 +184667.6964211436 + 30 +0.0 + 11 +534977.3661527182 + 21 +184651.0897554535 + 31 +0.0 + 0 +LINE + 5 +48B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534973.6249792506 + 20 +184638.3108424999 + 30 +0.0 + 11 +534997.4323029246 + 21 +184875.9428753415 + 31 +0.0 + 0 +LINE + 5 +48C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535129.9446164009 + 20 +184529.3614422962 + 30 +0.0 + 11 +534964.4371350048 + 21 +184653.9172751708 + 31 +0.0 + 0 +LINE + 5 +48D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535051.122321311 + 20 +184492.0917463117 + 30 +0.0 + 11 +535084.6606727746 + 21 +184570.6188037027 + 31 +0.0 + 0 +LINE + 5 +48E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534553.9285474718 + 20 +184777.7111798236 + 30 +0.0 + 11 +534643.6579189425 + 21 +184769.3010137052 + 31 +0.0 + 0 +LINE + 5 +48F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534530.5281655633 + 20 +184928.6853843727 + 30 +0.0 + 11 +534999.4790852679 + 21 +184873.6110308273 + 31 +0.0 + 0 +LINE + 5 +490 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534864.6453430343 + 20 +184478.5048502061 + 30 +0.0 + 11 +534927.7956627994 + 21 +184897.846314246 + 31 +0.0 + 0 +LINE + 5 +491 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535350.3893007875 + 20 +184674.6506536572 + 30 +0.0 + 11 +534920.9074000498 + 21 +184896.7485383992 + 31 +0.0 + 0 +LINE + 5 +492 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535583.6379881881 + 20 +184575.7674960427 + 30 +0.0 + 11 +535094.0071012423 + 21 +184802.1060054018 + 31 +0.0 + 0 +LINE + 5 +493 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535328.5779771762 + 20 +184584.6675441836 + 30 +0.0 + 11 +535325.7982992511 + 21 +184702.0634602962 + 31 +0.0 + 0 +LINE + 5 +494 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535273.2764353342 + 20 +184612.8942887018 + 30 +0.0 + 11 +535355.2701688879 + 21 +184685.9875752475 + 31 +0.0 + 0 +LINE + 5 +495 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535098.6584225843 + 20 +184687.8064271212 + 30 +0.0 + 11 +535290.7012472688 + 21 +184625.1423636691 + 31 +0.0 + 0 +LINE + 5 +496 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535098.5090148775 + 20 +184438.0892804688 + 30 +0.0 + 11 +535183.8986896964 + 21 +184762.1240560096 + 31 +0.0 + 0 +LINE + 5 +497 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535006.8823547946 + 20 +184457.0934690072 + 30 +0.0 + 11 +535127.0631374186 + 21 +184439.6565824029 + 31 +0.0 + 0 +LINE + 5 +498 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535092.7796099318 + 20 +184343.4867310913 + 30 +0.0 + 11 +534991.7531499059 + 21 +184409.6787649087 + 31 +0.0 + 0 +LINE + 5 +499 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534995.7606139729 + 20 +184404.26444609 + 30 +0.0 + 11 +535008.3974384137 + 21 +184458.6513154741 + 31 +0.0 + 0 +LINE + 5 +49A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534961.226757078 + 20 +184068.0072542187 + 30 +0.0 + 11 +535146.0188931681 + 21 +184599.3917053508 + 31 +0.0 + 0 +LINE + 5 +49B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535140.5844114282 + 20 +184611.286921755 + 30 +0.0 + 11 +535163.459076143 + 21 +184603.1319057388 + 31 +0.0 + 0 +LINE + 5 +49C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535057.2515549811 + 20 +184782.193123236 + 30 +0.0 + 11 +535076.4625545096 + 21 +184823.2427842622 + 31 +0.0 + 0 +LINE + 5 +49D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535044.0759987184 + 20 +184773.9632749442 + 30 +0.0 + 11 +535063.411640211 + 21 +184788.2908497806 + 31 +0.0 + 0 +LINE + 5 +49E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534982.1929300688 + 20 +184790.6652419575 + 30 +0.0 + 11 +535052.0692800617 + 21 +184773.9572174507 + 31 +0.0 + 0 +LINE + 5 +49F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535087.0886008305 + 20 +184556.2761598885 + 30 +0.0 + 11 +535505.4896536701 + 21 +184439.6663665903 + 31 +0.0 + 0 +LINE + 5 +4A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535476.0032534414 + 20 +184427.86715771 + 30 +0.0 + 11 +535494.9407156182 + 21 +184628.2559917115 + 31 +0.0 + 0 +LINE + 5 +4A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535227.7655735143 + 20 +184213.6345013193 + 30 +0.0 + 11 +535495.623878412 + 21 +184458.2494913671 + 31 +0.0 + 0 +LINE + 5 +4A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535457.6518015389 + 20 +184323.7658987257 + 30 +0.0 + 11 +535116.8482574903 + 21 +184525.0588110716 + 31 +0.0 + 0 +LINE + 5 +4A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535074.8677798265 + 20 +184403.5864576378 + 30 +0.0 + 11 +535108.5224187205 + 21 +184392.2128473538 + 31 +0.0 + 0 +LINE + 5 +4A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535261.6946601973 + 20 +184498.0562876151 + 30 +0.0 + 11 +535299.3017138007 + 21 +184583.481984685 + 31 +0.0 + 0 +LINE + 5 +4A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535289.0272950536 + 20 +184549.86692231 + 30 +0.0 + 11 +535274.9106969223 + 21 +184632.0454103658 + 31 +0.0 + 0 +LINE + 5 +4A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535276.0861163686 + 20 +184552.0571062738 + 30 +0.0 + 11 +535337.3547991832 + 21 +184603.7320143421 + 31 +0.0 + 0 +LINE + 5 +4A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535488.6783927928 + 20 +184532.6462587168 + 30 +0.0 + 11 +535324.7376213809 + 21 +184603.3139771145 + 31 +0.0 + 0 +LINE + 5 +4A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535258.9681390138 + 20 +183992.1531128462 + 30 +0.0 + 11 +535103.3700778348 + 21 +184075.7331806402 + 31 +0.0 + 0 +LINE + 5 +4A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535153.1660462351 + 20 +184036.1810629035 + 30 +0.0 + 11 +535273.7238639583 + 21 +184270.2849582326 + 31 +0.0 + 0 +LINE + 5 +4AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534876.9652630151 + 20 +184594.0981846576 + 30 +0.0 + 11 +534923.966796239 + 21 +184593.1154270327 + 31 +0.0 + 0 +LINE + 5 +4AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534910.7692790155 + 20 +184530.6802114966 + 30 +0.0 + 11 +534923.0614345329 + 21 +184594.787157772 + 31 +0.0 + 0 +LINE + 5 +4AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534863.8211214823 + 20 +184514.823476302 + 30 +0.0 + 11 +534963.400889941 + 21 +184483.7298636502 + 31 +0.0 + 0 +LINE + 5 +4AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534899.6889578032 + 20 +184346.7861861114 + 30 +0.0 + 11 +535020.3411757364 + 21 +184619.9194386656 + 31 +0.0 + 0 +LINE + 5 +4AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534977.5298769468 + 20 +184708.6716297057 + 30 +0.0 + 11 +535045.4811634307 + 21 +184697.6178331832 + 31 +0.0 + 0 +LINE + 5 +4AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535039.4059462963 + 20 +184666.3601996268 + 30 +0.0 + 11 +535049.2339964726 + 21 +184725.6559109923 + 31 +0.0 + 0 +LINE + 5 +4B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535033.6208638784 + 20 +184672.7317913196 + 30 +0.0 + 11 +535103.8602096413 + 21 +184660.2854977361 + 31 +0.0 + 0 +LINE + 5 +4B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535100.9838456271 + 20 +184657.9305313283 + 30 +0.0 + 11 +535111.5524690118 + 21 +184713.0657650223 + 31 +0.0 + 0 +LINE + 5 +4B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535041.0242654582 + 20 +184721.8822971619 + 30 +0.0 + 11 +535117.4799406871 + 21 +184709.2088002577 + 31 +0.0 + 0 +LINE + 5 +4B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535069.0006836904 + 20 +184166.9860368055 + 30 +0.0 + 11 +535106.5476183001 + 21 +184273.2630251185 + 31 +0.0 + 0 +LINE + 5 +4B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534693.2491391094 + 20 +184660.1320577132 + 30 +0.0 + 11 +534706.6944115045 + 21 +184924.3913516068 + 31 +0.0 + 0 +LINE + 5 +4B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534453.6923026645 + 20 +184480.7570328502 + 30 +0.0 + 11 +534407.5047163943 + 21 +185779.3420802661 + 31 +0.0 + 0 +LINE + 5 +4B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534427.7785696117 + 20 +185126.4152517712 + 30 +0.0 + 11 +534574.430876923 + 21 +185107.6857172062 + 31 +0.0 + 0 +LINE + 5 +4B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534499.9886731898 + 20 +184978.4702767471 + 30 +0.0 + 11 +534481.4814355449 + 21 +185472.5776425573 + 31 +0.0 + 0 +LINE + 5 +4B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534542.2000731028 + 20 +185102.4948084494 + 30 +0.0 + 11 +534616.655279584 + 21 +185136.8098267719 + 31 +0.0 + 0 +LINE + 5 +4B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534582.1093678846 + 20 +185033.4834774686 + 30 +0.0 + 11 +534546.4247380123 + 21 +185113.7582286117 + 31 +0.0 + 0 +LINE + 5 +4BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534569.1238130012 + 20 +185045.2214964583 + 30 +0.0 + 11 +534763.3838295403 + 21 +185002.5917092368 + 31 +0.0 + 0 +LINE + 5 +4BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534533.7798853447 + 20 +184843.5471823721 + 30 +0.0 + 11 +534721.6786173013 + 21 +185326.3483563077 + 31 +0.0 + 0 +LINE + 5 +4BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534780.2392892977 + 20 +185055.6794768792 + 30 +0.0 + 11 +534612.3492284322 + 21 +185137.243968068 + 31 +0.0 + 0 +LINE + 5 +4BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534757.0855742783 + 20 +184999.6659132573 + 30 +0.0 + 11 +534779.9103061629 + 21 +185056.4607395681 + 31 +0.0 + 0 +LINE + 5 +4BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535044.1957613281 + 20 +184922.0779391688 + 30 +0.0 + 11 +534770.4313874075 + 21 +185037.8321344448 + 31 +0.0 + 0 +LINE + 5 +4BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534979.8393764768 + 20 +184945.3141880438 + 30 +0.0 + 11 +535016.6800176997 + 21 +185052.2747811184 + 31 +0.0 + 0 +LINE + 5 +4C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535091.5038241661 + 20 +185020.0536223748 + 30 +0.0 + 11 +534390.4684959374 + 21 +185301.8710613853 + 31 +0.0 + 0 +LINE + 5 +4C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534625.7109155098 + 20 +185281.0968958392 + 30 +0.0 + 11 +534699.6758553083 + 21 +185714.0090754798 + 31 +0.0 + 0 +LINE + 5 +4C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534559.8039878591 + 20 +185303.1401241614 + 30 +0.0 + 11 +534745.8576411948 + 21 +185248.4267236806 + 31 +0.0 + 0 +LINE + 5 +4C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534581.3384455677 + 20 +185372.4846649576 + 30 +0.0 + 11 +534642.8832316696 + 21 +185353.8329892748 + 31 +0.0 + 0 +LINE + 5 +4C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534546.4703744269 + 20 +185330.7535896875 + 30 +0.0 + 11 +534596.0251223342 + 21 +185378.5195030866 + 31 +0.0 + 0 +LINE + 5 +4C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534587.7380689568 + 20 +185359.8275659777 + 30 +0.0 + 11 +534630.9501635513 + 21 +185760.7387938477 + 31 +0.0 + 0 +LINE + 5 +4C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534157.7326287101 + 20 +185538.9153082807 + 30 +0.0 + 11 +534848.8426457485 + 21 +185522.3086425906 + 31 +0.0 + 0 +LINE + 5 +4C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534817.5674024062 + 20 +185443.5239161787 + 30 +0.0 + 11 +534841.3747260803 + 21 +185681.1559490204 + 31 +0.0 + 0 +LINE + 5 +4C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534973.8870395568 + 20 +185334.5745159751 + 30 +0.0 + 11 +534808.3795581605 + 21 +185459.1303488497 + 31 +0.0 + 0 +LINE + 5 +4C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534895.0647444666 + 20 +185297.3048199906 + 30 +0.0 + 11 +534928.6030959303 + 21 +185375.8318773816 + 31 +0.0 + 0 +LINE + 5 +4CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534406.089309661 + 20 +185659.9740734423 + 30 +0.0 + 11 +534495.8186811316 + 21 +185651.5639073239 + 31 +0.0 + 0 +LINE + 5 +4CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534374.470588719 + 20 +185733.8984580516 + 30 +0.0 + 11 +534843.4215084236 + 21 +185678.8241045062 + 31 +0.0 + 0 +LINE + 5 +4CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534708.5877661901 + 20 +185283.717923885 + 30 +0.0 + 11 +534771.7380859552 + 21 +185703.0593879249 + 31 +0.0 + 0 +LINE + 5 +4CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535078.9923763787 + 20 +185538.2018863312 + 30 +0.0 + 11 +534764.8498232055 + 21 +185701.9616120782 + 31 +0.0 + 0 +LINE + 5 +4D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534942.4514380332 + 20 +185243.3023541477 + 30 +0.0 + 11 +535027.841112852 + 21 +185567.3371296885 + 31 +0.0 + 0 +LINE + 5 +4D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534850.8247779503 + 20 +185262.3065426861 + 30 +0.0 + 11 +534971.0055605743 + 21 +185244.8696560818 + 31 +0.0 + 0 +LINE + 5 +4D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534936.7220330874 + 20 +185148.6998047703 + 30 +0.0 + 11 +534835.6955730616 + 21 +185214.8918385876 + 31 +0.0 + 0 +LINE + 5 +4D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534839.7030371286 + 20 +185209.4775197689 + 30 +0.0 + 11 +534852.3398615693 + 21 +185263.864389153 + 31 +0.0 + 0 +LINE + 5 +4D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534805.1691802337 + 20 +184873.2203278976 + 30 +0.0 + 11 +534989.9613163239 + 21 +185404.6047790297 + 31 +0.0 + 0 +LINE + 5 +4D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534984.5268345839 + 20 +185416.4999954338 + 30 +0.0 + 11 +535007.4014992987 + 21 +185408.3449794178 + 31 +0.0 + 0 +LINE + 5 +4D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534901.1939781368 + 20 +185587.4061969149 + 30 +0.0 + 11 +534920.4049776653 + 21 +185628.4558579411 + 31 +0.0 + 0 +LINE + 5 +4D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534888.0184218741 + 20 +185579.1763486232 + 30 +0.0 + 11 +534907.3540633668 + 21 +185593.5039234594 + 31 +0.0 + 0 +LINE + 5 +4D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534826.1353532244 + 20 +185595.8783156365 + 30 +0.0 + 11 +534896.0117032174 + 21 +185579.1702911296 + 31 +0.0 + 0 +LINE + 5 +4DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534931.0310239862 + 20 +185361.4892335674 + 30 +0.0 + 11 +535274.7483125908 + 21 +185272.5382705694 + 31 +0.0 + 0 +LINE + 5 +4DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535071.7079966699 + 20 +185018.8475749982 + 30 +0.0 + 11 +535225.3427913389 + 21 +185153.0973355788 + 31 +0.0 + 0 +LINE + 5 +4DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535237.7886563097 + 20 +185124.5939782508 + 30 +0.0 + 11 +534960.7906806459 + 21 +185330.2718847505 + 31 +0.0 + 0 +LINE + 5 +4DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534918.8102029823 + 20 +185208.7995313166 + 30 +0.0 + 11 +534952.4648418761 + 21 +185197.4259210327 + 31 +0.0 + 0 +LINE + 5 +4E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534979.4409143216 + 20 +184844.1047242348 + 30 +0.0 + 11 +535117.6662871139 + 21 +185075.4980319115 + 31 +0.0 + 0 +LINE + 5 +4E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534720.9076861708 + 20 +185399.3112583365 + 30 +0.0 + 11 +534767.9092193946 + 21 +185398.3285007116 + 31 +0.0 + 0 +LINE + 5 +4E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534754.7117021712 + 20 +185335.8932851755 + 30 +0.0 + 11 +534767.0038576885 + 21 +185400.0002314509 + 31 +0.0 + 0 +LINE + 5 +4E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534707.7635446379 + 20 +185320.0365499808 + 30 +0.0 + 11 +534807.3433130968 + 21 +185288.9429373291 + 31 +0.0 + 0 +LINE + 5 +4E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534743.6313809589 + 20 +185151.9992597903 + 30 +0.0 + 11 +534864.2835988922 + 21 +185425.1325123446 + 31 +0.0 + 0 +LINE + 5 +4EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534912.9431068461 + 20 +184972.1991104843 + 30 +0.0 + 11 +534950.4900414558 + 21 +185078.4760987974 + 31 +0.0 + 0 +LINE + 5 +4ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534537.1915622652 + 20 +185503.4776332377 + 30 +0.0 + 11 +534550.6368346601 + 21 +185729.6044252857 + 31 +0.0 + 0 +LINE + 5 +4F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535204.4961575484 + 20 +185229.1919298231 + 30 +0.0 + 11 +535370.5322272506 + 21 +185193.6261991774 + 31 +0.0 + 0 +LINE + 5 +4F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535127.1242449161 + 20 +184779.6941977527 + 30 +0.0 + 11 +535293.5571175311 + 21 +185516.6960290042 + 31 +0.0 + 0 +LINE + 5 +4F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535310.5577928031 + 20 +185281.1508338489 + 30 +0.0 + 11 +535749.7250002055 + 21 +185277.1594001404 + 31 +0.0 + 0 +LINE + 5 +4F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535321.8102417574 + 20 +185349.72932479 + 30 +0.0 + 11 +535297.4628153631 + 21 +185157.3320250695 + 31 +0.0 + 0 +LINE + 5 +4F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535393.7012431163 + 20 +185339.5272597694 + 30 +0.0 + 11 +535385.1014189776 + 21 +185275.795880317 + 31 +0.0 + 0 +LINE + 5 +4F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535346.9444020168 + 20 +185367.2952780401 + 30 +0.0 + 11 +535402.0006421976 + 21 +185325.9907269572 + 31 +0.0 + 0 +LINE + 5 +4F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535382.2264866398 + 20 +185331.1913556245 + 30 +0.0 + 11 +535784.8986583672 + 21 +185352.4568174781 + 31 +0.0 + 0 +LINE + 5 +4F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535466.2111560569 + 20 +185520.4169102442 + 30 +0.0 + 11 +535514.7099456254 + 21 +185115.9919336981 + 31 +0.0 + 0 +LINE + 5 +4F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535501.4979983462 + 20 +185117.6476644367 + 30 +0.0 + 11 +535739.8858672794 + 21 +185132.0350074303 + 31 +0.0 + 0 +LINE + 5 +4F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535418.8674089755 + 20 +184945.9561199044 + 30 +0.0 + 11 +535515.4397776946 + 21 +185129.2063845734 + 31 +0.0 + 0 +LINE + 5 +4FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535369.5064323645 + 20 +185017.8273827992 + 30 +0.0 + 11 +535452.3764747868 + 21 +184997.2391378445 + 31 +0.0 + 0 +LINE + 5 +4FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535717.5064167423 + 20 +185601.3754019604 + 30 +0.0 + 11 +535737.9102122855 + 21 +185129.6426019159 + 31 +0.0 + 0 +LINE + 5 +4FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535326.3598811704 + 20 +185199.7522087382 + 30 +0.0 + 11 +535750.4056180268 + 21 +185204.2732045837 + 31 +0.0 + 0 +LINE + 5 +4FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535597.4474089884 + 20 +184751.4979048362 + 30 +0.0 + 11 +535748.2235633978 + 21 +185210.8983017991 + 31 +0.0 + 0 +LINE + 5 +4FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535547.1804223578 + 20 +184541.7709254714 + 30 +0.0 + 11 +535682.3923593902 + 21 +185024.9225824591 + 31 +0.0 + 0 +LINE + 5 +500 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535505.1377379638 + 20 +184758.6825038902 + 30 +0.0 + 11 +535620.5885034062 + 21 +184780.1452271111 + 31 +0.0 + 0 +LINE + 5 +501 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535524.1856060168 + 20 +184817.7772444247 + 30 +0.0 + 11 +535609.4175360436 + 21 +184748.4871370208 + 31 +0.0 + 0 +LINE + 5 +502 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535570.296748796 + 20 +185002.1058677334 + 30 +0.0 + 11 +535539.0553429453 + 21 +184802.52829905 + 31 +0.0 + 0 +LINE + 5 +503 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535357.746004057 + 20 +184958.474605842 + 30 +0.0 + 11 +535657.2550122715 + 21 +184929.8059817427 + 31 +0.0 + 0 +LINE + 5 +504 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535298.4922117697 + 20 +184889.1393465063 + 30 +0.0 + 11 +535341.8549400053 + 21 +185002.5727601311 + 31 +0.0 + 0 +LINE + 5 +505 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535241.1734845259 + 20 +185019.5210662647 + 30 +0.0 + 11 +535249.717781515 + 21 +184899.043989793 + 31 +0.0 + 0 +LINE + 5 +506 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535246.9440076642 + 20 +184905.1824582619 + 30 +0.0 + 11 +535300.5910023385 + 21 +184889.7027665412 + 31 +0.0 + 0 +LINE + 5 +507 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534936.51385834 + 20 +185038.9531902914 + 30 +0.0 + 11 +534936.5261047019 + 21 +185038.9510308092 + 31 +0.0 + 0 +LINE + 5 +508 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535080.6527128276 + 20 +185013.5362284448 + 30 +0.0 + 11 +535490.5647417293 + 21 +184941.2537170008 + 31 +0.0 + 0 +LINE + 5 +509 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535501.4412534025 + 20 +184948.5153462196 + 30 +0.0 + 11 +535497.0379026665 + 21 +184924.6330290301 + 31 +0.0 + 0 +LINE + 5 +50A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535656.8736195291 + 20 +185058.0328070582 + 30 +0.0 + 11 +535700.4612669717 + 21 +185045.6128970883 + 31 +0.0 + 0 +LINE + 5 +50B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535646.6482386795 + 20 +185069.727561105 + 30 +0.0 + 11 +535663.8755498464 + 21 +185052.9238060906 + 31 +0.0 + 0 +LINE + 5 +50C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535653.2693595921 + 20 +185133.4820169923 + 30 +0.0 + 11 +535647.9167757512 + 21 +185061.8355780196 + 31 +0.0 + 0 +LINE + 5 +50D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535438.6044568951 + 20 +184992.5553584505 + 30 +0.0 + 11 +535394.6297386165 + 21 +184644.0500522233 + 31 +0.0 + 0 +LINE + 5 +50E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535304.0071378401 + 20 +184686.4677601972 + 30 +0.0 + 11 +535412.5316292262 + 21 +184958.1988788722 + 31 +0.0 + 0 +LINE + 5 +50F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535285.9196378086 + 20 +184980.2736785974 + 30 +0.0 + 11 +535280.0577219055 + 21 +184945.2361034543 + 31 +0.0 + 0 +LINE + 5 +510 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535408.97011748 + 20 +184810.9000931193 + 30 +0.0 + 11 +535499.2992886763 + 21 +184787.3951780687 + 31 +0.0 + 0 +LINE + 5 +511 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535464.4760482091 + 20 +184792.1782756448 + 30 +0.0 + 11 +535543.352293473 + 21 +184819.2175096397 + 31 +0.0 + 0 +LINE + 5 +512 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535464.5747593956 + 20 +184805.3031096497 + 30 +0.0 + 11 +535525.357753368 + 21 +184753.0577724275 + 31 +0.0 + 0 +LINE + 5 +513 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535479.3097783617 + 20 +184592.3356562343 + 30 +0.0 + 11 +535522.9332737854 + 21 +184765.446873669 + 31 +0.0 + 0 +LINE + 5 +514 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535442.4387356393 + 20 +185206.0210956518 + 30 +0.0 + 11 +535448.962877189 + 21 +185159.464189451 + 31 +0.0 + 0 +LINE + 5 +515 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535385.2221178641 + 20 +185162.5376566434 + 30 +0.0 + 11 +535450.4688616026 + 21 +185160.624523209 + 31 +0.0 + 0 +LINE + 5 +516 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535362.082434586 + 20 +185206.3568374276 + 30 +0.0 + 11 +535347.2644751583 + 21 +185103.0932372945 + 31 +0.0 + 0 +LINE + 5 +517 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535201.914047268 + 20 +185144.1545844069 + 30 +0.0 + 11 +535490.7907191858 + 21 +185068.5966611639 + 31 +0.0 + 0 +LINE + 5 +518 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535571.5812368377 + 20 +185125.0116500937 + 30 +0.0 + 11 +535571.5035935779 + 21 +185056.1672042472 + 31 +0.0 + 0 +LINE + 5 +519 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535539.6771781332 + 20 +185057.1807123762 + 30 +0.0 + 11 +535599.7813427349 + 21 +185056.9330147139 + 31 +0.0 + 0 +LINE + 5 +51A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535545.0448302518 + 20 +185063.9077228577 + 30 +0.0 + 11 +535543.957332922 + 21 +184992.5824589834 + 31 +0.0 + 0 +LINE + 5 +51B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535541.1738633348 + 20 +184995.0465275259 + 30 +0.0 + 11 +535597.2888617337 + 21 +184993.4043492656 + 31 +0.0 + 0 +LINE + 5 +51C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535594.7469779589 + 20 +185064.4360151786 + 30 +0.0 + 11 +535594.4263687719 + 21 +184986.9377248218 + 31 +0.0 + 0 +LINE + 5 +51D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535478.3345188717 + 20 +185397.9158045933 + 30 +0.0 + 11 +535741.3567721097 + 21 +185426.7783072673 + 31 +0.0 + 0 +LINE + 5 +521 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534391.2765926995 + 20 +184519.6503847673 + 30 +0.0 + 11 +534386.096584341 + 21 +184657.946565643 + 31 +0.0 + 0 +LINE + 5 +52B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534256.5953021055 + 20 +184456.2129860037 + 30 +0.0 + 11 +534150.4528097157 + 21 +184882.3790791057 + 31 +0.0 + 0 +LINE + 5 +52F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534288.5721563849 + 20 +184537.5636853628 + 30 +0.0 + 11 +534215.4902316121 + 21 +184934.1190157052 + 31 +0.0 + 0 +LINE + 5 +530 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534453.0403708427 + 20 +184663.3012758095 + 30 +0.0 + 11 +534104.3003871109 + 21 +184622.7857454523 + 31 +0.0 + 0 +LINE + 5 +534 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534447.258926724 + 20 +184850.4577674675 + 30 +0.0 + 11 +534358.4101113065 + 21 +184835.3587940743 + 31 +0.0 + 0 +LINE + 5 +535 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534473.2590024992 + 20 +184926.5403161469 + 30 +0.0 + 11 +534009.7420030087 + 21 +184836.5395345194 + 31 +0.0 + 0 +LINE + 5 +536 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534173.7545980421 + 20 +184452.6269133669 + 30 +0.0 + 11 +534079.4116061442 + 21 +184866.0693231767 + 31 +0.0 + 0 +LINE + 5 +537 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533755.4398820817 + 20 +184661.6264292207 + 30 +0.0 + 11 +534086.3626894285 + 21 +184865.4899125348 + 31 +0.0 + 0 +LINE + 5 +54B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534152.8220239885 + 20 +184566.9747456222 + 30 +0.0 + 11 +534106.0257041126 + 21 +184562.4787046947 + 31 +0.0 + 0 +LINE + 5 +54C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534123.8568246477 + 20 +184501.2056948098 + 30 +0.0 + 11 +534106.8034721114 + 21 +184564.2134785772 + 31 +0.0 + 0 +LINE + 5 +557 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534476.3853151561 + 20 +184841.3974169092 + 30 +0.0 + 11 +534252.8962295165 + 21 +185308.7896885875 + 31 +0.0 + 0 +LINE + 5 +55A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533961.5249641592 + 20 +184881.5255266349 + 30 +0.0 + 11 +534304.3350339336 + 21 +185057.7811684468 + 31 +0.0 + 0 +LINE + 5 +55B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533907.0202036754 + 20 +184975.68771859 + 30 +0.0 + 11 +534585.0093833956 + 21 +185309.1577660268 + 31 +0.0 + 0 +LINE + 5 +55C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534351.9801533095 + 20 +185270.8440629181 + 30 +0.0 + 11 +534245.8376609196 + 21 +185697.0101560202 + 31 +0.0 + 0 +LINE + 5 +55D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534416.053427876 + 20 +185297.7558171074 + 30 +0.0 + 11 +534234.6140266268 + 21 +185229.2776323616 + 31 +0.0 + 0 +LINE + 5 +55E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534389.3918617133 + 20 +185365.2951323006 + 30 +0.0 + 11 +534329.4147947651 + 21 +185342.0917458582 + 31 +0.0 + 0 +LINE + 5 +55F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534427.284004527 + 20 +185326.2893565586 + 30 +0.0 + 11 +534374.294889134 + 21 +185370.214396944 + 31 +0.0 + 0 +LINE + 5 +560 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534354.0779169706 + 20 +185514.3239438399 + 30 +0.0 + 11 +534310.8750828159 + 21 +185748.7500926196 + 31 +0.0 + 0 +LINE + 5 +564 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534082.1685787133 + 20 +185266.8570599263 + 30 +0.0 + 11 +534042.8498380052 + 21 +185342.6551891283 + 31 +0.0 + 0 +LINE + 5 +565 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534438.4337275536 + 20 +185715.179827652 + 30 +0.0 + 11 +534231.2455671621 + 21 +185651.1706114339 + 31 +0.0 + 0 +LINE + 5 +566 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534269.1394492462 + 20 +185267.2579902813 + 30 +0.0 + 11 +534174.7964573482 + 21 +185680.700400091 + 31 +0.0 + 0 +LINE + 5 +56B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534038.9544153992 + 20 +185209.4610571617 + 30 +0.0 + 11 +533929.5639759587 + 21 +185526.2001676052 + 31 +0.0 + 0 +LINE + 5 +56C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534128.9026977911 + 20 +185235.266299162 + 30 +0.0 + 11 +534010.36305539 + 21 +185208.8879234353 + 31 +0.0 + 0 +LINE + 5 +56D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534143.9452490913 + 20 +185183.4172834368 + 30 +0.0 + 11 +534127.2753217763 + 21 +185236.706441965 + 31 +0.0 + 0 +LINE + 5 +56E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534203.536687036 + 20 +184850.6856394941 + 30 +0.0 + 11 +533979.511130468 + 21 +185366.7574547194 + 31 +0.0 + 0 +LINE + 5 +56F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533984.0405412705 + 20 +185379.0258777179 + 30 +0.0 + 11 +533961.8400215264 + 21 +185369.1825299575 + 31 +0.0 + 0 +LINE + 5 +573 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534041.5016409995 + 20 +185328.1711071394 + 30 +0.0 + 11 +533705.4015758481 + 21 +185213.7569711722 + 31 +0.0 + 0 +LINE + 5 +574 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533926.8507846999 + 20 +184975.9659141336 + 30 +0.0 + 11 +533763.6036657633 + 21 +185098.3465764448 + 31 +0.0 + 0 +LINE + 5 +575 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533753.3249201474 + 20 +185068.9920483031 + 30 +0.0 + 11 +534014.1606413901 + 21 +185294.815001671 + 31 +0.0 + 0 +LINE + 5 +57B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534031.9313018756 + 20 +184808.6148959472 + 30 +0.0 + 11 +533876.783424875 + 21 +185029.0196435895 + 31 +0.0 + 0 +LINE + 5 +57C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534248.2068751925 + 20 +185381.6058225365 + 30 +0.0 + 11 +534201.4105553166 + 21 +185377.1097816092 + 31 +0.0 + 0 +LINE + 5 +57D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534219.2416758517 + 20 +185315.8367717241 + 30 +0.0 + 11 +534202.1883233154 + 21 +185378.8445554916 + 31 +0.0 + 0 +LINE + 5 +57E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534267.2444791151 + 20 +185303.536510522 + 30 +0.0 + 11 +534170.26974444 + 21 +185265.0807714352 + 31 +0.0 + 0 +LINE + 5 +585 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534088.6604468999 + 20 +184941.3248589964 + 30 +0.0 + 11 +534043.2684698303 + 21 +185044.4952954651 + 31 +0.0 + 0 +LINE + 5 +588 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533778.699490766 + 20 +185175.787427945 + 30 +0.0 + 11 +533615.7892077258 + 21 +185127.9007145659 + 31 +0.0 + 0 +LINE + 5 +589 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533889.4801228333 + 20 +184733.3371193682 + 30 +0.0 + 11 +533668.380798012 + 21 +185455.8235821609 + 31 +0.0 + 0 +LINE + 5 +58A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533669.0481535236 + 20 +185219.6666077623 + 30 +0.0 + 11 +533156.2970385719 + 21 +185130.5605879663 + 31 +0.0 + 0 +LINE + 5 +58B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533652.6970921362 + 20 +185287.2111842932 + 30 +0.0 + 11 +533691.368935235 + 21 +185097.1743282281 + 31 +0.0 + 0 +LINE + 5 +58D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533726.3554435946 + 20 +185312.8337458587 + 30 +0.0 + 11 +533574.5071917399 + 21 +185257.5403092498 + 31 +0.0 + 0 +LINE + 5 +58E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533593.8368982549 + 20 +185264.2056083881 + 30 +0.0 + 11 +533277.4741264265 + 21 +185310.1755935641 + 31 +0.0 + 0 +LINE + 5 +58F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533672.2874569829 + 20 +185028.0485366832 + 30 +0.0 + 11 +533252.0779246593 + 21 +185038.8519140487 + 31 +0.0 + 0 +LINE + 5 +590 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533710.405074358 + 20 +184829.6561084765 + 30 +0.0 + 11 +533658.6782495932 + 21 +184939.5278570125 + 31 +0.0 + 0 +LINE + 5 +591 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533757.8097503218 + 20 +184963.9603378841 + 30 +0.0 + 11 +533758.301905461 + 21 +184843.1816611668 + 31 +0.0 + 0 +LINE + 5 +592 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533760.6087077835 + 20 +184849.5104272049 + 30 +0.0 + 11 +533708.2700168314 + 21 +184830.060945907 + 31 +0.0 + 0 +LINE + 5 +593 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534060.1620768055 + 20 +185006.1286428275 + 30 +0.0 + 11 +534060.1500263014 + 21 +185006.1255732843 + 31 +0.0 + 0 +LINE + 5 +594 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533918.3284564037 + 20 +184970.0003236548 + 30 +0.0 + 11 +532885.2387837082 + 21 +184800.028308228 + 31 +0.0 + 0 +LINE + 5 +595 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533494.4232462245 + 20 +185058.1154689717 + 30 +0.0 + 11 +533576.3287827944 + 21 +184703.1402534146 + 31 +0.0 + 0 +LINE + 5 +596 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533720.0668251423 + 20 +184684.4216508722 + 30 +0.0 + 11 +533604.0388960189 + 21 +184929.9588760215 + 31 +0.0 + 0 +LINE + 5 +597 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533716.1249475926 + 20 +184921.4756006983 + 30 +0.0 + 11 +533724.5914895052 + 21 +184886.9747108834 + 31 +0.0 + 0 +LINE + 5 +598 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533431.9734486657 + 20 +185232.4302220629 + 30 +0.0 + 11 +533540.1338697607 + 21 +185087.9672749981 + 31 +0.0 + 0 +LINE + 5 +599 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533603.4661137124 + 20 +185095.8003762957 + 30 +0.0 + 11 +533538.5453041319 + 21 +185089.0116995892 + 31 +0.0 + 0 +LINE + 5 +59A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533787.6357425715 + 20 +185091.1815131837 + 30 +0.0 + 11 +533565.5971262563 + 21 +185014.9532196935 + 31 +0.0 + 0 +LINE + 5 +59D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533835.4049733451 + 20 +184778.3242658983 + 30 +0.0 + 11 +533961.3461259023 + 21 +184945.405927624 + 31 +0.0 + 0 +LINE + 5 +59E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533589.8584304239 + 20 +185107.2802195277 + 30 +0.0 + 11 +533607.2332131394 + 21 +184991.399632075 + 31 +0.0 + 0 +LINE + 5 +59F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534448.9792157222 + 20 +184662.8294633956 + 30 +0.0 + 11 +534595.7315551097 + 21 +184795.9757854659 + 31 +0.0 + 0 +LINE + 5 +5A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531733.2840274471 + 20 +186204.7351113824 + 30 +0.0 + 11 +531448.5837936163 + 21 +186119.7760350217 + 31 +0.0 + 0 +LINE + 5 +5A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531632.4721077171 + 20 +185930.7358159032 + 30 +0.0 + 11 +531639.7393499542 + 21 +186196.0561477955 + 31 +0.0 + 0 +LINE + 5 +5A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531358.457913672 + 20 +185930.1338576856 + 30 +0.0 + 11 +531685.1949769023 + 21 +186008.8922798291 + 31 +0.0 + 0 +LINE + 5 +5A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531770.0292339276 + 20 +185963.2831550198 + 30 +0.0 + 11 +531808.2136621512 + 21 +186140.5612032772 + 31 +0.0 + 0 +LINE + 5 +5A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532232.1680833026 + 20 +186022.1457130604 + 30 +0.0 + 11 +532232.1680833026 + 21 +186186.3597618883 + 31 +0.0 + 0 +LINE + 5 +5A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531627.5907608017 + 20 +186001.9470050684 + 30 +0.0 + 11 +531869.3182729818 + 21 +185971.1207754074 + 31 +0.0 + 0 +LINE + 5 +5A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531611.397048721 + 20 +186201.9375863602 + 30 +0.0 + 11 +531901.0963274493 + 21 +186217.1136835819 + 31 +0.0 + 0 +LINE + 5 +5A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533414.1140397175 + 20 +185165.5370379062 + 30 +0.0 + 11 +533424.4254015407 + 21 +184724.7392205304 + 31 +0.0 + 0 +LINE + 5 +5A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533322.7171241251 + 20 +184642.9320605513 + 30 +0.0 + 11 +532990.6437599907 + 21 +184514.5291438661 + 31 +0.0 + 0 +LINE + 5 +5AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534153.2048046347 + 20 +184752.2472177889 + 30 +0.0 + 11 +533885.0218290623 + 21 +184579.4395168853 + 31 +0.0 + 0 +LINE + 5 +5AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531550.2442337178 + 20 +185166.8802593773 + 30 +0.0 + 11 +531510.6297846931 + 21 +185399.9897693373 + 31 +0.0 + 0 +LINE + 5 +5AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532988.2362401025 + 20 +186147.3083667564 + 30 +0.0 + 11 +533381.9029377306 + 21 +186201.5675327487 + 31 +0.0 + 0 +LINE + 5 +5C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532778.6411400246 + 20 +187622.1886596294 + 30 +0.0 + 11 +533427.582290831 + 21 +185080.1812356924 + 31 +0.0 + 0 +LINE + 5 +5D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534248.5818166204 + 20 +185619.4487363936 + 30 +0.0 + 11 +534493.593518952 + 21 +185630.1835954607 + 31 +0.0 + 0 +LINE + 5 +5DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534282.0183703715 + 20 +185616.188519107 + 30 +0.0 + 11 +534172.0588715453 + 21 +185831.2875668419 + 31 +0.0 + 0 +LINE + 5 +5DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533826.1828457042 + 20 +185498.1855968445 + 30 +0.0 + 11 +534504.1720254244 + 21 +185831.6556442813 + 31 +0.0 + 0 +LINE + 5 +5E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534271.1427953385 + 20 +185793.3419411726 + 30 +0.0 + 11 +534165.0003029485 + 21 +186219.5080342747 + 31 +0.0 + 0 +LINE + 5 +5E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534335.2160699049 + 20 +185820.2536953619 + 30 +0.0 + 11 +534153.7766686557 + 21 +185751.7755106161 + 31 +0.0 + 0 +LINE + 5 +5E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534308.5545037421 + 20 +185887.7930105551 + 30 +0.0 + 11 +534248.577436794 + 21 +185864.5896241127 + 31 +0.0 + 0 +LINE + 5 +5E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534303.1196496177 + 20 +185874.6926405317 + 30 +0.0 + 11 +534230.0377248448 + 21 +186271.2479708741 + 31 +0.0 + 0 +LINE + 5 +5E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534358.301923027 + 20 +185987.6211864558 + 30 +0.0 + 11 +534062.9865863768 + 21 +185953.4249086355 + 31 +0.0 + 0 +LINE + 5 +5E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534067.6732275388 + 20 +185940.9616670905 + 30 +0.0 + 11 +534026.1561056284 + 21 +186176.1469138242 + 31 +0.0 + 0 +LINE + 5 +5E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533919.9417536444 + 20 +185820.6237579156 + 30 +0.0 + 11 +534075.6678596591 + 21 +185957.2116849322 + 31 +0.0 + 0 +LINE + 5 +5E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534001.3312207422 + 20 +185789.3549381808 + 30 +0.0 + 11 +533962.0124800341 + 21 +185865.1530673827 + 31 +0.0 + 0 +LINE + 5 +5E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534357.5963695824 + 20 +186237.6777059064 + 30 +0.0 + 11 +534024.2894962416 + 21 +186173.6684896884 + 31 +0.0 + 0 +LINE + 5 +5E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534188.3020912749 + 20 +185789.7558685358 + 30 +0.0 + 11 +534093.959099377 + 21 +186203.1982783455 + 31 +0.0 + 0 +LINE + 5 +5EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533638.9909350334 + 20 +185915.9627476106 + 30 +0.0 + 11 +534100.9101826614 + 21 +186202.6188677036 + 31 +0.0 + 0 +LINE + 5 +5EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533717.7276796531 + 20 +185860.915757104 + 30 +0.0 + 11 +533711.7175495929 + 21 +185978.1906737143 + 31 +0.0 + 0 +LINE + 5 +5EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533770.762714852 + 20 +185893.2003459607 + 30 +0.0 + 11 +533683.5308453329 + 21 +185959.9551347054 + 31 +0.0 + 0 +LINE + 5 +5ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533939.2875136152 + 20 +185980.9652082985 + 30 +0.0 + 11 +533752.4704865293 + 21 +185904.110606927 + 31 +0.0 + 0 +LINE + 5 +5EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533958.117057428 + 20 +185731.9589354162 + 30 +0.0 + 11 +533848.7266179877 + 21 +186048.6980458597 + 31 +0.0 + 0 +LINE + 5 +5EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534048.06533982 + 20 +185757.7641774165 + 30 +0.0 + 11 +533929.5256974189 + 21 +185731.3858016898 + 31 +0.0 + 0 +LINE + 5 +5F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534063.1078911201 + 20 +185705.9151616913 + 30 +0.0 + 11 +534046.4379638052 + 21 +185759.2043202194 + 31 +0.0 + 0 +LINE + 5 +5F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534282.8840061187 + 20 +185012.2849875451 + 30 +0.0 + 11 +533898.6737724969 + 21 +185889.2553329739 + 31 +0.0 + 0 +LINE + 5 +5F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533903.2031832994 + 20 +185901.5237559724 + 30 +0.0 + 11 +533881.0026635552 + 21 +185891.680408212 + 31 +0.0 + 0 +LINE + 5 +5F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533973.5175888728 + 20 +186078.1849544206 + 30 +0.0 + 11 +533951.289621666 + 21 +186117.6824815214 + 31 +0.0 + 0 +LINE + 5 +5F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533987.2718768551 + 20 +186070.9637877669 + 30 +0.0 + 11 +533966.918612191 + 21 +186083.8047787778 + 31 +0.0 + 0 +LINE + 5 +5F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534047.7321300739 + 20 +186092.2482343965 + 30 +0.0 + 11 +533979.3014454954 + 21 +186070.3597949963 + 31 +0.0 + 0 +LINE + 5 +5F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533960.6642830283 + 20 +185850.6689853939 + 30 +0.0 + 11 +533624.564217877 + 21 +185736.2548494267 + 31 +0.0 + 0 +LINE + 5 +5F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533846.0134267288 + 20 +185498.4637923881 + 30 +0.0 + 11 +533682.7663077922 + 21 +185620.8444546993 + 31 +0.0 + 0 +LINE + 5 +5F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533672.4875621763 + 20 +185591.4899265576 + 30 +0.0 + 11 +533933.323283419 + 21 +185817.3128799255 + 31 +0.0 + 0 +LINE + 5 +5F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533984.2730984368 + 20 +185699.3213145349 + 30 +0.0 + 11 +533951.5635824718 + 21 +185685.4619748932 + 31 +0.0 + 0 +LINE + 5 +5FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533790.9027081983 + 20 +185779.5505123624 + 30 +0.0 + 11 +533747.0106001366 + 21 +185861.9235847253 + 31 +0.0 + 0 +LINE + 5 +5FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533759.7708675354 + 20 +185829.171307324 + 30 +0.0 + 11 +533767.7003971879 + 21 +185912.175553007 + 31 +0.0 + 0 +LINE + 5 +5FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533772.511944799 + 20 +185832.3234433795 + 30 +0.0 + 11 +533707.5492968536 + 21 +185879.270242947 + 31 +0.0 + 0 +LINE + 5 +5FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533609.8257327368 + 20 +185818.9870339748 + 30 +0.0 + 11 +533720.1623939 + 21 +185879.7972284508 + 31 +0.0 + 0 +LINE + 5 +5FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533892.3579233192 + 20 +185253.3677321921 + 30 +0.0 + 11 +533795.9460669039 + 21 +185551.517521844 + 31 +0.0 + 0 +LINE + 5 +5FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534167.3695172214 + 20 +185904.103700791 + 30 +0.0 + 11 +534120.5731973455 + 21 +185899.6076598636 + 31 +0.0 + 0 +LINE + 5 +600 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534138.4043178805 + 20 +185838.3346499785 + 30 +0.0 + 11 +534121.3509653443 + 21 +185901.3424337461 + 31 +0.0 + 0 +LINE + 5 +601 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534186.407121144 + 20 +185826.0343887765 + 30 +0.0 + 11 +534089.4323864689 + 21 +185787.5786496897 + 31 +0.0 + 0 +LINE + 5 +602 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534163.2101264513 + 20 +185655.7847719955 + 30 +0.0 + 11 +534022.4637309971 + 21 +185919.1271034002 + 31 +0.0 + 0 +LINE + 5 +603 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534058.5158018959 + 20 +186010.8331931783 + 30 +0.0 + 11 +533991.5818118574 + 21 +185994.7271468006 + 31 +0.0 + 0 +LINE + 5 +604 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533999.9782917924 + 20 +185964.0115637281 + 30 +0.0 + 11 +533985.742053636 + 21 +186022.4059254402 + 31 +0.0 + 0 +LINE + 5 +605 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534005.2705259052 + 20 +185970.7980663162 + 30 +0.0 + 11 +533936.1590559625 + 21 +185953.1322620743 + 31 +0.0 + 0 +LINE + 5 +606 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533939.2035281584 + 20 +185950.9990659342 + 30 +0.0 + 11 +533924.5400241045 + 21 +186005.1892075063 + 31 +0.0 + 0 +LINE + 5 +607 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533994.2110735139 + 20 +186019.257029288 + 30 +0.0 + 11 +533918.9176883678 + 21 +186000.8996342736 + 31 +0.0 + 0 +LINE + 5 +608 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534007.8230889289 + 20 +185463.8227372508 + 30 +0.0 + 11 +533962.4311118591 + 21 +185566.9931737196 + 31 +0.0 + 0 +LINE + 5 +609 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533680.2879975476 + 20 +185926.3723861391 + 30 +0.0 + 11 +533183.0921970397 + 21 +185960.4920697405 + 31 +0.0 + 0 +LINE + 5 +60A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533635.3074283488 + 20 +185874.3556080672 + 30 +0.0 + 11 +533409.7069375618 + 21 +185902.1750854693 + 31 +0.0 + 0 +LINE + 5 +60B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533697.862132795 + 20 +185698.2853061994 + 30 +0.0 + 11 +533534.9518497547 + 21 +185650.3985928204 + 31 +0.0 + 0 +LINE + 5 +60C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533771.9073970045 + 20 +185375.8751922475 + 30 +0.0 + 11 +533587.5434400409 + 21 +185978.3214604154 + 31 +0.0 + 0 +LINE + 5 +60E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533571.859734165 + 20 +185809.7090625476 + 30 +0.0 + 11 +533610.5315772639 + 21 +185619.6722064826 + 31 +0.0 + 0 +LINE + 5 +60F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533500.9333528127 + 20 +185794.1576434707 + 30 +0.0 + 11 +533514.2766247555 + 21 +185731.2481625001 + 31 +0.0 + 0 +LINE + 5 +610 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533545.4819450334 + 20 +185825.3455892097 + 30 +0.0 + 11 +533493.6698337688 + 21 +185780.0381875042 + 31 +0.0 + 0 +LINE + 5 +611 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533512.9995402838 + 20 +185786.7034866426 + 30 +0.0 + 11 +533196.6367684554 + 21 +185832.6734718186 + 31 +0.0 + 0 +LINE + 5 +612 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533591.4500990117 + 20 +185550.5464149377 + 30 +0.0 + 11 +533281.9833857183 + 21 +185528.8296416967 + 31 +0.0 + 0 +LINE + 5 +616 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533979.3247188343 + 20 +185528.626521082 + 30 +0.0 + 11 +533979.3126683303 + 21 +185528.6234515387 + 31 +0.0 + 0 +LINE + 5 +619 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533592.716804391 + 20 +185246.1291783604 + 30 +0.0 + 11 +533497.5594804018 + 21 +185639.2600493747 + 31 +0.0 + 0 +LINE + 5 +61B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533351.1360906946 + 20 +185754.9281003174 + 30 +0.0 + 11 +533459.2965117895 + 21 +185610.4651532526 + 31 +0.0 + 0 +LINE + 5 +61C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533522.6287557413 + 20 +185618.2982545502 + 30 +0.0 + 11 +533457.7079461609 + 21 +185611.5095778437 + 31 +0.0 + 0 +LINE + 5 +61D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533706.7983846004 + 20 +185613.6793914381 + 30 +0.0 + 11 +533484.7597682852 + 21 +185537.451097948 + 31 +0.0 + 0 +LINE + 5 +620 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533365.6423109871 + 20 +185989.5037721182 + 30 +0.0 + 11 +533355.2628067224 + 21 +185733.4928732219 + 31 +0.0 + 0 +LINE + 5 +621 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533337.2744785237 + 20 +186336.5469027501 + 30 +0.0 + 11 +533396.5976925238 + 21 +186535.0100937501 + 31 +0.0 + 0 +LINE + 5 +622 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533550.0795055239 + 20 +186180.2816337501 + 30 +0.0 + 11 +533609.1965935239 + 21 +186660.1642687501 + 31 +0.0 + 0 +LINE + 5 +623 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533538.3571319998 + 20 +185927.2096775935 + 30 +0.0 + 11 +533580.5614965238 + 21 +186464.9701427501 + 31 +0.0 + 0 +LINE + 5 +624 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533458.1223385238 + 20 +186169.4847237501 + 30 +0.0 + 11 +533567.2457225238 + 21 +186212.8623077501 + 31 +0.0 + 0 +LINE + 5 +625 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533465.3862375238 + 20 +186231.1470737501 + 30 +0.0 + 11 +533562.4058715238 + 21 +186179.6418167501 + 31 +0.0 + 0 +LINE + 5 +626 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533474.9917335238 + 20 +186420.9127537501 + 30 +0.0 + 11 +533482.9234825238 + 21 +186219.0605337501 + 31 +0.0 + 0 +LINE + 5 +627 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533054.7558316947 + 20 +186318.1436929638 + 30 +0.0 + 11 +533574.2870045238 + 21 +186366.7882467501 + 31 +0.0 + 0 +LINE + 5 +628 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533417.7957455238 + 20 +186355.0216147501 + 30 +0.0 + 11 +533418.0925675238 + 21 +186330.7385657501 + 31 +0.0 + 0 +LINE + 5 +629 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533347.6302755237 + 20 +186386.0827237501 + 30 +0.0 + 11 +533383.5869865237 + 21 +185953.2266277501 + 31 +0.0 + 0 +LINE + 5 +62A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533362.2817485238 + 20 +185976.7798857501 + 30 +0.0 + 11 +533556.7744945238 + 21 +186028.6150477501 + 31 +0.0 + 0 +LINE + 5 +62B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533258.2867925238 + 20 +185940.5511634717 + 30 +0.0 + 11 +533328.6913695239 + 21 +186347.3338157501 + 31 +0.0 + 0 +LINE + 5 +62C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533353.6739045237 + 20 +186202.1253807501 + 30 +0.0 + 11 +533446.8430955237 + 21 +186196.5269837501 + 31 +0.0 + 0 +LINE + 5 +62D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533411.7521155238 + 20 +186194.4875667501 + 30 +0.0 + 11 +533483.9128905238 + 21 +186236.2656087501 + 31 +0.0 + 0 +LINE + 5 +62E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533409.3115775239 + 20 +186207.3838757501 + 30 +0.0 + 11 +533479.0483035237 + 21 +186167.8751847501 + 31 +0.0 + 0 +LINE + 5 +62F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533464.9410045238 + 20 +186001.2828717501 + 30 +0.0 + 11 +533474.2744135237 + 21 +186179.5618397501 + 31 +0.0 + 0 +LINE + 5 +631 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533828.2799445249 + 20 +186210.2886838591 + 30 +0.0 + 11 +534061.4320714794 + 21 +186167.5716401304 + 31 +0.0 + 0 +LINE + 5 +632 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533878.5348859357 + 20 +186281.5377210867 + 30 +0.0 + 11 +533888.0084184373 + 21 +186196.6756450849 + 31 +0.0 + 0 +LINE + 5 +633 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533682.6241340539 + 20 +186064.3491011722 + 30 +0.0 + 11 +533742.8463203225 + 21 +185963.5383080481 + 31 +0.0 + 0 +LINE + 5 +634 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533744.6558089154 + 20 +186067.0101066368 + 30 +0.0 + 11 +533709.2791370904 + 21 +185963.019280259 + 31 +0.0 + 0 +LINE + 5 +635 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533835.7364357564 + 20 +186271.9532591409 + 30 +0.0 + 11 +533852.6960106894 + 21 +186024.3600566836 + 31 +0.0 + 0 +LINE + 5 +636 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533733.19405122 + 20 +186303.439136011 + 30 +0.0 + 11 +533854.626565084 + 21 +186302.1702375712 + 31 +0.0 + 0 +LINE + 5 +637 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533835.5538564261 + 20 +186402.4709471534 + 30 +0.0 + 11 +533725.5431140586 + 21 +186352.6174865919 + 31 +0.0 + 0 +LINE + 5 +638 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533730.3361853824 + 20 +186357.3504649146 + 30 +0.0 + 11 +533734.4512997048 + 21 +186301.6666546332 + 31 +0.0 + 0 +LINE + 5 +639 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533774.1936004964 + 20 +186550.921799029 + 30 +0.0 + 11 +533848.7703066101 + 21 +186141.4209470101 + 31 +0.0 + 0 +LINE + 5 +63A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533878.8332329101 + 20 +186207.9637909363 + 30 +0.0 + 11 +533536.7480498949 + 21 +186128.1674759979 + 31 +0.0 + 0 +LINE + 5 +63B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533545.052813288 + 20 +186227.8808082367 + 30 +0.0 + 11 +533837.5602881303 + 21 +186220.4819401955 + 31 +0.0 + 0 +LINE + 5 +63C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533814.2894553135 + 20 +186346.879572664 + 30 +0.0 + 11 +533779.3969418796 + 21 +186340.2082732231 + 31 +0.0 + 0 +LINE + 5 +63D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533698.1930436881 + 20 +186172.6657522801 + 30 +0.0 + 11 +533707.521963026 + 21 +186079.7958892214 + 31 +0.0 + 0 +LINE + 5 +63E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533699.9134321882 + 20 +186114.1127416054 + 30 +0.0 + 11 +533752.6629064465 + 21 +186049.5366221229 + 31 +0.0 + 0 +LINE + 5 +63F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533712.2556086878 + 20 +186118.5783536354 + 30 +0.0 + 11 +533684.3718017468 + 21 +186043.434219279 + 31 +0.0 + 0 +LINE + 5 +640 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533517.6614423957 + 20 +186030.7981312433 + 30 +0.0 + 11 +533695.1477506907 + 21 +186050.0104533972 + 31 +0.0 + 0 +LINE + 5 +641 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533938.7951369609 + 20 +186482.5712296238 + 30 +0.0 + 11 +533968.2654247545 + 21 +186185.4345043938 + 31 +0.0 + 0 +LINE + 5 +643 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534367.7944644015 + 20 +186130.8678290536 + 30 +0.0 + 11 +534035.7211002671 + 21 +186002.4649123684 + 31 +0.0 + 0 +LINE + 5 +64E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532380.4365915808 + 20 +183829.5073398477 + 30 +0.0 + 11 +532354.2882743064 + 21 +183002.9918967023 + 31 +0.0 + 0 +ENDSEC + 0 +SECTION + 2 +OBJECTS + 0 +DICTIONARY + 5 +C +330 +0 +100 +AcDbDictionary +281 + 1 + 3 +ACAD_CIP_PREVIOUS_PRODUCT_INFO +350 +B4 + 3 +ACAD_COLOR +350 +62 + 3 +ACAD_DETAILVIEWSTYLE +350 +69 + 3 +ACAD_GROUP +350 +D + 3 +ACAD_LAYOUT +350 +61 + 3 +ACAD_MATERIAL +350 +10 + 3 +ACAD_MLEADERSTYLE +350 +65 + 3 +ACAD_MLINESTYLE +350 +5E + 3 +ACAD_PLOTSETTINGS +350 +60 + 3 +ACAD_PLOTSTYLENAME +350 +E + 3 +ACAD_SCALELIST +350 +42 + 3 +ACAD_SECTIONVIEWSTYLE +350 +67 + 3 +ACAD_TABLESTYLE +350 +63 + 3 +ACAD_VISUALSTYLE +350 +29 + 3 +ACDB_RECOMPOSE_DATA +350 +658 + 3 +AcDbVariableDictionary +350 +34B + 0 +DICTIONARY + 5 +345 +330 +2 +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +ACAD_LAYERSTATES +360 +346 + 0 +DICTIONARY + 5 +340 +330 +54 +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +ADSK_XREC_LAYER_RECONCILED +360 +341 + 0 +DICTIONARY + 5 +135 +330 +6F +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +ACAD_SORTENTS +360 +136 + 0 +XRECORD + 5 +B4 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbXrecord +280 + 1 +300 +ACDMAC +300 +2018 +300 +ACDMAC_F_S + 0 +DICTIONARY + 5 +62 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +DICTIONARY + 5 +69 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Imperial24 +350 +6A + 0 +DICTIONARY + 5 +D +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +DICTIONARY + 5 +61 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Layout1 +350 +6E + 3 +Model +350 +72 + 0 +DICTIONARY + 5 +10 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +ByBlock +350 +19 + 3 +ByLayer +350 +11 + 3 +Global +350 +21 + 0 +DICTIONARY + 5 +65 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Standard +350 +66 + 0 +DICTIONARY + 5 +5E +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Standard +350 +5F + 0 +DICTIONARY + 5 +60 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +ACDBDICTIONARYWDFLT + 5 +E +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Normal +350 +F +100 +AcDbDictionaryWithDefault +340 +F + 0 +DICTIONARY + 5 +42 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +A0 +350 +43 + 3 +A1 +350 +44 + 3 +A2 +350 +45 + 3 +A3 +350 +46 + 3 +A4 +350 +47 + 3 +A5 +350 +48 + 3 +A6 +350 +49 + 3 +A7 +350 +4A + 3 +A8 +350 +4B + 3 +A9 +350 +4C + 3 +B0 +350 +4D + 3 +B1 +350 +4E + 3 +B2 +350 +4F + 3 +B3 +350 +50 + 3 +B4 +350 +51 + 3 +B5 +350 +52 + 3 +B6 +350 +53 + 0 +DICTIONARY + 5 +67 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Imperial24 +350 +68 + 0 +DICTIONARY + 5 +63 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Standard +350 +64 + 0 +DICTIONARY + 5 +29 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +2dWireframe +350 +2F + 3 +Basic +350 +2E + 3 +Brighten +350 +35 + 3 +ColorChange +350 +39 + 3 +Conceptual +350 +32 + 3 +Dim +350 +34 + 3 +EdgeColorOff +350 +41 + 3 +Facepattern +350 +38 + 3 +Flat +350 +2A + 3 +FlatWithEdges +350 +2B + 3 +Gouraud +350 +2C + 3 +GouraudWithEdges +350 +2D + 3 +Hidden +350 +31 + 3 +JitterOff +350 +3F + 3 +Linepattern +350 +37 + 3 +OverhangOff +350 +40 + 3 +Realistic +350 +33 + 3 +Shaded +350 +3E + 3 +Shaded with edges +350 +3D + 3 +Shades of Gray +350 +3A + 3 +Sketchy +350 +3B + 3 +Thicken +350 +36 + 3 +Wireframe +350 +30 + 3 +X-Ray +350 +3C + 0 +XRECORD + 5 +658 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbXrecord +280 + 1 + 90 + 1 +330 +64 + 0 +DICTIONARY + 5 +34B +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +CANNOSCALE +350 +351 + 3 +CMLEADERSTYLE +350 +34D + 3 +CTABLESTYLE +350 +34C + 3 +CVIEWDETAILSTYLE +350 +34E + 3 +CVIEWSECTIONSTYLE +350 +34F + 3 +LAYEREVAL +350 +353 + 3 +LAYERNOTIFY +350 +354 + 3 +LIGHTINGUNITS +350 +352 + 3 +MSLTSCALE +350 +350 + 0 +DICTIONARY + 5 +346 +102 +{ACAD_REACTORS +330 +345 +102 +} +330 +345 +100 +AcDbDictionary +281 + 1 + 0 +XRECORD + 5 +341 +102 +{ACAD_REACTORS +330 +340 +102 +} +330 +340 +100 +AcDbXrecord +280 + 1 +290 + 1 + 0 +SORTENTSTABLE + 5 +136 +102 +{ACAD_REACTORS +330 +135 +102 +} +330 +135 +100 +AcDbSortentsTable +330 +6F +331 +2D6 + 5 +2D7 +331 +25E + 5 +25F +331 +280 + 5 +281 +331 +2F8 + 5 +2F9 +331 +1F8 + 5 +1F9 +331 +90 + 5 +90 +331 +271 + 5 +272 +331 +2E9 + 5 +2EA +331 +1E9 + 5 +1EA +331 +2A2 + 5 +2A3 +331 +21A + 5 +21B +331 +182 + 5 +182 +331 +10A + 5 +10A +331 +FB + 5 +FB +331 +293 + 5 +294 +331 +30B + 5 +30C +331 +20B + 5 +20C +331 +12C + 5 +12D +331 +23C + 5 +23D +331 +1A4 + 5 +1A4 +331 +11D + 5 +11E +331 +D4 + 5 +D4 +331 +2B5 + 5 +2B6 +331 +22D + 5 +22E +331 +1C6 + 5 +1C7 +331 +14E + 5 +14E +331 +13F + 5 +13F +331 +24F + 5 +250 +331 +1B7 + 5 +1B7 +331 +E7 + 5 +E7 +331 +C5 + 5 +C5 +331 +A3 + 5 +A3 +331 +81 + 5 +81 +331 +76 + 5 +76 +331 +160 + 5 +160 +331 +1C9 + 5 +1CA +331 +151 + 5 +151 +331 +270 + 5 +271 +331 +2E8 + 5 +2E9 +331 +1E8 + 5 +1E9 +331 +2D9 + 5 +2DA +331 +261 + 5 +262 +331 +292 + 5 +293 +331 +30A + 5 +30B +331 +20A + 5 +20B +331 +A2 + 5 +A2 +331 +283 + 5 +284 +331 +2FB + 5 +2FC +331 +1FB + 5 +1FC +331 +11C + 5 +11D +331 +2B4 + 5 +2B5 +331 +22C + 5 +22D +331 +194 + 5 +194 +331 +2A5 + 5 +2A6 +331 +31D + 5 +31E +331 +21D + 5 +21E +331 +185 + 5 +185 +331 +13E + 5 +13E +331 +10D + 5 +10D +331 +24E + 5 +24F +331 +1B6 + 5 +1B6 +331 +12F + 5 +130 +331 +E6 + 5 +E6 +331 +2C7 + 5 +2C8 +331 +23F + 5 +240 +331 +1A7 + 5 +1A7 +331 +D7 + 5 +D7 +331 +C4 + 5 +C4 +331 +93 + 5 +93 +331 +80 + 5 +80 +331 +1C8 + 5 +1C9 +331 +150 + 5 +150 +331 +141 + 5 +141 +331 +251 + 5 +252 +331 +2D8 + 5 +2D9 +331 +260 + 5 +261 +331 +1B9 + 5 +1B9 +331 +E9 + 5 +E9 +331 +282 + 5 +283 +331 +1FA + 5 +1FB +331 +92 + 5 +92 +331 +273 + 5 +274 +331 +2EB + 5 +2EC +331 +1EB + 5 +1EC +331 +2A4 + 5 +2A5 +331 +31C + 5 +31D +331 +21C + 5 +21D +331 +184 + 5 +184 +331 +10C + 5 +10C +331 +295 + 5 +296 +331 +20D + 5 +20E +331 +12E + 5 +12F +331 +2C6 + 5 +2C7 +331 +23E + 5 +23F +331 +1A6 + 5 +1A6 +331 +11F + 5 +120 +331 +D6 + 5 +D6 +331 +2B7 + 5 +2B8 +331 +22F + 5 +230 +331 +C7 + 5 +C7 +331 +A5 + 5 +A5 +331 +83 + 5 +83 +331 +140 + 5 +140 +331 +250 + 5 +251 +331 +1B8 + 5 +1B8 +331 +131 + 5 +132 +331 +E8 + 5 +E8 +331 +2C9 + 5 +2CA +331 +241 + 5 +242 +331 +1CB + 5 +1CC +331 +D9 + 5 +D9 +331 +272 + 5 +273 +331 +2EA + 5 +2EB +331 +1EA + 5 +1EB +331 +2DB + 5 +2DC +331 +263 + 5 +264 +331 +294 + 5 +295 +331 +20C + 5 +20D +331 +A4 + 5 +A4 +331 +285 + 5 +286 +331 +1FD + 5 +1FE +331 +11E + 5 +11F +331 +2B6 + 5 +2B7 +331 +22E + 5 +22F +331 +10F + 5 +10F +331 +C6 + 5 +C6 +331 +2A7 + 5 +2A8 +331 +31F + 5 +320 +331 +21F + 5 +220 +331 +187 + 5 +187 +331 +B7 + 5 +B7 +331 +95 + 5 +95 +331 +82 + 5 +82 +331 +130 + 5 +131 +331 +2C8 + 5 +2C9 +331 +240 + 5 +241 +331 +D8 + 5 +D8 +331 +2B9 + 5 +2BA +331 +231 + 5 +232 +331 +1CA + 5 +1CB +331 +199 + 5 +199 +331 +143 + 5 +143 +331 +253 + 5 +254 +331 +2DA + 5 +2DB +331 +262 + 5 +263 +331 +1DD + 5 +1DE +331 +1BB + 5 +1BB +331 +EB + 5 +EB +331 +C9 + 5 +C9 +331 +284 + 5 +285 +331 +1FC + 5 +1FD +331 +94 + 5 +94 +331 +275 + 5 +276 +331 +2ED + 5 +2EE +331 +1ED + 5 +1EE +331 +2A6 + 5 +2A7 +331 +31E + 5 +31F +331 +21E + 5 +21F +331 +186 + 5 +186 +331 +FF + 5 +FF +331 +297 + 5 +298 +331 +20F + 5 +210 +331 +A7 + 5 +A7 +331 +85 + 5 +85 +331 +2B8 + 5 +2B9 +331 +230 + 5 +231 +331 +111 + 5 +111 +331 +C8 + 5 +C8 +331 +2A9 + 5 +2AA +331 +221 + 5 +222 +331 +142 + 5 +142 +331 +252 + 5 +253 +331 +133 + 5 +134 +331 +EA + 5 +EA +331 +2CB + 5 +2CC +331 +243 + 5 +244 +331 +1DC + 5 +1DD +331 +1AB + 5 +1AB +331 +1CD + 5 +1CE +331 +DB + 5 +DB +331 +B9 + 5 +B9 +331 +274 + 5 +275 +331 +2EC + 5 +2ED +331 +1EC + 5 +1ED +331 +2DD + 5 +2DE +331 +265 + 5 +266 +331 +296 + 5 +297 +331 +20E + 5 +20F +331 +A6 + 5 +A6 +331 +287 + 5 +288 +331 +1FF + 5 +200 +331 +97 + 5 +97 +331 +84 + 5 +84 +331 +110 + 5 +110 +331 +2A8 + 5 +2A9 +331 +320 + 5 +321 +331 +220 + 5 +221 +331 +188 + 5 +188 +331 +B8 + 5 +B8 +331 +299 + 5 +29A +331 +311 + 5 +312 +331 +211 + 5 +212 +331 +179 + 5 +179 +331 +2CA + 5 +2CB +331 +242 + 5 +243 +331 +123 + 5 +124 +331 +DA + 5 +DA +331 +2BB + 5 +2BC +331 +233 + 5 +234 +331 +1CC + 5 +1CD +331 +145 + 5 +145 +331 +255 + 5 +256 +331 +1BD + 5 +1BD +331 +2DC + 5 +2DD +331 +264 + 5 +265 +331 +167 + 5 +167 +331 +ED + 5 +ED +331 +CB + 5 +CB +331 +A9 + 5 +A9 +331 +286 + 5 +287 +331 +1FE + 5 +1FF +331 +96 + 5 +96 +331 +277 + 5 +278 +331 +2EF + 5 +2F0 +331 +1EF + 5 +1F0 +331 +87 + 5 +87 +331 +298 + 5 +299 +331 +310 + 5 +311 +331 +210 + 5 +211 +331 +F1 + 5 +F1 +331 +A8 + 5 +A8 +331 +289 + 5 +28A +331 +201 + 5 +202 +331 +169 + 5 +169 +331 +122 + 5 +123 +331 +2BA + 5 +2BB +331 +232 + 5 +233 +331 +113 + 5 +113 +331 +CA + 5 +CA +331 +2AB + 5 +2AC +331 +323 + 5 +324 +331 +223 + 5 +224 +331 +18B + 5 +18B +331 +144 + 5 +144 +331 +254 + 5 +255 +331 +2CD + 5 +2CE +331 +245 + 5 +246 +331 +1BC + 5 +1BC +331 +1DE + 5 +1DF +331 +1CF + 5 +1D0 +331 +1AD + 5 +1AD +331 +EC + 5 +EC +331 +BB + 5 +BB +331 +99 + 5 +99 +331 +276 + 5 +277 +331 +2EE + 5 +2EF +331 +1EE + 5 +1EF +331 +2DF + 5 +2E0 +331 +267 + 5 +268 +331 +86 + 5 +86 +331 +F0 + 5 +F0 +331 +288 + 5 +289 +331 +200 + 5 +201 +331 +168 + 5 +168 +331 +98 + 5 +98 +331 +279 + 5 +27A +331 +2F1 + 5 +2F2 +331 +1F1 + 5 +1F2 +331 +112 + 5 +112 +331 +2AA + 5 +2AB +331 +322 + 5 +323 +331 +222 + 5 +223 +331 +BA + 5 +BA +331 +29B + 5 +29C +331 +213 + 5 +214 +331 +17B + 5 +17B +331 +134 + 5 +11B +331 +2CC + 5 +2CD +331 +244 + 5 +245 +331 +125 + 5 +126 +331 +DC + 5 +DC +331 +2BD + 5 +2BE +331 +235 + 5 +236 +331 +1CE + 5 +1CF +331 +19D + 5 +19D +331 +147 + 5 +147 +331 +257 + 5 +258 +331 +2DE + 5 +2DF +331 +1BF + 5 +1C0 +331 +EF + 5 +EF +331 +CD + 5 +CD +331 +AB + 5 +AB +331 +89 + 5 +89 +331 +278 + 5 +279 +331 +2F0 + 5 +2F1 +331 +1F0 + 5 +1F1 +331 +88 + 5 +88 +331 +269 + 5 +26A +331 +2E1 + 5 +2E2 +331 +1E1 + 5 +1E2 +331 +29A + 5 +29B +331 +312 + 5 +313 +331 +212 + 5 +213 +331 +17A + 5 +17A +331 +AA + 5 +AA +331 +28B + 5 +28C +331 +203 + 5 +204 +331 +16B + 5 +16B +331 +124 + 5 +125 +331 +2BC + 5 +2BD +331 +234 + 5 +235 +331 +115 + 5 +115 +331 +225 + 5 +226 +331 +18D + 5 +18D +331 +146 + 5 +146 +331 +256 + 5 +257 +331 +137 + 5 +137 +331 +EE + 5 +EE +331 +2CF + 5 +2D0 +331 +247 + 5 +248 +331 +1AF + 5 +1AF +331 +1D1 + 5 +1D2 +331 +159 + 5 +159 +331 +DF + 5 +DF +331 +BD + 5 +BD +331 +9B + 5 +9B +331 +79 + 5 +79 +331 +268 + 5 +269 +331 +2E0 + 5 +2E1 +331 +1E0 + 5 +1E1 +331 +2D1 + 5 +2D2 +331 +28A + 5 +28B +331 +202 + 5 +203 +331 +16A + 5 +16A +331 +9A + 5 +9A +331 +27B + 5 +27C +331 +2F3 + 5 +2F4 +331 +1F3 + 5 +1F4 +331 +114 + 5 +114 +331 +2AC + 5 +2AD +331 +224 + 5 +225 +331 +324 + 5 +1BF +331 +18C + 5 +18C +331 +105 + 5 +105 +331 +BC + 5 +BC +331 +29D + 5 +29E +331 +215 + 5 +216 +331 +17D + 5 +17D +331 +2CE + 5 +2CF +331 +246 + 5 +247 +331 +1AE + 5 +1AE +331 +237 + 5 +238 +331 +1D0 + 5 +1D1 +331 +19F + 5 +19F +331 +1C1 + 5 +1C2 +331 +149 + 5 +149 +331 +127 + 5 +128 +331 +DE + 5 +DE +331 +AD + 5 +AD +331 +8B + 5 +8B +331 +78 + 5 +78 +331 +2D0 + 5 +2D1 +331 +258 + 5 +259 +331 +27A + 5 +27B +331 +2F2 + 5 +2F3 +331 +1F2 + 5 +1F3 +331 +8A + 5 +8A +331 +26B + 5 +26C +331 +2E3 + 5 +2E4 +331 +104 + 5 +104 +331 +29C + 5 +29D +331 +214 + 5 +215 +331 +17C + 5 +17C +331 +AC + 5 +AC +331 +28D + 5 +28E +331 +205 + 5 +206 +331 +16D + 5 +16D +331 +126 + 5 +127 +331 +2BE + 5 +2BF +331 +236 + 5 +237 +331 +19E + 5 +19E +331 +117 + 5 +117 +331 +2AF + 5 +2B0 +331 +227 + 5 +228 +331 +1C0 + 5 +1C1 +331 +148 + 5 +148 +331 +139 + 5 +139 +331 +249 + 5 +24A +331 +1B1 + 5 +1B1 +331 +1D3 + 5 +1D4 +331 +15B + 5 +15B +331 +E1 + 5 +E1 +331 +BF + 5 +BF +331 +9D + 5 +9D +331 +7B + 5 +7B +331 +26A + 5 +26B +331 +2E2 + 5 +2E3 +331 +1E2 + 5 +1E3 +331 +7A + 5 +7A +331 +2D3 + 5 +2D4 +331 +25B + 5 +25C +331 +28C + 5 +28D +331 +204 + 5 +205 +331 +16C + 5 +16C +331 +9C + 5 +9C +331 +27D + 5 +27E +331 +2F5 + 5 +2F6 +331 +1F5 + 5 +1F6 +331 +116 + 5 +116 +331 +2AE + 5 +2AF +331 +226 + 5 +227 +331 +18E + 5 +18E +331 +107 + 5 +107 +331 +BE + 5 +BE +331 +29F + 5 +2A0 +331 +317 + 5 +318 +331 +217 + 5 +218 +331 +17F + 5 +17F +331 +138 + 5 +138 +331 +248 + 5 +249 +331 +1B0 + 5 +1B0 +331 +129 + 5 +12A +331 +E0 + 5 +E0 +331 +239 + 5 +23A +331 +1A1 + 5 +1A1 +331 +1D2 + 5 +1D3 +331 +15A + 5 +15A +331 +1C3 + 5 +1C4 +331 +14B + 5 +14B +331 +D1 + 5 +D1 +331 +AF + 5 +AF +331 +8D + 5 +8D +331 +73 + 5 +73 +331 +2D2 + 5 +2D3 +331 +25A + 5 +25B +331 +27C + 5 +27D +331 +2F4 + 5 +2F5 +331 +1F4 + 5 +1F5 +331 +8C + 5 +8C +331 +26D + 5 +26E +331 +2E5 + 5 +2E6 +331 +1E5 + 5 +1E6 +331 +106 + 5 +106 +331 +216 + 5 +217 +331 +AE + 5 +AE +331 +28F + 5 +290 +331 +307 + 5 +308 +331 +207 + 5 +208 +331 +16F + 5 +16F +331 +238 + 5 +239 +331 +1A0 + 5 +1A0 +331 +119 + 5 +119 +331 +D0 + 5 +D0 +331 +2B1 + 5 +2B2 +331 +229 + 5 +22A +331 +1C2 + 5 +1C3 +331 +14A + 5 +14A +331 +13B + 5 +13B +331 +24B + 5 +24C +331 +1B3 + 5 +1B3 +331 +15D + 5 +15D +331 +E3 + 5 +E3 +331 +C1 + 5 +C1 +331 +9F + 5 +9F +331 +7D + 5 +7D +331 +26C + 5 +26D +331 +2E4 + 5 +2E5 +331 +1E4 + 5 +1E5 +331 +7C + 5 +7C +331 +2D5 + 5 +2D6 +331 +25D + 5 +25E +331 +28E + 5 +28F +331 +206 + 5 +207 +331 +16E + 5 +16E +331 +9E + 5 +9E +331 +27F + 5 +280 +331 +2F7 + 5 +2F8 +331 +1F7 + 5 +1F8 +331 +118 + 5 +118 +331 +2B0 + 5 +2B1 +331 +228 + 5 +229 +331 +2A1 + 5 +2A2 +331 +319 + 5 +31A +331 +219 + 5 +21A +331 +181 + 5 +181 +331 +13A + 5 +13A +331 +109 + 5 +109 +331 +24A + 5 +24B +331 +1B2 + 5 +1B2 +331 +12B + 5 +12C +331 +E2 + 5 +E2 +331 +23B + 5 +23C +331 +1A3 + 5 +1A3 +331 +1D4 + 5 +1D6 +331 +15C + 5 +15C +331 +14D + 5 +14D +331 +D3 + 5 +D3 +331 +C0 + 5 +C0 +331 +8F + 5 +8F +331 +75 + 5 +75 +331 +2D4 + 5 +2D5 +331 +25C + 5 +25D +331 +27E + 5 +27F +331 +2F6 + 5 +2F7 +331 +1F6 + 5 +1F7 +331 +8E + 5 +8E +331 +26F + 5 +270 +331 +2E7 + 5 +2E8 +331 +1E7 + 5 +1E8 +331 +2A0 + 5 +2A1 +331 +318 + 5 +319 +331 +218 + 5 +219 +331 +180 + 5 +180 +331 +108 + 5 +108 +331 +F9 + 5 +F9 +331 +291 + 5 +292 +331 +309 + 5 +30A +331 +209 + 5 +20A +331 +171 + 5 +171 +331 +12A + 5 +12B +331 +2C2 + 5 +2C3 +331 +23A + 5 +23B +331 +1A2 + 5 +1A2 +331 +11B + 5 +11C +331 +D2 + 5 +D2 +331 +2B3 + 5 +2B4 +331 +22B + 5 +22C +331 +14C + 5 +14C +331 +24D + 5 +24E +331 +1D7 + 5 +1DC +331 +1B5 + 5 +1B5 +331 +13D + 5 +13D +331 +C3 + 5 +C3 +331 +A1 + 5 +A1 +331 +7F + 5 +7F +331 +74 + 5 +74 +331 +26E + 5 +26F +331 +2E6 + 5 +2E7 +331 +1E6 + 5 +1E7 +331 +7E + 5 +7E +331 +2D7 + 5 +2D8 +331 +25F + 5 +260 +331 +290 + 5 +291 +331 +308 + 5 +309 +331 +208 + 5 +209 +331 +170 + 5 +170 +331 +A0 + 5 +A0 +331 +281 + 5 +282 +331 +2F9 + 5 +2FA +331 +1F9 + 5 +1FA +331 +11A + 5 +11A +331 +2B2 + 5 +2B3 +331 +22A + 5 +22B +331 +2A3 + 5 +2A4 +331 +21B + 5 +21C +331 +183 + 5 +183 +331 +13C + 5 +13C +331 +10B + 5 +10B +331 +24C + 5 +24D +331 +1B4 + 5 +1B4 +331 +12D + 5 +12E +331 +E4 + 5 +E4 +331 +2C5 + 5 +2C6 +331 +23D + 5 +23E +331 +1A5 + 5 +1A5 +331 +1D6 + 5 +1D7 +331 +15E + 5 +15E +331 +1C7 + 5 +1C8 +331 +14F + 5 +14F +331 +D5 + 5 +D5 +331 +C2 + 5 +C2 +331 +91 + 5 +91 +331 +77 + 5 +77 + 0 +ACDBDETAILVIEWSTYLE + 5 +6A +102 +{ACAD_REACTORS +330 +69 +102 +} +330 +69 +100 +AcDbModelDocViewStyle + 70 + 0 + 3 +Imperial24 +290 + 0 +300 +Imperial24 + 90 + 0 +100 +AcDbDetailViewStyle + 70 + 0 + 71 + 0 + 90 + 3 + 71 + 1 +340 +55 + 62 + 256 + 40 +0.24 +340 +0 + 62 + 256 + 40 +0.24 +300 + + 40 +0.36 +280 + 3 + 71 + 2 +340 +5C + 90 + 25 + 62 + 256 + 71 + 3 +340 +55 + 62 + 256 + 40 +0.24 + 90 + 1 + 40 +0.75 + 90 + 1 +300 +%<\AcVar ViewType \f "%tc1">% %<\AcVar ViewDetailId>%\PSCALE %<\AcVar ViewScale \f "%sn">% + 71 + 4 +340 +5C + 90 + 25 + 62 + 256 +340 +5C + 90 + 25 + 62 + 256 +280 + 0 + 0 +LAYOUT + 5 +6E +102 +{ACAD_REACTORS +330 +61 +102 +} +330 +61 +100 +AcDbPlotSettings + 1 + + 2 + + 4 + + 6 + + 40 +0.0 + 41 +0.0 + 42 +0.0 + 43 +0.0 + 44 +0.0 + 45 +0.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 + 49 +0.0 +140 +0.0 +141 +0.0 +142 +1.0 +143 +1.0 + 70 + 688 + 72 + 0 + 73 + 0 + 74 + 5 + 7 + + 75 + 16 +147 +1.0 + 76 + 0 + 77 + 2 + 78 + 300 +148 +0.0 +149 +0.0 +100 +AcDbLayout + 1 +Layout1 + 70 + 1 + 71 + 1 + 10 +0.0 + 20 +0.0 + 11 +12.0 + 21 +9.0 + 12 +0.0 + 22 +0.0 + 32 +0.0 + 14 +1.000000000000000E+20 + 24 +1.000000000000000E+20 + 34 +1.000000000000000E+20 + 15 +-1.000000000000000E+20 + 25 +-1.000000000000000E+20 + 35 +-1.000000000000000E+20 +146 +0.0 + 13 +0.0 + 23 +0.0 + 33 +0.0 + 16 +1.0 + 26 +0.0 + 36 +0.0 + 17 +0.0 + 27 +1.0 + 37 +0.0 + 76 + 0 +330 +6B + 0 +LAYOUT + 5 +72 +102 +{ACAD_REACTORS +330 +61 +102 +} +330 +61 +100 +AcDbPlotSettings + 1 + + 2 + + 4 + + 6 + + 40 +0.0 + 41 +0.0 + 42 +0.0 + 43 +0.0 + 44 +0.0 + 45 +0.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 + 49 +0.0 +140 +0.0 +141 +0.0 +142 +1.0 +143 +1.0 + 70 + 1712 + 72 + 0 + 73 + 0 + 74 + 0 + 7 + + 75 + 0 +147 +1.0 + 76 + 0 + 77 + 2 + 78 + 300 +148 +0.0 +149 +0.0 +100 +AcDbLayout + 1 +Model + 70 + 1 + 71 + 0 + 10 +0.0 + 20 +0.0 + 11 +12.0 + 21 +9.0 + 12 +0.0 + 22 +0.0 + 32 +0.0 + 14 +0.0 + 24 +0.0 + 34 +0.0 + 15 +0.0 + 25 +0.0 + 35 +0.0 +146 +0.0 + 13 +0.0 + 23 +0.0 + 33 +0.0 + 16 +1.0 + 26 +0.0 + 36 +0.0 + 17 +0.0 + 27 +1.0 + 37 +0.0 + 76 + 0 +330 +6F +331 +B3 + 0 +MATERIAL + 5 +19 +102 +{ACAD_XDICTIONARY +360 +1A +102 +} +102 +{ACAD_REACTORS +330 +10 +102 +} +330 +10 +100 +AcDbMaterial + 1 +ByBlock + 72 + 0 + 43 +0.0208333333333333 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0208333333333333 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +1.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +1.0 + 77 + 0 + 47 +0.0208333333333333 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0208333333333333 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +1.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +1.0 +171 + 0 + 49 +0.0208333333333333 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0208333333333333 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +1.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +1.0 +175 + 0 +142 +0.0208333333333333 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0208333333333333 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +1.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +1.0 +179 + 0 +144 +0.0208333333333333 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0208333333333333 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +1.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +1.0 +147 +0.0208333333333333 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0208333333333333 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +1.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +1.0 + 0 +MATERIAL + 5 +11 +102 +{ACAD_XDICTIONARY +360 +12 +102 +} +102 +{ACAD_REACTORS +330 +10 +102 +} +330 +10 +100 +AcDbMaterial + 1 +ByLayer + 72 + 0 + 43 +0.0208333333333333 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0208333333333333 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +1.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +1.0 + 77 + 0 + 47 +0.0208333333333333 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0208333333333333 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +1.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +1.0 +171 + 0 + 49 +0.0208333333333333 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0208333333333333 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +1.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +1.0 +175 + 0 +142 +0.0208333333333333 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0208333333333333 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +1.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +1.0 +179 + 0 +144 +0.0208333333333333 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0208333333333333 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +1.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +1.0 +147 +0.0208333333333333 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0208333333333333 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +1.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +1.0 + 0 +MATERIAL + 5 +21 +102 +{ACAD_XDICTIONARY +360 +22 +102 +} +102 +{ACAD_REACTORS +330 +10 +102 +} +330 +10 +100 +AcDbMaterial + 1 +Global + 72 + 0 + 43 +0.0208333333333333 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0208333333333333 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +1.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +1.0 + 77 + 0 + 47 +0.0208333333333333 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0208333333333333 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +1.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +1.0 +171 + 0 + 49 +0.0208333333333333 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0208333333333333 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +1.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +1.0 +175 + 0 +142 +0.0208333333333333 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0208333333333333 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +1.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +1.0 +179 + 0 +144 +0.0208333333333333 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0208333333333333 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +1.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +1.0 +147 +0.0208333333333333 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0208333333333333 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +1.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +1.0 + 0 +MLEADERSTYLE + 5 +66 +102 +{ACAD_REACTORS +330 +65 +102 +} +330 +65 +100 +AcDbMLeaderStyle +179 + 2 +170 + 2 +171 + 1 +172 + 0 + 90 + 2 + 40 +0.0 + 41 +0.0 +173 + 1 + 91 +-1056964608 +340 +5A + 92 + -2 +290 + 1 + 42 +0.09 +291 + 1 + 43 +0.36 + 3 +Standard + 44 +0.18 +300 + +342 +55 +174 + 1 +178 + 6 +175 + 1 +176 + 0 + 93 +-1056964608 + 45 +0.18 +292 + 0 +297 + 0 + 46 +0.18 + 94 +-1056964608 + 47 +1.0 + 49 +1.0 +140 +1.0 +293 + 1 +141 +0.0 +294 + 1 +177 + 0 +142 +1.0 +295 + 0 +296 + 0 +143 +0.125 +271 + 0 +272 + 9 +273 + 9 +298 + 0 + 0 +MLINESTYLE + 5 +5F +102 +{ACAD_REACTORS +330 +5E +102 +} +330 +5E +100 +AcDbMlineStyle + 2 +STANDARD + 70 + 0 + 3 + + 62 + 256 + 51 +90.0 + 52 +90.0 + 71 + 2 + 49 +0.5 + 62 + 256 + 6 +BYLAYER + 49 +-0.5 + 62 + 256 + 6 +BYLAYER + 0 +ACDBPLACEHOLDER + 5 +F +102 +{ACAD_REACTORS +330 +E +102 +} +330 +E + 0 +SCALE + 5 +43 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1:1 +140 +1.0 +141 +1.0 +290 + 1 + 0 +SCALE + 5 +44 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1/128" = 1'-0" +140 +0.0078125 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +45 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1/64" = 1'-0" +140 +0.015625 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +46 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1/32" = 1'-0" +140 +0.03125 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +47 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1/16" = 1'-0" +140 +0.0625 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +48 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +3/32" = 1'-0" +140 +0.09375 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +49 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1/8" = 1'-0" +140 +0.125 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +4A +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +3/16" = 1'-0" +140 +0.1875 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +4B +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1/4" = 1'-0" +140 +0.25 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +4C +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +3/8" = 1'-0" +140 +0.375 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +4D +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1/2" = 1'-0" +140 +0.5 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +4E +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +3/4" = 1'-0" +140 +0.75 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +4F +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1" = 1'-0" +140 +1.0 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +50 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1-1/2" = 1'-0" +140 +1.5 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +51 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +3" = 1'-0" +140 +3.0 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +52 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +6" = 1'-0" +140 +6.0 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +53 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1'-0" = 1'-0" +140 +12.0 +141 +12.0 +290 + 0 + 0 +ACDBSECTIONVIEWSTYLE + 5 +68 +102 +{ACAD_REACTORS +330 +67 +102 +} +330 +67 +100 +AcDbModelDocViewStyle + 70 + 0 + 3 +Imperial24 +290 + 0 +300 +Imperial24 + 90 + 0 +100 +AcDbSectionViewStyle + 70 + 0 + 71 + 0 + 90 + 78 + 71 + 1 +340 +55 + 62 + 256 + 40 +0.24 +340 +0 +340 +0 + 62 + 256 + 40 +0.24 +300 +I, O, Q, S, X, Z + 40 +0.48 + 90 + 3 + 40 +0.18 + 90 + 1 + 71 + 2 +340 +5C + 90 + 25 + 62 + 256 +340 +5C + 90 + 50 + 62 + 256 + 40 +0.24 + 40 +0.0 + 40 +0.24 + 71 + 3 +340 +55 + 62 + 256 + 40 +0.24 + 90 + 1 + 40 +0.75 + 90 + 1 +300 +%<\AcVar ViewType \f "%tc1">% %<\AcVar ViewSectionStartId>%-%<\AcVar ViewSectionEndId>%\PSCALE %<\AcVar ViewScale \f "%sn">% + 71 + 4 + 62 + 256 + 62 + 257 +300 +ANSI31 + 40 +1.0 + 90 + 0 +290 + 0 +290 + 0 + 90 + 6 + 40 +0.0 + 40 +1.570796326794896 + 40 +0.2617993877991494 + 40 +1.308996938995747 + 40 +-0.2617993877991494 + 40 +1.832595714594046 + 0 +TABLESTYLE + 5 +64 +102 +{ACAD_XDICTIONARY +360 +656 +102 +} +102 +{ACAD_REACTORS +330 +63 +102 +} +330 +63 +100 +AcDbTableStyle +280 + 0 + 3 +Standard + 70 + 0 + 71 + 0 + 40 +0.06 + 41 +0.06 +280 + 0 +281 + 0 + 7 +Standard +140 +0.18 +170 + 2 + 62 + 0 + 63 + 7 +283 + 0 + 90 + 512 + 91 + 0 + 1 + +274 + -2 +284 + 1 + 64 + 0 +275 + -2 +285 + 1 + 65 + 0 +276 + -2 +286 + 1 + 66 + 0 +277 + -2 +287 + 1 + 67 + 0 +278 + -2 +288 + 1 + 68 + 0 +279 + -2 +289 + 1 + 69 + 0 + 7 +Standard +140 +0.25 +170 + 5 + 62 + 0 + 63 + 7 +283 + 0 + 90 + 512 + 91 + 0 + 1 + +274 + -2 +284 + 1 + 64 + 0 +275 + -2 +285 + 1 + 65 + 0 +276 + -2 +286 + 1 + 66 + 0 +277 + -2 +287 + 1 + 67 + 0 +278 + -2 +288 + 1 + 68 + 0 +279 + -2 +289 + 1 + 69 + 0 + 7 +Standard +140 +0.18 +170 + 5 + 62 + 0 + 63 + 7 +283 + 0 + 90 + 512 + 91 + 0 + 1 + +274 + -2 +284 + 1 + 64 + 0 +275 + -2 +285 + 1 + 65 + 0 +276 + -2 +286 + 1 + 66 + 0 +277 + -2 +287 + 1 + 67 + 0 +278 + -2 +288 + 1 + 68 + 0 +279 + -2 +289 + 1 + 69 + 0 + 0 +VISUALSTYLE + 5 +2F +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +2dWireframe + 70 + 4 +177 + 3 +291 + 0 + 70 + 58 + 90 + 0 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +2E +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Basic + 70 + 7 +177 + 3 +291 + 1 + 70 + 58 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 0 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +35 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Brighten + 70 + 12 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +50.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +39 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +ColorChange + 70 + 16 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 8 +420 + 8421504 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 8 +420 + 8421504 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +32 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Conceptual + 70 + 9 +177 + 3 +291 + 0 + 70 + 58 + 90 + 3 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +179.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +34 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Dim + 70 + 11 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +-50.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +41 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +EdgeColorOff + 70 + 22 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 0 + 90 + 2 +176 + 0 + 90 + 0 +176 + 0 + 90 + 0 +176 + 0 + 40 +0.6 +176 + 0 + 40 +30.0 +176 + 0 + 62 + 7 +420 + 16777215 +176 + 0 + 90 + 1 +176 + 0 + 90 + 4 +176 + 0 + 62 + 7 +176 + 0 + 62 + 257 +176 + 0 + 90 + 1 +176 + 0 + 90 + 1 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 8 +176 + 2 + 62 + 7 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 1 +176 + 0 + 90 + 6 +176 + 0 + 90 + 2 +176 + 0 + 62 + 7 +176 + 0 + 90 + 5 +176 + 0 + 90 + 0 +176 + 0 + 90 + 0 +176 + 0 +290 + 0 +176 + 0 + 90 + 1 +176 + 0 + 40 +0.0 +176 + 0 + 90 + 0 +176 + 0 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 0 + 40 +0.0 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 0 +176 + 0 + 62 + 18 +420 + 0 +176 + 0 + 90 + 50 +176 + 0 + 90 + 3 +176 + 0 + 62 + 5 +420 + 255 +176 + 0 +290 + 0 +176 + 1 + 90 + 50 +176 + 0 + 90 + 50 +176 + 0 + 90 + 50 +176 + 0 +290 + 0 +176 + 1 + 90 + 50 +176 + 0 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 0 + 1 +strokes_ogs.tif +176 + 0 +290 + 0 +176 + 1 + 40 +1.0 +176 + 0 + 40 +1.0 +176 + 0 + 0 +VISUALSTYLE + 5 +38 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Facepattern + 70 + 15 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +2A +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Flat + 70 + 0 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 13 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +2B +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +FlatWithEdges + 70 + 1 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 13 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +2C +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Gouraud + 70 + 2 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 13 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +2D +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +GouraudWithEdges + 70 + 3 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 13 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +31 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Hidden + 70 + 6 +177 + 3 +291 + 0 + 70 + 58 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 40 +40.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +3F +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +JitterOff + 70 + 20 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 0 + 90 + 2 +176 + 0 + 90 + 0 +176 + 0 + 90 + 0 +176 + 0 + 40 +0.6 +176 + 0 + 40 +30.0 +176 + 0 + 62 + 7 +420 + 16777215 +176 + 0 + 90 + 1 +176 + 0 + 90 + 4 +176 + 0 + 62 + 7 +176 + 0 + 62 + 257 +176 + 0 + 90 + 1 +176 + 0 + 90 + 1 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 10 +176 + 2 + 62 + 7 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 1 +176 + 0 + 90 + 6 +176 + 0 + 90 + 2 +176 + 0 + 62 + 7 +176 + 0 + 90 + 5 +176 + 0 + 90 + 0 +176 + 0 + 90 + 0 +176 + 0 +290 + 0 +176 + 0 + 90 + 1 +176 + 0 + 40 +0.0 +176 + 0 + 90 + 0 +176 + 0 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 0 + 40 +0.0 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 0 +176 + 0 + 62 + 18 +420 + 0 +176 + 0 + 90 + 50 +176 + 0 + 90 + 3 +176 + 0 + 62 + 5 +420 + 255 +176 + 0 +290 + 0 +176 + 1 + 90 + 50 +176 + 0 + 90 + 50 +176 + 0 + 90 + 50 +176 + 0 +290 + 0 +176 + 1 + 90 + 50 +176 + 0 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 0 + 1 +strokes_ogs.tif +176 + 0 +290 + 0 +176 + 1 + 40 +1.0 +176 + 0 + 40 +1.0 +176 + 0 + 0 +VISUALSTYLE + 5 +37 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Linepattern + 70 + 14 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 7 +176 + 1 + 90 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +40 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +OverhangOff + 70 + 21 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 0 + 90 + 2 +176 + 0 + 90 + 0 +176 + 0 + 90 + 0 +176 + 0 + 40 +0.6 +176 + 0 + 40 +30.0 +176 + 0 + 62 + 7 +420 + 16777215 +176 + 0 + 90 + 1 +176 + 0 + 90 + 4 +176 + 0 + 62 + 7 +176 + 0 + 62 + 257 +176 + 0 + 90 + 1 +176 + 0 + 90 + 1 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 9 +176 + 2 + 62 + 7 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 1 +176 + 0 + 90 + 6 +176 + 0 + 90 + 2 +176 + 0 + 62 + 7 +176 + 0 + 90 + 5 +176 + 0 + 90 + 0 +176 + 0 + 90 + 0 +176 + 0 +290 + 0 +176 + 0 + 90 + 1 +176 + 0 + 40 +0.0 +176 + 0 + 90 + 0 +176 + 0 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 0 + 40 +0.0 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 0 +176 + 0 + 62 + 18 +420 + 0 +176 + 0 + 90 + 50 +176 + 0 + 90 + 3 +176 + 0 + 62 + 5 +420 + 255 +176 + 0 +290 + 0 +176 + 1 + 90 + 50 +176 + 0 + 90 + 50 +176 + 0 + 90 + 50 +176 + 0 +290 + 0 +176 + 1 + 90 + 50 +176 + 0 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 0 + 1 +strokes_ogs.tif +176 + 0 +290 + 0 +176 + 1 + 40 +1.0 +176 + 0 + 40 +1.0 +176 + 0 + 0 +VISUALSTYLE + 5 +33 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Realistic + 70 + 8 +177 + 3 +291 + 0 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 13 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +3E +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Shaded + 70 + 27 +177 + 3 +291 + 0 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 0 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 8 +420 + 7895160 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 5 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +3D +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Shaded with edges + 70 + 26 +177 + 3 +291 + 0 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 5 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +3A +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Shades of Gray + 70 + 23 +177 + 3 +291 + 0 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 62 + 7 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +40.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +3B +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Sketchy + 70 + 24 +177 + 3 +291 + 0 + 70 + 58 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 62 + 7 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +40.0 +176 + 1 + 90 + 11 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 6 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +36 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Thicken + 70 + 13 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 12 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +30 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Wireframe + 70 + 5 +177 + 3 +291 + 0 + 70 + 58 + 90 + 0 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +3C +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +X-Ray + 70 + 25 +177 + 3 +291 + 0 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.5 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 13 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +DICTIONARYVAR + 5 +351 +102 +{ACAD_REACTORS +330 +34B +102 +} +330 +34B +100 +DictionaryVariables +280 + 0 + 1 +1:1 + 0 +DICTIONARYVAR + 5 +34D +102 +{ACAD_REACTORS +330 +34B +102 +} +330 +34B +100 +DictionaryVariables +280 + 0 + 1 +STANDARD + 0 +DICTIONARYVAR + 5 +34C +102 +{ACAD_REACTORS +330 +34B +102 +} +330 +34B +100 +DictionaryVariables +280 + 0 + 1 +STANDARD + 0 +DICTIONARYVAR + 5 +34E +102 +{ACAD_REACTORS +330 +34B +102 +} +330 +34B +100 +DictionaryVariables +280 + 0 + 1 +Imperial24 + 0 +DICTIONARYVAR + 5 +34F +102 +{ACAD_REACTORS +330 +34B +102 +} +330 +34B +100 +DictionaryVariables +280 + 0 + 1 +Imperial24 + 0 +DICTIONARYVAR + 5 +353 +102 +{ACAD_REACTORS +330 +34B +102 +} +330 +34B +100 +DictionaryVariables +280 + 0 + 1 +1 + 0 +DICTIONARYVAR + 5 +354 +102 +{ACAD_REACTORS +330 +34B +102 +} +330 +34B +100 +DictionaryVariables +280 + 0 + 1 +15 + 0 +DICTIONARYVAR + 5 +352 +102 +{ACAD_REACTORS +330 +34B +102 +} +330 +34B +100 +DictionaryVariables +280 + 0 + 1 +0 + 0 +DICTIONARYVAR + 5 +350 +102 +{ACAD_REACTORS +330 +34B +102 +} +330 +34B +100 +DictionaryVariables +280 + 0 + 1 +0 + 0 +DICTIONARY + 5 +1A +330 +19 +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +BUMPTILE +360 +1C + 3 +DIFFUSETILE +360 +1B + 3 +OPACITYTILE +360 +1F + 3 +REFLECTIONTILE +360 +1E + 3 +REFRACTIONTILE +360 +20 + 3 +SPECULARTILE +360 +1D + 0 +DICTIONARY + 5 +12 +330 +11 +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +BUMPTILE +360 +14 + 3 +DIFFUSETILE +360 +13 + 3 +OPACITYTILE +360 +17 + 3 +REFLECTIONTILE +360 +16 + 3 +REFRACTIONTILE +360 +18 + 3 +SPECULARTILE +360 +15 + 0 +DICTIONARY + 5 +22 +330 +21 +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +BUMPTILE +360 +24 + 3 +DIFFUSETILE +360 +23 + 3 +OPACITYTILE +360 +27 + 3 +REFLECTIONTILE +360 +26 + 3 +REFRACTIONTILE +360 +28 + 3 +SPECULARTILE +360 +25 + 0 +DICTIONARY + 5 +656 +330 +64 +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +ACAD_ROUNDTRIP_2008_TABLESTYLE_CELLSTYLEMAP +360 +657 + 0 +XRECORD + 5 +1C +102 +{ACAD_REACTORS +330 +1A +102 +} +330 +1A +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +1B +102 +{ACAD_REACTORS +330 +1A +102 +} +330 +1A +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +1F +102 +{ACAD_REACTORS +330 +1A +102 +} +330 +1A +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +1E +102 +{ACAD_REACTORS +330 +1A +102 +} +330 +1A +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +20 +102 +{ACAD_REACTORS +330 +1A +102 +} +330 +1A +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +1D +102 +{ACAD_REACTORS +330 +1A +102 +} +330 +1A +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +14 +102 +{ACAD_REACTORS +330 +12 +102 +} +330 +12 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +13 +102 +{ACAD_REACTORS +330 +12 +102 +} +330 +12 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +17 +102 +{ACAD_REACTORS +330 +12 +102 +} +330 +12 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +16 +102 +{ACAD_REACTORS +330 +12 +102 +} +330 +12 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +18 +102 +{ACAD_REACTORS +330 +12 +102 +} +330 +12 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +15 +102 +{ACAD_REACTORS +330 +12 +102 +} +330 +12 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +24 +102 +{ACAD_REACTORS +330 +22 +102 +} +330 +22 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +23 +102 +{ACAD_REACTORS +330 +22 +102 +} +330 +22 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +27 +102 +{ACAD_REACTORS +330 +22 +102 +} +330 +22 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +26 +102 +{ACAD_REACTORS +330 +22 +102 +} +330 +22 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +28 +102 +{ACAD_REACTORS +330 +22 +102 +} +330 +22 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +25 +102 +{ACAD_REACTORS +330 +22 +102 +} +330 +22 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +CELLSTYLEMAP + 5 +657 +102 +{ACAD_REACTORS +330 +656 +102 +} +330 +656 +100 +AcDbCellStyleMap + 90 + 3 +300 +CELLSTYLE + 1 +TABLEFORMAT_BEGIN + 90 + 5 +170 + 1 + 91 + 0 + 92 + 32768 + 62 + 257 + 93 + 1 +300 +CONTENTFORMAT + 1 +CONTENTFORMAT_BEGIN + 90 + 0 + 91 + 0 + 92 + 512 + 93 + 0 +300 + + 40 +0.0 +140 +1.0 + 94 + 5 + 62 + 0 +340 +55 +144 +0.25 +309 +CONTENTFORMAT_END +171 + 0 + 94 + 0 +309 +TABLEFORMAT_END + 1 +CELLSTYLE_BEGIN + 90 + 1 + 91 + 1 +300 +_TITLE +309 +CELLSTYLE_END +300 +CELLSTYLE + 1 +TABLEFORMAT_BEGIN + 90 + 5 +170 + 1 + 91 + 0 + 92 + 0 + 62 + 257 + 93 + 1 +300 +CONTENTFORMAT + 1 +CONTENTFORMAT_BEGIN + 90 + 0 + 91 + 0 + 92 + 512 + 93 + 0 +300 + + 40 +0.0 +140 +1.0 + 94 + 5 + 62 + 0 +340 +55 +144 +0.18 +309 +CONTENTFORMAT_END +171 + 0 + 94 + 0 +309 +TABLEFORMAT_END + 1 +CELLSTYLE_BEGIN + 90 + 2 + 91 + 1 +300 +_HEADER +309 +CELLSTYLE_END +300 +CELLSTYLE + 1 +TABLEFORMAT_BEGIN + 90 + 5 +170 + 1 + 91 + 0 + 92 + 0 + 62 + 257 + 93 + 1 +300 +CONTENTFORMAT + 1 +CONTENTFORMAT_BEGIN + 90 + 0 + 91 + 0 + 92 + 512 + 93 + 0 +300 + + 40 +0.0 +140 +1.0 + 94 + 2 + 62 + 0 +340 +55 +144 +0.18 +309 +CONTENTFORMAT_END +171 + 0 + 94 + 0 +309 +TABLEFORMAT_END + 1 +CELLSTYLE_BEGIN + 90 + 3 + 91 + 2 +300 +_DATA +309 +CELLSTYLE_END + 0 +ENDSEC + 0 +SECTION + 2 +ACDSDATA + 70 + 2 + 71 + 8 + 0 +ACDSSCHEMA + 90 + 0 + 1 +AcDb_Thumbnail_Schema + 2 +AcDbDs::ID +280 + 10 + 91 + 8 + 2 +Thumbnail_Data +280 + 15 + 91 + 0 +101 +ACDSRECORD + 95 + 0 + 90 + 1 + 2 +AcDbDs::TreatedAsObjectData +280 + 1 +291 + 1 +101 +ACDSRECORD + 95 + 0 + 90 + 2 + 2 +AcDbDs::Legacy +280 + 1 +291 + 1 +101 +ACDSRECORD + 1 +AcDbDs::ID + 90 + 3 + 2 +AcDs:Indexable +280 + 1 +291 + 1 +101 +ACDSRECORD + 1 +AcDbDs::ID + 90 + 4 + 2 +AcDbDs::HandleAttribute +280 + 7 +282 + 1 + 0 +ACDSSCHEMA + 90 + 1 + 1 +AcDbDs::TreatedAsObjectDataSchema + 2 +AcDbDs::TreatedAsObjectData +280 + 1 + 91 + 0 + 0 +ACDSSCHEMA + 90 + 2 + 1 +AcDbDs::LegacySchema + 2 +AcDbDs::Legacy +280 + 1 + 91 + 0 + 0 +ACDSSCHEMA + 90 + 3 + 1 +AcDbDs::IndexedPropertySchema + 2 +AcDs:Indexable +280 + 1 + 91 + 0 + 0 +ACDSSCHEMA + 90 + 4 + 1 +AcDbDs::HandleAttributeSchema + 2 +AcDbDs::HandleAttribute +280 + 7 + 91 + 1 +284 + 1 + 0 +ACDSRECORD + 90 + 0 + 2 +AcDbDs::ID +280 + 10 +320 +72 + 2 +Thumbnail_Data +280 + 15 + 94 + 3606 +310 +89504E470D0A1A0A0000000D4948445200000100000000A50803000000840AD3BD00000300504C5445212830FFFFFF2128300000000000000000000000000000000000000000000000000000330000660000990000CC0000FF0033000033330033660033990033CC0033FF0066000066330066660066990066CC0066FF0099 +310 +000099330099660099990099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF0000FF3300FF6600FF9900FFCC00FFFF3300003300333300663300993300CC3300FF3333003333333333663333993333CC3333FF3366003366333366663366993366CC3366FF3399003399333399663399993399CC3399FF33CC00 +310 +33CC3333CC6633CC9933CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF6600006600336600666600996600CC6600FF6633006633336633666633996633CC6633FF6666006666336666666666996666CC6666FF6699006699336699666699996699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066 +310 +FF3366FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF9933009933339933669933999933CC9933FF9966009966339966669966999966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC3399CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFFCC0000CC00 +310 +33CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFFCCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0000FF0033FF0066FF0099FF00CCFF00FFFF3300FF3333 +310 +FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33FFCC66FFCC99FFCCCCFFCCFFFFFF00FFFF33FFFF66FFFF99FFFFCCFFFFFF0000000D0D0D1A1A1A2828283535354343435050505D5D5D6B6B6B787878868686939393A1A1A1AEAEAEBB +310 +BBBBC9C9C9D6D6D6E4E4E4F1F1F1FFFFFF0000000000000000000000000000000000000000000000000000000000002E4550F100000AD14944415478DAED9DDB7ADC360C84F1FEEF3BF7BDC8AE38FF80B29D7E962269C98BA475DCD404411C6606DCAACB2CD587AF8F37C0B2803EDD16FAB8FD6BFEAFFA98F3D7D402FA94A3 +310 +573B697D8CFBEB75FA9A7FF9F9DBD79FD3EF57E053B6FFE7ACFB7E3F62FFAFED57BF029AF8BF9EB7FF3203607F9A6D57CFDBFF6BA3D2A4F87BBC01F4B2C0F68BA224D0B30DA03FD1FFB57D8F82DA6907F428336C5EAF9729D436F86803684481F7E1BF7ED56E3FA4079588DBA51F8960FB7D72E79F6680D7C15B22788743D5 +310 +9E01C4D8A0DB5F7FDBBF4624DC6F8935AECDDD0DA057D0F3F4B7D5C33303E8BD46F2BCA301D48FDF9CE09508D52D355284BC44D43D0D206BFE6D677AF584E903329B8DFFF65D3FDC37EF6DF9DFCBA0DABD03304045BAD0CD6E40855B3BF2A1392CF476125F23336ADA375EF706680BE21AFBDBDCDF6B21310C9875861124DD +310 +0635D2386179DC6788DF22A17DF59D2A84AF6E15E43D0C6027EFBB6EADB0467E18DF3F5A86F1553652374A82F867CDCA5CA1D25179A10C03DC69FB3303A81C1016F76F113F0DB021881A8E7593E6072E4DFF15E12101342B868B6133E936D8B150C5BCEFF9D60D72FF16EEB7BCB07D55EFD487107283ED63EB722C00D591B7 +310 +C7621F60FDC2D8FEE56FC1EB902546F50CEB6E82D7D1E3775A0239F1E27760347106FFCBB76806F01A007DAFD74F337FB972E78F90A7490EE4F75863A8C81BD62E5900B8F205F03656F2F86EED8DF7054114F856C7DF4803086DF645B7AF2A5CFB8101A01218DF3F921F4A6245916CAE724537B052D532FDD6F8D7C87F7619 +310 +46681C6E63D71DC160408B57BC069EB98AF1CB8F8D1192316E04018DCE77DC046D7C8AAE481990F679C76B1C19208E11D0B69AC9AA4801064101AD51175D28273AEDE355CB56F3A180B16A6F34C4E34FE580B0125B9398232F51178D3374DAC7C980F45CC97D7F739871A8EDBA6FE5B4A282BC407F280F79A47D46F873AA63 +310 +14C706110BBC90C6252A7A0620B62B9820690FD23E2A730877E4F2E8E7B0AF5544C4C51C20F5303A01D83B3479F4FE9DF0F0A377436CF1CBCD52CE121BFEE9B97FD8766200014B3EDF00F2D6B6D13E02BE9F6DB2E11C88916269CCDA71BA1C82208FA2B3DCDFDB9A0DF2F568874EB03CCE032F0404EEDD83125D01A852492D +310 +EF63CC4740DF35A17DBC700F61A0F28C06645295189A5037B9FB4F0984DCB20E8EFE5B8E6BB40F2D529EDF4877AAB92D00D2E147BBBBE44E15B4C4C1C89F00654D681F5E7D23FBE53FE1CF8E12A039551715EE53A778806CFF4EFB94036216C23BE03961BFE6776060A98AE6389976F2E93AF0ECADBF99D03E860CB423AE59 +310 +9CD6D48DDD5980A7A8106D81A21E1EFCEA47B48FE23B2AC42EEA0668996D800756368ECA19D5A42591C3D964049ABE9B06EFCE62DD5E3EA7310A10A2E10BA3F35009ADF3090E10675F13325CD1D9E73F55C5558850EE95A3D14284898A8DF6E82F8EAE84B45F71F0CF334D894AC922FF81EB8124C11A93F120AEDE191EA089 +310 +13F7BB41984BD006740F50444113D6421D11F51F0AEC405F8EF3800C546E13F88654510008B9B27AEC0E5110F2A380BCAB100A81238B78F4AFEF5B931A8E91DF51020081CE050611E03CA11389C5146FA56175A911F414BF7705E26FA2EF9A08B6931FEE9EAE08A9D843E4C81990686201D3DE0B15D9B0085BED23BBA0F26A +310 +043805986F737AF77D870012F0291E22EA696B3A70A7786487B502AD139110B706B4AF6008AD7740CD509440A9A019823F089C79BB157E81EAB8FD23E9D86938004A329C45E3D00A96CBC09A52260BC24E427A99E824E2910668999D20A7835FAE8AF44E824A08A9FA90442265BC5056845AB71D94C171AD50B017EE1168E0 +310 +90FF58F56380320B656EC65914DC419F372530775815E4618711DCF7AF11F445F2B38A6532549213A8AC3CBE9277710B39E14E00ED8846B8A0DA7422B7880218D8A9FA5E0DDF0493211614CB48E60082003A7016D95D0D3AA7860238F759DFAAE15BEFC8B0E215EE88B48EC27B8516E2B3034280F8B314128F6747EBE9F6D5 +310 +F0ADE225D217C88B438BAA2E9E22C9769C053CD99722B17BA062A7E0DC61658F4CEC03F87761CA4806BB3615FEF19A4AA7EA0BDBB7E41CCC664B9C5FA8E1A3ED909AA984BA93D07A33F1818488B3F55EC11837D0045073357CC570915D6CEA4891F4CA61D1D11BBB1CB78E0C84A87CCB8FC67E8A718EC00E77D5F0AEAB055D +310 +A2E050C46A802D918E2745C07023CB95E7AE4C5354C3430BE089DE815F844E20EED1358CE2E1F83123FA80C880C44F9CE8463C21209CBFC79542CD986D2E206097E344DD7C6439EC099BC894C8FA89B478BAB247EEBDD84603C02812A090D219AA89361393D32F3302FB276AF81EDB3CAE5A928751440EF60CFDD450BE5BA8 +310 +4E4C203090E0CD70ED2115989E7509B9DF47CC2CDA9CA40C495D405292A99B54277A29064536534C5125E75621ADB53B70A67C6E3800077C2C034EAF8232FD830A8202A89470A21AF52DAFB689B99FA48FB1C8D3AAF40AD6BC122B6A9DEC8ECCA2DD3397E62B84D9670928A34AA93851474A03FEFD420D3FA7BEC97E26F718 +310 +22A3B36E8072FC0F92A8F8D1BCA70D070292C7D16AD451A5404BED7F550D3F3F2906FA152D0F465FAA3EECBB34A1BE890729439C729E26C42027CC97B2F776A14A8C3E29F1390EBF886A7182F9E2F015E4F4C416831D3AE9F00392953B63FEA44AD904026891F42F4E0CC5CCD9BCBB0E51D239812FE8BA06E8A53C9CDA078C +310 +96841ABE280D7628BA89A75C28A2130A604D1A63F93381D10D00A30BF82349DC16DD425E18D85FFAC909B324D25E472062BEE6C8D1B256A310C890A954A12E0C40A0F7BDE68A3A77FB0DE49023C0217E5012AB5D0D4F42201E9EF420CBD92429F431272E35051CB8DD89FA2388601AD7F37D506C22E292028D9322E00E3E5A +310 +5358122C6AED68237D77224B50607E434114E16EE799CE935C80905C6A9BD42B810A892CC4D0D5F875A06A21C4FEEE929E668050252803C477CC6FC5E86C8F6DC8217BA7AD7F1004C8D21AB09F7DF10EF38B71A3E87571417E3600A0F33DC047E4F8469604C01339CC107CBC1E33D11E63DA96D2C07FBFBA845D2168F0915F +310 +777947892805E8738813CEF03223933DB687A4C5A442F1B6000EBB1044013C03E4BA9801F27D1455F87A390DD4FE13BCAC01569CF45045C577A5D77438F518C783C93E95A274A83E0112F3507307B9D4FC78F062D6F5785914FD820D7C021129529E2D354C5EDEB99607B497C27CB681D46ED33D16F8D47D76E45A2160E201 +310 +C6EAF9CC200D10121A1A804F08B559B46B3DC59FF296E87330E5132C09852431171D89C5BBECAB3900B27B8AC4BD36267096F0A14702C602CA108F9580FEBF34E828B9F80E6A84B8D0C756BCB335354010AF357D8AF20A06988A3551C8CCB0644B1C7DF07EC68EE8626FEAA953251487A97A4F3F796CD6C135C57C503C9671 +310 +DDE7B4829BDD1D5F8A2701E403103153E5D335B841573540E9275A657F56D00B65764DDE4E4A670D44FFFEBDD8A7D5F28925E5749CFBC7E9DCF7C1D44A80E4B17D3EA50A16FE091FB880FDF0F1B5AAD600544D3E8FE4EE06C81931A2E83E0E10BCCBFDFDBFAA7FDC9A889EA1F46DEF6C3DE10ECCC61DB726A9BD3618EFF2D5 +310 +E3AE00E66B85F767DB8353F51C03B48A08A2378C57DEED51E9BF2A131C2C76DD77710AF24EEFAAFFAD01381E335308B89CFC710600D1998C5F3CA2F09C8F1E532F8A82EEEEA0D3931CA07FBCD4D70D8E1E5300ED18E0874F3E3DC8049AB486BFD265DE32067CF8A7AE7FFC87CEAFB5D65A6BADB5D65A6BADB5D65A6BADB5D6 +310 +5A6BADB5D65A6BADB5D65A6BADB5D65A6BADB5D65A6BADB5D65A07AEFF00554FE27454DCB1F00000000049454E44AE426082 + 0 +ENDSEC + 0 +EOF diff --git a/testdata/barnsbury_extended1_axial.graph b/testdata/barnsbury_extended1_axial.graph new file mode 100644 index 00000000..ca2e3909 Binary files /dev/null and b/testdata/barnsbury_extended1_axial.graph differ diff --git a/testdata/barnsbury_extended1_segment.graph b/testdata/barnsbury_extended1_segment.graph new file mode 100644 index 00000000..5d6632b5 Binary files /dev/null and b/testdata/barnsbury_extended1_segment.graph differ diff --git a/testdata/barnsbury_extended2.dxf b/testdata/barnsbury_extended2.dxf new file mode 100644 index 00000000..ecbdb668 --- /dev/null +++ b/testdata/barnsbury_extended2.dxf @@ -0,0 +1,206288 @@ + 0 +SECTION + 2 +HEADER + 9 +$ACADVER + 1 +AC1032 + 9 +$ACADMAINTVER + 90 + 29 + 9 +$DWGCODEPAGE + 3 +ANSI_1252 + 9 +$LASTSAVEDBY + 1 +petros + 9 +$REQUIREDVERSIONS +160 + 0 + 9 +$INSBASE + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$EXTMIN + 10 +519734.4698767327 + 20 +175043.3191102119 + 30 +0.0 + 9 +$EXTMAX + 10 +553979.5277822344 + 20 +197652.3201767497 + 30 +0.0 + 9 +$LIMMIN + 10 +0.0 + 20 +0.0 + 9 +$LIMMAX + 10 +12.0 + 20 +9.0 + 9 +$ORTHOMODE + 70 + 0 + 9 +$REGENMODE + 70 + 1 + 9 +$FILLMODE + 70 + 1 + 9 +$QTEXTMODE + 70 + 0 + 9 +$MIRRTEXT + 70 + 0 + 9 +$LTSCALE + 40 +1.0 + 9 +$ATTMODE + 70 + 1 + 9 +$TEXTSIZE + 40 +0.2 + 9 +$TRACEWID + 40 +0.05 + 9 +$TEXTSTYLE + 7 +Standard + 9 +$CLAYER + 8 +0 + 9 +$CELTYPE + 6 +ByLayer + 9 +$CECOLOR + 62 + 256 + 9 +$CELTSCALE + 40 +1.0 + 9 +$DISPSILH + 70 + 0 + 9 +$DIMSCALE + 40 +1.0 + 9 +$DIMASZ + 40 +0.18 + 9 +$DIMEXO + 40 +0.0625 + 9 +$DIMDLI + 40 +0.38 + 9 +$DIMRND + 40 +0.0 + 9 +$DIMDLE + 40 +0.0 + 9 +$DIMEXE + 40 +0.18 + 9 +$DIMTP + 40 +0.0 + 9 +$DIMTM + 40 +0.0 + 9 +$DIMTXT + 40 +0.18 + 9 +$DIMCEN + 40 +0.09 + 9 +$DIMTSZ + 40 +0.0 + 9 +$DIMTOL + 70 + 0 + 9 +$DIMLIM + 70 + 0 + 9 +$DIMTIH + 70 + 1 + 9 +$DIMTOH + 70 + 1 + 9 +$DIMSE1 + 70 + 0 + 9 +$DIMSE2 + 70 + 0 + 9 +$DIMTAD + 70 + 0 + 9 +$DIMZIN + 70 + 0 + 9 +$DIMBLK + 1 + + 9 +$DIMASO + 70 + 1 + 9 +$DIMSHO + 70 + 1 + 9 +$DIMPOST + 1 + + 9 +$DIMAPOST + 1 + + 9 +$DIMALT + 70 + 0 + 9 +$DIMALTD + 70 + 2 + 9 +$DIMALTF + 40 +25.4 + 9 +$DIMLFAC + 40 +1.0 + 9 +$DIMTOFL + 70 + 0 + 9 +$DIMTVP + 40 +0.0 + 9 +$DIMTIX + 70 + 0 + 9 +$DIMSOXD + 70 + 0 + 9 +$DIMSAH + 70 + 0 + 9 +$DIMBLK1 + 1 + + 9 +$DIMBLK2 + 1 + + 9 +$DIMSTYLE + 2 +Standard + 9 +$DIMCLRD + 70 + 0 + 9 +$DIMCLRE + 70 + 0 + 9 +$DIMCLRT + 70 + 0 + 9 +$DIMTFAC + 40 +1.0 + 9 +$DIMGAP + 40 +0.09 + 9 +$DIMJUST + 70 + 0 + 9 +$DIMSD1 + 70 + 0 + 9 +$DIMSD2 + 70 + 0 + 9 +$DIMTOLJ + 70 + 1 + 9 +$DIMTZIN + 70 + 0 + 9 +$DIMALTZ + 70 + 0 + 9 +$DIMALTTZ + 70 + 0 + 9 +$DIMUPT + 70 + 0 + 9 +$DIMDEC + 70 + 4 + 9 +$DIMTDEC + 70 + 4 + 9 +$DIMALTU + 70 + 2 + 9 +$DIMALTTD + 70 + 2 + 9 +$DIMTXSTY + 7 +Standard + 9 +$DIMAUNIT + 70 + 0 + 9 +$DIMADEC + 70 + 0 + 9 +$DIMALTRND + 40 +0.0 + 9 +$DIMAZIN + 70 + 0 + 9 +$DIMDSEP + 70 + 46 + 9 +$DIMATFIT + 70 + 3 + 9 +$DIMFRAC + 70 + 0 + 9 +$DIMLDRBLK + 1 + + 9 +$DIMLUNIT + 70 + 2 + 9 +$DIMLWD + 70 + -2 + 9 +$DIMLWE + 70 + -2 + 9 +$DIMTMOVE + 70 + 0 + 9 +$DIMFXL + 40 +1.0 + 9 +$DIMFXLON + 70 + 0 + 9 +$DIMJOGANG + 40 +0.7853981633974483 + 9 +$DIMTFILL + 70 + 0 + 9 +$DIMTFILLCLR + 70 + 0 + 9 +$DIMARCSYM + 70 + 0 + 9 +$DIMLTYPE + 6 + + 9 +$DIMLTEX1 + 6 + + 9 +$DIMLTEX2 + 6 + + 9 +$DIMTXTDIRECTION + 70 + 0 + 9 +$LUNITS + 70 + 2 + 9 +$LUPREC + 70 + 4 + 9 +$SKETCHINC + 40 +0.1 + 9 +$FILLETRAD + 40 +0.0 + 9 +$AUNITS + 70 + 0 + 9 +$AUPREC + 70 + 0 + 9 +$MENU + 1 +. + 9 +$ELEVATION + 40 +0.0 + 9 +$PELEVATION + 40 +0.0 + 9 +$THICKNESS + 40 +0.0 + 9 +$LIMCHECK + 70 + 0 + 9 +$CHAMFERA + 40 +0.0 + 9 +$CHAMFERB + 40 +0.0 + 9 +$CHAMFERC + 40 +0.0 + 9 +$CHAMFERD + 40 +0.0 + 9 +$SKPOLY + 70 + 0 + 9 +$TDCREATE + 40 +2458404.565312500 + 9 +$TDUCREATE + 40 +2458404.523645833 + 9 +$TDUPDATE + 40 +2458404.657638889 + 9 +$TDUUPDATE + 40 +2458404.615972222 + 9 +$TDINDWG + 40 +0.0820949074 + 9 +$TDUSRTIMER + 40 +0.0820949074 + 9 +$USRTIMER + 70 + 1 + 9 +$ANGBASE + 50 +0.0 + 9 +$ANGDIR + 70 + 0 + 9 +$PDMODE + 70 + 0 + 9 +$PDSIZE + 40 +0.0 + 9 +$PLINEWID + 40 +0.0 + 9 +$SPLFRAME + 70 + 0 + 9 +$SPLINETYPE + 70 + 6 + 9 +$SPLINESEGS + 70 + 8 + 9 +$HANDSEED + 5 +22F6 + 9 +$SURFTAB1 + 70 + 6 + 9 +$SURFTAB2 + 70 + 6 + 9 +$SURFTYPE + 70 + 6 + 9 +$SURFU + 70 + 6 + 9 +$SURFV + 70 + 6 + 9 +$UCSBASE + 2 + + 9 +$UCSNAME + 2 + + 9 +$UCSORG + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSXDIR + 10 +1.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSYDIR + 10 +0.0 + 20 +1.0 + 30 +0.0 + 9 +$UCSORTHOREF + 2 + + 9 +$UCSORTHOVIEW + 70 + 0 + 9 +$UCSORGTOP + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGBOTTOM + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGLEFT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGRIGHT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGFRONT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGBACK + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSBASE + 2 + + 9 +$PUCSNAME + 2 + + 9 +$PUCSORG + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSXDIR + 10 +1.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSYDIR + 10 +0.0 + 20 +1.0 + 30 +0.0 + 9 +$PUCSORTHOREF + 2 + + 9 +$PUCSORTHOVIEW + 70 + 0 + 9 +$PUCSORGTOP + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGBOTTOM + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGLEFT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGRIGHT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGFRONT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGBACK + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$USERI1 + 70 + 0 + 9 +$USERI2 + 70 + 0 + 9 +$USERI3 + 70 + 0 + 9 +$USERI4 + 70 + 0 + 9 +$USERI5 + 70 + 0 + 9 +$USERR1 + 40 +0.0 + 9 +$USERR2 + 40 +0.0 + 9 +$USERR3 + 40 +0.0 + 9 +$USERR4 + 40 +0.0 + 9 +$USERR5 + 40 +0.0 + 9 +$WORLDVIEW + 70 + 1 + 9 +$SHADEDGE + 70 + 3 + 9 +$SHADEDIF + 70 + 70 + 9 +$TILEMODE + 70 + 1 + 9 +$MAXACTVP + 70 + 64 + 9 +$PINSBASE + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PLIMCHECK + 70 + 0 + 9 +$PEXTMIN + 10 +1.000000000000000E+20 + 20 +1.000000000000000E+20 + 30 +1.000000000000000E+20 + 9 +$PEXTMAX + 10 +-1.000000000000000E+20 + 20 +-1.000000000000000E+20 + 30 +-1.000000000000000E+20 + 9 +$PLIMMIN + 10 +0.0 + 20 +0.0 + 9 +$PLIMMAX + 10 +12.0 + 20 +9.0 + 9 +$UNITMODE + 70 + 0 + 9 +$VISRETAIN + 70 + 1 + 9 +$PLINEGEN + 70 + 0 + 9 +$PSLTSCALE + 70 + 1 + 9 +$TREEDEPTH + 70 + 3020 + 9 +$CMLSTYLE + 2 +Standard + 9 +$CMLJUST + 70 + 0 + 9 +$CMLSCALE + 40 +1.0 + 9 +$PROXYGRAPHICS + 70 + 1 + 9 +$MEASUREMENT + 70 + 0 + 9 +$CELWEIGHT +370 + -1 + 9 +$ENDCAPS +280 + 0 + 9 +$JOINSTYLE +280 + 0 + 9 +$LWDISPLAY +290 + 0 + 9 +$INSUNITS + 70 + 0 + 9 +$HYPERLINKBASE + 1 + + 9 +$STYLESHEET + 1 + + 9 +$XEDIT +290 + 1 + 9 +$CEPSNTYPE +380 + 0 + 9 +$PSTYLEMODE +290 + 1 + 9 +$FINGERPRINTGUID + 2 +{2B8CF25F-82C1-5146-94DB-BDE3530BDA2A} + 9 +$VERSIONGUID + 2 +{58F8BA06-8073-9041-99B1-34838A46B6E6} + 9 +$EXTNAMES +290 + 1 + 9 +$PSVPSCALE + 40 +0.0 + 9 +$OLESTARTUP +290 + 0 + 9 +$SORTENTS +280 + 127 + 9 +$INDEXCTL +280 + 0 + 9 +$HIDETEXT +280 + 0 + 9 +$XCLIPFRAME +280 + 2 + 9 +$HALOGAP +280 + 0 + 9 +$OBSCOLOR + 70 + 257 + 9 +$OBSLTYPE +280 + 0 + 9 +$INTERSECTIONDISPLAY +280 + 0 + 9 +$INTERSECTIONCOLOR + 70 + 257 + 9 +$DIMASSOC +280 + 1 + 9 +$PROJECTNAME + 1 + + 9 +$CAMERADISPLAY +290 + 0 + 9 +$LENSLENGTH + 40 +50.0 + 9 +$CAMERAHEIGHT + 40 +0.0 + 9 +$STEPSPERSEC + 40 +2.0 + 9 +$STEPSIZE + 40 +6.0 + 9 +$3DDWFPREC + 40 +2.0 + 9 +$PSOLWIDTH + 40 +0.25 + 9 +$PSOLHEIGHT + 40 +4.0 + 9 +$LOFTANG1 + 40 +1.570796326794896 + 9 +$LOFTANG2 + 40 +1.570796326794896 + 9 +$LOFTMAG1 + 40 +0.0 + 9 +$LOFTMAG2 + 40 +0.0 + 9 +$LOFTPARAM + 70 + 7 + 9 +$LOFTNORMALS +280 + 1 + 9 +$LATITUDE + 40 +37.795 + 9 +$LONGITUDE + 40 +-122.394 + 9 +$NORTHDIRECTION + 40 +0.0 + 9 +$TIMEZONE + 70 + -8000 + 9 +$LIGHTGLYPHDISPLAY +280 + 1 + 9 +$TILEMODELIGHTSYNCH +280 + 1 + 9 +$CMATERIAL +347 +11 + 9 +$SOLIDHIST +280 + 0 + 9 +$SHOWHIST +280 + 1 + 9 +$DWFFRAME +280 + 2 + 9 +$DGNFRAME +280 + 0 + 9 +$REALWORLDSCALE +290 + 1 + 9 +$INTERFERECOLOR + 62 + 1 + 9 +$INTERFEREOBJVS +345 +33 + 9 +$INTERFEREVPVS +346 +30 + 9 +$CSHADOW +280 + 0 + 9 +$SHADOWPLANELOCATION + 40 +0.0 + 0 +ENDSEC + 0 +SECTION + 2 +CLASSES + 0 +CLASS + 1 +ACDBDICTIONARYWDFLT + 2 +AcDbDictionaryWithDefault + 3 +ObjectDBX Classes + 90 + 0 + 91 + 1 +280 + 0 +281 + 0 + 0 +CLASS + 1 +MATERIAL + 2 +AcDbMaterial + 3 +ObjectDBX Classes + 90 + 1153 + 91 + 3 +280 + 0 +281 + 0 + 0 +CLASS + 1 +VISUALSTYLE + 2 +AcDbVisualStyle + 3 +ObjectDBX Classes + 90 + 4095 + 91 + 24 +280 + 0 +281 + 0 + 0 +CLASS + 1 +SCALE + 2 +AcDbScale + 3 +ObjectDBX Classes + 90 + 1153 + 91 + 17 +280 + 0 +281 + 0 + 0 +CLASS + 1 +TABLESTYLE + 2 +AcDbTableStyle + 3 +ObjectDBX Classes + 90 + 4095 + 91 + 1 +280 + 0 +281 + 0 + 0 +CLASS + 1 +MLEADERSTYLE + 2 +AcDbMLeaderStyle + 3 +ACDB_MLEADERSTYLE_CLASS + 90 + 4095 + 91 + 1 +280 + 0 +281 + 0 + 0 +CLASS + 1 +ACDBSECTIONVIEWSTYLE + 2 +AcDbSectionViewStyle + 3 +ObjectDBX Classes + 90 + 1025 + 91 + 1 +280 + 0 +281 + 0 + 0 +CLASS + 1 +ACDBDETAILVIEWSTYLE + 2 +AcDbDetailViewStyle + 3 +ObjectDBX Classes + 90 + 1025 + 91 + 1 +280 + 0 +281 + 0 + 0 +CLASS + 1 +SORTENTSTABLE + 2 +AcDbSortentsTable + 3 +ObjectDBX Classes + 90 + 0 + 91 + 1 +280 + 0 +281 + 0 + 0 +CLASS + 1 +DICTIONARYVAR + 2 +AcDbDictionaryVar + 3 +ObjectDBX Classes + 90 + 0 + 91 + 9 +280 + 0 +281 + 0 + 0 +CLASS + 1 +CELLSTYLEMAP + 2 +AcDbCellStyleMap + 3 +ObjectDBX Classes + 90 + 1152 + 91 + 3 +280 + 0 +281 + 0 + 0 +ENDSEC + 0 +SECTION + 2 +TABLES + 0 +TABLE + 2 +VPORT + 5 +8 +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +VPORT + 5 +B3 +330 +8 +100 +AcDbSymbolTableRecord +100 +AcDbViewportTableRecord + 2 +*Active + 70 + 0 + 10 +0.0 + 20 +0.0 + 11 +1.0 + 21 +1.0 + 12 +530257.0980907157 + 22 +182183.4473277476 + 13 +0.0 + 23 +0.0 + 14 +1.0 + 24 +1.0 + 15 +0.0 + 25 +0.0 + 16 +0.0 + 26 +0.0 + 36 +1.0 + 17 +0.0 + 27 +0.0 + 37 +0.0 + 40 +22470.11987693544 + 41 +1.512419503219871 + 42 +50.0 + 43 +0.0 + 44 +0.0 + 50 +0.0 + 51 +0.0 + 71 + 0 + 72 + 1000 + 73 + 1 + 74 + 3 + 75 + 0 + 76 + 0 + 77 + 0 + 78 + 0 +281 + 0 + 65 + 1 +110 +0.0 +120 +0.0 +130 +0.0 +111 +1.0 +121 +0.0 +131 +0.0 +112 +0.0 +122 +1.0 +132 +0.0 + 79 + 0 +146 +0.0 +348 +2F + 60 + 3 + 61 + 5 +292 + 1 +282 + 1 +141 +0.0 +142 +0.0 + 63 + 250 +421 + 3355443 +1001 +ACAD_NAV_VCDISPLAY +1070 + 1 + 0 +ENDTAB + 0 +TABLE + 2 +LTYPE + 5 +5 +330 +0 +100 +AcDbSymbolTable + 70 + 2 + 0 +LTYPE + 5 +5A +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByBlock + 70 + 0 + 3 + + 72 + 65 + 73 + 0 + 40 +0.0 + 0 +LTYPE + 5 +5B +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByLayer + 70 + 0 + 3 + + 72 + 65 + 73 + 0 + 40 +0.0 + 0 +LTYPE + 5 +5C +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +Continuous + 70 + 0 + 3 +Solid line + 72 + 65 + 73 + 0 + 40 +0.0 + 0 +ENDTAB + 0 +TABLE + 2 +LAYER + 5 +2 +102 +{ACAD_XDICTIONARY +360 +345 +102 +} +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +LAYER + 5 +54 +102 +{ACAD_XDICTIONARY +360 +340 +102 +} +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +0 + 70 + 0 + 62 + 7 + 6 +Continuous +370 + -3 +390 +F +347 +21 +348 +0 + 0 +ENDTAB + 0 +TABLE + 2 +STYLE + 5 +3 +330 +0 +100 +AcDbSymbolTable + 70 + 2 + 0 +STYLE + 5 +55 +330 +3 +100 +AcDbSymbolTableRecord +100 +AcDbTextStyleTableRecord + 2 +Standard + 70 + 0 + 40 +0.0 + 41 +1.0 + 50 +0.0 + 71 + 0 + 42 +0.2 + 3 +txt + 4 + + 0 +STYLE + 5 +59 +330 +3 +100 +AcDbSymbolTableRecord +100 +AcDbTextStyleTableRecord + 2 +Annotative + 70 + 0 + 40 +0.0 + 41 +1.0 + 50 +0.0 + 71 + 0 + 42 +0.2 + 3 +txt + 4 + +1001 +AcadAnnotative +1000 +AnnotativeData +1002 +{ +1070 + 1 +1070 + 1 +1002 +} + 0 +ENDTAB + 0 +TABLE + 2 +VIEW + 5 +6 +330 +0 +100 +AcDbSymbolTable + 70 + 2 + 0 +ENDTAB + 0 +TABLE + 2 +UCS + 5 +7 +330 +0 +100 +AcDbSymbolTable + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +APPID + 5 +9 +330 +0 +100 +AcDbSymbolTable + 70 + 4 + 0 +APPID + 5 +56 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD + 70 + 0 + 0 +APPID + 5 +5D +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +AcadAnnotative + 70 + 0 + 0 +APPID + 5 +B2 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD_NAV_VCDISPLAY + 70 + 0 + 0 +APPID + 5 +F2 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD_EXEMPT_FROM_CAD_STANDARDS + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +DIMSTYLE + 5 +A +330 +0 +100 +AcDbSymbolTable + 70 + 3 +100 +AcDbDimStyleTable + 71 + 1 +340 +57 + 0 +DIMSTYLE +105 +57 +330 +A +100 +AcDbSymbolTableRecord +100 +AcDbDimStyleTableRecord + 2 +Standard + 70 + 0 +340 +55 + 0 +DIMSTYLE +105 +58 +330 +A +100 +AcDbSymbolTableRecord +100 +AcDbDimStyleTableRecord + 2 +Annotative + 70 + 0 +340 +55 +1001 +AcadAnnotative +1000 +AnnotativeData +1002 +{ +1070 + 1 +1070 + 1 +1002 +} + 0 +ENDTAB + 0 +TABLE + 2 +BLOCK_RECORD + 5 +1 +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +BLOCK_RECORD + 5 +6F +102 +{ACAD_XDICTIONARY +360 +135 +102 +} +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Model_Space +340 +72 + 70 + 0 +280 + 1 +281 + 0 + 0 +BLOCK_RECORD + 5 +6B +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Paper_Space +340 +6E + 70 + 0 +280 + 1 +281 + 0 + 0 +ENDTAB + 0 +ENDSEC + 0 +SECTION + 2 +BLOCKS + 0 +BLOCK + 5 +70 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbBlockBegin + 2 +*Model_Space + 70 + 0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +*Model_Space + 1 + + 0 +ENDBLK + 5 +71 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbBlockEnd + 0 +BLOCK + 5 +6C +330 +6B +100 +AcDbEntity + 67 + 1 + 8 +0 +100 +AcDbBlockBegin + 2 +*Paper_Space + 70 + 0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +*Paper_Space + 1 + + 0 +ENDBLK + 5 +6D +330 +6B +100 +AcDbEntity + 67 + 1 + 8 +0 +100 +AcDbBlockEnd + 0 +ENDSEC + 0 +SECTION + 2 +ENTITIES + 0 +LINE + 5 +73 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530635.6962680001 + 20 +184468.675646 + 30 +0.0 + 11 +530732.3778539999 + 21 +183731.866556 + 31 +0.0 + 0 +LINE + 5 +74 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530655.0804069999 + 20 +184267.843134 + 30 +0.0 + 11 +531386.6646780001 + 21 +184568.766995 + 31 +0.0 + 0 +LINE + 5 +75 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530781.419478 + 20 +184322.997346 + 30 +0.0 + 11 +530814.78724 + 21 +184178.968574 + 31 +0.0 + 0 +LINE + 5 +76 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530667.7613100001 + 20 +184203.901437 + 30 +0.0 + 11 +531124.6861069999 + 21 +184392.857349 + 31 +0.0 + 0 +LINE + 5 +77 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530798.725861 + 20 +184207.390438 + 30 +0.0 + 11 +530856.762846 + 21 +184149.487013 + 31 +0.0 + 0 +LINE + 5 +78 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530747.8703240001 + 20 +184145.998012 + 30 +0.0 + 11 +530810.7554050001 + 21 +184207.340453 + 31 +0.0 + 0 +LINE + 5 +79 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530753.9386890001 + 20 +184164.022852 + 30 +0.0 + 11 +530781.427723 + 21 +183967.049235 + 31 +0.0 + 0 +LINE + 5 +7A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530638.0708449999 + 20 +184123.954322 + 30 +0.0 + 11 +531070.9777789999 + 21 +184116.826362 + 31 +0.0 + 0 +LINE + 5 +7B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530837.4941380001 + 20 +183967.908989 + 30 +0.0 + 11 +530855.6744979999 + 21 +184153.675814 + 31 +0.0 + 0 +LINE + 5 +7C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530776.9259189999 + 20 +183970.168342 + 30 +0.0 + 11 +530838.1125180001 + 21 +183968.488823 + 31 +0.0 + 0 +LINE + 5 +7D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530803.8790240001 + 20 +183673.983124 + 30 +0.0 + 11 +530817.351454 + 21 +183970.908131 + 31 +0.0 + 0 +LINE + 5 +7E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530803.31836 + 20 +183742.403539 + 30 +0.0 + 11 +530916.415863 + 21 +183745.002795 + 31 +0.0 + 0 +LINE + 5 +7F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530912.1861470001 + 20 +183663.646083 + 30 +0.0 + 11 +530932.996681 + 21 +184479.6069563149 + 31 +0.0 + 0 +LINE + 5 +80 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530995.2139119999 + 20 +184191.1051 + 30 +0.0 + 11 +531426.867596 + 21 +184272.091918 + 31 +0.0 + 0 +LINE + 5 +81 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530992.995991 + 20 +184260.565217 + 30 +0.0 + 11 +531006.3035189999 + 21 +184067.090599 + 31 +0.0 + 0 +LINE + 5 +82 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531065.5030580001 + 20 +184264.454104 + 30 +0.0 + 11 +531069.386482 + 21 +184200.262479 + 31 +0.0 + 0 +LINE + 5 +83 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531014.2600029999 + 20 +184282.658893 + 30 +0.0 + 11 +531076.262863 + 21 +184252.777446 + 31 +0.0 + 0 +LINE + 5 +84 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531055.8563370001 + 20 +184254.05708 + 30 +0.0 + 11 +531446.820644 + 21 +184352.768824 + 31 +0.0 + 0 +LINE + 5 +85 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531101.674141 + 20 +184455.949289 + 30 +0.0 + 11 +531227.444303 + 21 +184068.530187 + 31 +0.0 + 0 +LINE + 5 +86 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531214.16151 + 20 +184067.600453 + 30 +0.0 + 11 +531445.270572 + 21 +184127.80322 + 31 +0.0 + 0 +LINE + 5 +87 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531166.2824399999 + 20 +183883.173244 + 30 +0.0 + 11 +531225.605654 + 21 +184081.636435 + 31 +0.0 + 0 +LINE + 5 +88 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531103.958023 + 20 +183944.145791 + 30 +0.0 + 11 +531189.2449350001 + 21 +183939.966987 + 31 +0.0 + 0 +LINE + 5 +89 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531199.1268957056 + 20 +184509.5863229855 + 30 +0.0 + 11 +531222.4027027056 + 21 +184422.5212449855 + 31 +0.0 + 0 +LINE + 5 +8A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531332.5770770001 + 20 +184583.962646 + 30 +0.0 + 11 +531443.794706 + 21 +184125.074001 + 31 +0.0 + 0 +LINE + 5 +8B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531026.4544489999 + 20 +184114.297086 + 30 +0.0 + 11 +531441.626255 + 21 +184200.71235 + 31 +0.0 + 0 +LINE + 5 +8C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531379.0874670001 + 20 +183726.907975 + 30 +0.0 + 11 +531438.2045550001 + 21 +184206.79061 + 31 +0.0 + 0 +LINE + 5 +8D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531367.365093476 + 20 +183473.8360188434 + 30 +0.0 + 11 +531409.569458 + 21 +184011.596484 + 31 +0.0 + 0 +LINE + 5 +8E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531287.1303 + 20 +183716.111065 + 30 +0.0 + 11 +531396.253684 + 21 +183759.488649 + 31 +0.0 + 0 +LINE + 5 +8F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531294.394199 + 20 +183777.773415 + 30 +0.0 + 11 +531391.413833 + 21 +183726.268158 + 31 +0.0 + 0 +LINE + 5 +90 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531303.999695 + 20 +183967.539095 + 30 +0.0 + 11 +531311.931444 + 21 +183765.686875 + 31 +0.0 + 0 +LINE + 5 +91 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530639.1597319652 + 20 +183843.3318650589 + 30 +0.0 + 11 +531403.294966 + 21 +183913.414588 + 31 +0.0 + 0 +LINE + 5 +92 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531055.773886 + 20 +183973.477395 + 30 +0.0 + 11 +531081.1604290001 + 21 +183854.721389 + 31 +0.0 + 0 +LINE + 5 +93 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530979.070082 + 20 +183853.471746 + 30 +0.0 + 11 +531006.056167 + 21 +183971.198048 + 31 +0.0 + 0 +LINE + 5 +94 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531002.3706249999 + 20 +183965.559662 + 30 +0.0 + 11 +531057.7609460001 + 21 +183972.597647 + 31 +0.0 + 0 +LINE + 5 +97 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531378.13104 + 20 +184039.148597 + 30 +0.0 + 11 +531423.297484 + 21 +184035.389673 + 31 +0.0 + 0 +LINE + 5 +98 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531365.8376540001 + 20 +184048.645878 + 30 +0.0 + 11 +531385.9885830001 + 21 +184035.489644 + 31 +0.0 + 0 +LINE + 5 +99 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531360.008395 + 20 +184112.477607 + 30 +0.0 + 11 +531368.607994 + 21 +184041.148025 + 31 +0.0 + 0 +LINE + 5 +9A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531176.638237 + 20 +183932.709065 + 30 +0.0 + 11 +531212.5949479999 + 21 +183499.852969 + 31 +0.0 + 0 +LINE + 5 +9B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531191.28971 + 20 +183523.406227 + 30 +0.0 + 11 +531385.782456 + 21 +183575.241389 + 31 +0.0 + 0 +LINE + 5 +9C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530904.180192 + 20 +183681.79089 + 30 +0.0 + 11 +531226.595062 + 21 +183515.558473 + 31 +0.0 + 0 +LINE + 5 +9D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531087.294754 + 20 +183504.461649 + 30 +0.0 + 11 +531157.6993310001 + 21 +183893.960157 + 31 +0.0 + 0 +LINE + 5 +9E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531029.2082989999 + 20 +183891.140964 + 30 +0.0 + 11 +531030.2306869999 + 21 +183855.631128 + 31 +0.0 + 0 +LINE + 5 +9F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531182.681866 + 20 +183748.751722 + 30 +0.0 + 11 +531275.851057 + 21 +183743.153325 + 31 +0.0 + 0 +LINE + 5 +A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531240.7600770002 + 20 +183741.113908 + 30 +0.0 + 11 +531312.920852 + 21 +183782.89195 + 31 +0.0 + 0 +LINE + 5 +A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531238.3195390001 + 20 +183754.010217 + 30 +0.0 + 11 +531308.0562649999 + 21 +183714.501526 + 31 +0.0 + 0 +LINE + 5 +A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531293.948966 + 20 +183547.909213 + 30 +0.0 + 11 +531303.2823749999 + 21 +183726.188181 + 31 +0.0 + 0 +LINE + 5 +A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530707.321114 + 20 +183575.611283 + 30 +0.0 + 11 +530731.6605340001 + 21 +183750.551207 + 31 +0.0 + 0 +LINE + 5 +A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530711.864142 + 20 +183690.118506 + 30 +0.0 + 11 +530973.265559 + 21 +183658.367594 + 31 +0.0 + 0 +LINE + 5 +A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531139.131454 + 20 +184142.888902 + 30 +0.0 + 11 +531154.5332279999 + 21 +184098.471616 + 31 +0.0 + 0 +LINE + 5 +A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531091.4007950001 + 20 +184089.16428 + 30 +0.0 + 11 +531155.7864770001 + 21 +184099.901207 + 31 +0.0 + 0 +LINE + 5 +A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531060.2262189999 + 20 +184127.683254 + 30 +0.0 + 11 +531065.6514689999 + 21 +184023.503075 + 31 +0.0 + 0 +LINE + 5 +A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530915.1048979999 + 20 +184035.689587 + 30 +0.0 + 11 +531213.1391220001 + 21 +184017.404821 + 31 +0.0 + 0 +LINE + 5 +A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531281.4989239999 + 20 +184088.374506 + 30 +0.0 + 11 +531294.732247 + 21 +184020.813845 + 31 +0.0 + 0 +LINE + 5 +AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531263.3103189999 + 20 +184015.655322 + 30 +0.0 + 11 +531322.3284660001 + 21 +184027.032065 + 31 +0.0 + 0 +LINE + 5 +AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531267.276193 + 20 +184023.293136 + 30 +0.0 + 11 +531279.9983229999 + 21 +183953.103227 + 31 +0.0 + 0 +LINE + 5 +AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531276.7909939999 + 20 +183954.982689 + 30 +0.0 + 11 +531332.164824 + 21 +183964.220045 + 31 +0.0 + 0 +LINE + 5 +AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531315.9385439999 + 20 +184033.420237 + 30 +0.0 + 11 +531330.6065079999 + 21 +183957.32202 + 31 +0.0 + 0 +LINE + 5 +AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530805.297175 + 20 +183814.47291 + 30 +0.0 + 11 +530917.998915 + 21 +183816.172423 + 31 +0.0 + 0 +LINE + 5 +AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531137.2515800001 + 20 +184338.103022 + 30 +0.0 + 11 +531389.731841 + 21 +184417.270361 + 31 +0.0 + 0 +LINE + 5 +B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531482.3151479505 + 20 +184748.9871594448 + 30 +0.0 + 11 +531515.6829099504 + 21 +184604.9583874448 + 31 +0.0 + 0 +LINE + 5 +B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531368.6569799505 + 20 +184629.8912504447 + 30 +0.0 + 11 +531825.5817769504 + 21 +184818.8471624447 + 31 +0.0 + 0 +LINE + 5 +B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531499.6215309505 + 20 +184633.3802514448 + 30 +0.0 + 11 +531557.6585159504 + 21 +184575.4768264448 + 31 +0.0 + 0 +LINE + 5 +BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531448.7659939505 + 20 +184571.9878254447 + 30 +0.0 + 11 +531511.6510749504 + 21 +184633.3302664447 + 31 +0.0 + 0 +LINE + 5 +BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531455.263586 + 20 +184588.2416564698 + 30 +0.0 + 11 +531482.7526199998 + 21 +184391.2680394698 + 31 +0.0 + 0 +LINE + 5 +BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531253.86750234 + 20 +184551.3453196492 + 30 +0.0 + 11 +531771.8734489504 + 21 +184542.8161754447 + 31 +0.0 + 0 +LINE + 5 +BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531538.3898079505 + 20 +184393.8988024447 + 30 +0.0 + 11 +531556.5701679504 + 21 +184579.6656274448 + 31 +0.0 + 0 +LINE + 5 +BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531477.8215889504 + 20 +184396.1581554448 + 30 +0.0 + 11 +531539.0081879505 + 21 +184394.4786364447 + 31 +0.0 + 0 +LINE + 5 +BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531504.7746939504 + 20 +184099.9729374447 + 30 +0.0 + 11 +531518.2471239504 + 21 +184396.8979444447 + 31 +0.0 + 0 +LINE + 5 +C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531504.2140299504 + 20 +184168.3933524448 + 30 +0.0 + 11 +531617.3115329505 + 21 +184170.9926084448 + 31 +0.0 + 0 +LINE + 5 +C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531613.0818169503 + 20 +184089.6358964447 + 30 +0.0 + 11 +531633.8923509504 + 21 +184844.9097024448 + 31 +0.0 + 0 +LINE + 5 +C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531696.1095819504 + 20 +184617.0949134447 + 30 +0.0 + 11 +532336.8255974543 + 21 +184713.6317642464 + 31 +0.0 + 0 +LINE + 5 +C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531693.8916609504 + 20 +184686.5550304448 + 30 +0.0 + 11 +531707.1991889504 + 21 +184493.0804124447 + 31 +0.0 + 0 +LINE + 5 +C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531766.3987279504 + 20 +184690.4439174447 + 30 +0.0 + 11 +531770.2821519504 + 21 +184626.2522924448 + 31 +0.0 + 0 +LINE + 5 +C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531715.1556729503 + 20 +184708.6487064448 + 30 +0.0 + 11 +531777.1585329505 + 21 +184678.7672594447 + 31 +0.0 + 0 +LINE + 5 +C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531756.7520069505 + 20 +184680.0468934447 + 30 +0.0 + 11 +531893.0496688435 + 21 +184714.4597021531 + 31 +0.0 + 0 +LINE + 5 +C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531802.5698109504 + 20 +184881.9391024447 + 30 +0.0 + 11 +531928.3399729504 + 21 +184494.5200004447 + 31 +0.0 + 0 +LINE + 5 +C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531915.0571799504 + 20 +184493.5902664447 + 30 +0.0 + 11 +532146.1662419505 + 21 +184553.7930334447 + 31 +0.0 + 0 +LINE + 5 +C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531867.1781099504 + 20 +184309.1630574448 + 30 +0.0 + 11 +531926.5013239504 + 21 +184507.6262484447 + 31 +0.0 + 0 +LINE + 5 +CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531804.8536929503 + 20 +184370.1356044448 + 30 +0.0 + 11 +531890.1406049505 + 21 +184365.9568004447 + 31 +0.0 + 0 +LINE + 5 +CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531914.954988917 + 20 +184937.2488970258 + 30 +0.0 + 11 +531938.230795917 + 21 +184850.1838190259 + 31 +0.0 + 0 +LINE + 5 +CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531727.3501189504 + 20 +184540.2868994447 + 30 +0.0 + 11 +532142.5219249505 + 21 +184626.7021634447 + 31 +0.0 + 0 +LINE + 5 +D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531988.0259699504 + 20 +184142.1008784448 + 30 +0.0 + 11 +532097.1493539504 + 21 +184185.4784624447 + 31 +0.0 + 0 +LINE + 5 +D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531995.2898689503 + 20 +184203.7632284447 + 30 +0.0 + 11 +532092.3095029504 + 21 +184152.2579714447 + 31 +0.0 + 0 +LINE + 5 +D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532004.8953649504 + 20 +184393.5289084448 + 30 +0.0 + 11 +532012.8271139505 + 21 +184191.6766884448 + 31 +0.0 + 0 +LINE + 5 +D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531770.6696699504 + 20 +184306.9436934447 + 30 +0.0 + 11 +532197.7006858273 + 21 +184339.4044014448 + 31 +0.0 + 0 +LINE + 5 +D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531756.6695559503 + 20 +184399.4672084447 + 30 +0.0 + 11 +531782.0560989504 + 21 +184280.7112024448 + 31 +0.0 + 0 +LINE + 5 +D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531679.9657519504 + 20 +184279.4615594447 + 30 +0.0 + 11 +531706.9518369503 + 21 +184397.1878614447 + 31 +0.0 + 0 +LINE + 5 +D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531703.2662949504 + 20 +184391.5494754448 + 30 +0.0 + 11 +531758.6566159504 + 21 +184398.5874604448 + 31 +0.0 + 0 +LINE + 5 +D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531375.9456139504 + 20 +184307.1536334448 + 30 +0.0 + 11 +531938.4319279503 + 21 +184318.4104104447 + 31 +0.0 + 0 +LINE + 5 +D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531947.6993769504 + 20 +184327.6377694447 + 30 +0.0 + 11 +531947.9961989505 + 21 +184303.3547204447 + 31 +0.0 + 0 +LINE + 5 +D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532079.0267099504 + 20 +184465.1384104447 + 30 +0.0 + 11 +532156.3508382652 + 21 +184461.3794864448 + 31 +0.0 + 0 +LINE + 5 +DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532066.7333239505 + 20 +184474.6356914448 + 30 +0.0 + 11 +532086.8842529504 + 21 +184461.4794574448 + 31 +0.0 + 0 +LINE + 5 +DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532060.9040649504 + 20 +184538.4674204447 + 30 +0.0 + 11 +532069.5036639504 + 21 +184467.1378384447 + 31 +0.0 + 0 +LINE + 5 +DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531877.5339069504 + 20 +184358.6988784447 + 30 +0.0 + 11 +531913.4906179503 + 21 +184005.4836986493 + 31 +0.0 + 0 +LINE + 5 +DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531605.0758619504 + 20 +184107.7807034448 + 30 +0.0 + 11 +531784.3258864618 + 21 +184010.3328863243 + 31 +0.0 + 0 +LINE + 5 +DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531761.9190629788 + 20 +183988.7626476783 + 30 +0.0 + 11 +531858.5950009506 + 21 +184319.9499704448 + 31 +0.0 + 0 +LINE + 5 +E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531730.1039689503 + 20 +184317.1307774448 + 30 +0.0 + 11 +531731.1263569504 + 21 +184281.6209414447 + 31 +0.0 + 0 +LINE + 5 +E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531883.5775359503 + 20 +184174.7415354448 + 30 +0.0 + 11 +531976.7467269504 + 21 +184169.1431384447 + 31 +0.0 + 0 +LINE + 5 +E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531941.6557469504 + 20 +184167.1037214447 + 30 +0.0 + 11 +532013.8165219504 + 21 +184208.8817634447 + 31 +0.0 + 0 +LINE + 5 +E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531939.2152089505 + 20 +184180.0000304447 + 30 +0.0 + 11 +532008.9519349505 + 21 +184140.4913394448 + 31 +0.0 + 0 +LINE + 5 +E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531994.8446359504 + 20 +184026.5398393117 + 30 +0.0 + 11 +532004.1780449503 + 21 +184152.1779944448 + 31 +0.0 + 0 +LINE + 5 +E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531409.1658425192 + 20 +184133.617550475 + 30 +0.0 + 11 +531674.1612289504 + 21 +184084.3574074447 + 31 +0.0 + 0 +LINE + 5 +E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531840.0271239504 + 20 +184568.8787154448 + 30 +0.0 + 11 +531855.4288979504 + 21 +184524.4614294448 + 31 +0.0 + 0 +LINE + 5 +E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531792.2964649504 + 20 +184515.1540934448 + 30 +0.0 + 11 +531856.6821469506 + 21 +184525.8910204447 + 31 +0.0 + 0 +LINE + 5 +E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531761.1218889504 + 20 +184553.6730674448 + 30 +0.0 + 11 +531766.5471389503 + 21 +184449.4928884447 + 31 +0.0 + 0 +LINE + 5 +EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531616.0005679503 + 20 +184461.6794004447 + 30 +0.0 + 11 +531914.0347919505 + 21 +184443.3946344448 + 31 +0.0 + 0 +LINE + 5 +EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531982.3945939504 + 20 +184514.3643194447 + 30 +0.0 + 11 +531995.6279169504 + 21 +184446.8036584448 + 31 +0.0 + 0 +LINE + 5 +EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531964.2059889504 + 20 +184441.6451354448 + 30 +0.0 + 11 +532023.2241359505 + 21 +184453.0218784447 + 31 +0.0 + 0 +LINE + 5 +ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531968.1718629504 + 20 +184449.2829494447 + 30 +0.0 + 11 +531980.8939929504 + 21 +184379.0930404447 + 31 +0.0 + 0 +LINE + 5 +EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531977.6866639505 + 20 +184380.9725024447 + 30 +0.0 + 11 +532033.0604939504 + 21 +184390.2098584447 + 31 +0.0 + 0 +LINE + 5 +EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532016.8342139503 + 20 +184459.4100504447 + 30 +0.0 + 11 +532031.5021779503 + 21 +184383.3118334448 + 31 +0.0 + 0 +LINE + 5 +F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531506.1928449503 + 20 +184240.4627234447 + 30 +0.0 + 11 +531618.8945849504 + 21 +184242.1622364448 + 31 +0.0 + 0 +LINE + 5 +F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531838.1472499504 + 20 +184764.0928354447 + 30 +0.0 + 11 +532090.6275109504 + 21 +184843.2601744448 + 31 +0.0 + 0 +LINE + 5 +F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531898.1410099429 + 20 +185489.5773460393 + 30 +0.0 + 11 +532384.9456462926 + 21 +183588.3773949871 + 31 +0.0 + 0 +LINE + 5 +FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532034.5704961169 + 20 +184072.7659341317 + 30 +0.0 + 11 +532153.81876062 + 21 +183879.2475727824 + 31 +0.0 + 0 +LINE + 5 +FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531848.4441497004 + 20 +184056.3091599104 + 30 +0.0 + 11 +531872.7555329124 + 21 +183888.2560305589 + 31 +0.0 + 0 +LINE + 5 +104 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531400.0540388189 + 20 +183972.7571852804 + 30 +0.0 + 11 +532184.2443917333 + 21 +184077.3429025231 + 31 +0.0 + 0 +LINE + 5 +105 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531934.003528394 + 20 +183974.8942294735 + 30 +0.0 + 11 +532082.7807717206 + 21 +183561.6762489006 + 31 +0.0 + 0 +LINE + 5 +106 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532002.2213451149 + 20 +183988.1590894068 + 30 +0.0 + 11 +531813.3438607319 + 21 +183944.1725686889 + 31 +0.0 + 0 +LINE + 5 +107 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532017.6216248512 + 20 +183917.199737725 + 30 +0.0 + 11 +531954.8704583398 + 21 +183903.1307362112 + 31 +0.0 + 0 +LINE + 5 +108 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532027.4228756862 + 20 +183970.6899285112 + 30 +0.0 + 11 +532007.8099904357 + 21 +183904.7157649685 + 31 +0.0 + 0 +LINE + 5 +109 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532005.8194622598 + 20 +183925.0652505675 + 30 +0.0 + 11 +532165.6070012576 + 21 +183554.8422905387 + 31 +0.0 + 0 +LINE + 5 +10A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532215.3406327096 + 20 +183914.506790095 + 30 +0.0 + 11 +531850.025606886 + 21 +183726.0905468235 + 31 +0.0 + 0 +LINE + 5 +10B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531846.9898456826 + 20 +183739.0551582372 + 30 +0.0 + 11 +531943.2723962862 + 21 +183520.502093417 + 31 +0.0 + 0 +LINE + 5 +10C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531657.2879060011 + 20 +183756.915025109 + 30 +0.0 + 11 +531862.6710068011 + 21 +183729.9954447442 + 31 +0.0 + 0 +LINE + 5 +10D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531707.5428474121 + 20 +183828.1640623365 + 30 +0.0 + 11 +531717.0163799135 + 21 +183743.3019863348 + 31 +0.0 + 0 +LINE + 5 +10F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532612.0618786471 + 20 +183803.7866919309 + 30 +0.0 + 11 +531940.3427695725 + 21 +183521.5239075487 + 31 +0.0 + 0 +LINE + 5 +110 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531863.1594357444 + 20 +183931.8064504249 + 30 +0.0 + 11 +532014.6676634007 + 21 +183535.7250404825 + 31 +0.0 + 0 +LINE + 5 +111 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531536.9533087979 + 20 +183521.91630484 + 30 +0.0 + 11 +532020.1225745254 + 21 +183540.0721337803 + 31 +0.0 + 0 +LINE + 5 +112 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531322.8230960095 + 20 +183496.2175151871 + 30 +0.0 + 11 +531822.8598906507 + 21 +183537.2174611747 + 31 +0.0 + 0 +LINE + 5 +113 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531511.6320955303 + 20 +183610.9754424221 + 30 +0.0 + 11 +531571.8542817987 + 21 +183510.1646492979 + 31 +0.0 + 0 +LINE + 5 +114 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531573.6637703916 + 20 +183613.6364478867 + 30 +0.0 + 11 +531538.2870985668 + 21 +183509.6456215089 + 31 +0.0 + 0 +LINE + 5 +115 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531762.5332163358 + 20 +183634.4117035529 + 30 +0.0 + 11 +531564.5281508437 + 21 +183594.3963889772 + 31 +0.0 + 0 +LINE + 5 +116 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531647.8000830325 + 20 +183818.5796003908 + 30 +0.0 + 11 +531724.9336515695 + 21 +183527.7567185295 + 31 +0.0 + 0 +LINE + 5 +117 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531562.2020126962 + 20 +183850.0654772609 + 30 +0.0 + 11 +531683.6345265603 + 21 +183848.7965788212 + 31 +0.0 + 0 +LINE + 5 +118 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531664.5618179023 + 20 +183949.0972884033 + 30 +0.0 + 11 +531554.5510755348 + 21 +183899.2438278418 + 31 +0.0 + 0 +LINE + 5 +119 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531559.3441468585 + 20 +183903.9768061644 + 30 +0.0 + 11 +531563.4592611811 + 21 +183848.292995883 + 31 +0.0 + 0 +LINE + 5 +11A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531576.9778841278 + 20 +184241.5424111468 + 30 +0.0 + 11 +531576.9801121507 + 21 +184241.5301770692 + 31 +0.0 + 0 +LINE + 5 +11B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531688.3652557219 + 20 +183680.3696937222 + 30 +0.0 + 11 +531664.4402060374 + 21 +183676.2047723989 + 31 +0.0 + 0 +LINE + 5 +11C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531845.0466985964 + 20 +183572.6468079129 + 30 +0.0 + 11 +531848.5375890713 + 21 +183527.4588575618 + 31 +0.0 + 0 +LINE + 5 +11D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531852.4623111796 + 20 +183586.2972429151 + 30 +0.0 + 11 +531842.6874311459 + 21 +183564.3063776991 + 31 +0.0 + 0 +LINE + 5 +11E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531914.5479255571 + 20 +183602.2297999917 + 30 +0.0 + 11 +531845.5021105826 + 21 +183582.3668242385 + 31 +0.0 + 0 +LINE + 5 +11F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531707.8411943864 + 20 +183754.5901321862 + 30 +0.0 + 11 +531365.7560113711 + 21 +183674.7938172478 + 31 +0.0 + 0 +LINE + 5 +122 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531374.0607747642 + 20 +183774.5071494866 + 30 +0.0 + 11 +531666.5682496065 + 21 +183767.1082814454 + 31 +0.0 + 0 +LINE + 5 +123 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531643.2974167897 + 20 +183893.5059139139 + 30 +0.0 + 11 +531608.4049033558 + 21 +183886.834614473 + 31 +0.0 + 0 +LINE + 5 +124 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531527.2010051643 + 20 +183719.29209353 + 30 +0.0 + 11 +531536.5299245022 + 21 +183626.4222304713 + 31 +0.0 + 0 +LINE + 5 +125 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531528.9213936644 + 20 +183660.7390828553 + 30 +0.0 + 11 +531581.6708679228 + 21 +183596.1629633728 + 31 +0.0 + 0 +LINE + 5 +126 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531541.263570164 + 20 +183665.2046948853 + 30 +0.0 + 11 +531513.379763223 + 21 +183590.0605605288 + 31 +0.0 + 0 +LINE + 5 +127 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531346.6694038719 + 20 +183577.4244724932 + 30 +0.0 + 11 +531524.155712167 + 21 +183596.6367946471 + 31 +0.0 + 0 +LINE + 5 +129 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531909.3516392598 + 20 +183825.1299313012 + 30 +0.0 + 11 +531867.9584077485 + 21 +183802.8429323333 + 31 +0.0 + 0 +LINE + 5 +12A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531848.70377308 + 20 +183863.6836230238 + 30 +0.0 + 11 +531869.5695376331 + 21 +183801.8336633017 + 31 +0.0 + 0 +LINE + 5 +12B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531881.7592038701 + 20 +183900.6011533052 + 30 +0.0 + 11 +531779.7769291967 + 21 +183878.6339348538 + 31 +0.0 + 0 +LINE + 5 +12C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531767.8030984371 + 20 +184029.1975708737 + 30 +0.0 + 11 +531797.2733862307 + 21 +183732.0608456437 + 31 +0.0 + 0 +LINE + 5 +12D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531878.2349730312 + 20 +183675.8916353841 + 30 +0.0 + 11 +531813.6487009317 + 21 +183652.0551673432 + 31 +0.0 + 0 +LINE + 5 +12E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531803.5459941819 + 20 +183682.2525717864 + 30 +0.0 + 11 +531824.1875434457 + 21 +183625.8034938436 + 31 +0.0 + 0 +LINE + 5 +12F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531811.718444662 + 20 +183679.5552745401 + 30 +0.0 + 11 +531744.4550535487 + 21 +183655.8042296553 + 31 +0.0 + 0 +LINE + 5 +130 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531745.7990662274 + 20 +183659.270202339 + 30 +0.0 + 11 +531763.7475182557 + 21 +183606.0776947413 + 31 +0.0 + 0 +LINE + 5 +131 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531829.4751229565 + 20 +183633.1302494412 + 30 +0.0 + 11 +531756.6892737099 + 21 +183606.5161939831 + 31 +0.0 + 0 +LINE + 5 +133 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532101.7684936581 + 20 +183858.112361732 + 30 +0.0 + 11 +532220.1805946465 + 21 +183621.4853892659 + 31 +0.0 + 0 +LINE + 5 +134 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531603.2015619726 + 20 +184097.5481402789 + 30 +0.0 + 11 +531677.7782680864 + 21 +183688.04728826 + 31 +0.0 + 0 +LINE + 5 +137 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530735.9131272892 + 20 +184226.3356863664 + 30 +0.0 + 11 +530283.9544628965 + 21 +184816.224090947 + 31 +0.0 + 0 +LINE + 5 +138 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530031.1888274785 + 20 +184139.9555640059 + 30 +0.0 + 11 +532155.7272385915 + 21 +185032.5284892478 + 31 +0.0 + 0 +LINE + 5 +139 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530736.1824591328 + 20 +184432.3874965597 + 30 +0.0 + 11 +530658.0779895487 + 21 +184557.9159257529 + 31 +0.0 + 0 +LINE + 5 +13A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530571.6050156501 + 20 +184436.4223187819 + 30 +0.0 + 11 +531028.5298126501 + 21 +184625.3782307819 + 31 +0.0 + 0 +LINE + 5 +13B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530666.7818999167 + 20 +184526.4514665502 + 30 +0.0 + 11 +530666.9708656795 + 21 +184608.4335532921 + 31 +0.0 + 0 +LINE + 5 +13C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530587.4192474452 + 20 +184533.9936815043 + 30 +0.0 + 11 +530675.2625699671 + 21 +184534.9832109703 + 31 +0.0 + 0 +LINE + 5 +13D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530604.4459568052 + 20 +184525.5195397091 + 30 +0.0 + 11 +530484.7853398737 + 21 +184684.3766753369 + 31 +0.0 + 0 +LINE + 5 +13F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530525.0832024871 + 20 +184723.3672426156 + 30 +0.0 + 11 +530669.1589131753 + 21 +184604.6995201719 + 31 +0.0 + 0 +LINE + 5 +140 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530483.8014128733 + 20 +184678.989008366 + 30 +0.0 + 11 +530525.9304985947 + 21 +184723.3935218478 + 31 +0.0 + 0 +LINE + 5 +141 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530293.6891368918 + 20 +184907.7016572334 + 30 +0.0 + 11 +530512.942028526 + 21 +184707.017488296 + 31 +0.0 + 0 +LINE + 5 +142 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530341.6169557605 + 20 +184858.8693757858 + 30 +0.0 + 11 +530423.5169519546 + 21 +184936.9090576151 + 31 +0.0 + 0 +LINE + 5 +143 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530363.0611291585 + 20 +184991.515820703 + 30 +0.0 + 11 +530950.6381382885 + 21 +184434.1646856795 + 31 +0.0 + 0 +LINE + 5 +144 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530794.3778468289 + 20 +184676.7579559348 + 30 +0.0 + 11 +531157.1550750989 + 21 +184924.2987611555 + 31 +0.0 + 0 +LINE + 5 +146 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530895.9427945592 + 20 +184674.477204796 + 30 +0.0 + 11 +530853.3539856806 + 21 +184722.662670036 + 31 +0.0 + 0 +LINE + 5 +147 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530872.5246082747 + 20 +184625.397131656 + 30 +0.0 + 11 +530895.3127741604 + 21 +184690.3429168817 + 31 +0.0 + 0 +LINE + 5 +148 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530881.7703476819 + 20 +184675.0240901761 + 30 +0.0 + 11 +531228.261643328 + 21 +184881.2784956878 + 31 +0.0 + 0 +LINE + 5 +149 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531056.8004158705 + 20 +184564.4609387729 + 30 +0.0 + 11 +530872.2051953306 + 21 +184927.5536250086 + 31 +0.0 + 0 +LINE + 5 +14A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530862.1453565096 + 20 +184918.8302863079 + 30 +0.0 + 11 +531068.2731269009 + 21 +185039.441703539 + 31 +0.0 + 0 +LINE + 5 +14B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530697.9914463482 + 20 +185015.5737333332 + 30 +0.0 + 11 +530880.1604013233 + 21 +184916.9768076993 + 31 +0.0 + 0 +LINE + 5 +14C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530696.9350081967 + 20 +184928.3907741009 + 30 +0.0 + 11 +530754.3600034362 + 21 +184991.5864201783 + 31 +0.0 + 0 +LINE + 5 +14D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531230.2997171692 + 20 +184634.8808927253 + 30 +0.0 + 11 +531185.2838804869 + 21 +184712.9556354173 + 31 +0.0 + 0 +LINE + 5 +14E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531310.676276314 + 20 +184636.9221898522 + 30 +0.0 + 11 +531065.3007066001 + 21 +185040.3313857042 + 31 +0.0 + 0 +LINE + 5 +14F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530762.244886776 + 20 +184753.1969188066 + 30 +0.0 + 11 +531117.1883003287 + 21 +184985.2538073602 + 31 +0.0 + 0 +LINE + 5 +150 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530857.7930969276 + 20 +185213.7272284981 + 30 +0.0 + 11 +531119.0590254821 + 21 +184978.5341598309 + 31 +0.0 + 0 +LINE + 5 +151 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530551.2309914298 + 20 +185447.3752691109 + 30 +0.0 + 11 +530733.9839065221 + 21 +185290.855504596 + 31 +0.0 + 0 +LINE + 5 +159 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530348.8181148427 + 20 +184670.0431449962 + 30 +0.0 + 11 +530754.9648854495 + 21 +185059.3532645555 + 31 +0.0 + 0 +LINE + 5 +15A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530768.0427135953 + 20 +185059.3665338815 + 30 +0.0 + 11 +530751.1019407378 + 21 +185076.7666714392 + 31 +0.0 + 0 +LINE + 5 +15B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530958.1276376175 + 20 +185054.7821770324 + 30 +0.0 + 11 +530999.5616859051 + 21 +185101.4584959087 + 31 +0.0 + 0 +LINE + 5 +15C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530956.1327284903 + 20 +185039.3761384984 + 30 +0.0 + 11 +530961.1058763477 + 21 +185062.9221409832 + 31 +0.0 + 0 +LINE + 5 +15D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530997.0898474322 + 20 +184990.0711256135 + 30 +0.0 + 11 +530952.7982457301 + 21 +185046.6406968503 + 31 +0.0 + 0 +LINE + 5 +15E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530292.8641702958 + 20 +185138.907267058 + 30 +0.0 + 11 +530369.4465080707 + 21 +185353.2161854958 + 31 +0.0 + 0 +LINE + 5 +160 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530370.209055034 + 20 +184973.0161857821 + 30 +0.0 + 11 +530279.2606443146 + 21 +185168.0844213306 + 31 +0.0 + 0 +LINE + 5 +167 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530103.8172967549 + 20 +184909.1432228739 + 30 +0.0 + 11 +530296.6434578779 + 21 +184802.4901862823 + 31 +0.0 + 0 +LINE + 5 +168 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530239.946090109 + 20 +184831.2897865306 + 30 +0.0 + 11 +530402.572414678 + 21 +185038.3924175608 + 31 +0.0 + 0 +LINE + 5 +169 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530862.2055151921 + 20 +184812.5389120712 + 30 +0.0 + 11 +530841.7372332033 + 21 +184854.8610028793 + 31 +0.0 + 0 +LINE + 5 +16A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530790.4707324915 + 20 +184816.8599962522 + 30 +0.0 + 11 +530843.6341425299 + 21 +184854.7341230553 + 31 +0.0 + 0 +LINE + 5 +16B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530795.6071824628 + 20 +184767.5732594106 + 30 +0.0 + 11 +530725.8663087268 + 21 +184845.1564635503 + 31 +0.0 + 0 +LINE + 5 +16C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530627.8983637173 + 20 +184730.1996766032 + 30 +0.0 + 11 +530825.9688616006 + 21 +184953.6427548386 + 31 +0.0 + 0 +LINE + 5 +16D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530924.4874933892 + 20 +184951.6836966566 + 30 +0.0 + 11 +530886.1381600594 + 21 +185008.8579249901 + 31 +0.0 + 0 +LINE + 5 +16E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530860.2504800935 + 20 +184990.3167291071 + 30 +0.0 + 11 +530910.0659924778 + 21 +185023.9468745498 + 31 +0.0 + 0 +LINE + 5 +16F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530868.4525274285 + 20 +184987.7108168294 + 30 +0.0 + 11 +530827.8842952691 + 21 +185046.3852955798 + 31 +0.0 + 0 +LINE + 5 +170 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530826.9412049412 + 20 +185042.7894761519 + 30 +0.0 + 11 +530872.6657967761 + 21 +185075.3601914692 + 31 +0.0 + 0 +LINE + 5 +171 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530910.0543372351 + 20 +185014.9114050643 + 30 +0.0 + 11 +530866.6906180778 + 21 +185079.1428277431 + 31 +0.0 + 0 +LINE + 5 +179 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531418.7837954784 + 20 +184696.3400722527 + 30 +0.0 + 11 +531280.8903155291 + 21 +184879.4025017154 + 31 +0.0 + 0 +LINE + 5 +17A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531365.823685466 + 20 +184738.3257753346 + 30 +0.0 + 11 +531592.6022829192 + 21 +184976.3217497332 + 31 +0.0 + 0 +LINE + 5 +17B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531322.1351667875 + 20 +184916.8361742784 + 30 +0.0 + 11 +531466.2108774758 + 21 +184798.1684518348 + 31 +0.0 + 0 +LINE + 5 +17C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531280.8533771736 + 20 +184872.4579400288 + 30 +0.0 + 11 +531322.982462895 + 21 +184916.8624535107 + 31 +0.0 + 0 +LINE + 5 +17D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531090.7411011921 + 20 +185101.1705888962 + 30 +0.0 + 11 +531309.9939928264 + 21 +184900.4864199589 + 31 +0.0 + 0 +LINE + 5 +17F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531234.6183701311 + 20 +185110.4794756935 + 30 +0.0 + 11 +531708.2884303343 + 21 +184665.0084063687 + 31 +0.0 + 0 +LINE + 5 +180 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531591.4298111294 + 20 +184870.2268875977 + 30 +0.0 + 11 +531810.6718730136 + 21 +185019.8265656036 + 31 +0.0 + 0 +LINE + 5 +181 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531638.9187541661 + 20 +184819.4880729046 + 30 +0.0 + 11 +531511.6900544397 + 21 +184965.8519211652 + 31 +0.0 + 0 +LINE + 5 +182 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531692.9947588596 + 20 +184867.9461364589 + 30 +0.0 + 11 +531650.4059499809 + 21 +184916.131601699 + 31 +0.0 + 0 +LINE + 5 +183 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531669.5765725753 + 20 +184818.8660633189 + 30 +0.0 + 11 +531692.3647384609 + 21 +184883.8118485445 + 31 +0.0 + 0 +LINE + 5 +184 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531678.8223119822 + 20 +184868.493021839 + 30 +0.0 + 11 +532025.3136076282 + 21 +185074.7474273507 + 31 +0.0 + 0 +LINE + 5 +185 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531803.886242807 + 20 +184855.9649338027 + 30 +0.0 + 11 +531669.257159631 + 21 +185121.0225566715 + 31 +0.0 + 0 +LINE + 5 +186 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531659.1973208101 + 20 +185112.2992179708 + 30 +0.0 + 11 +531865.3250912015 + 21 +185232.9106352019 + 31 +0.0 + 0 +LINE + 5 +187 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531525.0175778789 + 20 +185192.8194795596 + 30 +0.0 + 11 +531677.2123656238 + 21 +185110.4457393622 + 31 +0.0 + 0 +LINE + 5 +188 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531361.9808639693 + 20 +184957.7832641063 + 30 +0.0 + 11 +531551.4119677366 + 21 +185185.0553518411 + 31 +0.0 + 0 +LINE + 5 +18B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531559.2968510764 + 20 +184946.6658504695 + 30 +0.0 + 11 +531914.240264629 + 21 +185178.722739023 + 31 +0.0 + 0 +LINE + 5 +18C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531495.5870839868 + 20 +185514.328262188 + 30 +0.0 + 11 +531683.1901243598 + 21 +185202.3268566529 + 31 +0.0 + 0 +LINE + 5 +18D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531462.5997031672 + 20 +185412.663348532 + 30 +0.0 + 11 +531570.4877017599 + 21 +185459.0282866746 + 31 +0.0 + 0 +LINE + 5 +18E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531511.2935385215 + 20 +185374.1416658756 + 30 +0.0 + 11 +531543.5981320772 + 21 +185479.1274464145 + 31 +0.0 + 0 +LINE + 5 +194 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531145.8700791432 + 20 +184863.5120766591 + 30 +0.0 + 11 +531379.525038466 + 21 +185080.3303849344 + 31 +0.0 + 0 +LINE + 5 +199 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531364.8828980397 + 20 +185058.1671364388 + 30 +0.0 + 11 +531313.3430297857 + 21 +185456.7339505713 + 31 +0.0 + 0 +LINE + 5 +19D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531306.0542879553 + 20 +185343.6943371587 + 30 +0.0 + 11 +531471.2618974372 + 21 +185366.875736194 + 31 +0.0 + 0 +LINE + 5 +19E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531447.4325044233 + 20 +185362.2124236505 + 30 +0.0 + 11 +531528.0241316422 + 21 +185383.6033531333 + 31 +0.0 + 0 +LINE + 5 +19F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531454.8133421622 + 20 +185351.359117895 + 30 +0.0 + 11 +531476.2768427921 + 21 +185428.5825972159 + 31 +0.0 + 0 +LINE + 5 +1A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531385.8070593464 + 20 +185499.2874665739 + 30 +0.0 + 11 +531481.1514824921 + 21 +185416.9376060774 + 31 +0.0 + 0 +LINE + 5 +1A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531046.8204185547 + 20 +185009.8251670371 + 30 +0.0 + 11 +531131.4314460383 + 21 +185132.7716499767 + 31 +0.0 + 0 +LINE + 5 +1A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531659.2574794926 + 20 +185006.0078437341 + 30 +0.0 + 11 +531638.7891975036 + 21 +185048.3299345422 + 31 +0.0 + 0 +LINE + 5 +1A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531587.5226967918 + 20 +185010.328927915 + 30 +0.0 + 11 +531640.6861068304 + 21 +185048.2030547182 + 31 +0.0 + 0 +LINE + 5 +1A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531592.6591467632 + 20 +184961.0421910735 + 30 +0.0 + 11 +531522.9182730272 + 21 +185038.625395213 + 31 +0.0 + 0 +LINE + 5 +1A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531424.9503280177 + 20 +184923.6686082661 + 30 +0.0 + 11 +531623.020825901 + 21 +185147.1116865014 + 31 +0.0 + 0 +LINE + 5 +1A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531721.5394576896 + 20 +185145.1526283194 + 30 +0.0 + 11 +531683.1901243598 + 21 +185202.3268566529 + 31 +0.0 + 0 +LINE + 5 +1A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531522.4751258036 + 20 +185175.0126803835 + 30 +0.0 + 11 +531707.1179567783 + 21 +185217.4158062127 + 31 +0.0 + 0 +LINE + 5 +1AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531190.971715833 + 20 +185002.7164624653 + 30 +0.0 + 11 +531271.9560624464 + 21 +185081.1135679418 + 31 +0.0 + 0 +LINE + 5 +1AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531510.9794785422 + 20 +185470.5053524346 + 30 +0.0 + 11 +531383.9700559601 + 21 +186031.2293542523 + 31 +0.0 + 0 +LINE + 5 +1AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531446.5789296222 + 20 +185494.6210341629 + 30 +0.0 + 11 +531394.317069799 + 21 +185715.8408406318 + 31 +0.0 + 0 +LINE + 5 +1AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531303.1927971798 + 20 +185374.8117721197 + 30 +0.0 + 11 +531201.7089334832 + 21 +185510.9511236965 + 31 +0.0 + 0 +LINE + 5 +1B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531179.1304861695 + 20 +185309.1540542189 + 30 +0.0 + 11 +531945.5235833686 + 21 +185894.4094584342 + 31 +0.0 + 0 +LINE + 5 +1B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531306.2594945883 + 20 +185492.8769809982 + 30 +0.0 + 11 +531119.7299674333 + 21 +185890.4829456162 + 31 +0.0 + 0 +LINE + 5 +1B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531363.9212119025 + 20 +185531.6681318393 + 30 +0.0 + 11 +531199.1434766117 + 21 +185429.4046678644 + 31 +0.0 + 0 +LINE + 5 +1B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531324.7054493229 + 20 +185592.7788688038 + 30 +0.0 + 11 +531270.3457337779 + 21 +185558.4180331335 + 31 +0.0 + 0 +LINE + 5 +1B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531369.4236081366 + 20 +185561.8345429817 + 30 +0.0 + 11 +531308.9422635012 + 21 +185594.6866734165 + 31 +0.0 + 0 +LINE + 5 +1B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531321.9057846517 + 20 +185578.8749408755 + 30 +0.0 + 11 +531173.5376807172 + 21 +185953.8202748729 + 31 +0.0 + 0 +LINE + 5 +1B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531458.9627071512 + 20 +185734.036583085 + 30 +0.0 + 11 +531071.0819022518 + 21 +185609.6976292752 + 31 +0.0 + 0 +LINE + 5 +1B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531078.0896100116 + 20 +185598.3755699595 + 30 +0.0 + 11 +530991.8880389454 + 21 +185821.0975061012 + 31 +0.0 + 0 +LINE + 5 +1B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530956.4097734758 + 20 +185451.7474070975 + 30 +0.0 + 11 +531082.7918483163 + 21 +185615.8646001648 + 31 +0.0 + 0 +LINE + 5 +1B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531042.3088874028 + 20 +185436.8032889021 + 30 +0.0 + 11 +530989.0780830457 + 21 +185503.5700563008 + 31 +0.0 + 0 +LINE + 5 +1BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531427.9086440181 + 20 +185996.2182578582 + 30 +0.0 + 11 +530990.5357910721 + 21 +185818.3049727551 + 31 +0.0 + 0 +LINE + 5 +1BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531225.67491972 + 20 +185473.3432035857 + 30 +0.0 + 11 +531053.182121386 + 21 +185860.7466894662 + 31 +0.0 + 0 +LINE + 5 +1BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530705.244826224 + 20 +185533.1168306179 + 30 +0.0 + 11 +531060.1140837643 + 21 +185861.5220430019 + 31 +0.0 + 0 +LINE + 5 +1BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530750.2210620191 + 20 +185452.1857979919 + 30 +0.0 + 11 +530721.6518899537 + 21 +185566.0863253691 + 31 +0.0 + 0 +LINE + 5 +1C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530796.0140686664 + 20 +185494.1144299564 + 30 +0.0 + 11 +530697.5223713036 + 21 +185542.7455561081 + 31 +0.0 + 0 +LINE + 5 +1C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530944.3922051936 + 20 +185612.8039722922 + 30 +0.0 + 11 +530775.9576853574 + 21 +185501.2824771057 + 31 +0.0 + 0 +LINE + 5 +1C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530993.2462747479 + 20 +185401.3925582406 + 30 +0.0 + 11 +530842.445202569 + 21 +185661.7511045552 + 31 +0.0 + 0 +LINE + 5 +1C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530910.7632248174 + 20 +185339.3410325321 + 30 +0.0 + 11 +530866.5377199338 + 21 +185054.4967921601 + 31 +0.0 + 0 +LINE + 5 +1C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531241.8445475885 + 20 +185051.9469660791 + 30 +0.0 + 11 +531241.8374840348 + 21 +185051.9572004795 + 31 +0.0 + 0 +LINE + 5 +1C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531058.6997013602 + 20 +185297.1334434182 + 30 +0.0 + 11 +530922.2746789083 + 21 +185514.9725242263 + 31 +0.0 + 0 +LINE + 5 +1C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530924.3468199957 + 20 +185527.8851535635 + 30 +0.0 + 11 +530904.4681140504 + 21 +185513.935543462 + 31 +0.0 + 0 +LINE + 5 +1C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530959.1812899459 + 20 +185714.807207831 + 30 +0.0 + 11 +530929.7367229487 + 21 +185749.2623184473 + 31 +0.0 + 0 +LINE + 5 +1CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530974.0721419792 + 20 +185710.3813506865 + 30 +0.0 + 11 +530951.620342561 + 21 +185719.0452490875 + 31 +0.0 + 0 +LINE + 5 +1CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531029.2769113626 + 20 +185742.952861627 + 30 +0.0 + 11 +530966.368846218 + 21 +185708.2478517434 + 31 +0.0 + 0 +LINE + 5 +1CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530990.5554871495 + 20 +185489.0985828673 + 30 +0.0 + 11 +530692.0265768201 + 21 +185303.9764231624 + 31 +0.0 + 0 +LINE + 5 +1CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530835.9437799745 + 20 +185306.8642317253 + 30 +0.0 + 11 +530970.1789346107 + 21 +185451.086004182 + 31 +0.0 + 0 +LINE + 5 +1CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531368.1091655745 + 20 +185350.5718122836 + 30 +0.0 + 11 +530668.7795996761 + 21 +185311.5128716326 + 31 +0.0 + 0 +LINE + 5 +1CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530837.7457079078 + 20 +185386.5022824307 + 30 +0.0 + 11 +530778.7567006423 + 21 +185458.8357962565 + 31 +0.0 + 0 +LINE + 5 +1D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530797.6081421722 + 20 +185429.1683182495 + 30 +0.0 + 11 +530789.3411006597 + 21 +185512.1396281498 + 31 +0.0 + 0 +LINE + 5 +1D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530809.4994571749 + 20 +185434.7241835344 + 30 +0.0 + 11 +530736.6862803595 + 21 +185468.2262566015 + 31 +0.0 + 0 +LINE + 5 +1D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530609.7436608612 + 20 +185359.4255856905 + 30 +0.0 + 11 +530748.9595424861 + 21 +185471.1817544603 + 31 +0.0 + 0 +LINE + 5 +1D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531183.0307102225 + 20 +185581.4869541878 + 30 +0.0 + 11 +531137.9864403011 + 21 +185568.0287342017 + 31 +0.0 + 0 +LINE + 5 +1D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531167.3269023387 + 20 +185511.358919597 + 30 +0.0 + 11 +531138.4141562844 + 21 +185569.8811441243 + 31 +0.0 + 0 +LINE + 5 +1D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531226.956583333 + 20 +185337.0486008117 + 30 +0.0 + 11 +531037.9542343994 + 21 +185568.2127058122 + 31 +0.0 + 0 +LINE + 5 +1D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531055.5968811997 + 20 +185665.1585449819 + 30 +0.0 + 11 +530905.7031021065 + 21 +185592.1718504262 + 31 +0.0 + 0 +LINE + 5 +1DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531342.5419517839 + 20 +185694.0402766141 + 30 +0.0 + 11 +531259.2409286286 + 21 +185945.1870251501 + 31 +0.0 + 0 +LINE + 5 +1DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530564.9552335094 + 20 +184893.4794901465 + 30 +0.0 + 11 +530687.4949689912 + 21 +184780.9839569827 + 31 +0.0 + 0 +LINE + 5 +1DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530476.7429703215 + 20 +184939.4505193447 + 30 +0.0 + 11 +530406.7340426724 + 21 +184768.7171604471 + 31 +0.0 + 0 +LINE + 5 +1E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531173.3663268639 + 20 +185528.1064924517 + 30 +0.0 + 11 +531070.7327473465 + 21 +185471.5685231011 + 31 +0.0 + 0 +LINE + 5 +1E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531054.9475551248 + 20 +184568.1054545053 + 30 +0.0 + 11 +531230.7725863386 + 21 +184476.7284847849 + 31 +0.0 + 0 +LINE + 5 +1E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533270.7018874835 + 20 +183269.704674172 + 30 +0.0 + 11 +533995.2261483039 + 21 +183104.4788902862 + 31 +0.0 + 0 +LINE + 5 +1E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533457.9214482086 + 20 +183355.7642878445 + 30 +0.0 + 11 +533604.5737555198 + 21 +183337.0347532795 + 31 +0.0 + 0 +LINE + 5 +1E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533530.1315517867 + 20 +183207.8193128204 + 30 +0.0 + 11 +533511.6243141418 + 21 +183701.9266786306 + 31 +0.0 + 0 +LINE + 5 +1E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533572.3429516997 + 20 +183331.8438445227 + 30 +0.0 + 11 +533646.7981581808 + 21 +183366.1588628451 + 31 +0.0 + 0 +LINE + 5 +1E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533612.2522464815 + 20 +183262.8325135418 + 30 +0.0 + 11 +533576.567616609 + 21 +183343.107264685 + 31 +0.0 + 0 +LINE + 5 +1E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533597.4568488472 + 20 +183274.7830833879 + 30 +0.0 + 11 +533791.7168653864 + 21 +183232.1532961663 + 31 +0.0 + 0 +LINE + 5 +1E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533594.7911288029 + 20 +183152.2117233308 + 30 +0.0 + 11 +533751.8214958982 + 21 +183555.6973923812 + 31 +0.0 + 0 +LINE + 5 +1EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533810.3821678945 + 20 +183285.0285129525 + 30 +0.0 + 11 +533642.492107029 + 21 +183366.5930041412 + 31 +0.0 + 0 +LINE + 5 +1EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533787.2284528753 + 20 +183229.0149493306 + 30 +0.0 + 11 +533810.0531847598 + 21 +183285.8097756414 + 31 +0.0 + 0 +LINE + 5 +1EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534074.3386399248 + 20 +183151.4269752421 + 30 +0.0 + 11 +533800.5742660043 + 21 +183267.181170518 + 31 +0.0 + 0 +LINE + 5 +1ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534009.9822550737 + 20 +183174.6632241171 + 30 +0.0 + 11 +534046.8228962965 + 21 +183281.6238171917 + 31 +0.0 + 0 +LINE + 5 +1EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534121.646702763 + 20 +183249.4026584481 + 30 +0.0 + 11 +533363.7016999166 + 21 +183552.296365491 + 31 +0.0 + 0 +LINE + 5 +1EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533655.8537941067 + 20 +183510.4459319125 + 30 +0.0 + 11 +533729.8187339051 + 21 +183943.3581115531 + 31 +0.0 + 0 +LINE + 5 +1F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533589.946866456 + 20 +183532.4891602347 + 30 +0.0 + 11 +533776.0005197917 + 21 +183477.7757597539 + 31 +0.0 + 0 +LINE + 5 +1F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533611.4813241646 + 20 +183601.8337010309 + 30 +0.0 + 11 +533673.0261102665 + 21 +183583.1820253481 + 31 +0.0 + 0 +LINE + 5 +1F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533576.6132530237 + 20 +183560.1026257608 + 30 +0.0 + 11 +533626.1680009311 + 21 +183607.8685391599 + 31 +0.0 + 0 +LINE + 5 +1F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533617.8809475537 + 20 +183589.176602051 + 30 +0.0 + 11 +533661.0930421482 + 21 +183990.087829921 + 31 +0.0 + 0 +LINE + 5 +1F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533444.4675323084 + 20 +183702.2585308958 + 30 +0.0 + 11 +533851.4514544708 + 21 +183685.6518652057 + 31 +0.0 + 0 +LINE + 5 +1F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533847.7102810031 + 20 +183672.8729522521 + 30 +0.0 + 11 +533871.5176046772 + 21 +183910.5049850937 + 31 +0.0 + 0 +LINE + 5 +1F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534004.0299181535 + 20 +183563.9235520484 + 30 +0.0 + 11 +533838.5224367574 + 21 +183688.479384923 + 31 +0.0 + 0 +LINE + 5 +1F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533925.2076230635 + 20 +183526.6538560638 + 30 +0.0 + 11 +533958.7459745272 + 21 +183605.1809134549 + 31 +0.0 + 0 +LINE + 5 +1F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533207.3255747524 + 20 +183960.3049635265 + 30 +0.0 + 11 +533517.743220695 + 21 +183803.8631234574 + 31 +0.0 + 0 +LINE + 5 +1F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533404.6134673158 + 20 +183963.2474941249 + 30 +0.0 + 11 +533873.5643870204 + 21 +183908.1731405794 + 31 +0.0 + 0 +LINE + 5 +1FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533738.7306447869 + 20 +183513.0669599583 + 30 +0.0 + 11 +533801.8809645518 + 21 +183932.4084239981 + 31 +0.0 + 0 +LINE + 5 +1FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534224.47460254 + 20 +183709.2127634093 + 30 +0.0 + 11 +533794.9927018023 + 21 +183931.3106481514 + 31 +0.0 + 0 +LINE + 5 +1FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534457.7232899407 + 20 +183610.3296057948 + 30 +0.0 + 11 +533968.0924029948 + 21 +183836.668115154 + 31 +0.0 + 0 +LINE + 5 +1FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534202.6632789289 + 20 +183619.2296539358 + 30 +0.0 + 11 +534199.8836010037 + 21 +183736.6255700483 + 31 +0.0 + 0 +LINE + 5 +1FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534147.3617370868 + 20 +183647.456398454 + 30 +0.0 + 11 +534229.3554706404 + 21 +183720.5496849997 + 31 +0.0 + 0 +LINE + 5 +1FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533972.7437243368 + 20 +183722.3685368734 + 30 +0.0 + 11 +534164.7865490214 + 21 +183659.7044734213 + 31 +0.0 + 0 +LINE + 5 +200 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533972.5943166301 + 20 +183472.651390221 + 30 +0.0 + 11 +534057.9839914489 + 21 +183796.6861657618 + 31 +0.0 + 0 +LINE + 5 +201 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533880.9676565471 + 20 +183491.6555787594 + 30 +0.0 + 11 +534001.1484391712 + 21 +183474.2186921551 + 31 +0.0 + 0 +LINE + 5 +202 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533966.8649116843 + 20 +183378.0488408435 + 30 +0.0 + 11 +533865.8384516585 + 21 +183444.2408746609 + 31 +0.0 + 0 +LINE + 5 +203 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533869.8459157255 + 20 +183438.8265558422 + 30 +0.0 + 11 +533882.4827401662 + 21 +183493.2134252263 + 31 +0.0 + 0 +LINE + 5 +204 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533835.3120588305 + 20 +183102.5693639709 + 30 +0.0 + 11 +534020.1041949208 + 21 +183633.953815103 + 31 +0.0 + 0 +LINE + 5 +205 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534014.6697131808 + 20 +183645.8490315072 + 30 +0.0 + 11 +534037.5443778956 + 21 +183637.6940154909 + 31 +0.0 + 0 +LINE + 5 +206 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533931.3368567337 + 20 +183816.7552329881 + 30 +0.0 + 11 +533950.5478562621 + 21 +183857.8048940144 + 31 +0.0 + 0 +LINE + 5 +207 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533918.1613004711 + 20 +183808.5253846964 + 30 +0.0 + 11 +533937.4969419636 + 21 +183822.8529595328 + 31 +0.0 + 0 +LINE + 5 +208 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533856.2782318214 + 20 +183825.2273517097 + 30 +0.0 + 11 +533926.1545818143 + 21 +183808.5193272029 + 31 +0.0 + 0 +LINE + 5 +209 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533961.1739025831 + 20 +183590.8382696407 + 30 +0.0 + 11 +534379.5749554228 + 21 +183474.2284763425 + 31 +0.0 + 0 +LINE + 5 +20A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534350.0885551939 + 20 +183462.4292674622 + 30 +0.0 + 11 +534369.0260173707 + 21 +183662.8181014637 + 31 +0.0 + 0 +LINE + 5 +20B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534101.8508752668 + 20 +183248.1966110715 + 30 +0.0 + 11 +534369.7091801646 + 21 +183492.8116011192 + 31 +0.0 + 0 +LINE + 5 +20C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534331.7371032914 + 20 +183358.3280084779 + 30 +0.0 + 11 +533990.9335592428 + 21 +183559.6209208238 + 31 +0.0 + 0 +LINE + 5 +20D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533948.9530815789 + 20 +183438.1485673899 + 30 +0.0 + 11 +533982.607720473 + 21 +183426.774957106 + 31 +0.0 + 0 +LINE + 5 +20E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534135.7799619498 + 20 +183532.6183973673 + 30 +0.0 + 11 +534173.3870155533 + 21 +183618.0440944372 + 31 +0.0 + 0 +LINE + 5 +20F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534163.1125968062 + 20 +183584.4290320622 + 30 +0.0 + 11 +534148.9959986748 + 21 +183666.607520118 + 31 +0.0 + 0 +LINE + 5 +210 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534150.1714181212 + 20 +183586.619216026 + 30 +0.0 + 11 +534211.4401009357 + 21 +183638.2941240943 + 31 +0.0 + 0 +LINE + 5 +211 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534362.7636945454 + 20 +183567.208368469 + 30 +0.0 + 11 +534198.8229231334 + 21 +183637.8760868667 + 31 +0.0 + 0 +LINE + 5 +212 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534133.0534407664 + 20 +183026.7152225984 + 30 +0.0 + 11 +533977.4553795874 + 21 +183110.2952903923 + 31 +0.0 + 0 +LINE + 5 +213 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534027.2513479877 + 20 +183070.7431726557 + 30 +0.0 + 11 +534147.8091657108 + 21 +183304.8470679847 + 31 +0.0 + 0 +LINE + 5 +214 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533751.0505647677 + 20 +183628.6602944098 + 30 +0.0 + 11 +533798.0520979916 + 21 +183627.6775367849 + 31 +0.0 + 0 +LINE + 5 +215 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533784.854580768 + 20 +183565.2423212487 + 30 +0.0 + 11 +533797.1467362854 + 21 +183629.3492675242 + 31 +0.0 + 0 +LINE + 5 +216 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533737.9064232347 + 20 +183549.3855860542 + 30 +0.0 + 11 +533837.4861916935 + 21 +183518.2919734023 + 31 +0.0 + 0 +LINE + 5 +217 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533773.7742595558 + 20 +183381.3482958636 + 30 +0.0 + 11 +533894.426477489 + 21 +183654.4815484178 + 31 +0.0 + 0 +LINE + 5 +218 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533851.6151786993 + 20 +183743.2337394579 + 30 +0.0 + 11 +533919.5664651833 + 21 +183732.1799429354 + 31 +0.0 + 0 +LINE + 5 +219 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533913.4912480489 + 20 +183700.922309379 + 30 +0.0 + 11 +533923.3192982251 + 21 +183760.2180207445 + 31 +0.0 + 0 +LINE + 5 +21A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533907.7061656309 + 20 +183707.2939010718 + 30 +0.0 + 11 +533977.9455113938 + 21 +183694.8476074883 + 31 +0.0 + 0 +LINE + 5 +21B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533975.0691473797 + 20 +183692.4926410805 + 30 +0.0 + 11 +533985.6377707644 + 21 +183747.6278747745 + 31 +0.0 + 0 +LINE + 5 +21C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533915.1095672107 + 20 +183756.444406914 + 30 +0.0 + 11 +533991.5652424396 + 21 +183743.7709100099 + 31 +0.0 + 0 +LINE + 5 +21D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533943.085985443 + 20 +183201.5481465576 + 30 +0.0 + 11 +533980.6329200526 + 21 +183307.8251348707 + 31 +0.0 + 0 +LINE + 5 +21E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533567.3344408618 + 20 +183694.6941674654 + 30 +0.0 + 11 +533580.779713257 + 21 +183958.953461359 + 31 +0.0 + 0 +LINE + 5 +21F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533299.3400004697 + 20 +184222.45492858 + 30 +0.0 + 11 +533281.5900181469 + 21 +184813.9041900183 + 31 +0.0 + 0 +LINE + 5 +220 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533203.5044763441 + 20 +184131.5129678913 + 30 +0.0 + 11 +533448.5161786756 + 21 +184142.2478269584 + 31 +0.0 + 0 +LINE + 5 +221 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533425.5537299617 + 20 +183189.4530703633 + 30 +0.0 + 11 +533355.5667372975 + 21 +184507.1397523095 + 31 +0.0 + 0 +LINE + 5 +222 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533416.2853748554 + 20 +184137.0569182016 + 30 +0.0 + 11 +533490.7405813366 + 21 +184171.371936524 + 31 +0.0 + 0 +LINE + 5 +223 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533456.1946696371 + 20 +184068.0455872208 + 30 +0.0 + 11 +533420.510039765 + 21 +184148.3203383639 + 31 +0.0 + 0 +LINE + 5 +224 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533443.2091147539 + 20 +184079.7836062105 + 30 +0.0 + 11 +533637.4691312929 + 21 +184037.1538189889 + 31 +0.0 + 0 +LINE + 5 +225 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533407.8651870973 + 20 +183878.1092921243 + 30 +0.0 + 11 +533595.763919054 + 21 +184360.9104660599 + 31 +0.0 + 0 +LINE + 5 +226 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533654.3245910503 + 20 +184090.2415866314 + 30 +0.0 + 11 +533486.4345301848 + 21 +184171.8060778201 + 31 +0.0 + 0 +LINE + 5 +227 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533631.1708760309 + 20 +184034.2280230095 + 30 +0.0 + 11 +533653.9956079153 + 21 +184091.0228493203 + 31 +0.0 + 0 +LINE + 5 +228 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533918.2810630807 + 20 +183956.640048921 + 30 +0.0 + 11 +533644.51668916 + 21 +184072.3942441969 + 31 +0.0 + 0 +LINE + 5 +229 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533853.9246782293 + 20 +183979.876297796 + 30 +0.0 + 11 +533890.7653194523 + 21 +184086.8368908706 + 31 +0.0 + 0 +LINE + 5 +22A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533965.5891259187 + 20 +184054.615732127 + 30 +0.0 + 11 +533264.55379769 + 21 +184336.4331711375 + 31 +0.0 + 0 +LINE + 5 +22B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533499.7962172624 + 20 +184315.6590055914 + 30 +0.0 + 11 +533573.761157061 + 21 +184748.571185232 + 31 +0.0 + 0 +LINE + 5 +22C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533433.8892896117 + 20 +184337.7022339136 + 30 +0.0 + 11 +533619.9429429473 + 21 +184282.9888334328 + 31 +0.0 + 0 +LINE + 5 +22D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533455.4237473202 + 20 +184407.0467747098 + 30 +0.0 + 11 +533516.9685334222 + 21 +184388.3950990269 + 31 +0.0 + 0 +LINE + 5 +22E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533420.5556761794 + 20 +184365.3156994397 + 30 +0.0 + 11 +533470.1104240868 + 21 +184413.0816128387 + 31 +0.0 + 0 +LINE + 5 +22F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533461.8233707093 + 20 +184394.3896757299 + 30 +0.0 + 11 +533505.0354653038 + 21 +184795.3009035999 + 31 +0.0 + 0 +LINE + 5 +230 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533288.409955464 + 20 +184507.4716045747 + 30 +0.0 + 11 +533695.3938776265 + 21 +184490.8649388846 + 31 +0.0 + 0 +LINE + 5 +231 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533691.6527041588 + 20 +184478.0860259309 + 30 +0.0 + 11 +533715.4600278328 + 21 +184715.7180587726 + 31 +0.0 + 0 +LINE + 5 +232 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533847.9723413094 + 20 +184369.1366257273 + 30 +0.0 + 11 +533682.4648599131 + 21 +184493.6924586019 + 31 +0.0 + 0 +LINE + 5 +233 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533769.1500462192 + 20 +184331.8669297427 + 30 +0.0 + 11 +533802.6883976829 + 21 +184410.3939871337 + 31 +0.0 + 0 +LINE + 5 +234 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533280.1746114135 + 20 +184638.1115223118 + 30 +0.0 + 11 +533369.903982884 + 21 +184629.7013561934 + 31 +0.0 + 0 +LINE + 5 +235 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533248.5558904716 + 20 +184768.4605678038 + 30 +0.0 + 11 +533717.5068101762 + 21 +184713.3862142584 + 31 +0.0 + 0 +LINE + 5 +236 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533582.6730679426 + 20 +184318.2800336372 + 30 +0.0 + 11 +533645.8233877078 + 21 +184737.6214976771 + 31 +0.0 + 0 +LINE + 5 +237 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534121.0039373072 + 20 +184485.2255270968 + 30 +0.0 + 11 +533638.9351249582 + 21 +184736.5237218303 + 31 +0.0 + 0 +LINE + 5 +238 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534046.6057020844 + 20 +184424.4427276146 + 30 +0.0 + 11 +534043.8260241596 + 21 +184541.8386437273 + 31 +0.0 + 0 +LINE + 5 +239 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533991.3041602425 + 20 +184452.6694721329 + 30 +0.0 + 11 +534073.2978937961 + 21 +184525.7627586786 + 31 +0.0 + 0 +LINE + 5 +23A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533816.6861474925 + 20 +184527.5816105521 + 30 +0.0 + 11 +534008.728972177 + 21 +184464.9175471002 + 31 +0.0 + 0 +LINE + 5 +23B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533816.5367397858 + 20 +184277.8644638999 + 30 +0.0 + 11 +533901.9264146046 + 21 +184601.8992394407 + 31 +0.0 + 0 +LINE + 5 +23C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533724.9100797029 + 20 +184296.8686524383 + 30 +0.0 + 11 +533845.0908623268 + 21 +184279.431765834 + 31 +0.0 + 0 +LINE + 5 +23D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533810.80733484 + 20 +184183.2619145225 + 30 +0.0 + 11 +533709.7808748143 + 21 +184249.4539483398 + 31 +0.0 + 0 +LINE + 5 +23E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533713.7883388813 + 20 +184244.0396295211 + 30 +0.0 + 11 +533726.4251633219 + 21 +184298.4264989052 + 31 +0.0 + 0 +LINE + 5 +23F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533679.2544819863 + 20 +183907.7824376498 + 30 +0.0 + 11 +533864.0466180764 + 21 +184439.1668887819 + 31 +0.0 + 0 +LINE + 5 +240 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533858.6121363364 + 20 +184451.062105186 + 30 +0.0 + 11 +533881.4868010512 + 21 +184442.9070891699 + 31 +0.0 + 0 +LINE + 5 +241 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533775.2792798895 + 20 +184621.968306667 + 30 +0.0 + 11 +533794.4902794179 + 21 +184663.0179676933 + 31 +0.0 + 0 +LINE + 5 +242 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533762.1037236266 + 20 +184613.7384583753 + 30 +0.0 + 11 +533781.4393651193 + 21 +184628.0660332116 + 31 +0.0 + 0 +LINE + 5 +243 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533700.2206549769 + 20 +184630.4404253886 + 30 +0.0 + 11 +533770.09700497 + 21 +184613.7324008818 + 31 +0.0 + 0 +LINE + 5 +244 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533805.1163257389 + 20 +184396.0513433196 + 30 +0.0 + 11 +534148.8336143433 + 21 +184307.1003803216 + 31 +0.0 + 0 +LINE + 5 +245 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533945.7932984225 + 20 +184053.4096847504 + 30 +0.0 + 11 +534099.4280930914 + 21 +184187.6594453309 + 31 +0.0 + 0 +LINE + 5 +246 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534111.8739580623 + 20 +184159.1560880029 + 30 +0.0 + 11 +533834.8759823985 + 21 +184364.8339945026 + 31 +0.0 + 0 +LINE + 5 +247 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533792.8955047349 + 20 +184243.3616410688 + 30 +0.0 + 11 +533826.5501436286 + 21 +184231.9880307849 + 31 +0.0 + 0 +LINE + 5 +248 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533979.7223851057 + 20 +184337.8314710463 + 30 +0.0 + 11 +534017.3294387088 + 21 +184423.2571681159 + 31 +0.0 + 0 +LINE + 5 +249 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534007.0550199618 + 20 +184389.6421057411 + 30 +0.0 + 11 +533992.9384218304 + 21 +184471.8205937969 + 31 +0.0 + 0 +LINE + 5 +24A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533994.1138412768 + 20 +184391.8322897049 + 30 +0.0 + 11 +534055.3825240914 + 21 +184443.5071977732 + 31 +0.0 + 0 +LINE + 5 +24B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534157.3418682092 + 20 +184390.7032924748 + 30 +0.0 + 11 +534042.765346289 + 21 +184443.0891605456 + 31 +0.0 + 0 +LINE + 5 +24C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533853.5262160743 + 20 +183878.666833987 + 30 +0.0 + 11 +533991.7515888664 + 21 +184110.0601416636 + 31 +0.0 + 0 +LINE + 5 +24D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533594.9929879234 + 20 +184433.8733680887 + 30 +0.0 + 11 +533641.9945211472 + 21 +184432.8906104638 + 31 +0.0 + 0 +LINE + 5 +24E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533628.7970039238 + 20 +184370.4553949276 + 30 +0.0 + 11 +533641.0891594411 + 21 +184434.5623412031 + 31 +0.0 + 0 +LINE + 5 +24F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533581.8488463905 + 20 +184354.5986597329 + 30 +0.0 + 11 +533681.4286148493 + 21 +184323.5050470813 + 31 +0.0 + 0 +LINE + 5 +250 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533617.7166827114 + 20 +184186.5613695425 + 30 +0.0 + 11 +533738.3689006447 + 21 +184459.6946220967 + 31 +0.0 + 0 +LINE + 5 +251 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533695.557601855 + 20 +184548.4468131368 + 30 +0.0 + 11 +533763.508888339 + 21 +184537.3930166142 + 31 +0.0 + 0 +LINE + 5 +252 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533757.4336712046 + 20 +184506.1353830579 + 30 +0.0 + 11 +533767.2617213808 + 21 +184565.4310944234 + 31 +0.0 + 0 +LINE + 5 +253 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533751.6485887866 + 20 +184512.5069747506 + 30 +0.0 + 11 +533821.8879345495 + 21 +184500.0606811671 + 31 +0.0 + 0 +LINE + 5 +254 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533819.0115705354 + 20 +184497.7057147594 + 30 +0.0 + 11 +533829.5801939202 + 21 +184552.8409484534 + 31 +0.0 + 0 +LINE + 5 +255 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533759.0519903664 + 20 +184561.6574805929 + 30 +0.0 + 11 +533835.5076655954 + 21 +184548.9839836887 + 31 +0.0 + 0 +LINE + 5 +256 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533787.0284085987 + 20 +184006.7612202365 + 30 +0.0 + 11 +533824.5753432083 + 21 +184113.0382085496 + 31 +0.0 + 0 +LINE + 5 +257 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533411.2768640178 + 20 +184499.9072411442 + 30 +0.0 + 11 +533424.7221364126 + 21 +184764.1665350379 + 31 +0.0 + 0 +LINE + 5 +258 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534079.0438751079 + 20 +184492.5166948246 + 30 +0.0 + 11 +534641.721189493 + 21 +184610.5719340789 + 31 +0.0 + 0 +LINE + 5 +25A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534078.5814593011 + 20 +184263.7540395752 + 30 +0.0 + 11 +534244.6175290032 + 21 +184228.1883089295 + 31 +0.0 + 0 +LINE + 5 +25B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534001.2095466687 + 20 +183814.2563075048 + 30 +0.0 + 11 +534167.6424192836 + 21 +184551.2581387564 + 31 +0.0 + 0 +LINE + 5 +25C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534184.6430945557 + 20 +184315.7129436011 + 30 +0.0 + 11 +534623.810301958 + 21 +184321.8368213024 + 31 +0.0 + 0 +LINE + 5 +25D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534195.8955435099 + 20 +184384.2914345422 + 30 +0.0 + 11 +534171.5481171157 + 21 +184191.8941348217 + 31 +0.0 + 0 +LINE + 5 +25E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534267.7865448688 + 20 +184374.0893695216 + 30 +0.0 + 11 +534259.1867207303 + 21 +184310.3579900692 + 31 +0.0 + 0 +LINE + 5 +25F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534221.0297037694 + 20 +184401.8573877923 + 30 +0.0 + 11 +534276.0859439502 + 21 +184360.5528367094 + 31 +0.0 + 0 +LINE + 5 +260 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534256.3117883924 + 20 +184365.7534653767 + 30 +0.0 + 11 +534658.9839601197 + 21 +184387.0189272303 + 31 +0.0 + 0 +LINE + 5 +261 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534340.2964578094 + 20 +184554.9790199963 + 30 +0.0 + 11 +534388.795247378 + 21 +184150.5540434503 + 31 +0.0 + 0 +LINE + 5 +262 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534375.5833000987 + 20 +184152.2097741889 + 30 +0.0 + 11 +534613.971169032 + 21 +184166.5971171824 + 31 +0.0 + 0 +LINE + 5 +263 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534292.9527107282 + 20 +183980.5182296566 + 30 +0.0 + 11 +534389.5250794471 + 21 +184163.7684943256 + 31 +0.0 + 0 +LINE + 5 +264 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534243.591734117 + 20 +184052.3894925513 + 30 +0.0 + 11 +534326.4617765393 + 21 +184031.8012475966 + 31 +0.0 + 0 +LINE + 5 +265 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534523.654663655 + 20 +184592.9361776223 + 30 +0.0 + 11 +534529.6593127575 + 21 +184503.01379338 + 31 +0.0 + 0 +LINE + 5 +267 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534200.4451829229 + 20 +184234.3143184903 + 30 +0.0 + 11 +534624.4909197793 + 21 +184238.8353143359 + 31 +0.0 + 0 +LINE + 5 +268 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534471.5327107409 + 20 +183786.0600145884 + 30 +0.0 + 11 +534606.9904846774 + 21 +184209.2224334297 + 31 +0.0 + 0 +LINE + 5 +269 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534421.2657241103 + 20 +183576.3330352236 + 30 +0.0 + 11 +534556.4776611428 + 21 +184059.4846922112 + 31 +0.0 + 0 +LINE + 5 +26A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534379.2230397164 + 20 +183793.2446136424 + 30 +0.0 + 11 +534494.6738051587 + 21 +183814.7073368633 + 31 +0.0 + 0 +LINE + 5 +26B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534398.2709077693 + 20 +183852.3393541769 + 30 +0.0 + 11 +534483.5028377962 + 21 +183783.049246773 + 31 +0.0 + 0 +LINE + 5 +26C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534444.3820505485 + 20 +184036.6679774855 + 30 +0.0 + 11 +534413.140644698 + 21 +183837.0904088021 + 31 +0.0 + 0 +LINE + 5 +26D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534231.8313058096 + 20 +183993.0367155942 + 30 +0.0 + 11 +534531.3403140241 + 21 +183964.3680914949 + 31 +0.0 + 0 +LINE + 5 +26E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534172.5775135222 + 20 +183923.7014562585 + 30 +0.0 + 11 +534215.9402417578 + 21 +184037.1348698832 + 31 +0.0 + 0 +LINE + 5 +26F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534115.2587862786 + 20 +184054.0831760169 + 30 +0.0 + 11 +534123.8030832675 + 21 +183933.6060995451 + 31 +0.0 + 0 +LINE + 5 +270 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534121.0293094167 + 20 +183939.744568014 + 30 +0.0 + 11 +534174.6763040911 + 21 +183924.2648762933 + 31 +0.0 + 0 +LINE + 5 +271 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533810.5991600926 + 20 +184073.5153000436 + 30 +0.0 + 11 +533810.6114064546 + 21 +184073.5131405614 + 31 +0.0 + 0 +LINE + 5 +272 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533954.7380145801 + 20 +184048.098338197 + 30 +0.0 + 11 +534364.6500434818 + 21 +183975.815826753 + 31 +0.0 + 0 +LINE + 5 +273 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534375.5265551551 + 20 +183983.0774559717 + 30 +0.0 + 11 +534371.123204419 + 21 +183959.1951387822 + 31 +0.0 + 0 +LINE + 5 +274 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534530.9589212817 + 20 +184092.5949168104 + 30 +0.0 + 11 +534574.5465687242 + 21 +184080.1750068405 + 31 +0.0 + 0 +LINE + 5 +275 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534520.7335404321 + 20 +184104.2896708572 + 30 +0.0 + 11 +534537.9608515989 + 21 +184087.4859158428 + 31 +0.0 + 0 +LINE + 5 +276 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534527.3546613447 + 20 +184168.0441267445 + 30 +0.0 + 11 +534522.0020775037 + 21 +184096.3976877718 + 31 +0.0 + 0 +LINE + 5 +277 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534312.6897586476 + 20 +184027.1174682027 + 30 +0.0 + 11 +534268.715040369 + 21 +183678.6121619755 + 31 +0.0 + 0 +LINE + 5 +278 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534178.0924395927 + 20 +183721.0298699493 + 30 +0.0 + 11 +534286.6169309787 + 21 +183992.7609886244 + 31 +0.0 + 0 +LINE + 5 +279 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534160.0049395611 + 20 +184014.8357883496 + 30 +0.0 + 11 +534154.1430236581 + 21 +183979.7982132065 + 31 +0.0 + 0 +LINE + 5 +27A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534283.0554192325 + 20 +183845.4622028715 + 30 +0.0 + 11 +534373.3845904289 + 21 +183821.9572878209 + 31 +0.0 + 0 +LINE + 5 +27B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534338.5613499616 + 20 +183826.740385397 + 30 +0.0 + 11 +534417.4375952255 + 21 +183853.7796193919 + 31 +0.0 + 0 +LINE + 5 +27C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534338.6600611481 + 20 +183839.8652194019 + 30 +0.0 + 11 +534399.4430551204 + 21 +183787.6198821797 + 31 +0.0 + 0 +LINE + 5 +27D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534353.3950801142 + 20 +183626.8977659865 + 30 +0.0 + 11 +534397.018575538 + 21 +183800.0089834212 + 31 +0.0 + 0 +LINE + 5 +27E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534316.5240373919 + 20 +184240.583205404 + 30 +0.0 + 11 +534323.0481789416 + 21 +184194.0262992032 + 31 +0.0 + 0 +LINE + 5 +27F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534259.3074196166 + 20 +184197.0997663956 + 30 +0.0 + 11 +534324.554163355 + 21 +184195.1866329612 + 31 +0.0 + 0 +LINE + 5 +280 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534236.1677363386 + 20 +184240.9189471798 + 30 +0.0 + 11 +534221.3497769107 + 21 +184137.6553470467 + 31 +0.0 + 0 +LINE + 5 +281 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534075.9993490205 + 20 +184178.7166941591 + 30 +0.0 + 11 +534364.8760209383 + 21 +184103.158770916 + 31 +0.0 + 0 +LINE + 5 +282 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534445.6665385903 + 20 +184159.5737598459 + 30 +0.0 + 11 +534445.5888953305 + 21 +184090.7293139994 + 31 +0.0 + 0 +LINE + 5 +283 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534413.7624798858 + 20 +184091.7428221283 + 30 +0.0 + 11 +534473.8666444875 + 21 +184091.4951244661 + 31 +0.0 + 0 +LINE + 5 +284 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534419.1301320043 + 20 +184098.4698326099 + 30 +0.0 + 11 +534418.0426346746 + 21 +184027.1445687356 + 31 +0.0 + 0 +LINE + 5 +285 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534415.2591650874 + 20 +184029.6086372781 + 30 +0.0 + 11 +534471.3741634863 + 21 +184027.9664590178 + 31 +0.0 + 0 +LINE + 5 +286 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534468.8322797114 + 20 +184098.9981249308 + 30 +0.0 + 11 +534468.5116705245 + 21 +184021.4998345739 + 31 +0.0 + 0 +LINE + 5 +287 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534352.4198206242 + 20 +184432.4779143455 + 30 +0.0 + 11 +534615.4420738622 + 21 +184461.3404170194 + 31 +0.0 + 0 +LINE + 5 +288 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533532.7624275796 + 20 +183279.5203883841 + 30 +0.0 + 11 +532822.6282750719 + 21 +183060.5581778998 + 31 +0.0 + 0 +LINE + 5 +289 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533342.1028701529 + 20 +183213.5023917251 + 30 +0.0 + 11 +533311.0032423038 + 21 +183772.1392497893 + 31 +0.0 + 0 +LINE + 5 +28A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533339.6295991045 + 20 +183351.3335597998 + 30 +0.0 + 11 +533194.7893030568 + 21 +183321.6859065113 + 31 +0.0 + 0 +LINE + 5 +28B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533278.6891237384 + 20 +183198.401309585 + 30 +0.0 + 11 +533234.487352922 + 21 +184185.8116573112 + 31 +0.0 + 0 +LINE + 5 +28C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533227.3181130724 + 20 +183318.9206275791 + 30 +0.0 + 11 +533150.504528331 + 21 +183347.5697367062 + 31 +0.0 + 0 +LINE + 5 +28D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533192.6831632028 + 20 +183247.1171745893 + 30 +0.0 + 11 +533222.2627044432 + 21 +183329.8364542056 + 31 +0.0 + 0 +LINE + 5 +28E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533206.543120186 + 20 +183260.1410566229 + 30 +0.0 + 11 +533016.016412499 + 21 +183203.0987351212 + 31 +0.0 + 0 +LINE + 5 +28F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533218.3705491292 + 20 +183138.1125505508 + 30 +0.0 + 11 +533031.596680065 + 21 +183528.7207214253 + 31 +0.0 + 0 +LINE + 5 +290 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532993.44798064 + 20 +183254.429505146 + 30 +0.0 + 11 +533154.7660373612 + 21 +183348.3247837068 + 31 +0.0 + 0 +LINE + 5 +291 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533020.7270185264 + 20 +183200.3049458331 + 30 +0.0 + 11 +532993.7175981719 + 21 +183255.2331889633 + 31 +0.0 + 0 +LINE + 5 +292 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532740.2254147078 + 20 +183101.4565594727 + 30 +0.0 + 11 +533004.5635047808 + 21 +183237.3658685307 + 31 +0.0 + 0 +LINE + 5 +293 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532802.6632449139 + 20 +183129.4420001883 + 30 +0.0 + 11 +532757.9244439029 + 21 +183233.3469615745 + 31 +0.0 + 0 +LINE + 5 +294 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532685.7206542239 + 20 +183195.6187514277 + 30 +0.0 + 11 +533412.4422479266 + 21 +183553.0579135474 + 31 +0.0 + 0 +LINE + 5 +295 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533130.6806038581 + 20 +183490.7750957559 + 30 +0.0 + 11 +533024.5381114682 + 21 +183916.9411888579 + 31 +0.0 + 0 +LINE + 5 +296 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533194.7538784246 + 20 +183517.6868499452 + 30 +0.0 + 11 +533013.3144771753 + 21 +183449.2086651994 + 31 +0.0 + 0 +LINE + 5 +297 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533168.0923122618 + 20 +183585.2261651385 + 30 +0.0 + 11 +533108.1152453137 + 21 +183562.0227786959 + 31 +0.0 + 0 +LINE + 5 +298 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533205.9844550757 + 20 +183546.2203893963 + 30 +0.0 + 11 +533152.9953396826 + 21 +183590.1454297818 + 31 +0.0 + 0 +LINE + 5 +299 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533162.6574581374 + 20 +183572.125795115 + 30 +0.0 + 11 +533089.5755333647 + 21 +183968.6811254574 + 31 +0.0 + 0 +LINE + 5 +29A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533327.1256725954 + 20 +183697.8633855617 + 30 +0.0 + 11 +532922.5243948965 + 21 +183650.8580632188 + 31 +0.0 + 0 +LINE + 5 +29B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532927.2110360585 + 20 +183638.3948216737 + 30 +0.0 + 11 +532885.6939141481 + 21 +183873.5800684076 + 31 +0.0 + 0 +LINE + 5 +29C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532779.4795621642 + 20 +183518.0569124989 + 30 +0.0 + 11 +532935.2056681789 + 21 +183654.6448395154 + 31 +0.0 + 0 +LINE + 5 +29D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532860.8690292618 + 20 +183486.7880927641 + 30 +0.0 + 11 +532821.5502885538 + 21 +183562.5862219661 + 31 +0.0 + 0 +LINE + 5 +29F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533293.6322814212 + 20 +183952.7605173787 + 30 +0.0 + 11 +532883.8273047613 + 21 +183871.1016442716 + 31 +0.0 + 0 +LINE + 5 +2A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533047.8398997946 + 20 +183487.189023119 + 30 +0.0 + 11 +532953.4969078967 + 21 +183900.6314329289 + 31 +0.0 + 0 +LINE + 5 +2A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532548.7839254298 + 20 +183646.44825568 + 30 +0.0 + 11 +532960.4479911811 + 21 +183900.052022287 + 31 +0.0 + 0 +LINE + 5 +2A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532323.5859293173 + 20 +183530.3935634832 + 30 +0.0 + 11 +532794.9132185243 + 21 +183792.7256292301 + 31 +0.0 + 0 +LINE + 5 +2A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532577.2654881728 + 20 +183558.3489116874 + 30 +0.0 + 11 +532571.2553581126 + 21 +183675.6238282977 + 31 +0.0 + 0 +LINE + 5 +2A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532630.3005233718 + 20 +183590.633500544 + 30 +0.0 + 11 +532543.0686538527 + 21 +183657.3882892886 + 31 +0.0 + 0 +LINE + 5 +2A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532798.8253221348 + 20 +183678.3983628817 + 30 +0.0 + 11 +532612.008295049 + 21 +183601.5437615102 + 31 +0.0 + 0 +LINE + 5 +2A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532817.6548659477 + 20 +183429.3920899996 + 30 +0.0 + 11 +532708.2644265074 + 21 +183746.131200443 + 31 +0.0 + 0 +LINE + 5 +2A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532982.2371375846 + 20 +183070.6166723318 + 30 +0.0 + 11 +532758.2115810168 + 21 +183586.6884875571 + 31 +0.0 + 0 +LINE + 5 +2A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532762.7409918191 + 20 +183598.9569105556 + 30 +0.0 + 11 +532740.5404720749 + 21 +183589.1135627954 + 31 +0.0 + 0 +LINE + 5 +2A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532833.0553973926 + 20 +183775.6181090037 + 30 +0.0 + 11 +532810.8274301857 + 21 +183815.1156361047 + 31 +0.0 + 0 +LINE + 5 +2AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532846.8096853747 + 20 +183768.3969423502 + 30 +0.0 + 11 +532826.4564207106 + 21 +183781.2379333611 + 31 +0.0 + 0 +LINE + 5 +2AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532907.2699385936 + 20 +183789.6813889798 + 30 +0.0 + 11 +532838.8392540151 + 21 +183767.7929495795 + 31 +0.0 + 0 +LINE + 5 +2AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532820.202091548 + 20 +183548.1021399771 + 30 +0.0 + 11 +532411.6965931075 + 21 +183400.5198149712 + 31 +0.0 + 0 +LINE + 5 +2AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532705.5512352486 + 20 +183195.8969469713 + 30 +0.0 + 11 +532420.1445797267 + 21 +183419.7888982393 + 31 +0.0 + 0 +LINE + 5 +2AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532468.0705552293 + 20 +183288.5226947296 + 30 +0.0 + 11 +532792.8610919387 + 21 +183514.7460345087 + 31 +0.0 + 0 +LINE + 5 +2B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532650.440516718 + 20 +183476.9836669457 + 30 +0.0 + 11 +532606.5484086562 + 21 +183559.3567393084 + 31 +0.0 + 0 +LINE + 5 +2B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532619.308676055 + 20 +183526.6044619072 + 30 +0.0 + 11 +532627.2382057076 + 21 +183609.6087075904 + 31 +0.0 + 0 +LINE + 5 +2B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532632.0497533188 + 20 +183529.7565979628 + 30 +0.0 + 11 +532567.0871053734 + 21 +183576.7033975304 + 31 +0.0 + 0 +LINE + 5 +2B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532319.1054598828 + 20 +183440.943242896 + 30 +0.0 + 11 +532579.7002024197 + 21 +183577.2303830341 + 31 +0.0 + 0 +LINE + 5 +2B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532691.0044244704 + 20 +182972.7019742909 + 30 +0.0 + 11 +532839.9141442266 + 21 +183067.6876560392 + 31 +0.0 + 0 +LINE + 5 +2B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532793.2164716504 + 20 +183024.5212818305 + 30 +0.0 + 11 +532655.4838754236 + 21 +183248.9506764272 + 31 +0.0 + 0 +LINE + 5 +2B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533026.9073257412 + 20 +183601.5368553743 + 30 +0.0 + 11 +532980.1110058653 + 21 +183597.0408144468 + 31 +0.0 + 0 +LINE + 5 +2B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532997.9421264003 + 20 +183535.767804562 + 30 +0.0 + 11 +532980.888773864 + 21 +183598.7755883294 + 31 +0.0 + 0 +LINE + 5 +2B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533045.9449296638 + 20 +183523.46754336 + 30 +0.0 + 11 +532948.9701949887 + 21 +183485.011804273 + 31 +0.0 + 0 +LINE + 5 +2B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533022.747934971 + 20 +183353.2179265787 + 30 +0.0 + 11 +532882.0015395169 + 21 +183616.5602579835 + 31 +0.0 + 0 +LINE + 5 +2BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532918.0536104154 + 20 +183708.2663477616 + 30 +0.0 + 11 +532851.1196203771 + 21 +183692.1603013838 + 31 +0.0 + 0 +LINE + 5 +2BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532859.5161003121 + 20 +183661.4447183112 + 30 +0.0 + 11 +532845.2798621558 + 21 +183719.8390800234 + 31 +0.0 + 0 +LINE + 5 +2BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532864.808334425 + 20 +183668.2312208995 + 30 +0.0 + 11 +532795.6968644821 + 21 +183650.5654166575 + 31 +0.0 + 0 +LINE + 5 +2BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532798.7413366781 + 20 +183648.4322205175 + 30 +0.0 + 11 +532784.0778326244 + 21 +183702.6223620896 + 31 +0.0 + 0 +LINE + 5 +2BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532853.7488820336 + 20 +183716.6901838713 + 30 +0.0 + 11 +532778.4554968875 + 21 +183698.3327888569 + 31 +0.0 + 0 +LINE + 5 +2C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533236.9410300952 + 20 +184128.2527506047 + 30 +0.0 + 11 +533126.981531269 + 21 +184343.3517983396 + 31 +0.0 + 0 +LINE + 5 +2C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532835.6102659117 + 20 +183916.0876363871 + 30 +0.0 + 11 +533298.551877255 + 21 +184154.1088557825 + 31 +0.0 + 0 +LINE + 5 +2C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532781.1055054279 + 20 +184010.2498283422 + 30 +0.0 + 11 +533459.0946851481 + 21 +184343.719875779 + 31 +0.0 + 0 +LINE + 5 +2C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533226.0654550621 + 20 +184305.4061726703 + 30 +0.0 + 11 +533119.9229626722 + 21 +184731.5722657724 + 31 +0.0 + 0 +LINE + 5 +2C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533290.1387296285 + 20 +184332.3179268596 + 30 +0.0 + 11 +533108.6993283792 + 21 +184263.8397421138 + 31 +0.0 + 0 +LINE + 5 +2C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533263.4771634658 + 20 +184399.8572420528 + 30 +0.0 + 11 +533203.5000965176 + 21 +184376.6538556104 + 31 +0.0 + 0 +LINE + 5 +2CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533301.3693062795 + 20 +184360.8514663108 + 30 +0.0 + 11 +533248.3801908866 + 21 +184404.7765066962 + 31 +0.0 + 0 +LINE + 5 +2CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533258.0423093414 + 20 +184386.7568720294 + 30 +0.0 + 11 +533184.9603845684 + 21 +184783.3122023718 + 31 +0.0 + 0 +LINE + 5 +2CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533313.2245827507 + 20 +184499.6854179535 + 30 +0.0 + 11 +533017.9092461005 + 21 +184465.4891401333 + 31 +0.0 + 0 +LINE + 5 +2CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533022.5958872625 + 20 +184453.0258985883 + 30 +0.0 + 11 +532981.0787653522 + 21 +184688.211145322 + 31 +0.0 + 0 +LINE + 5 +2CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532874.8644133682 + 20 +184332.6879894133 + 30 +0.0 + 11 +533030.5905193829 + 21 +184469.2759164299 + 31 +0.0 + 0 +LINE + 5 +2CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532956.2538804658 + 20 +184301.4191696784 + 30 +0.0 + 11 +532916.9351397578 + 21 +184377.2172988805 + 31 +0.0 + 0 +LINE + 5 +2D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533312.5190293062 + 20 +184749.7419374041 + 30 +0.0 + 11 +532979.2121559653 + 21 +184685.7327211861 + 31 +0.0 + 0 +LINE + 5 +2D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533143.2247509987 + 20 +184301.8201000335 + 30 +0.0 + 11 +533048.8817591007 + 21 +184715.2625098432 + 31 +0.0 + 0 +LINE + 5 +2D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532593.9135947571 + 20 +184428.0269791083 + 30 +0.0 + 11 +533055.8328423851 + 21 +184714.6830992013 + 31 +0.0 + 0 +LINE + 5 +2D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532672.6503393768 + 20 +184372.9799886018 + 30 +0.0 + 11 +532666.6402093166 + 21 +184490.254905212 + 31 +0.0 + 0 +LINE + 5 +2D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532725.6853745756 + 20 +184405.2645774584 + 30 +0.0 + 11 +532638.4535050566 + 21 +184472.0193662031 + 31 +0.0 + 0 +LINE + 5 +2D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532894.2101733389 + 20 +184493.0294397962 + 30 +0.0 + 11 +532707.3931462528 + 21 +184416.1748384246 + 31 +0.0 + 0 +LINE + 5 +2D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532913.0397171517 + 20 +184244.0231669139 + 30 +0.0 + 11 +532803.6492777113 + 21 +184560.7622773574 + 31 +0.0 + 0 +LINE + 5 +2D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533002.9879995437 + 20 +184269.8284089141 + 30 +0.0 + 11 +532884.4483571425 + 21 +184243.4500331875 + 31 +0.0 + 0 +LINE + 5 +2D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533018.0305508438 + 20 +184217.9793931889 + 30 +0.0 + 11 +533001.3606235288 + 21 +184271.2685517172 + 31 +0.0 + 0 +LINE + 5 +2D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533077.6219887886 + 20 +183885.2477492463 + 30 +0.0 + 11 +532853.5964322206 + 21 +184401.3195644716 + 31 +0.0 + 0 +LINE + 5 +2DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532858.1258430229 + 20 +184413.5879874701 + 30 +0.0 + 11 +532835.9253232789 + 21 +184403.7446397097 + 31 +0.0 + 0 +LINE + 5 +2DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532928.4402485964 + 20 +184590.2491859182 + 30 +0.0 + 11 +532906.2122813898 + 21 +184629.7467130191 + 31 +0.0 + 0 +LINE + 5 +2DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532942.1945365787 + 20 +184583.0280192646 + 30 +0.0 + 11 +532921.8412719146 + 21 +184595.8690102754 + 31 +0.0 + 0 +LINE + 5 +2DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533002.6547897976 + 20 +184604.3124658941 + 30 +0.0 + 11 +532934.2241052192 + 21 +184582.424026494 + 31 +0.0 + 0 +LINE + 5 +2DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532915.586942752 + 20 +184362.7332168916 + 30 +0.0 + 11 +532579.4868776007 + 21 +184248.3190809244 + 31 +0.0 + 0 +LINE + 5 +2DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532800.9360864524 + 20 +184010.5280238858 + 30 +0.0 + 11 +532637.6889675159 + 21 +184132.908686197 + 31 +0.0 + 0 +LINE + 5 +2E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532627.4102219 + 20 +184103.5541580553 + 30 +0.0 + 11 +532888.2459431427 + 21 +184329.3771114232 + 31 +0.0 + 0 +LINE + 5 +2E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532939.1957581605 + 20 +184211.3855460326 + 30 +0.0 + 11 +532906.4862421954 + 21 +184197.5262063909 + 31 +0.0 + 0 +LINE + 5 +2E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532745.8253679221 + 20 +184291.6147438601 + 30 +0.0 + 11 +532701.9332598602 + 21 +184373.9878162229 + 31 +0.0 + 0 +LINE + 5 +2E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532714.6935272589 + 20 +184341.2355388216 + 30 +0.0 + 11 +532722.6230569118 + 21 +184424.2397845048 + 31 +0.0 + 0 +LINE + 5 +2E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532727.4346045228 + 20 +184344.3876748772 + 30 +0.0 + 11 +532662.4719565772 + 21 +184391.3344744447 + 31 +0.0 + 0 +LINE + 5 +2E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532564.7483924605 + 20 +184331.0512654725 + 30 +0.0 + 11 +532675.0850536235 + 21 +184391.8614599485 + 31 +0.0 + 0 +LINE + 5 +2E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532906.0166036281 + 20 +183843.1770056994 + 30 +0.0 + 11 +532750.8687266275 + 21 +184063.5817533417 + 31 +0.0 + 0 +LINE + 5 +2E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533122.292176945 + 20 +184416.1679322887 + 30 +0.0 + 11 +533075.4958570691 + 21 +184411.6718913614 + 31 +0.0 + 0 +LINE + 5 +2E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533093.3269776042 + 20 +184350.3988814763 + 30 +0.0 + 11 +533076.273625068 + 21 +184413.4066652438 + 31 +0.0 + 0 +LINE + 5 +2E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533141.3297808676 + 20 +184338.0986202742 + 30 +0.0 + 11 +533044.3550461925 + 21 +184299.6428811874 + 31 +0.0 + 0 +LINE + 5 +2EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533118.132786175 + 20 +184167.8490034932 + 30 +0.0 + 11 +532977.3863907207 + 21 +184431.1913348979 + 31 +0.0 + 0 +LINE + 5 +2EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533013.4384616195 + 20 +184522.897424676 + 30 +0.0 + 11 +532946.5044715811 + 21 +184506.7913782983 + 31 +0.0 + 0 +LINE + 5 +2EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532954.9009515162 + 20 +184476.0757952258 + 30 +0.0 + 11 +532940.6647133597 + 21 +184534.470156938 + 31 +0.0 + 0 +LINE + 5 +2ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532960.1931856289 + 20 +184482.8622978139 + 30 +0.0 + 11 +532891.0817156861 + 21 +184465.196493572 + 31 +0.0 + 0 +LINE + 5 +2EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532894.1261878822 + 20 +184463.0632974319 + 30 +0.0 + 11 +532879.4626838282 + 21 +184517.2534390039 + 31 +0.0 + 0 +LINE + 5 +2EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532949.1337332375 + 20 +184531.3212607857 + 30 +0.0 + 11 +532873.8403480914 + 21 +184512.9638657713 + 31 +0.0 + 0 +LINE + 5 +2F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532962.7457486525 + 20 +183975.8869687485 + 30 +0.0 + 11 +532917.3537715828 + 21 +184079.0574052173 + 31 +0.0 + 0 +LINE + 5 +2F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532635.2106572713 + 20 +184438.4366176368 + 30 +0.0 + 11 +532065.2785999623 + 21 +184514.0689499459 + 31 +0.0 + 0 +LINE + 5 +2F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532590.2300880724 + 20 +184386.4198395649 + 30 +0.0 + 11 +532364.6295972854 + 21 +184414.239316967 + 31 +0.0 + 0 +LINE + 5 +2F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532652.7847925186 + 20 +184210.3495376971 + 30 +0.0 + 11 +532489.8745094785 + 21 +184162.4628243181 + 31 +0.0 + 0 +LINE + 5 +2F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532763.565424586 + 20 +183767.8992291204 + 30 +0.0 + 11 +532542.4660997646 + 21 +184490.3856919131 + 31 +0.0 + 0 +LINE + 5 +2F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532543.1334552761 + 20 +184254.2287175145 + 30 +0.0 + 11 +532030.3823403246 + 21 +184165.1226977185 + 31 +0.0 + 0 +LINE + 5 +2F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532526.7823938887 + 20 +184321.7732940453 + 30 +0.0 + 11 +532565.4542369875 + 21 +184131.7364379803 + 31 +0.0 + 0 +LINE + 5 +2F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532455.8560125364 + 20 +184306.2218749684 + 30 +0.0 + 11 +532469.199284479 + 21 +184243.3123939978 + 31 +0.0 + 0 +LINE + 5 +2F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532500.404604757 + 20 +184337.4098207074 + 30 +0.0 + 11 +532448.5924934926 + 21 +184292.102419002 + 31 +0.0 + 0 +LINE + 5 +2F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532467.9222000074 + 20 +184298.7677181402 + 30 +0.0 + 11 +532151.5594281791 + 21 +184344.7377033163 + 31 +0.0 + 0 +LINE + 5 +2FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532546.3727587354 + 20 +184062.6106464354 + 30 +0.0 + 11 +532126.1632264118 + 21 +184073.4140238009 + 31 +0.0 + 0 +LINE + 5 +307 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532584.4903761105 + 20 +183864.2182182287 + 30 +0.0 + 11 +532532.7635513458 + 21 +183974.0899667647 + 31 +0.0 + 0 +LINE + 5 +308 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532631.8950520743 + 20 +183998.5224476362 + 30 +0.0 + 11 +532632.3872072136 + 21 +183877.743770919 + 31 +0.0 + 0 +LINE + 5 +309 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532634.6940095361 + 20 +183884.0725369571 + 30 +0.0 + 11 +532582.3553185839 + 21 +183864.6230556592 + 31 +0.0 + 0 +LINE + 5 +30A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532934.2473785581 + 20 +184040.6907525797 + 30 +0.0 + 11 +532934.235328054 + 21 +184040.6876830364 + 31 +0.0 + 0 +LINE + 5 +30B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532792.4137581561 + 20 +184004.5624334069 + 30 +0.0 + 11 +532167.9345982127 + 21 +183901.8182242516 + 31 +0.0 + 0 +LINE + 5 +310 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532368.5085479771 + 20 +184092.6775787239 + 30 +0.0 + 11 +532506.9565822644 + 21 +183612.623907776 + 31 +0.0 + 0 +LINE + 5 +311 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532594.1521268948 + 20 +183661.7019549843 + 30 +0.0 + 11 +532478.1241977714 + 21 +183964.5209857737 + 31 +0.0 + 0 +LINE + 5 +312 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532590.2102493453 + 20 +183956.0377104505 + 30 +0.0 + 11 +532598.6767912577 + 21 +183921.5368206355 + 31 +0.0 + 0 +LINE + 5 +317 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532306.0587504182 + 20 +184266.992331815 + 30 +0.0 + 11 +532414.2191715132 + 21 +184122.5293847503 + 31 +0.0 + 0 +LINE + 5 +318 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532477.551415465 + 20 +184130.3624860479 + 30 +0.0 + 11 +532412.6306058845 + 21 +184123.5738093414 + 31 +0.0 + 0 +LINE + 5 +319 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532661.721044324 + 20 +184125.7436229359 + 30 +0.0 + 11 +532439.6824280089 + 21 +184049.5153294456 + 31 +0.0 + 0 +LINE + 5 +31C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532847.7714891929 + 20 +183350.8987513204 + 30 +0.0 + 11 +532995.8222172223 + 21 +183426.7421009539 + 31 +0.0 + 0 +LINE + 5 +31D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532774.0262611857 + 20 +183284.1426261447 + 30 +0.0 + 11 +532909.8188335092 + 21 +183159.1966094306 + 31 +0.0 + 0 +LINE + 5 +31E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532709.4902750978 + 20 +183812.8863756505 + 30 +0.0 + 11 +532835.4314276548 + 21 +183979.9680373762 + 31 +0.0 + 0 +LINE + 5 +31F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532463.9437321764 + 20 +184141.8423292799 + 30 +0.0 + 11 +532481.318514892 + 21 +184025.9617418272 + 31 +0.0 + 0 +LINE + 5 +320 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533323.0645174747 + 20 +183697.3915731477 + 30 +0.0 + 11 +533469.8168568623 + 21 +183830.5378952181 + 31 +0.0 + 0 +LINE + 5 +322 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530605.199969855 + 20 +185171.8313899503 + 30 +0.0 + 11 +532736.3514167985 + 21 +185388.7767557458 + 31 +0.0 + 0 +LINE + 5 +323 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530632.5473901829 + 20 +185377.7313809267 + 30 +0.0 + 11 +530347.847156352 + 21 +185292.772304566 + 31 +0.0 + 0 +LINE + 5 +324 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530537.8475188889 + 20 +185421.3935488612 + 30 +0.0 + 11 +530918.4513398055 + 21 +185724.2180642567 + 31 +0.0 + 0 +LINE + 5 +325 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530524.4682282156 + 20 +184838.4117535552 + 30 +0.0 + 11 +530539.0027126899 + 21 +185369.0524173398 + 31 +0.0 + 0 +LINE + 5 +326 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530335.1690853607 + 20 +184982.8667579243 + 30 +0.0 + 11 +530559.2802786548 + 21 +185043.4543895813 + 31 +0.0 + 0 +LINE + 5 +327 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530707.0247008471 + 20 +184994.505863614 + 30 +0.0 + 11 +530707.477024887 + 21 +185313.5574728215 + 31 +0.0 + 0 +LINE + 5 +332 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531131.4314460383 + 20 +185132.7716499767 + 30 +0.0 + 11 +531131.4314460383 + 21 +185359.3560314326 + 31 +0.0 + 0 +LINE + 5 +333 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530501.6760625544 + 20 +185036.5091148205 + 30 +0.0 + 11 +530743.4035747344 + 21 +185005.6828851596 + 31 +0.0 + 0 +LINE + 5 +334 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530485.4823504737 + 20 +185236.4996961124 + 30 +0.0 + 11 +530775.1816292018 + 21 +185251.6757933341 + 31 +0.0 + 0 +LINE + 5 +335 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532544.9929155682 + 20 +185376.4324141973 + 30 +0.0 + 11 +536042.6124124007 + 21 +185481.9872221566 + 31 +0.0 + 0 +LINE + 5 +358 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532320.5649707108 + 20 +184501.5680036159 + 30 +0.0 + 11 +532310.185466446 + 21 +184245.5571047196 + 31 +0.0 + 0 +LINE + 5 +366 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532121.1286102474 + 20 +185156.5429902478 + 30 +0.0 + 11 +532552.7822942476 + 21 +185237.5298082478 + 31 +0.0 + 0 +LINE + 5 +367 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532107.1836522989 + 20 +185396.4993852853 + 30 +0.0 + 11 +532132.2182172474 + 21 +185032.5284892478 + 31 +0.0 + 0 +LINE + 5 +368 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532191.4177562475 + 20 +185229.8919942478 + 30 +0.0 + 11 +532195.3011802475 + 21 +185165.7003692478 + 31 +0.0 + 0 +LINE + 5 +36B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532227.5888392475 + 20 +185421.3871792478 + 30 +0.0 + 11 +532353.3590012474 + 21 +185033.9680772478 + 31 +0.0 + 0 +LINE + 5 +36C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532340.0762082474 + 20 +185033.0383432478 + 30 +0.0 + 11 +532571.1852702475 + 21 +185093.2411102478 + 31 +0.0 + 0 +LINE + 5 +36D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532292.1971382474 + 20 +184848.6111342478 + 30 +0.0 + 11 +532351.5203522474 + 21 +185047.0743252478 + 31 +0.0 + 0 +LINE + 5 +36E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532229.8727212474 + 20 +184909.5836812478 + 30 +0.0 + 11 +532315.1596332476 + 21 +184905.4048772478 + 31 +0.0 + 0 +LINE + 5 +36F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532325.0415939529 + 20 +185475.0242132333 + 30 +0.0 + 11 +532348.3174009531 + 21 +185387.9591352333 + 31 +0.0 + 0 +LINE + 5 +370 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532458.4917752475 + 20 +185549.4005362478 + 30 +0.0 + 11 +532569.7094042475 + 21 +185090.5118912478 + 31 +0.0 + 0 +LINE + 5 +371 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532152.3691472474 + 20 +185079.7349762478 + 30 +0.0 + 11 +532567.5409532475 + 21 +185166.1502402478 + 31 +0.0 + 0 +LINE + 5 +372 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532505.0021652475 + 20 +184692.3458652478 + 30 +0.0 + 11 +532564.1192532476 + 21 +185172.2285002478 + 31 +0.0 + 0 +LINE + 5 +373 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532493.2797917234 + 20 +184439.2739090913 + 30 +0.0 + 11 +532535.4841562475 + 21 +184977.0343742478 + 31 +0.0 + 0 +LINE + 5 +374 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532413.0449982474 + 20 +184681.5489552478 + 30 +0.0 + 11 +532522.1683822475 + 21 +184724.9265392478 + 31 +0.0 + 0 +LINE + 5 +375 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532420.3088972474 + 20 +184743.2113052478 + 30 +0.0 + 11 +532517.3285312475 + 21 +184691.7060482478 + 31 +0.0 + 0 +LINE + 5 +376 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532429.9143932474 + 20 +184932.9769852478 + 30 +0.0 + 11 +532437.8461422474 + 21 +184731.1247652478 + 31 +0.0 + 0 +LINE + 5 +377 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532009.6784914185 + 20 +184830.2079244615 + 30 +0.0 + 11 +532529.2096642474 + 21 +184878.8524782478 + 31 +0.0 + 0 +LINE + 5 +37C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532372.7184052476 + 20 +184867.0858462478 + 30 +0.0 + 11 +532373.0152272474 + 21 +184842.8027972478 + 31 +0.0 + 0 +LINE + 5 +37D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532504.0457382474 + 20 +185004.5864872478 + 30 +0.0 + 11 +532549.2121822474 + 21 +185000.8275632478 + 31 +0.0 + 0 +LINE + 5 +37E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532491.7523522475 + 20 +185014.0837682478 + 30 +0.0 + 11 +532511.9032812475 + 21 +185000.9275342478 + 31 +0.0 + 0 +LINE + 5 +37F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532485.9230932474 + 20 +185077.9154972478 + 30 +0.0 + 11 +532494.5226922474 + 21 +185006.5859152478 + 31 +0.0 + 0 +LINE + 5 +380 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532302.5529352474 + 20 +184898.1469552478 + 30 +0.0 + 11 +532338.5096462474 + 21 +184465.2908592478 + 31 +0.0 + 0 +LINE + 5 +381 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532317.2044082475 + 20 +184488.8441172478 + 30 +0.0 + 11 +532511.6971542474 + 21 +184540.6792792478 + 31 +0.0 + 0 +LINE + 5 +383 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532213.2094522475 + 20 +184469.8995392478 + 30 +0.0 + 11 +532283.6140292475 + 21 +184859.3980472478 + 31 +0.0 + 0 +LINE + 5 +385 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532308.5965642474 + 20 +184714.1896122478 + 30 +0.0 + 11 +532401.7657552476 + 21 +184708.5912152478 + 31 +0.0 + 0 +LINE + 5 +386 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532366.6747752475 + 20 +184706.5517982478 + 30 +0.0 + 11 +532438.8355502475 + 21 +184748.3298402478 + 31 +0.0 + 0 +LINE + 5 +387 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532364.2342372475 + 20 +184719.4481072478 + 30 +0.0 + 11 +532433.9709632472 + 21 +184679.9394162478 + 31 +0.0 + 0 +LINE + 5 +388 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532419.8636642474 + 20 +184513.3471032478 + 30 +0.0 + 11 +532429.1970732474 + 21 +184691.6260712478 + 31 +0.0 + 0 +LINE + 5 +38B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532265.0461522474 + 20 +185108.3267922478 + 30 +0.0 + 11 +532280.4479262474 + 21 +185063.9095062478 + 31 +0.0 + 0 +LINE + 5 +38C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532217.3154932475 + 20 +185054.6021702478 + 30 +0.0 + 11 +532281.7011752476 + 21 +185065.3390972478 + 31 +0.0 + 0 +LINE + 5 +38D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532186.1409172473 + 20 +185093.1211442478 + 30 +0.0 + 11 +532191.5661672472 + 21 +184988.9409652478 + 31 +0.0 + 0 +LINE + 5 +38E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532041.0195962473 + 20 +185001.1274772478 + 30 +0.0 + 11 +532339.0538202476 + 21 +184982.8427112478 + 31 +0.0 + 0 +LINE + 5 +38F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532407.4136222474 + 20 +185053.8123962478 + 30 +0.0 + 11 +532420.6469452474 + 21 +184986.2517352478 + 31 +0.0 + 0 +LINE + 5 +390 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532389.2250172473 + 20 +184981.0932122478 + 30 +0.0 + 11 +532448.2431642476 + 21 +184992.4699552478 + 31 +0.0 + 0 +LINE + 5 +391 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532393.1908912475 + 20 +184988.7310262478 + 30 +0.0 + 11 +532405.9130212474 + 21 +184918.5411172478 + 31 +0.0 + 0 +LINE + 5 +392 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532402.7056922474 + 20 +184920.4205792478 + 30 +0.0 + 11 +532458.0795222474 + 21 +184929.6579352478 + 31 +0.0 + 0 +LINE + 5 +393 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532441.8532422473 + 20 +184998.8581272478 + 30 +0.0 + 11 +532456.5212062474 + 21 +184922.7599102478 + 31 +0.0 + 0 +LINE + 5 +396 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532481.8907751978 + 20 +185659.2708376926 + 30 +0.0 + 11 +533213.4750461979 + 21 +185960.1946986926 + 31 +0.0 + 0 +LINE + 5 +397 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532608.229846198 + 20 +185714.4250496926 + 30 +0.0 + 11 +532641.5976081978 + 21 +185570.3962776926 + 31 +0.0 + 0 +LINE + 5 +398 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532494.571678198 + 20 +185595.3291406926 + 30 +0.0 + 11 +532951.4964751979 + 21 +185784.2850526926 + 31 +0.0 + 0 +LINE + 5 +399 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532625.5362291979 + 20 +185598.8181416926 + 30 +0.0 + 11 +532683.5732141979 + 21 +185540.9147166926 + 31 +0.0 + 0 +LINE + 5 +39A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532574.6806921979 + 20 +185537.4257156926 + 30 +0.0 + 11 +532637.5657731979 + 21 +185598.7681566926 + 31 +0.0 + 0 +LINE + 5 +39C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532379.7822005875 + 20 +185516.783209897 + 30 +0.0 + 11 +532897.7881471978 + 21 +185508.2540656925 + 31 +0.0 + 0 +LINE + 5 +3A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532630.1287281979 + 20 +185133.8312426926 + 30 +0.0 + 11 +532743.226231198 + 21 +185136.4304986926 + 31 +0.0 + 0 +LINE + 5 +3A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532738.9965151979 + 20 +185055.0737866926 + 30 +0.0 + 11 +532759.8070491979 + 21 +185810.3475926926 + 31 +0.0 + 0 +LINE + 5 +3A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532822.0242801978 + 20 +185582.5328036926 + 30 +0.0 + 11 +533308.048428696 + 21 +185701.9470633644 + 31 +0.0 + 0 +LINE + 5 +3A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532819.806359198 + 20 +185651.9929206926 + 30 +0.0 + 11 +532833.1138871978 + 21 +185458.5183026926 + 31 +0.0 + 0 +LINE + 5 +3A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532892.3134261978 + 20 +185655.8818076926 + 30 +0.0 + 11 +532896.1968501978 + 21 +185591.6901826926 + 31 +0.0 + 0 +LINE + 5 +3A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532841.0703711978 + 20 +185674.0865966926 + 30 +0.0 + 11 +532903.0732311979 + 21 +185644.2051496926 + 31 +0.0 + 0 +LINE + 5 +3A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532882.6667051979 + 20 +185645.4847836926 + 30 +0.0 + 11 +533018.9643670911 + 21 +185679.8975924009 + 31 +0.0 + 0 +LINE + 5 +3A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532928.4845091979 + 20 +185847.3769926925 + 30 +0.0 + 11 +533171.7912461943 + 21 +185088.6905515849 + 31 +0.0 + 0 +LINE + 5 +3A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533040.9718781979 + 20 +185459.0281566926 + 30 +0.0 + 11 +533342.0861666041 + 21 +185539.2294065369 + 31 +0.0 + 0 +LINE + 5 +3AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533040.8696871645 + 20 +185902.6867872737 + 30 +0.0 + 11 +533064.1454941646 + 21 +185815.6217092737 + 31 +0.0 + 0 +LINE + 5 +3AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532853.2648171979 + 20 +185505.7247896926 + 30 +0.0 + 11 +533314.949234796 + 21 +185601.8213459973 + 31 +0.0 + 0 +LINE + 5 +3B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532896.5843681978 + 20 +185272.3815836926 + 30 +0.0 + 11 +533323.6153840747 + 21 +185304.8422916926 + 31 +0.0 + 0 +LINE + 5 +3B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532501.8603121979 + 20 +185272.5915236926 + 30 +0.0 + 11 +533064.3466261978 + 21 +185283.8483006926 + 31 +0.0 + 0 +LINE + 5 +3B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533003.4486051978 + 20 +185324.1367686926 + 30 +0.0 + 11 +533056.9763947938 + 21 +184798.3148205676 + 31 +0.0 + 0 +LINE + 5 +3BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532730.9905601978 + 20 +185073.2185936926 + 30 +0.0 + 11 +532910.2405847092 + 21 +184975.7707765721 + 31 +0.0 + 0 +LINE + 5 +3BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532887.8337612262 + 20 +184954.2005379262 + 30 +0.0 + 11 +532984.509699198 + 21 +185285.3878606926 + 31 +0.0 + 0 +LINE + 5 +3BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533009.4922341978 + 20 +185140.1794256926 + 30 +0.0 + 11 +533223.8406176101 + 21 +185128.4247817856 + 31 +0.0 + 0 +LINE + 5 +3C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533120.7593341979 + 20 +184991.9777295595 + 30 +0.0 + 11 +533164.6698493871 + 21 +185152.1929908819 + 31 +0.0 + 0 +LINE + 5 +3C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532535.0805407667 + 20 +185099.0554407228 + 30 +0.0 + 11 +532800.0759271978 + 21 +185049.7952976926 + 31 +0.0 + 0 +LINE + 5 +3C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532965.9418221979 + 20 +185534.3166056926 + 30 +0.0 + 11 +532981.3435961978 + 21 +185489.8993196926 + 31 +0.0 + 0 +LINE + 5 +3C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532918.2111631979 + 20 +185480.5919836926 + 30 +0.0 + 11 +532982.596845198 + 21 +185491.3289106925 + 31 +0.0 + 0 +LINE + 5 +3C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532887.0365871978 + 20 +185519.1109576926 + 30 +0.0 + 11 +532892.4618371978 + 21 +185414.9307786926 + 31 +0.0 + 0 +LINE + 5 +3CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532632.1075431978 + 20 +185205.9006136926 + 30 +0.0 + 11 +532744.8092831978 + 21 +185207.6001266926 + 31 +0.0 + 0 +LINE + 5 +3CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532964.0619481979 + 20 +185729.5307256926 + 30 +0.0 + 11 +533287.3999608604 + 21 +185848.0166997513 + 31 +0.0 + 0 +LINE + 5 +3CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533160.4851943644 + 20 +185038.2038243795 + 30 +0.0 + 11 +533312.3771077996 + 21 +184720.5496568575 + 31 +0.0 + 0 +LINE + 5 +3D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532525.9687370664 + 20 +184938.1950755283 + 30 +0.0 + 11 +533310.1590899808 + 21 +185042.7807927709 + 31 +0.0 + 0 +LINE + 5 +3D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532783.2026042486 + 20 +184722.3529153568 + 30 +0.0 + 11 +533016.3547312032 + 21 +184679.6358716281 + 31 +0.0 + 0 +LINE + 5 +3D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532833.4575456594 + 20 +184793.6019525844 + 30 +0.0 + 11 +532842.931078161 + 21 +184708.7398765826 + 31 +0.0 + 0 +LINE + 5 +3DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532637.5467937776 + 20 +184576.4133326699 + 30 +0.0 + 11 +532697.7689800461 + 21 +184475.6025395458 + 31 +0.0 + 0 +LINE + 5 +3DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532699.5784686391 + 20 +184579.0743381345 + 30 +0.0 + 11 +532664.2017968141 + 21 +184475.0835117567 + 31 +0.0 + 0 +LINE + 5 +3E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532790.6590954802 + 20 +184784.0174906387 + 30 +0.0 + 11 +532807.6186704129 + 21 +184536.4242881813 + 31 +0.0 + 0 +LINE + 5 +3E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532688.1167109437 + 20 +184815.5033675087 + 30 +0.0 + 11 +532809.5492248078 + 21 +184814.234469069 + 31 +0.0 + 0 +LINE + 5 +3E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532790.4765161498 + 20 +184914.5351786511 + 30 +0.0 + 11 +532680.4657737823 + 21 +184864.6817180896 + 31 +0.0 + 0 +LINE + 5 +3E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532685.2588451061 + 20 +184869.4146964122 + 30 +0.0 + 11 +532689.3739594284 + 21 +184813.7308861308 + 31 +0.0 + 0 +LINE + 5 +3E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532702.8925823753 + 20 +185206.9803013947 + 30 +0.0 + 11 +532702.8948103981 + 21 +185206.968067317 + 31 +0.0 + 0 +LINE + 5 +3E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532729.1162602199 + 20 +185062.9860305268 + 30 +0.0 + 11 +532803.6929663337 + 21 +184653.4851785078 + 31 +0.0 + 0 +LINE + 5 +3EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532833.7558926337 + 20 +184720.028022434 + 30 +0.0 + 11 +532491.6707096186 + 21 +184640.2317074956 + 31 +0.0 + 0 +LINE + 5 +3EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532499.9754730116 + 20 +184739.9450397345 + 30 +0.0 + 11 +532792.482947854 + 21 +184732.5461716932 + 31 +0.0 + 0 +LINE + 5 +3ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532769.2121150372 + 20 +184858.9438041617 + 30 +0.0 + 11 +532734.3196016032 + 21 +184852.2725047208 + 31 +0.0 + 0 +LINE + 5 +3EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532653.1157034118 + 20 +184684.7299837778 + 30 +0.0 + 11 +532662.4446227496 + 21 +184591.8601207191 + 31 +0.0 + 0 +LINE + 5 +3EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532654.8360919118 + 20 +184626.1769731031 + 30 +0.0 + 11 +532707.5855661703 + 21 +184561.6008536206 + 31 +0.0 + 0 +LINE + 5 +3F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532667.1782684115 + 20 +184630.6425851331 + 30 +0.0 + 11 +532639.2944614704 + 21 +184555.4984507766 + 31 +0.0 + 0 +LINE + 5 +3F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532472.5841021193 + 20 +184542.862362741 + 30 +0.0 + 11 +532650.0704104144 + 21 +184562.0746848949 + 31 +0.0 + 0 +LINE + 5 +3F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532893.7177966846 + 20 +184994.6354611215 + 30 +0.0 + 11 +532923.1880844783 + 21 +184697.4987358915 + 31 +0.0 + 0 +LINE + 5 +3FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531861.8278255367 + 20 +185191.7735766143 + 30 +0.0 + 11 +531538.5384386285 + 21 +185607.8478836246 + 31 +0.0 + 0 +LINE + 5 +3FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531733.7040754842 + 20 +185347.6380927605 + 30 +0.0 + 11 +532464.1482035561 + 21 +185651.3189967688 + 31 +0.0 + 0 +LINE + 5 +3FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531862.0971573802 + 20 +185397.8253868076 + 30 +0.0 + 11 +531783.9926877962 + 21 +185523.3538160008 + 31 +0.0 + 0 +LINE + 5 +3FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531697.5197138976 + 20 +185401.8602090297 + 30 +0.0 + 11 +532154.4445108975 + 21 +185590.8161210297 + 31 +0.0 + 0 +LINE + 5 +400 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531792.6965981643 + 20 +185491.8893567981 + 30 +0.0 + 11 +531792.885563927 + 21 +185573.87144354 + 31 +0.0 + 0 +LINE + 5 +401 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531713.3339456926 + 20 +185499.4315717521 + 30 +0.0 + 11 +531801.1772682144 + 21 +185500.4211012181 + 31 +0.0 + 0 +LINE + 5 +402 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531730.3606550528 + 20 +185490.9574299569 + 30 +0.0 + 11 +531610.7000381212 + 21 +185649.8145655846 + 31 +0.0 + 0 +LINE + 5 +403 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531620.0352627024 + 20 +185437.4863894554 + 30 +0.0 + 11 +531921.4650168662 + 21 +185748.2907083182 + 31 +0.0 + 0 +LINE + 5 +404 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531650.9979007347 + 20 +185688.8051328634 + 30 +0.0 + 11 +531795.0736114228 + 21 +185570.1374104197 + 31 +0.0 + 0 +LINE + 5 +405 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531609.7161111208 + 20 +185644.4268986138 + 30 +0.0 + 11 +531651.8451968421 + 21 +185688.8314120956 + 31 +0.0 + 0 +LINE + 5 +406 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531419.6038351391 + 20 +185873.1395474812 + 30 +0.0 + 11 +531638.8567267734 + 21 +185672.4553785438 + 31 +0.0 + 0 +LINE + 5 +407 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531467.5316540078 + 20 +185824.3072660336 + 30 +0.0 + 11 +531549.4316502019 + 21 +185902.346947863 + 31 +0.0 + 0 +LINE + 5 +408 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531488.9758274058 + 20 +185956.9537109508 + 30 +0.0 + 11 +532119.1862890298 + 21 +185356.9691234335 + 31 +0.0 + 0 +LINE + 5 +409 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531920.2925450763 + 20 +185642.1958461826 + 30 +0.0 + 11 +532283.0697733463 + 21 +185889.7366514033 + 31 +0.0 + 0 +LINE + 5 +40A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531967.7814881132 + 20 +185591.4570314894 + 30 +0.0 + 11 +531840.5527883868 + 21 +185737.8208797502 + 31 +0.0 + 0 +LINE + 5 +40B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532021.8574928065 + 20 +185639.9150950438 + 30 +0.0 + 11 +531979.268683928 + 21 +185688.1005602838 + 31 +0.0 + 0 +LINE + 5 +40C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531998.4393065221 + 20 +185590.8350219038 + 30 +0.0 + 11 +532021.2274724078 + 21 +185655.7808071295 + 31 +0.0 + 0 +LINE + 5 +40D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532007.6850459294 + 20 +185640.4619804239 + 30 +0.0 + 11 +532354.1763415755 + 21 +185846.7163859356 + 31 +0.0 + 0 +LINE + 5 +40E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532182.715114118 + 20 +185529.8988290208 + 30 +0.0 + 11 +531998.1198935781 + 21 +185892.9915152565 + 31 +0.0 + 0 +LINE + 5 +40F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531988.0600547572 + 20 +185884.2681765558 + 30 +0.0 + 11 +532194.1878251482 + 21 +186004.8795937868 + 31 +0.0 + 0 +LINE + 5 +410 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531823.9061445957 + 20 +185981.011623581 + 30 +0.0 + 11 +532006.0750995708 + 21 +185882.4146979472 + 31 +0.0 + 0 +LINE + 5 +411 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531822.8497064442 + 20 +185893.8286643487 + 30 +0.0 + 11 +531880.2747016837 + 21 +185957.0243104261 + 31 +0.0 + 0 +LINE + 5 +412 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532356.2144154167 + 20 +185600.3187829731 + 30 +0.0 + 11 +532311.1985787343 + 21 +185678.3935256651 + 31 +0.0 + 0 +LINE + 5 +413 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532436.5909745613 + 20 +185602.3600801 + 30 +0.0 + 11 +532191.2154048476 + 21 +186005.769275952 + 31 +0.0 + 0 +LINE + 5 +414 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531888.1595850236 + 20 +185718.6348090544 + 30 +0.0 + 11 +532243.1029985761 + 21 +185950.691697608 + 31 +0.0 + 0 +LINE + 5 +415 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531983.707795175 + 20 +186179.1651187459 + 30 +0.0 + 11 +532196.6318225811 + 21 +185988.747421823 + 31 +0.0 + 0 +LINE + 5 +416 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531651.967628694 + 20 +186274.3789995667 + 30 +0.0 + 11 +531834.7205437863 + 21 +186117.8592350517 + 31 +0.0 + 0 +LINE + 5 +417 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531474.7328130902 + 20 +185635.481035244 + 30 +0.0 + 11 +531880.8795836971 + 21 +186024.7911548032 + 31 +0.0 + 0 +LINE + 5 +419 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532084.0423358651 + 20 +186020.2200672802 + 30 +0.0 + 11 +532125.4763841526 + 21 +186066.8963861565 + 31 +0.0 + 0 +LINE + 5 +41A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532082.0474267376 + 20 +186004.8140287462 + 30 +0.0 + 11 +532087.0205745952 + 21 +186028.360031231 + 31 +0.0 + 0 +LINE + 5 +41B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532123.0045456797 + 20 +185955.5090158614 + 30 +0.0 + 11 +532078.7129439776 + 21 +186012.0785870981 + 31 +0.0 + 0 +LINE + 5 +41C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531418.7788685433 + 20 +186104.3451573058 + 30 +0.0 + 11 +531495.3612063181 + 21 +186318.6540757437 + 31 +0.0 + 0 +LINE + 5 +41D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531496.1237532815 + 20 +185938.45407603 + 30 +0.0 + 11 +531405.175342562 + 21 +186133.5223115784 + 31 +0.0 + 0 +LINE + 5 +41F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531988.1202134396 + 20 +185777.976802319 + 30 +0.0 + 11 +531967.6519314506 + 21 +185820.2988931271 + 31 +0.0 + 0 +LINE + 5 +420 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531916.3854307389 + 20 +185782.2978865 + 30 +0.0 + 11 +531969.5488407774 + 21 +185820.1720133031 + 31 +0.0 + 0 +LINE + 5 +421 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531921.5218807102 + 20 +185733.0111496584 + 30 +0.0 + 11 +531851.7810069742 + 21 +185810.5943537981 + 31 +0.0 + 0 +LINE + 5 +422 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531753.8130619647 + 20 +185695.637566851 + 30 +0.0 + 11 +531951.8835598482 + 21 +185919.0806450864 + 31 +0.0 + 0 +LINE + 5 +423 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532050.4021916367 + 20 +185917.1215869044 + 30 +0.0 + 11 +532012.0528583068 + 21 +185974.2958152379 + 31 +0.0 + 0 +LINE + 5 +424 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531986.1651783409 + 20 +185955.7546193549 + 30 +0.0 + 11 +532035.9806907252 + 21 +185989.3847647976 + 31 +0.0 + 0 +LINE + 5 +425 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531994.3672256759 + 20 +185953.1487070773 + 30 +0.0 + 11 +531953.7989935165 + 21 +186011.8231858276 + 31 +0.0 + 0 +LINE + 5 +426 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531952.8559031887 + 20 +186008.2273663998 + 30 +0.0 + 11 +531998.5804950235 + 21 +186040.7980817171 + 31 +0.0 + 0 +LINE + 5 +427 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532035.9690354825 + 20 +185980.3492953121 + 30 +0.0 + 11 +531992.6053163253 + 21 +186044.5807179909 + 31 +0.0 + 0 +LINE + 5 +428 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532589.7485624646 + 20 +185685.3582884609 + 30 +0.0 + 11 +532589.9375282275 + 21 +185767.3403752028 + 31 +0.0 + 0 +LINE + 5 +429 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532510.3859099931 + 20 +185692.900503415 + 30 +0.0 + 11 +532598.229232515 + 21 +185693.8900328809 + 31 +0.0 + 0 +LINE + 5 +42A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532526.4656307082 + 20 +185685.9832563354 + 30 +0.0 + 11 +532406.8050137765 + 21 +185844.8403919632 + 31 +0.0 + 0 +LINE + 5 +42B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532357.8334418678 + 20 +185569.8587237367 + 30 +0.0 + 11 +532718.5169811667 + 21 +185941.7596399811 + 31 +0.0 + 0 +LINE + 5 +42C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532448.049865035 + 20 +185882.2740645263 + 30 +0.0 + 11 +532592.1255757233 + 21 +185763.6063420826 + 31 +0.0 + 0 +LINE + 5 +42D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532406.7680754211 + 20 +185837.8958302767 + 30 +0.0 + 11 +532448.8971611424 + 21 +185882.3003437585 + 31 +0.0 + 0 +LINE + 5 +42E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532216.6557994395 + 20 +186066.608479144 + 30 +0.0 + 11 +532435.9086910739 + 21 +185865.9243102067 + 31 +0.0 + 0 +LINE + 5 +42F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532360.5330683786 + 20 +186075.9173659413 + 30 +0.0 + 11 +532834.2031285817 + 21 +185630.4462966165 + 31 +0.0 + 0 +LINE + 5 +430 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532717.3445093768 + 20 +185835.6647778455 + 30 +0.0 + 11 +532936.5865712611 + 21 +185985.2644558515 + 31 +0.0 + 0 +LINE + 5 +431 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532764.8334524136 + 20 +185784.9259631524 + 30 +0.0 + 11 +532637.6047526871 + 21 +185931.289811413 + 31 +0.0 + 0 +LINE + 5 +432 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532818.9094571071 + 20 +185833.3840267067 + 30 +0.0 + 11 +532776.3206482284 + 21 +185881.5694919468 + 31 +0.0 + 0 +LINE + 5 +433 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532795.4912708226 + 20 +185784.3039535667 + 30 +0.0 + 11 +532818.2794367084 + 21 +185849.2497387923 + 31 +0.0 + 0 +LINE + 5 +434 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532804.7370102297 + 20 +185833.9309120868 + 30 +0.0 + 11 +533151.2283058758 + 21 +186040.1853175985 + 31 +0.0 + 0 +LINE + 5 +435 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532929.8009410545 + 20 +185821.4028240506 + 30 +0.0 + 11 +532795.1718578784 + 21 +186086.4604469193 + 31 +0.0 + 0 +LINE + 5 +436 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532785.1120190575 + 20 +186077.7371082186 + 30 +0.0 + 11 +532991.2397894489 + 21 +186198.3485254497 + 31 +0.0 + 0 +LINE + 5 +438 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532487.8955622168 + 20 +185923.2211543541 + 30 +0.0 + 11 +532719.6710319343 + 21 +186201.2963692519 + 31 +0.0 + 0 +LINE + 5 +439 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532685.2115493238 + 20 +185912.1037407173 + 30 +0.0 + 11 +533069.5807117685 + 21 +186166.970324897 + 31 +0.0 + 0 +LINE + 5 +43A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532596.3237212511 + 20 +186341.3319926437 + 30 +0.0 + 11 +532804.5149513248 + 21 +186072.8212737525 + 31 +0.0 + 0 +LINE + 5 +43B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532563.3363404315 + 20 +186239.6670789878 + 30 +0.0 + 11 +532671.2243390242 + 21 +186286.0320171303 + 31 +0.0 + 0 +LINE + 5 +43C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532612.0301757858 + 20 +186201.1453963313 + 30 +0.0 + 11 +532644.3347693412 + 21 +186306.1311768702 + 31 +0.0 + 0 +LINE + 5 +43D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532271.7847773906 + 20 +185828.9499669069 + 30 +0.0 + 11 +532505.4397367133 + 21 +186045.7682751822 + 31 +0.0 + 0 +LINE + 5 +43E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532456.1709398957 + 20 +185958.2385074901 + 30 +0.0 + 11 +532414.07966705 + 21 +186283.737681027 + 31 +0.0 + 0 +LINE + 5 +43F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532406.7909252194 + 20 +186170.6980676144 + 30 +0.0 + 11 +532571.9985347014 + 21 +186193.8794666497 + 31 +0.0 + 0 +LINE + 5 +440 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532548.1691416875 + 20 +186189.2161541062 + 30 +0.0 + 11 +532628.7607689065 + 21 +186210.607083589 + 31 +0.0 + 0 +LINE + 5 +441 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532555.5499794265 + 20 +186178.3628483507 + 30 +0.0 + 11 +532577.0134800563 + 21 +186255.5863276716 + 31 +0.0 + 0 +LINE + 5 +442 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532486.5436966105 + 20 +186326.2911970296 + 30 +0.0 + 11 +532581.8881197563 + 21 +186243.9413365331 + 31 +0.0 + 0 +LINE + 5 +443 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532172.7351168023 + 20 +185975.263057285 + 30 +0.0 + 11 +532257.3461442857 + 21 +186098.2095402245 + 31 +0.0 + 0 +LINE + 5 +444 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532785.17217774 + 20 +185971.4457339819 + 30 +0.0 + 11 +532764.7038957511 + 21 +186013.76782479 + 31 +0.0 + 0 +LINE + 5 +445 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532713.4373950393 + 20 +185975.7668181629 + 30 +0.0 + 11 +532766.6008050778 + 21 +186013.640944966 + 31 +0.0 + 0 +LINE + 5 +446 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532718.5738450106 + 20 +185926.4800813213 + 30 +0.0 + 11 +532648.8329712746 + 21 +186004.063285461 + 31 +0.0 + 0 +LINE + 5 +447 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532550.865026265 + 20 +185889.1064985139 + 30 +0.0 + 11 +532766.6531342508 + 21 +186130.2671868515 + 31 +0.0 + 0 +LINE + 5 +448 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532847.4541559371 + 20 +186110.5905185672 + 30 +0.0 + 11 +532809.1048226073 + 21 +186167.7647469007 + 31 +0.0 + 0 +LINE + 5 +449 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532783.2171426415 + 20 +186149.2235510178 + 30 +0.0 + 11 +532833.0326550259 + 21 +186182.8536964605 + 31 +0.0 + 0 +LINE + 5 +44A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532316.8864140805 + 20 +185968.1543527131 + 30 +0.0 + 11 +532397.8707606938 + 21 +186046.5514581896 + 31 +0.0 + 0 +LINE + 5 +44B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532611.7161158065 + 20 +186297.5090828903 + 30 +0.0 + 11 +532545.1449756013 + 21 +186591.4088218426 + 31 +0.0 + 0 +LINE + 5 +44C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532547.3155668865 + 20 +186321.6247646187 + 30 +0.0 + 11 +532495.053707063 + 21 +186542.8445710875 + 31 +0.0 + 0 +LINE + 5 +44D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532403.9294344441 + 20 +186201.8155025754 + 30 +0.0 + 11 +532302.4455707475 + 21 +186337.9548541522 + 31 +0.0 + 0 +LINE + 5 +44E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532279.8671234338 + 20 +186136.1577846746 + 30 +0.0 + 11 +533406.1995619062 + 21 +186996.2805453936 + 31 +0.0 + 0 +LINE + 5 +44F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532406.9961318524 + 20 +186319.8807114539 + 30 +0.0 + 11 +532220.4666046975 + 21 +186717.4866760719 + 31 +0.0 + 0 +LINE + 5 +450 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532464.6578491668 + 20 +186358.671862295 + 30 +0.0 + 11 +532299.8801138759 + 21 +186256.40839832 + 31 +0.0 + 0 +LINE + 5 +451 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532425.4420865872 + 20 +186419.7825992595 + 30 +0.0 + 11 +532371.082371042 + 21 +186385.4217635892 + 31 +0.0 + 0 +LINE + 5 +452 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532470.160245401 + 20 +186388.8382734374 + 30 +0.0 + 11 +532409.6789007655 + 21 +186421.6904038722 + 31 +0.0 + 0 +LINE + 5 +453 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532422.6424219159 + 20 +186405.8786713312 + 30 +0.0 + 11 +532274.2743179815 + 21 +186780.8240053286 + 31 +0.0 + 0 +LINE + 5 +454 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532644.1853054258 + 20 +186588.1231077161 + 30 +0.0 + 11 +532171.8185395161 + 21 +186436.7013597309 + 31 +0.0 + 0 +LINE + 5 +455 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532178.8262472758 + 20 +186425.3793004152 + 30 +0.0 + 11 +532092.6246762097 + 21 +186648.1012365569 + 31 +0.0 + 0 +LINE + 5 +456 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532057.1464107401 + 20 +186278.7511375533 + 30 +0.0 + 11 +532183.5284855803 + 21 +186442.8683306205 + 31 +0.0 + 0 +LINE + 5 +457 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532143.045524667 + 20 +186263.8070193578 + 30 +0.0 + 11 +532089.8147203099 + 21 +186330.5737867564 + 31 +0.0 + 0 +LINE + 5 +459 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532428.4229887346 + 20 +186782.4538492132 + 30 +0.0 + 11 +532091.2724283363 + 21 +186645.3087032108 + 31 +0.0 + 0 +LINE + 5 +45A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532326.4115569843 + 20 +186300.3469340414 + 30 +0.0 + 11 +532153.9187586503 + 21 +186687.7504199219 + 31 +0.0 + 0 +LINE + 5 +45B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531805.9814634882 + 20 +186360.1205610736 + 30 +0.0 + 11 +532160.8507210284 + 21 +186688.5257734576 + 31 +0.0 + 0 +LINE + 5 +45C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531638.584156153 + 20 +186248.3972793169 + 30 +0.0 + 11 +532019.1879770698 + 21 +186551.2217947124 + 31 +0.0 + 0 +LINE + 5 +45D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531850.9576992835 + 20 +186279.1895284476 + 30 +0.0 + 11 +531822.388527218 + 21 +186393.0900558247 + 31 +0.0 + 0 +LINE + 5 +45E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531896.7507059305 + 20 +186321.1181604121 + 30 +0.0 + 11 +531798.2590085679 + 21 +186369.7492865638 + 31 +0.0 + 0 +LINE + 5 +45F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532045.128842458 + 20 +186439.807702748 + 30 +0.0 + 11 +531876.6943226217 + 21 +186328.2862075614 + 31 +0.0 + 0 +LINE + 5 +460 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532093.9829120121 + 20 +186228.3962886964 + 30 +0.0 + 11 +531943.1818398332 + 21 +186488.7548350109 + 31 +0.0 + 0 +LINE + 5 +461 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532011.4998620817 + 20 +186166.3447629878 + 30 +0.0 + 11 +531995.1789584217 + 21 +186015.2308868018 + 31 +0.0 + 0 +LINE + 5 +462 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532367.7592458358 + 20 +186017.384856327 + 30 +0.0 + 11 +532367.7521822822 + 21 +186017.3950907273 + 31 +0.0 + 0 +LINE + 5 +463 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532159.4363386243 + 20 +186124.1371738739 + 30 +0.0 + 11 +532023.0113161725 + 21 +186341.976254682 + 31 +0.0 + 0 +LINE + 5 +464 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532025.08345726 + 20 +186354.8888840192 + 30 +0.0 + 11 +532005.2047513147 + 21 +186340.9392739177 + 31 +0.0 + 0 +LINE + 5 +465 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532059.9179272102 + 20 +186541.8109382867 + 30 +0.0 + 11 +532030.473360213 + 21 +186576.266048903 + 31 +0.0 + 0 +LINE + 5 +466 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532074.8087792434 + 20 +186537.3850811423 + 30 +0.0 + 11 +532052.356979825 + 21 +186546.0489795433 + 31 +0.0 + 0 +LINE + 5 +467 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532130.0135486268 + 20 +186569.9565920827 + 30 +0.0 + 11 +532067.1054834822 + 21 +186535.2515821992 + 31 +0.0 + 0 +LINE + 5 +468 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532091.2921244135 + 20 +186316.102313323 + 30 +0.0 + 11 +531792.7632140843 + 21 +186130.9801536181 + 31 +0.0 + 0 +LINE + 5 +469 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531936.6804172386 + 20 +186133.8679621811 + 30 +0.0 + 11 +532070.9155718749 + 21 +186278.0897346377 + 31 +0.0 + 0 +LINE + 5 +46A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532468.8458028386 + 20 +186177.5755427393 + 30 +0.0 + 11 +531769.5162369404 + 21 +186138.5166020882 + 31 +0.0 + 0 +LINE + 5 +46B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531938.4823451721 + 20 +186213.5060128864 + 30 +0.0 + 11 +531879.4933379066 + 21 +186285.8395267122 + 31 +0.0 + 0 +LINE + 5 +46C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531898.3447794365 + 20 +186256.1720487052 + 30 +0.0 + 11 +531890.077737924 + 21 +186339.1433586055 + 31 +0.0 + 0 +LINE + 5 +46D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531910.2360944391 + 20 +186261.7279139901 + 30 +0.0 + 11 +531837.4229176238 + 21 +186295.2299870572 + 31 +0.0 + 0 +LINE + 5 +46E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531710.4802981255 + 20 +186186.4293161462 + 30 +0.0 + 11 +531849.6961797504 + 21 +186298.185484916 + 31 +0.0 + 0 +LINE + 5 +46F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532283.7673474868 + 20 +186408.4906846435 + 30 +0.0 + 11 +532238.7230775654 + 21 +186395.0324646574 + 31 +0.0 + 0 +LINE + 5 +470 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532268.0635396029 + 20 +186338.3626500527 + 30 +0.0 + 11 +532239.1507935487 + 21 +186396.88487458 + 31 +0.0 + 0 +LINE + 5 +471 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532327.6932205972 + 20 +186164.0523312674 + 30 +0.0 + 11 +532138.6908716636 + 21 +186395.2164362678 + 31 +0.0 + 0 +LINE + 5 +472 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532156.333518464 + 20 +186492.1622754376 + 30 +0.0 + 11 +532006.4397393707 + 21 +186419.1755808819 + 31 +0.0 + 0 +LINE + 5 +473 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532443.2785890483 + 20 +186521.0440070698 + 30 +0.0 + 11 +532392.4614716871 + 21 +186789.2089363239 + 31 +0.0 + 0 +LINE + 5 +474 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531690.8699317568 + 20 +185858.9173803943 + 30 +0.0 + 11 +531813.4096672386 + 21 +185746.4218472305 + 31 +0.0 + 0 +LINE + 5 +475 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531602.6576685688 + 20 +185904.8884095925 + 30 +0.0 + 11 +531532.6487409198 + 21 +185734.1550506949 + 31 +0.0 + 0 +LINE + 5 +476 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532274.1029641282 + 20 +186355.1102229073 + 30 +0.0 + 11 +532171.4693846109 + 21 +186298.5722535568 + 31 +0.0 + 0 +LINE + 5 +477 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532180.8622533723 + 20 +185533.5433447531 + 30 +0.0 + 11 +532356.6872845859 + 21 +185442.1663750327 + 31 +0.0 + 0 +LINE + 5 +478 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534574.6571852977 + 20 +184195.4021252921 + 30 +0.0 + 11 +535121.1408465514 + 21 +184069.916780534 + 31 +0.0 + 0 +LINE + 5 +479 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534591.6805218133 + 20 +184183.5721895806 + 30 +0.0 + 11 +534563.5622932388 + 21 +184974.1290065872 + 31 +0.0 + 0 +LINE + 5 +47A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534583.8361464561 + 20 +184321.2021780923 + 30 +0.0 + 11 +534730.4884537673 + 21 +184302.4726435274 + 31 +0.0 + 0 +LINE + 5 +47C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534698.2576499472 + 20 +184297.2817347705 + 30 +0.0 + 11 +534772.7128564283 + 21 +184331.596753093 + 31 +0.0 + 0 +LINE + 5 +47D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534738.1669447289 + 20 +184228.2704037896 + 30 +0.0 + 11 +534702.4823148565 + 21 +184308.5451549328 + 31 +0.0 + 0 +LINE + 5 +47E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534723.3715470947 + 20 +184240.2209736357 + 30 +0.0 + 11 +534917.6315636337 + 21 +184197.5911864141 + 31 +0.0 + 0 +LINE + 5 +47F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534720.7058270503 + 20 +184117.6496135786 + 30 +0.0 + 11 +534877.7361941458 + 21 +184521.135282629 + 31 +0.0 + 0 +LINE + 5 +480 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534936.2968661421 + 20 +184250.4664032003 + 30 +0.0 + 11 +534768.4068052764 + 21 +184332.030894389 + 31 +0.0 + 0 +LINE + 5 +481 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534913.1431511226 + 20 +184194.4528395783 + 30 +0.0 + 11 +534935.9678830071 + 21 +184251.2476658892 + 31 +0.0 + 0 +LINE + 5 +482 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535200.2533381722 + 20 +184116.8648654899 + 30 +0.0 + 11 +534926.4889642517 + 21 +184232.6190607658 + 31 +0.0 + 0 +LINE + 5 +483 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535135.8969533211 + 20 +184140.101114365 + 30 +0.0 + 11 +535172.7375945441 + 21 +184247.0617074395 + 31 +0.0 + 0 +LINE + 5 +484 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535247.5614010104 + 20 +184214.8405486959 + 30 +0.0 + 11 +534562.2605079586 + 21 +184461.1649807091 + 31 +0.0 + 0 +LINE + 5 +485 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534781.7684923542 + 20 +184475.8838221603 + 30 +0.0 + 11 +534855.7334321526 + 21 +184908.796001801 + 31 +0.0 + 0 +LINE + 5 +486 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534715.8615647035 + 20 +184497.9270504825 + 30 +0.0 + 11 +534901.9152180392 + 21 +184443.2136500017 + 31 +0.0 + 0 +LINE + 5 +487 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534737.396022412 + 20 +184567.2715912787 + 30 +0.0 + 11 +534798.940808514 + 21 +184548.6199155959 + 31 +0.0 + 0 +LINE + 5 +488 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534702.5279512712 + 20 +184525.5405160086 + 30 +0.0 + 11 +534752.0826991785 + 21 +184573.3064294077 + 31 +0.0 + 0 +LINE + 5 +489 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534743.7956458011 + 20 +184554.6144922988 + 30 +0.0 + 11 +534787.0077403957 + 21 +184955.5257201689 + 31 +0.0 + 0 +LINE + 5 +48A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534570.3822305559 + 20 +184667.6964211436 + 30 +0.0 + 11 +534977.3661527182 + 21 +184651.0897554535 + 31 +0.0 + 0 +LINE + 5 +48B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534973.6249792506 + 20 +184638.3108424999 + 30 +0.0 + 11 +534997.4323029246 + 21 +184875.9428753415 + 31 +0.0 + 0 +LINE + 5 +48C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535129.9446164009 + 20 +184529.3614422962 + 30 +0.0 + 11 +534964.4371350048 + 21 +184653.9172751708 + 31 +0.0 + 0 +LINE + 5 +48D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535051.1223213111 + 20 +184492.0917463117 + 30 +0.0 + 11 +535084.6606727746 + 21 +184570.6188037027 + 31 +0.0 + 0 +LINE + 5 +48E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534553.9285474718 + 20 +184777.7111798236 + 30 +0.0 + 11 +534643.6579189425 + 21 +184769.3010137052 + 31 +0.0 + 0 +LINE + 5 +48F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534530.5281655633 + 20 +184928.6853843727 + 30 +0.0 + 11 +534999.4790852679 + 21 +184873.6110308273 + 31 +0.0 + 0 +LINE + 5 +490 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534864.6453430343 + 20 +184478.5048502061 + 30 +0.0 + 11 +534927.7956627994 + 21 +184897.846314246 + 31 +0.0 + 0 +LINE + 5 +491 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535350.3893007875 + 20 +184674.6506536572 + 30 +0.0 + 11 +534920.9074000498 + 21 +184896.7485383992 + 31 +0.0 + 0 +LINE + 5 +492 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535583.6379881881 + 20 +184575.7674960427 + 30 +0.0 + 11 +535094.0071012423 + 21 +184802.1060054018 + 31 +0.0 + 0 +LINE + 5 +493 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535328.5779771762 + 20 +184584.6675441836 + 30 +0.0 + 11 +535325.7982992511 + 21 +184702.0634602962 + 31 +0.0 + 0 +LINE + 5 +494 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535273.2764353342 + 20 +184612.8942887018 + 30 +0.0 + 11 +535355.2701688879 + 21 +184685.9875752475 + 31 +0.0 + 0 +LINE + 5 +495 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535098.6584225843 + 20 +184687.8064271212 + 30 +0.0 + 11 +535290.7012472688 + 21 +184625.1423636691 + 31 +0.0 + 0 +LINE + 5 +496 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535098.5090148775 + 20 +184438.0892804688 + 30 +0.0 + 11 +535183.8986896964 + 21 +184762.1240560096 + 31 +0.0 + 0 +LINE + 5 +497 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535006.8823547946 + 20 +184457.0934690072 + 30 +0.0 + 11 +535127.0631374186 + 21 +184439.6565824029 + 31 +0.0 + 0 +LINE + 5 +498 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535092.7796099318 + 20 +184343.4867310913 + 30 +0.0 + 11 +534991.7531499059 + 21 +184409.6787649087 + 31 +0.0 + 0 +LINE + 5 +499 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534995.7606139729 + 20 +184404.26444609 + 30 +0.0 + 11 +535008.3974384137 + 21 +184458.6513154741 + 31 +0.0 + 0 +LINE + 5 +49A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534961.226757078 + 20 +184068.0072542187 + 30 +0.0 + 11 +535146.0188931681 + 21 +184599.3917053508 + 31 +0.0 + 0 +LINE + 5 +49B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535140.5844114282 + 20 +184611.286921755 + 30 +0.0 + 11 +535163.459076143 + 21 +184603.1319057388 + 31 +0.0 + 0 +LINE + 5 +49C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535057.2515549811 + 20 +184782.193123236 + 30 +0.0 + 11 +535076.4625545096 + 21 +184823.2427842622 + 31 +0.0 + 0 +LINE + 5 +49D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535044.0759987184 + 20 +184773.9632749442 + 30 +0.0 + 11 +535063.411640211 + 21 +184788.2908497806 + 31 +0.0 + 0 +LINE + 5 +49E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534982.1929300688 + 20 +184790.6652419575 + 30 +0.0 + 11 +535052.0692800618 + 21 +184773.9572174507 + 31 +0.0 + 0 +LINE + 5 +49F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535087.0886008305 + 20 +184556.2761598885 + 30 +0.0 + 11 +535505.4896536701 + 21 +184439.6663665903 + 31 +0.0 + 0 +LINE + 5 +4A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535227.7655735143 + 20 +184213.6345013193 + 30 +0.0 + 11 +535495.623878412 + 21 +184458.2494913671 + 31 +0.0 + 0 +LINE + 5 +4A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535457.6518015389 + 20 +184323.7658987257 + 30 +0.0 + 11 +535116.8482574903 + 21 +184525.0588110716 + 31 +0.0 + 0 +LINE + 5 +4A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535074.8677798265 + 20 +184403.5864576378 + 30 +0.0 + 11 +535108.5224187205 + 21 +184392.2128473538 + 31 +0.0 + 0 +LINE + 5 +4A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535261.6946601973 + 20 +184498.0562876151 + 30 +0.0 + 11 +535299.3017138008 + 21 +184583.481984685 + 31 +0.0 + 0 +LINE + 5 +4A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535289.0272950536 + 20 +184549.86692231 + 30 +0.0 + 11 +535274.9106969223 + 21 +184632.0454103658 + 31 +0.0 + 0 +LINE + 5 +4A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535276.0861163686 + 20 +184552.0571062738 + 30 +0.0 + 11 +535337.3547991832 + 21 +184603.7320143421 + 31 +0.0 + 0 +LINE + 5 +4A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535404.9953774325 + 20 +184001.071612279 + 30 +0.0 + 11 +535103.3700778348 + 21 +184075.7331806402 + 31 +0.0 + 0 +LINE + 5 +4A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535153.1660462351 + 20 +184036.1810629035 + 30 +0.0 + 11 +535273.7238639583 + 21 +184270.2849582326 + 31 +0.0 + 0 +LINE + 5 +4AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534876.9652630151 + 20 +184594.0981846576 + 30 +0.0 + 11 +534923.966796239 + 21 +184593.1154270327 + 31 +0.0 + 0 +LINE + 5 +4AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534910.7692790155 + 20 +184530.6802114966 + 30 +0.0 + 11 +534923.0614345329 + 21 +184594.787157772 + 31 +0.0 + 0 +LINE + 5 +4AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534863.8211214823 + 20 +184514.823476302 + 30 +0.0 + 11 +534963.400889941 + 21 +184483.7298636502 + 31 +0.0 + 0 +LINE + 5 +4AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534899.6889578032 + 20 +184346.7861861114 + 30 +0.0 + 11 +535020.3411757364 + 21 +184619.9194386656 + 31 +0.0 + 0 +LINE + 5 +4AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534977.5298769468 + 20 +184708.6716297057 + 30 +0.0 + 11 +535045.4811634307 + 21 +184697.6178331832 + 31 +0.0 + 0 +LINE + 5 +4AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535039.4059462963 + 20 +184666.3601996268 + 30 +0.0 + 11 +535049.2339964726 + 21 +184725.6559109923 + 31 +0.0 + 0 +LINE + 5 +4B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535033.6208638784 + 20 +184672.7317913196 + 30 +0.0 + 11 +535103.8602096413 + 21 +184660.2854977361 + 31 +0.0 + 0 +LINE + 5 +4B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535100.983845627 + 20 +184657.9305313283 + 30 +0.0 + 11 +535111.5524690118 + 21 +184713.0657650223 + 31 +0.0 + 0 +LINE + 5 +4B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535041.0242654582 + 20 +184721.8822971619 + 30 +0.0 + 11 +535117.4799406871 + 21 +184709.2088002577 + 31 +0.0 + 0 +LINE + 5 +4B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535069.0006836904 + 20 +184166.9860368055 + 30 +0.0 + 11 +535106.5476183001 + 21 +184273.2630251185 + 31 +0.0 + 0 +LINE + 5 +4B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534693.2491391094 + 20 +184660.1320577132 + 30 +0.0 + 11 +534706.6944115045 + 21 +184924.3913516068 + 31 +0.0 + 0 +LINE + 5 +4B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534453.6923026645 + 20 +184480.7570328502 + 30 +0.0 + 11 +534405.8297581176 + 21 +185826.4342959219 + 31 +0.0 + 0 +LINE + 5 +4B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534427.7785696117 + 20 +185126.4152517712 + 30 +0.0 + 11 +534574.430876923 + 21 +185107.6857172062 + 31 +0.0 + 0 +LINE + 5 +4B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534499.9886731898 + 20 +184978.4702767471 + 30 +0.0 + 11 +534481.4814355449 + 21 +185472.5776425573 + 31 +0.0 + 0 +LINE + 5 +4B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534542.2000731028 + 20 +185102.4948084494 + 30 +0.0 + 11 +534616.655279584 + 21 +185136.8098267719 + 31 +0.0 + 0 +LINE + 5 +4B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534582.1093678846 + 20 +185033.4834774686 + 30 +0.0 + 11 +534546.4247380123 + 21 +185113.7582286117 + 31 +0.0 + 0 +LINE + 5 +4BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534569.1238130012 + 20 +185045.2214964583 + 30 +0.0 + 11 +534763.3838295403 + 21 +185002.5917092368 + 31 +0.0 + 0 +LINE + 5 +4BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534533.7798853447 + 20 +184843.5471823721 + 30 +0.0 + 11 +534721.6786173013 + 21 +185326.3483563077 + 31 +0.0 + 0 +LINE + 5 +4BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534780.2392892977 + 20 +185055.6794768792 + 30 +0.0 + 11 +534612.3492284322 + 21 +185137.243968068 + 31 +0.0 + 0 +LINE + 5 +4BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534757.0855742783 + 20 +184999.6659132573 + 30 +0.0 + 11 +534779.9103061629 + 21 +185056.460739568 + 31 +0.0 + 0 +LINE + 5 +4BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535044.1957613281 + 20 +184922.0779391688 + 30 +0.0 + 11 +534770.4313874075 + 21 +185037.8321344448 + 31 +0.0 + 0 +LINE + 5 +4BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534979.8393764768 + 20 +184945.3141880438 + 30 +0.0 + 11 +535016.6800176997 + 21 +185052.2747811184 + 31 +0.0 + 0 +LINE + 5 +4C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535091.5038241661 + 20 +185020.0536223748 + 30 +0.0 + 11 +534390.4684959374 + 21 +185301.8710613853 + 31 +0.0 + 0 +LINE + 5 +4C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534625.7109155097 + 20 +185281.0968958392 + 30 +0.0 + 11 +534699.6758553083 + 21 +185714.0090754798 + 31 +0.0 + 0 +LINE + 5 +4C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534559.803987859 + 20 +185303.1401241614 + 30 +0.0 + 11 +534745.8576411947 + 21 +185248.4267236806 + 31 +0.0 + 0 +LINE + 5 +4C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534581.3384455677 + 20 +185372.4846649576 + 30 +0.0 + 11 +534642.8832316696 + 21 +185353.8329892748 + 31 +0.0 + 0 +LINE + 5 +4C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534546.4703744269 + 20 +185330.7535896875 + 30 +0.0 + 11 +534596.0251223342 + 21 +185378.5195030866 + 31 +0.0 + 0 +LINE + 5 +4C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534587.7380689568 + 20 +185359.8275659777 + 30 +0.0 + 11 +534630.9501635514 + 21 +185760.7387938477 + 31 +0.0 + 0 +LINE + 5 +4C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534157.7326287101 + 20 +185538.9153082807 + 30 +0.0 + 11 +534848.8426457485 + 21 +185522.3086425906 + 31 +0.0 + 0 +LINE + 5 +4C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534817.5674024061 + 20 +185443.5239161787 + 30 +0.0 + 11 +534840.6786983336 + 21 +185674.2085705321 + 31 +0.0 + 0 +LINE + 5 +4C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534973.8870395568 + 20 +185334.5745159751 + 30 +0.0 + 11 +534808.3795581604 + 21 +185459.1303488497 + 31 +0.0 + 0 +LINE + 5 +4C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534895.0647444666 + 20 +185297.3048199906 + 30 +0.0 + 11 +534928.6030959303 + 21 +185375.8318773816 + 31 +0.0 + 0 +LINE + 5 +4CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534406.089309661 + 20 +185659.9740734423 + 30 +0.0 + 11 +534495.8186811316 + 21 +185651.5639073239 + 31 +0.0 + 0 +LINE + 5 +4CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534374.470588719 + 20 +185733.8984580516 + 30 +0.0 + 11 +534808.8712390222 + 21 +185692.4860401358 + 31 +0.0 + 0 +LINE + 5 +4CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534708.5877661901 + 20 +185283.717923885 + 30 +0.0 + 11 +534771.7380859553 + 21 +185703.0593879249 + 31 +0.0 + 0 +LINE + 5 +4CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535078.9923763787 + 20 +185538.2018863312 + 30 +0.0 + 11 +534764.8498232055 + 21 +185701.9616120782 + 31 +0.0 + 0 +LINE + 5 +4D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534942.4514380332 + 20 +185243.3023541477 + 30 +0.0 + 11 +535027.841112852 + 21 +185567.3371296885 + 31 +0.0 + 0 +LINE + 5 +4D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534850.8247779503 + 20 +185262.3065426861 + 30 +0.0 + 11 +534971.0055605743 + 21 +185244.8696560818 + 31 +0.0 + 0 +LINE + 5 +4D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534936.7220330874 + 20 +185148.6998047703 + 30 +0.0 + 11 +534835.6955730616 + 21 +185214.8918385876 + 31 +0.0 + 0 +LINE + 5 +4D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534839.7030371286 + 20 +185209.4775197689 + 30 +0.0 + 11 +534852.3398615693 + 21 +185263.864389153 + 31 +0.0 + 0 +LINE + 5 +4D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534805.1691802337 + 20 +184873.2203278976 + 30 +0.0 + 11 +534989.9613163239 + 21 +185404.6047790297 + 31 +0.0 + 0 +LINE + 5 +4D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534984.5268345839 + 20 +185416.4999954338 + 30 +0.0 + 11 +535007.4014992987 + 21 +185408.3449794178 + 31 +0.0 + 0 +LINE + 5 +4D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534901.1939781368 + 20 +185587.4061969149 + 30 +0.0 + 11 +535027.7864360749 + 21 +185783.166830838 + 31 +0.0 + 0 +LINE + 5 +4D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534888.0184218741 + 20 +185579.1763486232 + 30 +0.0 + 11 +534907.3540633668 + 21 +185593.5039234594 + 31 +0.0 + 0 +LINE + 5 +4D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534826.1353532244 + 20 +185595.8783156365 + 30 +0.0 + 11 +534896.0117032174 + 21 +185579.1702911296 + 31 +0.0 + 0 +LINE + 5 +4DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534931.0310239862 + 20 +185361.4892335674 + 30 +0.0 + 11 +535274.7483125908 + 21 +185272.5382705694 + 31 +0.0 + 0 +LINE + 5 +4DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535071.7079966699 + 20 +185018.8475749982 + 30 +0.0 + 11 +535225.3427913389 + 21 +185153.0973355788 + 31 +0.0 + 0 +LINE + 5 +4DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535237.7886563097 + 20 +185124.5939782508 + 30 +0.0 + 11 +534960.7906806459 + 21 +185330.2718847505 + 31 +0.0 + 0 +LINE + 5 +4DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534918.8102029823 + 20 +185208.7995313166 + 30 +0.0 + 11 +534952.4648418761 + 21 +185197.4259210327 + 31 +0.0 + 0 +LINE + 5 +4E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534979.4409143216 + 20 +184844.1047242348 + 30 +0.0 + 11 +535117.6662871139 + 21 +185075.4980319115 + 31 +0.0 + 0 +LINE + 5 +4E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534720.9076861708 + 20 +185399.3112583365 + 30 +0.0 + 11 +534767.9092193946 + 21 +185398.3285007116 + 31 +0.0 + 0 +LINE + 5 +4E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534754.7117021711 + 20 +185335.8932851755 + 30 +0.0 + 11 +534767.0038576885 + 21 +185400.0002314509 + 31 +0.0 + 0 +LINE + 5 +4E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534707.7635446379 + 20 +185320.0365499808 + 30 +0.0 + 11 +534807.3433130968 + 21 +185288.9429373291 + 31 +0.0 + 0 +LINE + 5 +4E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534743.6313809589 + 20 +185151.9992597903 + 30 +0.0 + 11 +534864.2835988922 + 21 +185425.1325123446 + 31 +0.0 + 0 +LINE + 5 +4EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534912.9431068461 + 20 +184972.1991104843 + 30 +0.0 + 11 +534950.4900414558 + 21 +185078.4760987974 + 31 +0.0 + 0 +LINE + 5 +4ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534537.1915622653 + 20 +185503.4776332377 + 30 +0.0 + 11 +534550.6368346601 + 21 +185729.6044252857 + 31 +0.0 + 0 +LINE + 5 +4F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535204.4961575484 + 20 +185229.1919298231 + 30 +0.0 + 11 +535370.5322272507 + 21 +185193.6261991774 + 31 +0.0 + 0 +LINE + 5 +4F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535127.1242449161 + 20 +184779.6941977527 + 30 +0.0 + 11 +535293.5571175311 + 21 +185516.6960290042 + 31 +0.0 + 0 +LINE + 5 +4F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535310.5577928031 + 20 +185281.1508338489 + 30 +0.0 + 11 +535749.7250002055 + 21 +185277.1594001404 + 31 +0.0 + 0 +LINE + 5 +4F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535321.8102417574 + 20 +185349.72932479 + 30 +0.0 + 11 +535297.4628153631 + 21 +185157.3320250695 + 31 +0.0 + 0 +LINE + 5 +4F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535393.7012431163 + 20 +185339.5272597694 + 30 +0.0 + 11 +535385.1014189776 + 21 +185275.795880317 + 31 +0.0 + 0 +LINE + 5 +4F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535346.9444020168 + 20 +185367.2952780401 + 30 +0.0 + 11 +535402.0006421976 + 21 +185325.9907269572 + 31 +0.0 + 0 +LINE + 5 +4F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535382.2264866398 + 20 +185331.1913556245 + 30 +0.0 + 11 +535784.8986583672 + 21 +185352.4568174781 + 31 +0.0 + 0 +LINE + 5 +4F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535466.2111560569 + 20 +185520.4169102442 + 30 +0.0 + 11 +535514.7099456254 + 21 +185115.9919336981 + 31 +0.0 + 0 +LINE + 5 +4F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535501.4979983462 + 20 +185117.6476644367 + 30 +0.0 + 11 +535720.675878737 + 21 +185130.8756334432 + 31 +0.0 + 0 +LINE + 5 +4F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535418.8674089755 + 20 +184945.9561199044 + 30 +0.0 + 11 +535515.4397776947 + 21 +185129.2063845734 + 31 +0.0 + 0 +LINE + 5 +4FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535369.5064323646 + 20 +185017.8273827992 + 30 +0.0 + 11 +535452.3764747868 + 21 +184997.2391378445 + 31 +0.0 + 0 +LINE + 5 +4FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535717.5064167423 + 20 +185601.3754019604 + 30 +0.0 + 11 +535737.9102122855 + 21 +185175.1889393928 + 31 +0.0 + 0 +LINE + 5 +4FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535326.3598811705 + 20 +185199.7522087382 + 30 +0.0 + 11 +535750.4056180268 + 21 +185204.2732045837 + 31 +0.0 + 0 +LINE + 5 +4FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535281.2005158721 + 20 +183938.4377093622 + 30 +0.0 + 11 +535738.3484018436 + 21 +185214.8857648657 + 31 +0.0 + 0 +LINE + 5 +502 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535570.296748796 + 20 +185002.1058677334 + 30 +0.0 + 11 +535539.0553429453 + 21 +184802.52829905 + 31 +0.0 + 0 +LINE + 5 +503 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535357.746004057 + 20 +184958.474605842 + 30 +0.0 + 11 +535657.2550122715 + 21 +184929.8059817427 + 31 +0.0 + 0 +LINE + 5 +504 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535298.4922117697 + 20 +184889.1393465063 + 30 +0.0 + 11 +535341.8549400053 + 21 +185002.5727601311 + 31 +0.0 + 0 +LINE + 5 +505 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535241.173484526 + 20 +185019.5210662647 + 30 +0.0 + 11 +535249.717781515 + 21 +184899.043989793 + 31 +0.0 + 0 +LINE + 5 +506 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535246.9440076642 + 20 +184905.1824582619 + 30 +0.0 + 11 +535300.5910023385 + 21 +184889.7027665412 + 31 +0.0 + 0 +LINE + 5 +507 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534936.51385834 + 20 +185038.9531902914 + 30 +0.0 + 11 +534936.5261047019 + 21 +185038.9510308092 + 31 +0.0 + 0 +LINE + 5 +508 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535080.6527128276 + 20 +185013.5362284448 + 30 +0.0 + 11 +535490.5647417293 + 21 +184941.2537170008 + 31 +0.0 + 0 +LINE + 5 +509 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535501.4412534025 + 20 +184948.5153462196 + 30 +0.0 + 11 +535497.0379026665 + 21 +184924.6330290301 + 31 +0.0 + 0 +LINE + 5 +50D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535438.6044568951 + 20 +184992.5553584505 + 30 +0.0 + 11 +535394.6297386166 + 21 +184644.0500522233 + 31 +0.0 + 0 +LINE + 5 +50E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535304.00713784 + 20 +184686.4677601972 + 30 +0.0 + 11 +535412.5316292262 + 21 +184958.1988788722 + 31 +0.0 + 0 +LINE + 5 +50F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535285.9196378086 + 20 +184980.2736785974 + 30 +0.0 + 11 +535280.0577219055 + 21 +184945.2361034543 + 31 +0.0 + 0 +LINE + 5 +510 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535408.97011748 + 20 +184810.9000931193 + 30 +0.0 + 11 +535499.2992886764 + 21 +184787.3951780687 + 31 +0.0 + 0 +LINE + 5 +511 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535464.4760482091 + 20 +184792.1782756448 + 30 +0.0 + 11 +535543.352293473 + 21 +184819.2175096397 + 31 +0.0 + 0 +LINE + 5 +512 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535464.5747593957 + 20 +184805.3031096497 + 30 +0.0 + 11 +535525.357753368 + 21 +184753.0577724275 + 31 +0.0 + 0 +LINE + 5 +513 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535479.3097783617 + 20 +184592.3356562343 + 30 +0.0 + 11 +535522.9332737854 + 21 +184765.446873669 + 31 +0.0 + 0 +LINE + 5 +514 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535442.4387356393 + 20 +185206.0210956518 + 30 +0.0 + 11 +535448.962877189 + 21 +185159.464189451 + 31 +0.0 + 0 +LINE + 5 +515 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535385.2221178641 + 20 +185162.5376566434 + 30 +0.0 + 11 +535450.4688616026 + 21 +185160.624523209 + 31 +0.0 + 0 +LINE + 5 +516 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535362.082434586 + 20 +185206.3568374276 + 30 +0.0 + 11 +535347.2644751583 + 21 +185103.0932372945 + 31 +0.0 + 0 +LINE + 5 +517 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535201.914047268 + 20 +185144.1545844069 + 30 +0.0 + 11 +535490.7907191858 + 21 +185068.5966611639 + 31 +0.0 + 0 +LINE + 5 +518 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535571.5812368377 + 20 +185125.0116500937 + 30 +0.0 + 11 +535571.5035935779 + 21 +185056.1672042472 + 31 +0.0 + 0 +LINE + 5 +519 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535539.6771781332 + 20 +185057.1807123762 + 30 +0.0 + 11 +535599.7813427349 + 21 +185056.9330147139 + 31 +0.0 + 0 +LINE + 5 +51A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535545.0448302518 + 20 +185063.9077228577 + 30 +0.0 + 11 +535543.9573329221 + 21 +184992.5824589834 + 31 +0.0 + 0 +LINE + 5 +51B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535541.1738633348 + 20 +184995.0465275259 + 30 +0.0 + 11 +535597.2888617337 + 21 +184993.4043492656 + 31 +0.0 + 0 +LINE + 5 +51C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535594.7469779589 + 20 +185064.4360151786 + 30 +0.0 + 11 +535594.4263687718 + 21 +184986.9377248218 + 31 +0.0 + 0 +LINE + 5 +521 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534391.2765926996 + 20 +184519.6503847673 + 30 +0.0 + 11 +534386.096584341 + 21 +184657.946565643 + 31 +0.0 + 0 +LINE + 5 +52B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534256.5953021054 + 20 +184456.2129860037 + 30 +0.0 + 11 +534150.4528097157 + 21 +184882.3790791057 + 31 +0.0 + 0 +LINE + 5 +52F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534288.5721563849 + 20 +184537.5636853628 + 30 +0.0 + 11 +534215.4902316121 + 21 +184934.1190157052 + 31 +0.0 + 0 +LINE + 5 +530 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534453.0403708429 + 20 +184663.3012758095 + 30 +0.0 + 11 +534104.3003871109 + 21 +184622.7857454523 + 31 +0.0 + 0 +LINE + 5 +534 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534447.258926724 + 20 +184850.4577674675 + 30 +0.0 + 11 +534358.4101113065 + 21 +184835.3587940743 + 31 +0.0 + 0 +LINE + 5 +535 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534473.2590024992 + 20 +184926.5403161469 + 30 +0.0 + 11 +534009.7420030087 + 21 +184836.5395345194 + 31 +0.0 + 0 +LINE + 5 +536 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534173.7545980421 + 20 +184452.6269133669 + 30 +0.0 + 11 +534079.4116061442 + 21 +184866.0693231767 + 31 +0.0 + 0 +LINE + 5 +537 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533755.4398820817 + 20 +184661.6264292206 + 30 +0.0 + 11 +534086.3626894285 + 21 +184865.4899125348 + 31 +0.0 + 0 +LINE + 5 +54B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534152.8220239885 + 20 +184566.9747456222 + 30 +0.0 + 11 +534106.0257041126 + 21 +184562.4787046947 + 31 +0.0 + 0 +LINE + 5 +54C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534123.8568246478 + 20 +184501.2056948098 + 30 +0.0 + 11 +534106.8034721114 + 21 +184564.2134785772 + 31 +0.0 + 0 +LINE + 5 +557 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534476.3853151561 + 20 +184841.3974169092 + 30 +0.0 + 11 +534252.8962295165 + 21 +185308.7896885875 + 31 +0.0 + 0 +LINE + 5 +55A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533961.5249641592 + 20 +184881.5255266349 + 30 +0.0 + 11 +534304.3350339336 + 21 +185057.7811684468 + 31 +0.0 + 0 +LINE + 5 +55B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533907.0202036754 + 20 +184975.68771859 + 30 +0.0 + 11 +534585.0093833957 + 21 +185309.1577660268 + 31 +0.0 + 0 +LINE + 5 +55C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534351.9801533095 + 20 +185270.8440629181 + 30 +0.0 + 11 +534245.8376609196 + 21 +185697.0101560202 + 31 +0.0 + 0 +LINE + 5 +55D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534416.053427876 + 20 +185297.7558171074 + 30 +0.0 + 11 +534234.6140266268 + 21 +185229.2776323616 + 31 +0.0 + 0 +LINE + 5 +55E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534389.3918617133 + 20 +185365.2951323006 + 30 +0.0 + 11 +534329.4147947651 + 21 +185342.0917458582 + 31 +0.0 + 0 +LINE + 5 +55F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534427.284004527 + 20 +185326.2893565586 + 30 +0.0 + 11 +534374.294889134 + 21 +185370.214396944 + 31 +0.0 + 0 +LINE + 5 +564 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534082.1685787133 + 20 +185266.8570599263 + 30 +0.0 + 11 +534042.8498380052 + 21 +185342.6551891283 + 31 +0.0 + 0 +LINE + 5 +565 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534438.4337275536 + 20 +185715.179827652 + 30 +0.0 + 11 +534231.2455671621 + 21 +185651.1706114339 + 31 +0.0 + 0 +LINE + 5 +566 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534269.1394492462 + 20 +185267.2579902813 + 30 +0.0 + 11 +534174.7964573482 + 21 +185680.700400091 + 31 +0.0 + 0 +LINE + 5 +56B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534038.9544153993 + 20 +185209.4610571617 + 30 +0.0 + 11 +533929.5639759587 + 21 +185526.2001676052 + 31 +0.0 + 0 +LINE + 5 +56C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534128.9026977911 + 20 +185235.266299162 + 30 +0.0 + 11 +534010.36305539 + 21 +185208.8879234353 + 31 +0.0 + 0 +LINE + 5 +56D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534143.9452490914 + 20 +185183.4172834368 + 30 +0.0 + 11 +534127.2753217763 + 21 +185236.706441965 + 31 +0.0 + 0 +LINE + 5 +56E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534203.536687036 + 20 +184850.6856394941 + 30 +0.0 + 11 +533979.511130468 + 21 +185366.7574547194 + 31 +0.0 + 0 +LINE + 5 +56F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533984.0405412705 + 20 +185379.0258777179 + 30 +0.0 + 11 +533961.8400215265 + 21 +185369.1825299575 + 31 +0.0 + 0 +LINE + 5 +573 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534041.5016409996 + 20 +185328.1711071394 + 30 +0.0 + 11 +533705.4015758481 + 21 +185213.7569711722 + 31 +0.0 + 0 +LINE + 5 +574 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533926.8507846999 + 20 +184975.9659141336 + 30 +0.0 + 11 +533763.6036657633 + 21 +185098.3465764448 + 31 +0.0 + 0 +LINE + 5 +575 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533753.3249201474 + 20 +185068.9920483031 + 30 +0.0 + 11 +534014.1606413901 + 21 +185294.815001671 + 31 +0.0 + 0 +LINE + 5 +57B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534031.9313018756 + 20 +184808.6148959472 + 30 +0.0 + 11 +533876.783424875 + 21 +185029.0196435895 + 31 +0.0 + 0 +LINE + 5 +57C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534248.2068751925 + 20 +185381.6058225365 + 30 +0.0 + 11 +534201.4105553166 + 21 +185377.1097816092 + 31 +0.0 + 0 +LINE + 5 +57D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534219.2416758518 + 20 +185315.8367717241 + 30 +0.0 + 11 +534202.1883233154 + 21 +185378.8445554916 + 31 +0.0 + 0 +LINE + 5 +57E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534267.2444791151 + 20 +185303.536510522 + 30 +0.0 + 11 +534170.26974444 + 21 +185265.0807714352 + 31 +0.0 + 0 +LINE + 5 +585 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534088.6604468999 + 20 +184941.3248589964 + 30 +0.0 + 11 +534043.2684698303 + 21 +185044.4952954651 + 31 +0.0 + 0 +LINE + 5 +588 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533778.699490766 + 20 +185175.787427945 + 30 +0.0 + 11 +533615.7892077258 + 21 +185127.9007145659 + 31 +0.0 + 0 +LINE + 5 +589 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533889.4801228333 + 20 +184733.3371193682 + 30 +0.0 + 11 +533668.380798012 + 21 +185455.8235821609 + 31 +0.0 + 0 +LINE + 5 +58A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533669.0481535236 + 20 +185219.6666077623 + 30 +0.0 + 11 +533156.2970385719 + 21 +185130.5605879663 + 31 +0.0 + 0 +LINE + 5 +58B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533652.6970921362 + 20 +185287.2111842932 + 30 +0.0 + 11 +533691.368935235 + 21 +185097.1743282281 + 31 +0.0 + 0 +LINE + 5 +58D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533726.3554435947 + 20 +185312.8337458587 + 30 +0.0 + 11 +533574.50719174 + 21 +185257.5403092498 + 31 +0.0 + 0 +LINE + 5 +58E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533593.8368982549 + 20 +185264.2056083881 + 30 +0.0 + 11 +533277.4741264265 + 21 +185310.1755935641 + 31 +0.0 + 0 +LINE + 5 +58F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533672.2874569829 + 20 +185028.0485366832 + 30 +0.0 + 11 +533252.0779246593 + 21 +185038.8519140487 + 31 +0.0 + 0 +LINE + 5 +590 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533710.405074358 + 20 +184829.6561084765 + 30 +0.0 + 11 +533658.6782495932 + 21 +184939.5278570125 + 31 +0.0 + 0 +LINE + 5 +591 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533757.8097503218 + 20 +184963.9603378841 + 30 +0.0 + 11 +533758.301905461 + 21 +184843.1816611668 + 31 +0.0 + 0 +LINE + 5 +592 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533760.6087077835 + 20 +184849.5104272049 + 30 +0.0 + 11 +533708.2700168314 + 21 +184830.060945907 + 31 +0.0 + 0 +LINE + 5 +593 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534060.1620768055 + 20 +185006.1286428275 + 30 +0.0 + 11 +534060.1500263014 + 21 +185006.1255732843 + 31 +0.0 + 0 +LINE + 5 +594 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533918.3284564037 + 20 +184970.0003236548 + 30 +0.0 + 11 +532885.2387837082 + 21 +184800.028308228 + 31 +0.0 + 0 +LINE + 5 +595 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533494.4232462246 + 20 +185058.1154689717 + 30 +0.0 + 11 +533576.3287827944 + 21 +184703.1402534146 + 31 +0.0 + 0 +LINE + 5 +596 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533720.0668251423 + 20 +184684.4216508722 + 30 +0.0 + 11 +533604.0388960189 + 21 +184929.9588760215 + 31 +0.0 + 0 +LINE + 5 +597 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533716.1249475926 + 20 +184921.4756006983 + 30 +0.0 + 11 +533724.5914895053 + 21 +184886.9747108834 + 31 +0.0 + 0 +LINE + 5 +598 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533431.9734486657 + 20 +185232.4302220629 + 30 +0.0 + 11 +533540.1338697607 + 21 +185087.9672749981 + 31 +0.0 + 0 +LINE + 5 +599 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533603.4661137124 + 20 +185095.8003762957 + 30 +0.0 + 11 +533538.5453041319 + 21 +185089.0116995892 + 31 +0.0 + 0 +LINE + 5 +59A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533787.6357425715 + 20 +185091.1815131837 + 30 +0.0 + 11 +533565.5971262563 + 21 +185014.9532196935 + 31 +0.0 + 0 +LINE + 5 +59D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533835.4049733451 + 20 +184778.3242658983 + 30 +0.0 + 11 +533961.3461259023 + 21 +184945.405927624 + 31 +0.0 + 0 +LINE + 5 +59E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533589.8584304239 + 20 +185107.2802195277 + 30 +0.0 + 11 +533607.2332131394 + 21 +184991.399632075 + 31 +0.0 + 0 +LINE + 5 +59F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534448.9792157222 + 20 +184662.8294633956 + 30 +0.0 + 11 +534595.7315551097 + 21 +184795.9757854659 + 31 +0.0 + 0 +LINE + 5 +5A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531733.2840274471 + 20 +186204.7351113824 + 30 +0.0 + 11 +531448.5837936163 + 21 +186119.7760350217 + 31 +0.0 + 0 +LINE + 5 +5A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531632.4721077171 + 20 +185930.7358159032 + 30 +0.0 + 11 +531639.7393499542 + 21 +186196.0561477955 + 31 +0.0 + 0 +LINE + 5 +5A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531358.4579136721 + 20 +185930.1338576855 + 30 +0.0 + 11 +531685.1949769023 + 21 +186008.8922798291 + 31 +0.0 + 0 +LINE + 5 +5A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531770.0292339276 + 20 +185963.2831550198 + 30 +0.0 + 11 +531808.2136621511 + 21 +186140.5612032772 + 31 +0.0 + 0 +LINE + 5 +5A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532232.1680833026 + 20 +186022.1457130604 + 30 +0.0 + 11 +532232.1680833026 + 21 +186186.3597618883 + 31 +0.0 + 0 +LINE + 5 +5A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531627.5907608017 + 20 +186001.9470050684 + 30 +0.0 + 11 +531869.3182729818 + 21 +185971.1207754074 + 31 +0.0 + 0 +LINE + 5 +5A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531611.397048721 + 20 +186201.9375863602 + 30 +0.0 + 11 +531901.0963274493 + 21 +186217.1136835819 + 31 +0.0 + 0 +LINE + 5 +5A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533414.1140397175 + 20 +185165.5370379062 + 30 +0.0 + 11 +533424.4254015407 + 21 +184724.7392205304 + 31 +0.0 + 0 +LINE + 5 +5A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533322.7171241251 + 20 +184642.9320605513 + 30 +0.0 + 11 +532990.6437599907 + 21 +184514.5291438661 + 31 +0.0 + 0 +LINE + 5 +5AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534153.2048046347 + 20 +184752.2472177889 + 30 +0.0 + 11 +533885.0218290623 + 21 +184579.4395168853 + 31 +0.0 + 0 +LINE + 5 +5AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531550.2442337178 + 20 +185166.8802593773 + 30 +0.0 + 11 +531510.6297846931 + 21 +185399.9897693373 + 31 +0.0 + 0 +LINE + 5 +5AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532988.2362401025 + 20 +186147.3083667564 + 30 +0.0 + 11 +533381.9029377306 + 21 +186201.5675327487 + 31 +0.0 + 0 +LINE + 5 +5C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532850.8247731416 + 20 +187339.4336963453 + 30 +0.0 + 11 +533427.582290831 + 21 +185080.1812356924 + 31 +0.0 + 0 +LINE + 5 +5D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534248.5818166204 + 20 +185619.4487363936 + 30 +0.0 + 11 +534493.593518952 + 21 +185630.1835954607 + 31 +0.0 + 0 +LINE + 5 +5DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534282.0183703715 + 20 +185616.188519107 + 30 +0.0 + 11 +534172.0588715453 + 21 +185831.2875668419 + 31 +0.0 + 0 +LINE + 5 +5DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533826.1828457042 + 20 +185498.1855968445 + 30 +0.0 + 11 +534909.8834741084 + 21 +186031.2054602447 + 31 +0.0 + 0 +LINE + 5 +5E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534271.1427953386 + 20 +185793.3419411726 + 30 +0.0 + 11 +534165.0003029485 + 21 +186219.5080342747 + 31 +0.0 + 0 +LINE + 5 +5E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534335.216069905 + 20 +185820.2536953619 + 30 +0.0 + 11 +534153.7766686557 + 21 +185751.7755106161 + 31 +0.0 + 0 +LINE + 5 +5E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534308.5545037421 + 20 +185887.7930105551 + 30 +0.0 + 11 +534248.577436794 + 21 +185864.5896241127 + 31 +0.0 + 0 +LINE + 5 +5E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534570.7220163379 + 20 +186012.2185426509 + 30 +0.0 + 11 +534062.9865863768 + 21 +185953.4249086355 + 31 +0.0 + 0 +LINE + 5 +5E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534067.6732275388 + 20 +185940.9616670905 + 30 +0.0 + 11 +534026.1561056284 + 21 +186176.1469138242 + 31 +0.0 + 0 +LINE + 5 +5E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533919.9417536444 + 20 +185820.6237579156 + 30 +0.0 + 11 +534075.6678596591 + 21 +185957.2116849322 + 31 +0.0 + 0 +LINE + 5 +5E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534001.3312207422 + 20 +185789.3549381808 + 30 +0.0 + 11 +533962.012480034 + 21 +185865.1530673827 + 31 +0.0 + 0 +LINE + 5 +5E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534357.5963695824 + 20 +186237.6777059064 + 30 +0.0 + 11 +534024.2894962416 + 21 +186173.6684896884 + 31 +0.0 + 0 +LINE + 5 +5E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534188.3020912749 + 20 +185789.7558685358 + 30 +0.0 + 11 +534093.959099377 + 21 +186203.1982783455 + 31 +0.0 + 0 +LINE + 5 +5EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533638.9909350334 + 20 +185915.9627476106 + 30 +0.0 + 11 +534100.9101826614 + 21 +186202.6188677036 + 31 +0.0 + 0 +LINE + 5 +5EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533717.7276796531 + 20 +185860.915757104 + 30 +0.0 + 11 +533711.7175495929 + 21 +185978.1906737143 + 31 +0.0 + 0 +LINE + 5 +5EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533770.762714852 + 20 +185893.2003459607 + 30 +0.0 + 11 +533683.5308453329 + 21 +185959.9551347054 + 31 +0.0 + 0 +LINE + 5 +5ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533939.2875136152 + 20 +185980.9652082985 + 30 +0.0 + 11 +533752.4704865293 + 21 +185904.110606927 + 31 +0.0 + 0 +LINE + 5 +5EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533958.117057428 + 20 +185731.9589354162 + 30 +0.0 + 11 +533848.7266179877 + 21 +186048.6980458597 + 31 +0.0 + 0 +LINE + 5 +5EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534048.06533982 + 20 +185757.7641774165 + 30 +0.0 + 11 +533929.525697419 + 21 +185731.3858016898 + 31 +0.0 + 0 +LINE + 5 +5F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534063.1078911201 + 20 +185705.9151616913 + 30 +0.0 + 11 +534046.4379638053 + 21 +185759.2043202194 + 31 +0.0 + 0 +LINE + 5 +5F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534282.8840061187 + 20 +185012.2849875451 + 30 +0.0 + 11 +533898.6737724969 + 21 +185889.2553329739 + 31 +0.0 + 0 +LINE + 5 +5F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533903.2031832994 + 20 +185901.5237559724 + 30 +0.0 + 11 +533881.0026635552 + 21 +185891.680408212 + 31 +0.0 + 0 +LINE + 5 +5F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533973.5175888728 + 20 +186078.1849544206 + 30 +0.0 + 11 +533951.289621666 + 21 +186117.6824815214 + 31 +0.0 + 0 +LINE + 5 +5F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533987.2718768551 + 20 +186070.9637877669 + 30 +0.0 + 11 +533966.918612191 + 21 +186083.8047787778 + 31 +0.0 + 0 +LINE + 5 +5F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534047.7321300739 + 20 +186092.2482343965 + 30 +0.0 + 11 +533979.3014454953 + 21 +186070.3597949963 + 31 +0.0 + 0 +LINE + 5 +5F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533960.6642830283 + 20 +185850.6689853939 + 30 +0.0 + 11 +533624.564217877 + 21 +185736.2548494267 + 31 +0.0 + 0 +LINE + 5 +5F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533846.0134267288 + 20 +185498.4637923881 + 30 +0.0 + 11 +533682.7663077922 + 21 +185620.8444546993 + 31 +0.0 + 0 +LINE + 5 +5F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533672.4875621763 + 20 +185591.4899265576 + 30 +0.0 + 11 +533933.323283419 + 21 +185817.3128799255 + 31 +0.0 + 0 +LINE + 5 +5F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533984.2730984368 + 20 +185699.3213145349 + 30 +0.0 + 11 +533951.5635824718 + 21 +185685.4619748932 + 31 +0.0 + 0 +LINE + 5 +5FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533790.9027081983 + 20 +185779.5505123624 + 30 +0.0 + 11 +533747.0106001366 + 21 +185861.9235847253 + 31 +0.0 + 0 +LINE + 5 +5FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533759.7708675354 + 20 +185829.171307324 + 30 +0.0 + 11 +533767.7003971879 + 21 +185912.175553007 + 31 +0.0 + 0 +LINE + 5 +5FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533772.511944799 + 20 +185832.3234433795 + 30 +0.0 + 11 +533707.5492968536 + 21 +185879.270242947 + 31 +0.0 + 0 +LINE + 5 +5FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533609.8257327368 + 20 +185818.9870339748 + 30 +0.0 + 11 +533720.1623939 + 21 +185879.7972284508 + 31 +0.0 + 0 +LINE + 5 +5FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533892.3579233192 + 20 +185253.3677321921 + 30 +0.0 + 11 +533795.9460669039 + 21 +185551.517521844 + 31 +0.0 + 0 +LINE + 5 +5FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534167.3695172214 + 20 +185904.103700791 + 30 +0.0 + 11 +534120.5731973455 + 21 +185899.6076598636 + 31 +0.0 + 0 +LINE + 5 +600 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534138.4043178805 + 20 +185838.3346499785 + 30 +0.0 + 11 +534121.3509653443 + 21 +185901.3424337461 + 31 +0.0 + 0 +LINE + 5 +601 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534186.407121144 + 20 +185826.0343887765 + 30 +0.0 + 11 +534089.4323864689 + 21 +185787.5786496897 + 31 +0.0 + 0 +LINE + 5 +602 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534163.2101264513 + 20 +185655.7847719955 + 30 +0.0 + 11 +534022.4637309971 + 21 +185919.1271034002 + 31 +0.0 + 0 +LINE + 5 +603 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534058.515801896 + 20 +186010.8331931783 + 30 +0.0 + 11 +533991.5818118574 + 21 +185994.7271468006 + 31 +0.0 + 0 +LINE + 5 +604 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533999.9782917924 + 20 +185964.0115637281 + 30 +0.0 + 11 +533985.742053636 + 21 +186022.4059254402 + 31 +0.0 + 0 +LINE + 5 +605 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534005.2705259052 + 20 +185970.7980663162 + 30 +0.0 + 11 +533936.1590559625 + 21 +185953.1322620743 + 31 +0.0 + 0 +LINE + 5 +606 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533939.2035281585 + 20 +185950.9990659342 + 30 +0.0 + 11 +533924.5400241045 + 21 +186005.1892075063 + 31 +0.0 + 0 +LINE + 5 +607 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533994.211073514 + 20 +186019.257029288 + 30 +0.0 + 11 +533918.9176883678 + 21 +186000.8996342736 + 31 +0.0 + 0 +LINE + 5 +608 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534007.823088929 + 20 +185463.8227372508 + 30 +0.0 + 11 +533962.4311118591 + 21 +185566.9931737196 + 31 +0.0 + 0 +LINE + 5 +609 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533680.2879975476 + 20 +185926.3723861391 + 30 +0.0 + 11 +533183.0921970396 + 21 +185960.4920697405 + 31 +0.0 + 0 +LINE + 5 +60A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533635.3074283488 + 20 +185874.3556080671 + 30 +0.0 + 11 +533409.7069375618 + 21 +185902.1750854693 + 31 +0.0 + 0 +LINE + 5 +60B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533697.8621327951 + 20 +185698.2853061994 + 30 +0.0 + 11 +533534.9518497547 + 21 +185650.3985928204 + 31 +0.0 + 0 +LINE + 5 +60C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533771.9073970045 + 20 +185375.8751922475 + 30 +0.0 + 11 +533587.5434400409 + 21 +185978.3214604154 + 31 +0.0 + 0 +LINE + 5 +60E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533571.859734165 + 20 +185809.7090625476 + 30 +0.0 + 11 +533610.5315772639 + 21 +185619.6722064826 + 31 +0.0 + 0 +LINE + 5 +60F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533500.9333528128 + 20 +185794.1576434707 + 30 +0.0 + 11 +533514.2766247555 + 21 +185731.2481625001 + 31 +0.0 + 0 +LINE + 5 +610 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533545.4819450334 + 20 +185825.3455892097 + 30 +0.0 + 11 +533493.6698337688 + 21 +185780.0381875042 + 31 +0.0 + 0 +LINE + 5 +611 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533512.9995402838 + 20 +185786.7034866426 + 30 +0.0 + 11 +533196.6367684554 + 21 +185832.6734718186 + 31 +0.0 + 0 +LINE + 5 +612 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533591.4500990117 + 20 +185550.5464149377 + 30 +0.0 + 11 +533281.9833857183 + 21 +185528.8296416967 + 31 +0.0 + 0 +LINE + 5 +616 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533979.3247188342 + 20 +185528.626521082 + 30 +0.0 + 11 +533979.3126683303 + 21 +185528.6234515387 + 31 +0.0 + 0 +LINE + 5 +619 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533592.716804391 + 20 +185246.1291783604 + 30 +0.0 + 11 +533497.5594804018 + 21 +185639.2600493747 + 31 +0.0 + 0 +LINE + 5 +61B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533351.1360906946 + 20 +185754.9281003174 + 30 +0.0 + 11 +533459.2965117895 + 21 +185610.4651532526 + 31 +0.0 + 0 +LINE + 5 +61C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533522.6287557413 + 20 +185618.2982545502 + 30 +0.0 + 11 +533457.707946161 + 21 +185611.5095778437 + 31 +0.0 + 0 +LINE + 5 +61D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533706.7983846004 + 20 +185613.6793914381 + 30 +0.0 + 11 +533484.7597682852 + 21 +185537.451097948 + 31 +0.0 + 0 +LINE + 5 +620 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533365.6423109871 + 20 +185989.5037721182 + 30 +0.0 + 11 +533355.2628067224 + 21 +185733.4928732219 + 31 +0.0 + 0 +LINE + 5 +623 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533538.3571319998 + 20 +185927.2096775935 + 30 +0.0 + 11 +533580.5614965238 + 21 +186464.9701427501 + 31 +0.0 + 0 +LINE + 5 +624 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533458.1223385239 + 20 +186169.4847237501 + 30 +0.0 + 11 +533567.2457225238 + 21 +186212.8623077501 + 31 +0.0 + 0 +LINE + 5 +625 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533465.3862375239 + 20 +186231.1470737501 + 30 +0.0 + 11 +533562.4058715238 + 21 +186179.6418167501 + 31 +0.0 + 0 +LINE + 5 +626 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533474.9917335238 + 20 +186420.9127537501 + 30 +0.0 + 11 +533482.9234825239 + 21 +186219.0605337501 + 31 +0.0 + 0 +LINE + 5 +629 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533360.3675759997 + 20 +186232.7478384316 + 30 +0.0 + 11 +533383.5869865237 + 21 +185953.2266277501 + 31 +0.0 + 0 +LINE + 5 +62A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533362.2817485238 + 20 +185976.7798857501 + 30 +0.0 + 11 +533556.7744945239 + 21 +186028.6150477501 + 31 +0.0 + 0 +LINE + 5 +62B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533258.2867925238 + 20 +185940.5511634717 + 30 +0.0 + 11 +533382.6655621308 + 21 +186525.8843834039 + 31 +0.0 + 0 +LINE + 5 +62C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533353.6739045237 + 20 +186202.1253807501 + 30 +0.0 + 11 +533446.8430955237 + 21 +186196.5269837501 + 31 +0.0 + 0 +LINE + 5 +62D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533411.7521155238 + 20 +186194.4875667501 + 30 +0.0 + 11 +533483.9128905238 + 21 +186236.2656087501 + 31 +0.0 + 0 +LINE + 5 +62E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533409.3115775239 + 20 +186207.3838757501 + 30 +0.0 + 11 +533479.0483035237 + 21 +186167.8751847501 + 31 +0.0 + 0 +LINE + 5 +62F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533464.9410045238 + 20 +186001.2828717501 + 30 +0.0 + 11 +533474.2744135237 + 21 +186179.5618397501 + 31 +0.0 + 0 +LINE + 5 +631 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533828.2799445249 + 20 +186210.2886838591 + 30 +0.0 + 11 +534061.4320714794 + 21 +186167.5716401304 + 31 +0.0 + 0 +LINE + 5 +633 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533682.6241340539 + 20 +186064.3491011722 + 30 +0.0 + 11 +533742.8463203225 + 21 +185963.5383080481 + 31 +0.0 + 0 +LINE + 5 +634 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533744.6558089154 + 20 +186067.0101066368 + 30 +0.0 + 11 +533709.2791370904 + 21 +185963.019280259 + 31 +0.0 + 0 +LINE + 5 +635 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533835.7364357564 + 20 +186271.9532591409 + 30 +0.0 + 11 +533852.6960106894 + 21 +186024.3600566836 + 31 +0.0 + 0 +LINE + 5 +63A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533878.8332329101 + 20 +186207.9637909363 + 30 +0.0 + 11 +533536.7480498949 + 21 +186128.1674759979 + 31 +0.0 + 0 +LINE + 5 +63B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533545.052813288 + 20 +186227.8808082367 + 30 +0.0 + 11 +533837.5602881303 + 21 +186220.4819401955 + 31 +0.0 + 0 +LINE + 5 +63D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533698.1930436881 + 20 +186172.6657522801 + 30 +0.0 + 11 +533707.5219630261 + 21 +186079.7958892214 + 31 +0.0 + 0 +LINE + 5 +63E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533699.9134321882 + 20 +186114.1127416054 + 30 +0.0 + 11 +533752.6629064465 + 21 +186049.5366221229 + 31 +0.0 + 0 +LINE + 5 +63F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533712.2556086878 + 20 +186118.5783536354 + 30 +0.0 + 11 +533684.3718017468 + 21 +186043.434219279 + 31 +0.0 + 0 +LINE + 5 +640 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533517.6614423957 + 20 +186030.7981312432 + 30 +0.0 + 11 +533695.1477506907 + 21 +186050.0104533972 + 31 +0.0 + 0 +LINE + 5 +641 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533938.7951369609 + 20 +186482.5712296237 + 30 +0.0 + 11 +533968.2654247546 + 21 +186185.4345043938 + 31 +0.0 + 0 +LINE + 5 +643 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534367.7944644015 + 20 +186130.8678290536 + 30 +0.0 + 11 +534035.7211002672 + 21 +186002.4649123684 + 31 +0.0 + 0 +LINE + 5 +64E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532380.4365915808 + 20 +183829.5073398477 + 30 +0.0 + 11 +532354.2882743065 + 21 +183002.9918967023 + 31 +0.0 + 0 +LINE + 5 +666 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536721.8421223054 + 20 +187156.3816589114 + 30 +0.0 + 11 +536115.335826082 + 21 +187063.9140026928 + 31 +0.0 + 0 +LINE + 5 +667 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536616.706362917 + 20 +187155.7945168107 + 30 +0.0 + 11 +536886.3043911481 + 21 +186412.0959092634 + 31 +0.0 + 0 +LINE + 5 +668 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536666.447967984 + 20 +187027.2281110592 + 30 +0.0 + 11 +536521.132606101 + 21 +187000.0042188773 + 31 +0.0 + 0 +LINE + 5 +669 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536552.2840148339 + 20 +187145.8392677637 + 30 +0.0 + 11 +536721.6738765864 + 21 +186681.3054352729 + 31 +0.0 + 0 +LINE + 5 +66A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536550.2106325194 + 20 +187014.8446578274 + 30 +0.0 + 11 +536489.8958197851 + 21 +186959.3178929346 + 31 +0.0 + 0 +LINE + 5 +66B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536491.0322792968 + 20 +187068.2603682839 + 30 +0.0 + 11 +536549.6500574119 + 21 +187002.8280783266 + 31 +0.0 + 0 +LINE + 5 +66C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536508.7832802601 + 20 +187061.4323469309 + 30 +0.0 + 11 +536310.8203374363 + 21 +187042.3293091405 + 31 +0.0 + 0 +LINE + 5 +66D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536473.6692727942 + 20 +187178.8966004267 + 30 +0.0 + 11 +536448.1715212629 + 21 +186746.6824336228 + 31 +0.0 + 0 +LINE + 5 +66E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536309.2993856575 + 20 +186986.2769338689 + 30 +0.0 + 11 +536494.1270439047 + 21 +186960.2274519697 + 31 +0.0 + 0 +LINE + 5 +66F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536314.1277275352 + 20 +187046.694654312 + 30 +0.0 + 11 +536309.8524477744 + 21 +186985.6344982014 + 31 +0.0 + 0 +LINE + 5 +672 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536127.4745693341 + 20 +186916.0368669632 + 30 +0.0 + 11 +536816.4822066296 + 21 +186869.139699889 + 31 +0.0 + 0 +LINE + 5 +673 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536525.5993654336 + 20 +186819.2249963617 + 30 +0.0 + 11 +536588.1901689714 + 21 +186384.522616666 + 31 +0.0 + 0 +LINE + 5 +674 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536595.0910224655 + 20 +186818.4924458963 + 30 +0.0 + 11 +536401.2259074044 + 21 +186813.4096047542 + 31 +0.0 + 0 +LINE + 5 +675 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536595.8985936714 + 20 +186745.8856553338 + 30 +0.0 + 11 +536531.5999819602 + 21 +186744.7305648122 + 31 +0.0 + 0 +LINE + 5 +676 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536616.2621607849 + 20 +186796.3097583272 + 30 +0.0 + 11 +536583.7757235719 + 21 +186735.6312042886 + 31 +0.0 + 0 +LINE + 5 +677 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536585.9204290146 + 20 +186755.9650186167 + 30 +0.0 + 11 +536667.9473822077 + 21 +186361.1629457988 + 31 +0.0 + 0 +LINE + 5 +678 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536785.6857709126 + 20 +186701.6185063583 + 30 +0.0 + 11 +536393.2771205099 + 21 +186592.4070356544 + 31 +0.0 + 0 +LINE + 5 +679 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536392.9120581205 + 20 +186605.7173220767 + 30 +0.0 + 11 +536443.2503469226 + 21 +186372.2610555652 + 31 +0.0 + 0 +LINE + 5 +67A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536210.6834718002 + 20 +186661.3818807413 + 30 +0.0 + 11 +536406.449603067 + 21 +186593.6876878588 + 31 +0.0 + 0 +LINE + 5 +67B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536274.2466349336 + 20 +186721.0619338121 + 30 +0.0 + 11 +536266.4513026214 + 21 +186636.0292779937 + 31 +0.0 + 0 +LINE + 5 +67C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536835.1377440049 + 20 +186601.9767823079 + 30 +0.0 + 11 +536747.1631200043 + 21 +186582.4177299131 + 31 +0.0 + 0 +LINE + 5 +67D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536903.7822790087 + 20 +186465.4897275121 + 30 +0.0 + 11 +536440.586236061 + 21 +186373.8514423475 + 31 +0.0 + 0 +LINE + 5 +67E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536447.5344701054 + 20 +186791.2729967184 + 30 +0.0 + 11 +536516.2484564788 + 21 +186372.8072102721 + 31 +0.0 + 0 +LINE + 5 +67F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536045.525813408 + 20 +186455.4018776182 + 30 +0.0 + 11 +536522.4664836628 + 21 +186375.9678136094 + 31 +0.0 + 0 +LINE + 5 +681 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536038.6420717368 + 20 +186547.7344716945 + 30 +0.0 + 11 +536077.3484423033 + 21 +186436.8681350233 + 31 +0.0 + 0 +LINE + 5 +682 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536099.9405019144 + 20 +186537.8596504822 + 30 +0.0 + 11 +536044.3633383144 + 21 +186443.113781093 + 31 +0.0 + 0 +LINE + 5 +683 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536289.1274002778 + 20 +186520.2075586261 + 30 +0.0 + 11 +536087.1204276245 + 21 +186520.8512670621 + 31 +0.0 + 0 +LINE + 5 +684 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536212.562739197 + 20 +186757.897542278 + 30 +0.0 + 11 +536230.836750314 + 21 +186423.2992863901 + 31 +0.0 + 0 +LINE + 5 +685 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536305.597141756 + 20 +186767.9575601927 + 30 +0.0 + 11 +536185.8705566588 + 21 +186747.6349041769 + 31 +0.0 + 0 +LINE + 5 +686 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536188.9556141511 + 20 +186849.6862783888 + 30 +0.0 + 11 +536305.430287944 + 21 +186817.7272212837 + 31 +0.0 + 0 +LINE + 5 +687 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536299.9534294918 + 20 +186821.6487819443 + 30 +0.0 + 11 +536304.633839147 + 21 +186766.0096351245 + 31 +0.0 + 0 +LINE + 5 +688 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536229.5279032986 + 20 +187152.256905888 + 30 +0.0 + 11 +536216.8978776463 + 21 +186589.7997511483 + 31 +0.0 + 0 +LINE + 5 +689 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536225.7235310675 + 20 +186580.1489684459 + 30 +0.0 + 11 +536201.4497697369 + 21 +186580.8831910964 + 31 +0.0 + 0 +LINE + 5 +68A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536357.5255991142 + 20 +186443.1033208429 + 30 +0.0 + 11 +536351.8528189064 + 21 +186398.1371475795 + 31 +0.0 + 0 +LINE + 5 +68B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536367.5361546681 + 20 +186454.9824817241 + 30 +0.0 + 11 +536353.5364037751 + 21 +186435.4081769457 + 31 +0.0 + 0 +LINE + 5 +68C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536431.5577923935 + 20 +186458.0969304032 + 30 +0.0 + 11 +536359.9274632249 + 21 +186452.5329107725 + 31 +0.0 + 0 +LINE + 5 +68D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536259.7350569179 + 20 +186648.932700403 + 30 +0.0 + 11 +535923.953342475 + 21 +186656.2281362882 + 31 +0.0 + 0 +LINE + 5 +68E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535865.5521283698 + 20 +186582.2711223863 + 30 +0.0 + 11 +535909.5661554791 + 21 +186409.5705157149 + 31 +0.0 + 0 +LINE + 5 +690 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535965.3597747557 + 20 +186727.1967157956 + 30 +0.0 + 11 +536221.8250015524 + 21 +186669.4993660018 + 31 +0.0 + 0 +LINE + 5 +691 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536224.4625911634 + 20 +186797.9942541284 + 30 +0.0 + 11 +536188.9413628585 + 21 +186798.4801241541 + 31 +0.0 + 0 +LINE + 5 +692 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536077.8143043649 + 20 +186671.3894402389 + 30 +0.0 + 11 +536066.1387435208 + 21 +186557.85564699 + 31 +0.0 + 0 +LINE + 5 +693 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536065.5907214598 + 20 +186593.0015681029 + 30 +0.0 + 11 +536104.2679961856 + 21 +186519.1324225704 + 31 +0.0 + 0 +LINE + 5 +694 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536078.5790034816 + 20 +186594.8924783798 + 30 +0.0 + 11 +536036.145709285 + 21 +186526.8956905047 + 31 +0.0 + 0 +LINE + 5 +695 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535870.3023852617 + 20 +186548.0618548403 + 30 +0.0 + 11 +536048.0244747275 + 21 +186531.1691975403 + 31 +0.0 + 0 +LINE + 5 +698 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536471.3175540789 + 20 +186677.4838745904 + 30 +0.0 + 11 +536426.2865221732 + 21 +186663.981426536 + 31 +0.0 + 0 +LINE + 5 +699 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536419.667447414 + 20 +186727.4520374456 + 30 +0.0 + 11 +536427.6616261824 + 21 +186662.6686232577 + 31 +0.0 + 0 +LINE + 5 +69A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536459.4750142634 + 20 +186756.9634448726 + 30 +0.0 + 11 +536355.1584437736 + 21 +186755.9653690792 + 31 +0.0 + 0 +LINE + 5 +69B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536373.7244359636 + 20 +186905.8589481565 + 30 +0.0 + 11 +536342.8050682326 + 21 +186608.8695139299 + 31 +0.0 + 0 +LINE + 5 +69C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536410.8090196552 + 20 +186537.5587762437 + 30 +0.0 + 11 +536342.7475201335 + 21 +186527.2052244266 + 31 +0.0 + 0 +LINE + 5 +69D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536338.9274579809 + 20 +186558.8178017327 + 30 +0.0 + 11 +536347.7887194486 + 21 +186499.3699253886 + 31 +0.0 + 0 +LINE + 5 +69E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536346.3900426166 + 20 +186554.5312891829 + 30 +0.0 + 11 +536275.7233642788 + 21 +186544.8000770359 + 31 +0.0 + 0 +LINE + 5 +69F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536277.7372782987 + 20 +186547.9247349442 + 30 +0.0 + 11 +536284.6157765886 + 21 +186492.208704432 + 31 +0.0 + 0 +LINE + 5 +6A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536354.4423756366 + 20 +186505.4829200722 + 30 +0.0 + 11 +536277.790117113 + 21 +186494.0584261355 + 31 +0.0 + 0 +LINE + 5 +6A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536666.4355173762 + 20 +186671.0755228247 + 30 +0.0 + 11 +536734.8141109666 + 21 +186415.4623038834 + 31 +0.0 + 0 +LINE + 5 +6A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537062.3019043448 + 20 +186308.8815913478 + 30 +0.0 + 11 +536916.986542462 + 21 +186281.6576991659 + 31 +0.0 + 0 +LINE + 5 +6A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536948.1379511946 + 20 +186427.4927480521 + 30 +0.0 + 11 +537117.5278129472 + 21 +185962.9589155613 + 31 +0.0 + 0 +LINE + 5 +6A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536946.0645688802 + 20 +186296.4981381159 + 30 +0.0 + 11 +536885.7497561461 + 21 +186240.971373223 + 31 +0.0 + 0 +LINE + 5 +6A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536886.8862156576 + 20 +186349.9138485724 + 30 +0.0 + 11 +536945.5039937727 + 21 +186284.4815586153 + 31 +0.0 + 0 +LINE + 5 +6A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536902.8495839172 + 20 +186342.7321635861 + 30 +0.0 + 11 +536704.8866410933 + 21 +186323.6291257958 + 31 +0.0 + 0 +LINE + 5 +6A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536874.5354492202 + 20 +186545.5129120825 + 30 +0.0 + 11 +536844.0254576235 + 21 +186028.3359139113 + 31 +0.0 + 0 +LINE + 5 +6A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536705.1533220182 + 20 +186267.9304141575 + 30 +0.0 + 11 +536889.9809802655 + 21 +186241.8809322582 + 31 +0.0 + 0 +LINE + 5 +6AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536709.981663896 + 20 +186328.3481346005 + 30 +0.0 + 11 +536705.7063841352 + 21 +186267.2879784899 + 31 +0.0 + 0 +LINE + 5 +6AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536412.9192928441 + 20 +186313.9919186686 + 30 +0.0 + 11 +536709.0047859222 + 21 +186287.9276338956 + 31 +0.0 + 0 +LINE + 5 +6AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536481.3018370568 + 20 +186311.6477386654 + 30 +0.0 + 11 +536479.0979397001 + 21 +186198.5418407067 + 31 +0.0 + 0 +LINE + 5 +6AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536397.9941025675 + 20 +186206.2212083415 + 30 +0.0 + 11 +537151.7037753856 + 21 +186153.369250425 + 31 +0.0 + 0 +LINE + 5 +6AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536921.4533017945 + 20 +186100.8784766501 + 30 +0.0 + 11 +536990.7057561739 + 21 +185456.6421274363 + 31 +0.0 + 0 +LINE + 5 +6AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536990.9449588264 + 20 +186100.1459261849 + 30 +0.0 + 11 +536797.0798437653 + 21 +186095.0630850427 + 31 +0.0 + 0 +LINE + 5 +6B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536991.7525300322 + 20 +186027.5391356223 + 30 +0.0 + 11 +536927.453918321 + 21 +186026.3840451008 + 31 +0.0 + 0 +LINE + 5 +6B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537012.1160971457 + 20 +186077.9632386158 + 30 +0.0 + 11 +536979.6296599327 + 21 +186017.2846845772 + 31 +0.0 + 0 +LINE + 5 +6B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536981.7743653753 + 20 +186037.6184989052 + 30 +0.0 + 11 +537010.3705357475 + 21 +185899.982918183 + 31 +0.0 + 0 +LINE + 5 +6B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537181.5397072733 + 20 +185983.2719866468 + 30 +0.0 + 11 +536789.1310568708 + 21 +185874.0605159429 + 31 +0.0 + 0 +LINE + 5 +6B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536788.7659944812 + 20 +185887.3708023651 + 30 +0.0 + 11 +536839.1042832833 + 21 +185653.9145358537 + 31 +0.0 + 0 +LINE + 5 +6B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536606.537408161 + 20 +185943.0353610298 + 30 +0.0 + 11 +536802.3035394278 + 21 +185875.3411681474 + 31 +0.0 + 0 +LINE + 5 +6B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536670.1005712944 + 20 +186002.7154141007 + 30 +0.0 + 11 +536662.3052389822 + 21 +185917.6827582823 + 31 +0.0 + 0 +LINE + 5 +6B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537232.0290754295 + 20 +185868.6402924852 + 30 +0.0 + 11 +537144.0544514289 + 21 +185849.0812400903 + 31 +0.0 + 0 +LINE + 5 +6B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536843.3884064661 + 20 +186072.926477007 + 30 +0.0 + 11 +536912.1023928396 + 21 +185654.4606905605 + 31 +0.0 + 0 +LINE + 5 +6B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536434.4960080977 + 20 +185829.387951983 + 30 +0.0 + 11 +536473.2023786641 + 21 +185718.5216153119 + 31 +0.0 + 0 +LINE + 5 +6BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536495.7944382751 + 20 +185819.5131307709 + 30 +0.0 + 11 +536440.2172746752 + 21 +185724.7672613815 + 31 +0.0 + 0 +LINE + 5 +6BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536684.9813366386 + 20 +185801.8610389146 + 30 +0.0 + 11 +536482.9743639853 + 21 +185802.5047473506 + 31 +0.0 + 0 +LINE + 5 +6BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536608.4166755578 + 20 +186039.5510225665 + 30 +0.0 + 11 +536622.7213326102 + 21 +185611.5270011947 + 31 +0.0 + 0 +LINE + 5 +6BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536701.4510781167 + 20 +186049.6110404813 + 30 +0.0 + 11 +536581.7244930196 + 21 +186029.2883844655 + 31 +0.0 + 0 +LINE + 5 +6BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536584.8095505118 + 20 +186131.3397586772 + 30 +0.0 + 11 +536701.2842243047 + 21 +186099.3807015723 + 31 +0.0 + 0 +LINE + 5 +6BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536695.8073658528 + 20 +186103.3022622328 + 30 +0.0 + 11 +536700.4877755078 + 21 +186047.6631154132 + 31 +0.0 + 0 +LINE + 5 +6C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536625.3818396596 + 20 +186433.9103861764 + 30 +0.0 + 11 +536612.7518140071 + 21 +185871.4532314369 + 31 +0.0 + 0 +LINE + 5 +6C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536621.5774674283 + 20 +185861.8024487344 + 30 +0.0 + 11 +536597.3037060976 + 21 +185862.5366713851 + 31 +0.0 + 0 +LINE + 5 +6C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536753.379535475 + 20 +185724.7568011315 + 30 +0.0 + 11 +536746.3417123108 + 21 +185647.6619285755 + 31 +0.0 + 0 +LINE + 5 +6C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536763.3900910289 + 20 +185736.6359620126 + 30 +0.0 + 11 +536749.3903401359 + 21 +185717.0616572342 + 31 +0.0 + 0 +LINE + 5 +6C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536827.4117287541 + 20 +185739.7504106917 + 30 +0.0 + 11 +536755.7813995857 + 21 +185734.186391061 + 31 +0.0 + 0 +LINE + 5 +6C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536655.5889932786 + 20 +185930.5861806915 + 30 +0.0 + 11 +536301.1658749766 + 21 +185909.6553059632 + 31 +0.0 + 0 +LINE + 5 +6C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536416.4623950756 + 20 +186213.4497288245 + 30 +0.0 + 11 +536311.4935309209 + 21 +186038.497775686 + 31 +0.0 + 0 +LINE + 5 +6C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536290.8938687045 + 20 +186061.8000255862 + 30 +0.0 + 11 +536617.6789379133 + 21 +185951.1528462902 + 31 +0.0 + 0 +LINE + 5 +6C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536620.3165275241 + 20 +186079.647734417 + 30 +0.0 + 11 +536584.7952992191 + 21 +186080.1336044426 + 31 +0.0 + 0 +LINE + 5 +6C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536471.5409159631 + 20 +185932.356697997 + 30 +0.0 + 11 +536461.9926798815 + 21 +185839.5091272786 + 31 +0.0 + 0 +LINE + 5 +6CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536461.4446578205 + 20 +185874.6550483916 + 30 +0.0 + 11 +536500.1219325463 + 21 +185800.785902859 + 31 +0.0 + 0 +LINE + 5 +6CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536474.4329398423 + 20 +185876.5459586684 + 30 +0.0 + 11 +536431.9996456458 + 21 +185808.5491707931 + 31 +0.0 + 0 +LINE + 5 +6CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536318.7496871943 + 20 +185827.4808156863 + 30 +0.0 + 11 +536443.8784110883 + 21 +185812.8226778289 + 31 +0.0 + 0 +LINE + 5 +6CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536450.5920255018 + 20 +186408.0864332379 + 30 +0.0 + 11 +536390.1276466231 + 21 +186145.4209132169 + 31 +0.0 + 0 +LINE + 5 +6CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536867.1714904397 + 20 +185959.137354879 + 30 +0.0 + 11 +536822.1404585341 + 21 +185945.6349068246 + 31 +0.0 + 0 +LINE + 5 +6CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536815.5213837749 + 20 +186009.1055177341 + 30 +0.0 + 11 +536823.5155625431 + 21 +185944.3221035461 + 31 +0.0 + 0 +LINE + 5 +6D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536855.3289506244 + 20 +186038.6169251611 + 30 +0.0 + 11 +536751.0123801345 + 21 +186037.6188493678 + 31 +0.0 + 0 +LINE + 5 +6D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536769.5783723245 + 20 +186187.512428445 + 30 +0.0 + 11 +536738.6590045934 + 21 +185890.5229942185 + 31 +0.0 + 0 +LINE + 5 +6D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536806.6629560161 + 20 +185819.2122565322 + 30 +0.0 + 11 +536738.6014564944 + 21 +185808.8587047152 + 31 +0.0 + 0 +LINE + 5 +6D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536734.7813943418 + 20 +185840.471282021 + 30 +0.0 + 11 +536743.6426558093 + 21 +185781.0234056772 + 31 +0.0 + 0 +LINE + 5 +6D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536742.2439789774 + 20 +185836.1847694715 + 30 +0.0 + 11 +536671.5773006395 + 21 +185826.4535573242 + 31 +0.0 + 0 +LINE + 5 +6D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536673.5912146595 + 20 +185829.5782152326 + 30 +0.0 + 11 +536680.4697129492 + 21 +185773.8621847206 + 31 +0.0 + 0 +LINE + 5 +6D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536750.2963119973 + 20 +185787.1364003606 + 30 +0.0 + 11 +536673.6440534738 + 21 +185775.711906424 + 31 +0.0 + 0 +LINE + 5 +6D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536553.2222514413 + 20 +186306.6114761733 + 30 +0.0 + 11 +536550.1362215744 + 21 +186193.939177168 + 31 +0.0 + 0 +LINE + 5 +6D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537062.2894537369 + 20 +185952.7290031131 + 30 +0.0 + 11 +537130.6680473274 + 21 +185697.1157841719 + 31 +0.0 + 0 +LINE + 5 +6D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537784.5734153324 + 20 +185861.9936452161 + 30 +0.0 + 11 +535864.4230040797 + 21 +185456.3307235448 + 31 +0.0 + 0 +LINE + 5 +6DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536363.2478164847 + 20 +185785.8285372621 + 30 +0.0 + 11 +536164.8419804048 + 21 +185674.9023051266 + 31 +0.0 + 0 +LINE + 5 +6DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536354.7066451306 + 20 +185972.485684567 + 30 +0.0 + 11 +536185.7730090109 + 21 +185955.3298043531 + 31 +0.0 + 0 +LINE + 5 +6DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536290.2634319545 + 20 +186424.0182927763 + 30 +0.0 + 11 +536361.4672387756 + 21 +185636.0952636998 + 31 +0.0 + 0 +LINE + 5 +6DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536269.7332366472 + 20 +185890.4593593341 + 30 +0.0 + 11 +535793.3462899222 + 21 +185739.96058906 + 31 +0.0 + 0 +LINE + 5 +6DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536280.0904017486 + 20 +185821.7399577195 + 30 +0.0 + 11 +536244.1610790384 + 21 +186012.3143575776 + 31 +0.0 + 0 +LINE + 5 +6DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536208.5412910284 + 20 +185809.3656713885 + 30 +0.0 + 11 +536197.1486584764 + 21 +185872.657484648 + 31 +0.0 + 0 +LINE + 5 +6E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536261.5672213085 + 20 +185797.3026806227 + 30 +0.0 + 11 +536196.4850589806 + 21 +185819.6983871253 + 31 +0.0 + 0 +LINE + 5 +6E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536216.9006975449 + 20 +185820.8233176042 + 30 +0.0 + 11 +535801.6962948423 + 21 +185660.6602255008 + 31 +0.0 + 0 +LINE + 5 +6E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536197.4579107648 + 20 +185611.9391870522 + 30 +0.0 + 11 +536024.7185410833 + 21 +185984.9229118754 + 31 +0.0 + 0 +LINE + 5 +6E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536037.8003302407 + 20 +185987.4056095272 + 30 +0.0 + 11 +535815.3572137982 + 21 +185900.4870750231 + 31 +0.0 + 0 +LINE + 5 +6E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536063.6966472942 + 20 +186176.1784400052 + 30 +0.0 + 11 +536028.0831420887 + 21 +185972.1231530161 + 31 +0.0 + 0 +LINE + 5 +6E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536132.7482219166 + 20 +186122.944386203 + 30 +0.0 + 11 +536047.5604990329 + 21 +186117.0816537993 + 31 +0.0 + 0 +LINE + 5 +6E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536069.9974182161 + 20 +185220.2754154892 + 30 +0.0 + 11 +535816.5024649587 + 21 +185903.3706867481 + 31 +0.0 + 0 +LINE + 5 +6E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536229.6915143036 + 20 +185963.0686055666 + 30 +0.0 + 11 +535827.5358233733 + 21 +185828.5099692703 + 31 +0.0 + 0 +LINE + 5 +6E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535834.0177546548 + 20 +186166.9563758262 + 30 +0.0 + 11 +535831.6474460902 + 21 +185822.8754476268 + 31 +0.0 + 0 +LINE + 5 +6E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535817.4316180108 + 20 +186521.407981259 + 30 +0.0 + 11 +535837.1688361796 + 21 +186020.0815070079 + 31 +0.0 + 0 +LINE + 5 +6EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535936.8362455865 + 20 +186076.2280642266 + 30 +0.0 + 11 +535905.2620010249 + 21 +186275.7532467011 + 31 +0.0 + 0 +LINE + 5 +6ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536125.7083849122 + 20 +186183.0401472969 + 30 +0.0 + 11 +535831.8734352128 + 21 +186118.321074803 + 31 +0.0 + 0 +LINE + 5 +6EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536160.7993853049 + 20 +186267.2245388372 + 30 +0.0 + 11 +536154.3770119736 + 21 +186145.9553397494 + 31 +0.0 + 0 +LINE + 5 +6EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536255.3969228534 + 20 +186160.7532505492 + 30 +0.0 + 11 +536210.2581796578 + 21 +186272.7810365171 + 31 +0.0 + 0 +LINE + 5 +6F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536214.7834336409 + 20 +186267.7913779211 + 30 +0.0 + 11 +536158.9751333219 + 21 +186266.0436625988 + 31 +0.0 + 0 +LINE + 5 +6F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536551.2962527581 + 20 +186235.8444073774 + 30 +0.0 + 11 +536551.2839351317 + 21 +186235.84270068 + 31 +0.0 + 0 +LINE + 5 +6F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536406.3186160096 + 20 +186215.75669558 + 30 +0.0 + 11 +535994.0212001858 + 21 +186158.6298734732 + 31 +0.0 + 0 +LINE + 5 +6F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535985.9011248552 + 20 +186148.3783300915 + 30 +0.0 + 11 +535982.7555381509 + 21 +186172.4586094986 + 31 +0.0 + 0 +LINE + 5 +6F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535871.6244540257 + 20 +185996.4107770663 + 30 +0.0 + 11 +535826.3290506108 + 21 +185994.8411902611 + 31 +0.0 + 0 +LINE + 5 +6F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535884.9478042856 + 20 +185988.4224090485 + 30 +0.0 + 11 +535863.3916885597 + 21 +185999.1219561155 + 31 +0.0 + 0 +LINE + 5 +6F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535898.2305643401 + 20 +185925.7164430408 + 30 +0.0 + 11 +535881.3163777869 + 21 +185995.543176206 + 31 +0.0 + 0 +LINE + 5 +6F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536059.2279425693 + 20 +186125.769405381 + 30 +0.0 + 11 +535994.0245275108 + 21 +186470.9334808305 + 31 +0.0 + 0 +LINE + 5 +6F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536093.2954599856 + 20 +186458.4035292444 + 30 +0.0 + 11 +536073.4867800939 + 21 +186166.4737735018 + 31 +0.0 + 0 +LINE + 5 +6F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536200.7582953935 + 20 +186184.3582513239 + 30 +0.0 + 11 +536195.5741412019 + 21 +186219.5025008576 + 31 +0.0 + 0 +LINE + 5 +6FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535897.5531420586 + 20 +186494.1360598406 + 30 +0.0 + 11 +535909.2141336433 + 21 +186315.9941943792 + 31 +0.0 + 0 +LINE + 5 +6FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536121.1503608934 + 20 +185921.4462868624 + 30 +0.0 + 11 +536100.6405274615 + 21 +185963.7482569175 + 31 +0.0 + 0 +LINE + 5 +6FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536162.2437088341 + 20 +185980.402945287 + 30 +0.0 + 11 +536099.5637782036 + 21 +185962.1814210873 + 31 +0.0 + 0 +LINE + 5 +700 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536197.7248129734 + 20 +185945.8102177876 + 30 +0.0 + 11 +536180.1063811039 + 21 +186048.6330454697 + 31 +0.0 + 0 +LINE + 5 +701 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536331.0425782463 + 20 +186054.2048949611 + 30 +0.0 + 11 +536032.9227071588 + 21 +186037.3741550549 + 31 +0.0 + 0 +LINE + 5 +702 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535973.3674328742 + 20 +185958.8698365539 + 30 +0.0 + 11 +535952.2940349445 + 21 +186024.4097148881 + 31 +0.0 + 0 +LINE + 5 +703 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535982.8930652049 + 20 +186033.2214834902 + 30 +0.0 + 11 +535925.6186659056 + 21 +186014.9947135762 + 31 +0.0 + 0 +LINE + 5 +704 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535979.8512915146 + 20 +186025.1708951824 + 30 +0.0 + 11 +535958.9768792235 + 21 +186093.3818534568 + 31 +0.0 + 0 +LINE + 5 +705 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535962.3826766682 + 20 +186091.8919271197 + 30 +0.0 + 11 +535908.4762301635 + 21 +186076.2175907711 + 31 +0.0 + 0 +LINE + 5 +706 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535932.7143681951 + 20 +186009.4008907609 + 30 +0.0 + 11 +535909.2139455117 + 21 +186083.2508598345 + 31 +0.0 + 0 +LINE + 5 +707 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536145.9352710763 + 20 +185727.8028134352 + 30 +0.0 + 11 +535904.4951732374 + 21 +185619.541883666 + 31 +0.0 + 0 +LINE + 5 +708 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536656.4544441961 + 20 +187136.1251621236 + 30 +0.0 + 11 +537180.346752627 + 21 +187503.3080437654 + 31 +0.0 + 0 +LINE + 5 +709 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536515.4172762577 + 20 +187784.5523831475 + 30 +0.0 + 11 +537317.0023862222 + 21 +185624.0405922396 + 31 +0.0 + 0 +LINE + 5 +70A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536777.6597608433 + 20 +187067.7809166893 + 30 +0.0 + 11 +536906.3904576726 + 21 +187140.4865038101 + 31 +0.0 + 0 +LINE + 5 +70B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536788.6769991006 + 20 +187232.0387480244 + 30 +0.0 + 11 +536958.0668608531 + 21 +186767.5049155334 + 31 +0.0 + 0 +LINE + 5 +70C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536874.5848913998 + 20 +187133.126055273 + 30 +0.0 + 11 +536956.4850630701 + 21 +187129.4572496127 + 31 +0.0 + 0 +LINE + 5 +70D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536885.4891276186 + 20 +187212.0970198499 + 30 +0.0 + 11 +536882.7489547515 + 21 +187124.2908701058 + 31 +0.0 + 0 +LINE + 5 +70E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536876.2998669652 + 20 +187195.4453712998 + 30 +0.0 + 11 +537040.0932225991 + 21 +187308.2548985325 + 31 +0.0 + 0 +LINE + 5 +70F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536827.560160896 + 20 +187307.9410842041 + 30 +0.0 + 11 +537125.289121818 + 21 +186993.5898679707 + 31 +0.0 + 0 +LINE + 5 +710 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537077.3380654208 + 20 +187266.3382699572 + 30 +0.0 + 11 +536952.6615164215 + 21 +187127.4296781066 + 31 +0.0 + 0 +LINE + 5 +711 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537034.7521778992 + 20 +187309.4666366411 + 30 +0.0 + 11 +537077.3283545836 + 21 +187265.49062204 + 31 +0.0 + 0 +LINE + 5 +712 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537271.3286449298 + 20 +187489.6990656824 + 30 +0.0 + 11 +537061.5184214732 + 21 +187279.1625218589 + 31 +0.0 + 0 +LINE + 5 +713 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537220.5059177099 + 20 +187443.88729939 + 30 +0.0 + 11 +537294.9987336095 + 21 +187358.7484616252 + 31 +0.0 + 0 +LINE + 5 +714 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537352.1225316942 + 20 +187416.831822214 + 30 +0.0 + 11 +536770.3320429272 + 21 +186853.4430962436 + 31 +0.0 + 0 +LINE + 5 +715 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537019.3396568531 + 20 +186999.2648424513 + 30 +0.0 + 11 +537251.2580226249 + 21 +186626.306883402 + 31 +0.0 + 0 +LINE + 5 +716 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536966.6307444098 + 20 +186953.9724857423 + 30 +0.0 + 11 +537118.2633265551 + 21 +187074.8735946857 + 31 +0.0 + 0 +LINE + 5 +717 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537012.7496896793 + 20 +186897.8882536064 + 30 +0.0 + 11 +537062.6995511437 + 21 +186938.3932785016 + 31 +0.0 + 0 +LINE + 5 +718 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536964.7079194511 + 20 +186923.3687037914 + 30 +0.0 + 11 +537028.6278447282 + 21 +186897.8442316993 + 31 +0.0 + 0 +LINE + 5 +719 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537013.8976801362 + 20 +186912.0247118622 + 30 +0.0 + 11 +537205.2581714437 + 21 +186557.0905487869 + 31 +0.0 + 0 +LINE + 5 +71A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536896.0044335675 + 20 +186741.8456366742 + 30 +0.0 + 11 +537266.6056255017 + 21 +186910.8617624756 + 31 +0.0 + 0 +LINE + 5 +71B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537258.3171737836 + 20 +186921.2828259197 + 30 +0.0 + 11 +537370.0700804652 + 21 +186710.2210824861 + 31 +0.0 + 0 +LINE + 5 +71C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537361.9414964869 + 20 +187081.1821708461 + 30 +0.0 + 11 +537255.7006555645 + 21 +186903.3626960374 + 31 +0.0 + 0 +LINE + 5 +71D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537274.8819629169 + 20 +187085.9384358377 + 30 +0.0 + 11 +537335.5830477656 + 21 +187025.8826446133 + 31 +0.0 + 0 +LINE + 5 +71E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536958.9961435952 + 20 +186565.5135013908 + 30 +0.0 + 11 +537038.9113655967 + 21 +186607.1746138472 + 31 +0.0 + 0 +LINE + 5 +71F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536957.6237427116 + 20 +186485.1227390502 + 30 +0.0 + 11 +537371.0851352754 + 21 +186713.1530580203 + 31 +0.0 + 0 +LINE + 5 +720 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537097.0737156445 + 20 +187028.1241264085 + 30 +0.0 + 11 +537313.8546541034 + 21 +186663.650188972 + 31 +0.0 + 0 +LINE + 5 +721 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537553.1330599754 + 20 +186913.1132527656 + 30 +0.0 + 11 +537307.0616539335 + 21 +186662.0663884133 + 31 +0.0 + 0 +LINE + 5 +722 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537799.5835817962 + 20 +187209.4810507865 + 30 +0.0 + 11 +537635.4473220064 + 21 +187033.5368753194 + 31 +0.0 + 0 +LINE + 5 +723 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537031.5442058048 + 20 +187444.7080065458 + 30 +0.0 + 11 +537403.263134856 + 21 +187022.4017121923 + 31 +0.0 + 0 +LINE + 5 +724 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537402.7212590529 + 20 +187009.3351083603 + 30 +0.0 + 11 +537420.8248222389 + 21 +187025.5220034305 + 31 +0.0 + 0 +LINE + 5 +725 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537390.0722291867 + 20 +186819.6161142883 + 30 +0.0 + 11 +537434.9476668381 + 21 +186776.2380761014 + 31 +0.0 + 0 +LINE + 5 +726 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537374.7647574835 + 20 +186822.2631873493 + 30 +0.0 + 11 +537398.078434724 + 21 +186816.2950313399 + 31 +0.0 + 0 +LINE + 5 +727 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537323.7656201309 + 20 +186783.4359047135 + 30 +0.0 + 11 +537382.1643115266 + 21 +186825.2862955662 + 31 +0.0 + 0 +LINE + 5 +728 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537502.3608783106 + 20 +187480.7089753924 + 30 +0.0 + 11 +537713.225832049 + 21 +187395.0985889557 + 31 +0.0 + 0 +LINE + 5 +729 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537333.3361530685 + 20 +187410.4756193646 + 30 +0.0 + 11 +537532.0891822454 + 21 +187493.0617158058 + 31 +0.0 + 0 +LINE + 5 +72A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537278.6197715838 + 20 +187627.3482159066 + 30 +0.0 + 11 +537166.0865990719 + 21 +187491.2134684705 + 31 +0.0 + 0 +LINE + 5 +72B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537197.2669548719 + 20 +187546.6372350203 + 30 +0.0 + 11 +537397.2796850536 + 21 +187375.3663122469 + 31 +0.0 + 0 +LINE + 5 +72C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537152.1190506236 + 20 +186925.7346225763 + 30 +0.0 + 11 +537195.271841091 + 21 +186944.3879497008 + 31 +0.0 + 0 +LINE + 5 +72D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537159.4812683694 + 20 +186997.2213246088 + 30 +0.0 + 11 +537195.0645548211 + 21 +186942.4981359836 + 31 +0.0 + 0 +LINE + 5 +72E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537110.0209214624 + 20 +186994.1816485354 + 30 +0.0 + 11 +537190.4945867636 + 21 +187060.5663774045 + 31 +0.0 + 0 +LINE + 5 +72F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537079.7999997003 + 20 +187163.3257541517 + 30 +0.0 + 11 +537294.6338995522 + 21 +186955.9489791322 + 31 +0.0 + 0 +LINE + 5 +730 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537288.4946466848 + 20 +186857.6023051026 + 30 +0.0 + 11 +537347.2452102594 + 21 +186893.4901168504 + 31 +0.0 + 0 +LINE + 5 +731 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537329.8196174723 + 20 +186920.1415077109 + 30 +0.0 + 11 +537361.3048608085 + 21 +186868.9433494563 + 31 +0.0 + 0 +LINE + 5 +732 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537326.8678900417 + 20 +186912.0574700774 + 30 +0.0 + 11 +537387.2115405508 + 21 +186950.0984974087 + 31 +0.0 + 0 +LINE + 5 +733 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537383.6589948769 + 20 +186951.1933745518 + 30 +0.0 + 11 +537414.259416117 + 21 +186904.1274206714 + 31 +0.0 + 0 +LINE + 5 +734 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537352.2780301041 + 20 +186869.3385356161 + 30 +0.0 + 11 +537418.292279855 + 21 +186909.9366467582 + 31 +0.0 + 0 +LINE + 5 +735 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537012.3990757676 + 20 +186374.590466218 + 30 +0.0 + 11 +537201.1498642903 + 21 +186504.5889459221 + 31 +0.0 + 0 +LINE + 5 +736 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537056.5950085385 + 20 +186425.7206142945 + 30 +0.0 + 11 +537284.7500739119 + 21 +186189.0438679987 + 31 +0.0 + 0 +LINE + 5 +737 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537236.7990175147 + 20 +186461.792269985 + 30 +0.0 + 11 +537112.1224685155 + 21 +186322.8836781344 + 31 +0.0 + 0 +LINE + 5 +738 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537194.2131299931 + 20 +186504.9206366692 + 30 +0.0 + 11 +537236.7893066778 + 21 +186460.944622068 + 31 +0.0 + 0 +LINE + 5 +739 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537430.7895970239 + 20 +186685.1530657104 + 30 +0.0 + 11 +537220.9793735673 + 21 +186474.6165218867 + 31 +0.0 + 0 +LINE + 5 +73A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537433.9827303069 + 20 +186541.0103316215 + 30 +0.0 + 11 +536968.8066354515 + 21 +186086.6767533849 + 31 +0.0 + 0 +LINE + 5 +73B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537178.8006089473 + 20 +186194.7188424793 + 30 +0.0 + 11 +537318.9589671305 + 21 +185969.3241220662 + 31 +0.0 + 0 +LINE + 5 +73C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537126.0916965039 + 20 +186149.4264857703 + 30 +0.0 + 11 +537277.724278649 + 21 +186270.3275947137 + 31 +0.0 + 0 +LINE + 5 +73D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537172.2106417733 + 20 +186093.3422536341 + 30 +0.0 + 11 +537222.1605032379 + 21 +186133.8472785297 + 31 +0.0 + 0 +LINE + 5 +73E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537124.1688715451 + 20 +186118.8227038192 + 30 +0.0 + 11 +537188.0887968223 + 21 +186093.2982317269 + 31 +0.0 + 0 +LINE + 5 +73F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537173.3586322302 + 20 +186107.4787118903 + 30 +0.0 + 11 +537364.7191235379 + 21 +185752.5445488149 + 31 +0.0 + 0 +LINE + 5 +740 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537155.5330697457 + 20 +185983.0593038168 + 30 +0.0 + 11 +537426.066577596 + 21 +186106.3157625034 + 31 +0.0 + 0 +LINE + 5 +741 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537417.7781258776 + 20 +186116.7368259474 + 30 +0.0 + 11 +537529.5310325594 + 21 +185905.6750825138 + 31 +0.0 + 0 +LINE + 5 +742 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537503.9215296564 + 20 +186247.3776691965 + 30 +0.0 + 11 +537415.1616076585 + 21 +186098.816696065 + 31 +0.0 + 0 +LINE + 5 +743 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537276.0178131017 + 20 +186420.2443479916 + 30 +0.0 + 11 +537495.0439998595 + 21 +186221.3366446411 + 31 +0.0 + 0 +LINE + 5 +744 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537256.5346677385 + 20 +186223.5781264364 + 30 +0.0 + 11 +537473.3156061973 + 21 +185859.104189 + 31 +0.0 + 0 +LINE + 5 +745 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537826.3898014322 + 20 +186263.1340956899 + 30 +0.0 + 11 +537506.7061623534 + 21 +186088.9441168782 + 31 +0.0 + 0 +LINE + 5 +746 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537726.2167847417 + 20 +186300.4072588124 + 30 +0.0 + 11 +537767.9602569887 + 21 +186190.6483855762 + 31 +0.0 + 0 +LINE + 5 +747 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537685.6628467619 + 20 +186253.3924978269 + 30 +0.0 + 11 +537789.1827203455 + 21 +186216.6605409855 + 31 +0.0 + 0 +LINE + 5 +748 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537191.005157899 + 20 +186640.1620065737 + 30 +0.0 + 11 +537397.7097547258 + 21 +186397.5140548614 + 31 +0.0 + 0 +LINE + 5 +749 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537376.1880186199 + 20 +186413.0837926604 + 30 +0.0 + 11 +537776.5833744317 + 21 +186447.6586735969 + 31 +0.0 + 0 +LINE + 5 +74A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537663.9550437875 + 20 +186459.7391990096 + 30 +0.0 + 11 +537680.1027461536 + 21 +186293.6964840227 + 31 +0.0 + 0 +LINE + 5 +74B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537676.4551569747 + 20 +186317.7023488992 + 30 +0.0 + 11 +537694.4058185397 + 21 +186236.2753509728 + 31 +0.0 + 0 +LINE + 5 +74C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537665.2983288273 + 20 +186310.7888695116 + 30 +0.0 + 11 +537741.541111767 + 21 +186286.0666999599 + 31 +0.0 + 0 +LINE + 5 +74D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537816.0225515165 + 20 +186373.4536291914 + 30 +0.0 + 11 +537729.6996959669 + 21 +186281.6907654688 + 31 +0.0 + 0 +LINE + 5 +74E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537341.3908721648 + 20 +186732.9116298796 + 30 +0.0 + 11 +537460.6349338569 + 21 +186643.1579815403 + 31 +0.0 + 0 +LINE + 5 +74F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537311.5800027175 + 20 +186121.188622604 + 30 +0.0 + 11 +537354.732793185 + 21 +186139.8419497287 + 31 +0.0 + 0 +LINE + 5 +750 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537318.9422204634 + 20 +186192.6753246367 + 30 +0.0 + 11 +537354.5255069153 + 21 +186137.9521360115 + 31 +0.0 + 0 +LINE + 5 +751 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537269.4818735563 + 20 +186189.6356485634 + 30 +0.0 + 11 +537349.9555388575 + 21 +186256.0203774324 + 31 +0.0 + 0 +LINE + 5 +752 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537239.2609517944 + 20 +186358.7797541795 + 30 +0.0 + 11 +537454.0948516461 + 21 +186151.40297916 + 31 +0.0 + 0 +LINE + 5 +753 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537447.955598779 + 20 +186053.0563051304 + 30 +0.0 + 11 +537506.7061623534 + 21 +186088.9441168782 + 31 +0.0 + 0 +LINE + 5 +754 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537486.2387035479 + 20 +186250.673700184 + 30 +0.0 + 11 +537520.7658129026 + 21 +186064.3973494842 + 31 +0.0 + 0 +LINE + 5 +755 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537328.1695798477 + 20 +186589.1920152922 + 30 +0.0 + 11 +537403.0583651141 + 21 +186504.9528297262 + 31 +0.0 + 0 +LINE + 5 +756 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537781.9530081804 + 20 +186249.6157882923 + 30 +0.0 + 11 +538347.5629563361 + 21 +186352.7088830488 + 31 +0.0 + 0 +LINE + 5 +757 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537808.7806551505 + 20 +186312.9346177544 + 30 +0.0 + 11 +538032.0195007378 + 21 +186355.7589401335 + 31 +0.0 + 0 +LINE + 5 +758 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537695.1658971131 + 20 +186461.2772245947 + 30 +0.0 + 11 +537835.4903706611 + 21 +186556.8907161218 + 31 +0.0 + 0 +LINE + 5 +759 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537634.8336085112 + 20 +186588.0147797442 + 30 +0.0 + 11 +538187.0293206833 + 21 +185797.4692952484 + 31 +0.0 + 0 +LINE + 5 +75A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537812.9945125742 + 20 +186453.201609507 + 30 +0.0 + 11 +538218.1599829396 + 21 +186622.6852642468 + 31 +0.0 + 0 +LINE + 5 +75B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537849.3030504672 + 20 +186393.945241889 + 30 +0.0 + 11 +537754.1263155464 + 21 +186562.9153790184 + 31 +0.0 + 0 +LINE + 5 +75C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537912.0233530926 + 20 +186430.531603359 + 30 +0.0 + 11 +537880.0009723833 + 21 +186486.3008855473 + 31 +0.0 + 0 +LINE + 5 +75D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537879.2087033646 + 20 +186387.1672886349 + 30 +0.0 + 11 +537914.5985604886 + 21 +186446.1995978881 + 31 +0.0 + 0 +LINE + 5 +75E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537898.2507986851 + 20 +186433.9189443802 + 30 +0.0 + 11 +538279.1561711739 + 21 +186566.2374803479 + 31 +0.0 + 0 +LINE + 5 +75F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538047.4547373327 + 20 +186290.3991899553 + 30 +0.0 + 11 +537939.6927833727 + 21 +186683.2083745763 + 31 +0.0 + 0 +LINE + 5 +760 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537928.0834629505 + 20 +186676.6875866997 + 30 +0.0 + 11 +538154.263771468 + 21 +186753.3572660519 + 31 +0.0 + 0 +LINE + 5 +761 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537786.7525790449 + 20 +186804.481882418 + 30 +0.0 + 11 +537945.3571269888 + 21 +186671.247204977 + 31 +0.0 + 0 +LINE + 5 +762 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537768.1756487449 + 20 +186719.2945470756 + 30 +0.0 + 11 +537837.1418002041 + 21 +186769.6432284317 + 31 +0.0 + 0 +LINE + 5 +763 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538310.7182931293 + 20 +186310.2960644154 + 30 +0.0 + 11 +538151.5311559336 + 21 +186754.8268337236 + 31 +0.0 + 0 +LINE + 5 +764 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537796.8990297919 + 20 +186534.5427282644 + 30 +0.0 + 11 +538191.2753803375 + 21 +186690.4353851786 + 31 +0.0 + 0 +LINE + 5 +765 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537878.7102166998 + 20 +187051.9664409037 + 30 +0.0 + 11 +538191.7557841509 + 21 +186683.4767583245 + 31 +0.0 + 0 +LINE + 5 +766 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537774.1933872137 + 20 +187223.955343289 + 30 +0.0 + 11 +538060.5889229859 + 21 +186830.8401531596 + 31 +0.0 + 0 +LINE + 5 +767 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537795.9429602493 + 20 +187010.4661386416 + 30 +0.0 + 11 +537910.9535407448 + 21 +187034.1746624962 + 31 +0.0 + 0 +LINE + 5 +768 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537835.8899593667 + 20 +186962.9346028185 + 30 +0.0 + 11 +537888.6580694558 + 21 +187059.2732110594 + 31 +0.0 + 0 +LINE + 5 +769 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537948.1741042493 + 20 +186809.6520217234 + 30 +0.0 + 11 +537843.9029074889 + 21 +186982.6686362065 + 31 +0.0 + 0 +LINE + 5 +76A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537734.8794656979 + 20 +186769.8160672527 + 30 +0.0 + 11 +538001.4046078766 + 21 +186909.4294068588 + 31 +0.0 + 0 +LINE + 5 +76B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537676.3851448579 + 20 +186854.8587612249 + 30 +0.0 + 11 +537393.6749490265 + 21 +186911.1355924097 + 31 +0.0 + 0 +LINE + 5 +76C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537375.1962385819 + 20 +186536.2752800831 + 30 +0.0 + 11 +537375.2067635943 + 21 +186536.2819028361 + 31 +0.0 + 0 +LINE + 5 +76D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537627.9359291571 + 20 +186708.8472713734 + 30 +0.0 + 11 +537851.369689718 + 21 +186835.902403186 + 31 +0.0 + 0 +LINE + 5 +76E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537864.1827212604 + 20 +186833.2840090631 + 30 +0.0 + 11 +537851.0895042071 + 21 +186853.7369364632 + 31 +0.0 + 0 +LINE + 5 +76F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538049.4576268318 + 20 +186790.5463905774 + 30 +0.0 + 11 +538085.1315570698 + 21 +186818.5018529167 + 31 +0.0 + 0 +LINE + 5 +770 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538044.4036657193 + 20 +186775.8568309237 + 30 +0.0 + 11 +538054.0127984559 + 21 +186797.9206248104 + 31 +0.0 + 0 +LINE + 5 +771 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538074.6024632878 + 20 +186719.3192105897 + 30 +0.0 + 11 +538042.5990825349 + 21 +186783.6437470564 + 31 +0.0 + 0 +LINE + 5 +772 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537822.6206570225 + 20 +186768.7814471842 + 30 +0.0 + 11 +537650.3374365978 + 21 +187074.8994248929 + 31 +0.0 + 0 +LINE + 5 +773 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537647.1135840797 + 20 +186930.989357222 + 30 +0.0 + 11 +537785.5072931152 + 21 +186790.7532074953 + 31 +0.0 + 0 +LINE + 5 +774 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537668.1921883292 + 20 +186397.4483159966 + 30 +0.0 + 11 +537658.8538896595 + 21 +187097.8055382497 + 31 +0.0 + 0 +LINE + 5 +775 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537726.6033647893 + 20 +186925.8085438502 + 30 +0.0 + 11 +537801.3756717691 + 21 +186981.6739384116 + 31 +0.0 + 0 +LINE + 5 +776 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537770.9347203141 + 20 +186964.0988260768 + 30 +0.0 + 11 +537854.1821676819 + 21 +186968.8364149881 + 31 +0.0 + 0 +LINE + 5 +777 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537775.9808103146 + 20 +186951.9823914832 + 30 +0.0 + 11 +537812.5434910686 + 21 +187023.3078286975 + 31 +0.0 + 0 +LINE + 5 +778 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537709.2294004969 + 20 +187154.7544464749 + 30 +0.0 + 11 +537814.9753444068 + 21 +187010.9201727383 + 31 +0.0 + 0 +LINE + 5 +779 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537906.755485458 + 20 +186572.5579692403 + 30 +0.0 + 11 +537895.2214540916 + 21 +186618.1329191403 + 31 +0.0 + 0 +LINE + 5 +77A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537837.3572619683 + 20 +186591.2244470575 + 30 +0.0 + 11 +537897.0540384935 + 21 +186617.6269567964 + 31 +0.0 + 0 +LINE + 5 +77B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537660.6728702619 + 20 +186539.0477106908 + 30 +0.0 + 11 +537899.6514691774 + 21 +186718.0671526615 + 31 +0.0 + 0 +LINE + 5 +77C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537995.7610246206 + 20 +186696.325209994 + 30 +0.0 + 11 +537929.2028703271 + 21 +186849.182053773 + 31 +0.0 + 0 +LINE + 5 +77D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538012.4363585128 + 20 +186408.4127906819 + 30 +0.0 + 11 +538266.8927353087 + 21 +186480.9779480708 + 31 +0.0 + 0 +LINE + 5 +77E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537245.604479096 + 20 +187219.2811807284 + 30 +0.0 + 11 +537128.0087242979 + 21 +187101.6271531425 + 31 +0.0 + 0 +LINE + 5 +77F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537295.2785441242 + 20 +187305.4625369827 + 30 +0.0 + 11 +537127.6708426229 + 21 +187382.6557244311 + 31 +0.0 + 0 +LINE + 5 +780 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537853.8333755165 + 20 +186584.479558069 + 30 +0.0 + 11 +537801.7029996276 + 21 +186689.4205773728 + 31 +0.0 + 0 +LINE + 5 +781 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536899.7243153653 + 20 +186743.5421234196 + 30 +0.0 + 11 +536800.9662122712 + 21 +186571.7543786009 + 31 +0.0 + 0 +LINE + 5 +783 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535586.4734308382 + 20 +184394.1960974984 + 30 +0.0 + 11 +535561.5356189229 + 21 +184248.4710130359 + 31 +0.0 + 0 +LINE + 5 +784 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535435.5965996541 + 20 +184328.331110552 + 30 +0.0 + 11 +535930.0442095312 + 21 +184325.8475888641 + 31 +0.0 + 0 +LINE + 5 +785 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535557.7175357064 + 20 +184280.8931118137 + 30 +0.0 + 11 +535588.8411184842 + 21 +184205.0483964429 + 31 +0.0 + 0 +LINE + 5 +786 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535487.0743208422 + 20 +184243.9492109997 + 30 +0.0 + 11 +535568.7914733332 + 21 +184276.1941403529 + 31 +0.0 + 0 +LINE + 5 +787 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535499.6421604393 + 20 +184258.2239901103 + 30 +0.0 + 11 +535448.8047659976 + 21 +184065.9486351876 + 31 +0.0 + 0 +LINE + 5 +788 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535377.2944345197 + 20 +184266.0902682582 + 30 +0.0 + 11 +535773.7507343056 + 21 +184092.074109011 + 31 +0.0 + 0 +LINE + 5 +789 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535500.8400115718 + 20 +184045.0556869529 + 30 +0.0 + 11 +535589.4576535479 + 21 +184209.3321377636 + 31 +0.0 + 0 +LINE + 5 +78A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535445.8597739096 + 20 +184070.5662199818 + 30 +0.0 + 11 +535501.6345348921 + 21 +184045.3512101935 + 31 +0.0 + 0 +LINE + 5 +78B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535356.1543586029 + 20 +183787.0083040362 + 30 +0.0 + 11 +535483.4250856285 + 21 +184055.6123401087 + 31 +0.0 + 0 +LINE + 5 +78C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535382.1014906933 + 20 +183850.3203397732 + 30 +0.0 + 11 +535487.4018487683 + 21 +183808.9725961122 + 31 +0.0 + 0 +LINE + 5 +78D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535452.0335797415 + 20 +183735.5839687168 + 30 +0.0 + 11 +535786.827845811 + 21 +184479.9884451362 + 31 +0.0 + 0 +LINE + 5 +78E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535732.6137383202 + 20 +184189.8761643216 + 30 +0.0 + 11 +536161.9960217083 + 21 +184097.6014531979 + 31 +0.0 + 0 +LINE + 5 +78F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535757.4347432706 + 20 +184254.7879871313 + 30 +0.0 + 11 +535694.8729741883 + 21 +184071.2245290002 + 31 +0.0 + 0 +LINE + 5 +790 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535825.8026772756 + 20 +184230.3293729652 + 30 +0.0 + 11 +535804.5553340466 + 21 +184169.6317938717 + 31 +0.0 + 0 +LINE + 5 +791 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535785.5893105132 + 20 +184266.9374343987 + 30 +0.0 + 11 +535831.2086497067 + 21 +184215.3997645391 + 31 +0.0 + 0 +LINE + 5 +792 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535812.8853327367 + 20 +184224.4727916954 + 30 +0.0 + 11 +536211.6009178603 + 21 +184164.2815968987 + 31 +0.0 + 0 +LINE + 5 +793 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535933.2264621044 + 20 +184392.9297529669 + 30 +0.0 + 11 +535899.3589393718 + 21 +183987.0175886406 + 31 +0.0 + 0 +LINE + 5 +794 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535886.7503514801 + 20 +183991.2978347278 + 30 +0.0 + 11 +536123.1576136287 + 21 +183957.4248647315 + 31 +0.0 + 0 +LINE + 5 +795 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535771.2636298454 + 20 +183839.7438249173 + 30 +0.0 + 11 +535902.732726932 + 21 +183999.8149291566 + 31 +0.0 + 0 +LINE + 5 +796 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535737.3734085965 + 20 +183920.0771140679 + 30 +0.0 + 11 +535814.406036274 + 21 +183883.2356424019 + 31 +0.0 + 0 +LINE + 5 +797 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536201.106608945 + 20 +184618.9043009928 + 30 +0.0 + 11 +536031.6290369863 + 21 +184315.407156295 + 31 +0.0 + 0 +LINE + 5 +798 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536195.6719275892 + 20 +184421.6693262116 + 30 +0.0 + 11 +536120.7409882194 + 21 +183955.4789103561 + 31 +0.0 + 0 +LINE + 5 +799 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535731.7144123902 + 20 +184106.9627553966 + 30 +0.0 + 11 +536147.9972755684 + 21 +184026.0689721152 + 31 +0.0 + 0 +LINE + 5 +79A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535907.0643571541 + 20 +183613.3305384817 + 30 +0.0 + 11 +536147.1928850759 + 21 +184032.9976250471 + 31 +0.0 + 0 +LINE + 5 +79B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535798.3692882026 + 20 +183384.4895215734 + 30 +0.0 + 11 +536045.2878480483 + 21 +183864.0713718078 + 31 +0.0 + 0 +LINE + 5 +79C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535818.0882093698 + 20 +183638.9418436739 + 30 +0.0 + 11 +535935.4963047334 + 21 +183636.7357447668 + 31 +0.0 + 0 +LINE + 5 +79D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535848.6369751698 + 20 +183692.9953592331 + 30 +0.0 + 11 +535918.1838751691 + 21 +183607.9728352728 + 31 +0.0 + 0 +LINE + 5 +79E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535930.8938513525 + 20 +183864.276079631 + 30 +0.0 + 11 +535860.13435468 + 21 +183675.0663415311 + 31 +0.0 + 0 +LINE + 5 +79F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535681.4081269931 + 20 +183875.025451509 + 30 +0.0 + 11 +536001.5261799184 + 21 +183775.9579769436 + 31 +0.0 + 0 +LINE + 5 +7A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535704.284593427 + 20 +183965.7628269584 + 30 +0.0 + 11 +535681.7619388092 + 21 +183846.4305364603 + 31 +0.0 + 0 +LINE + 5 +7A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535587.1340509217 + 20 +183884.7654212547 + 30 +0.0 + 11 +535657.5548369951 + 21 +183982.8910746541 + 31 +0.0 + 0 +LINE + 5 +7A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535651.975287795 + 20 +183979.1170519671 + 30 +0.0 + 11 +535705.7767228348 + 21 +183964.1829808213 + 31 +0.0 + 0 +LINE + 5 +7A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535317.4870858738 + 20 +184027.8933693026 + 30 +0.0 + 11 +535840.5484441047 + 21 +183820.7113623827 + 31 +0.0 + 0 +LINE + 5 +7A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535852.6636240436 + 20 +183825.6360126378 + 30 +0.0 + 11 +535843.5449650507 + 21 +183803.1281333459 + 31 +0.0 + 0 +LINE + 5 +7A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536026.9531291101 + 20 +183901.6390592341 + 30 +0.0 + 11 +536067.1503137992 + 21 +183880.7028820203 + 31 +0.0 + 0 +LINE + 5 +7A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536019.289980287 + 20 +183915.1520839083 + 30 +0.0 + 11 +536032.7838736293 + 21 +183895.2256874684 + 31 +0.0 + 0 +LINE + 5 +7A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536038.6037317582 + 20 +183976.2704026984 + 30 +0.0 + 11 +536018.9446260733 + 21 +183907.1662643642 + 31 +0.0 + 0 +LINE + 5 +7A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535799.9732583504 + 20 +183881.4187253341 + 30 +0.0 + 11 +535665.7081056945 + 21 +183468.3446960213 + 31 +0.0 + 0 +LINE + 5 +7A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535655.1711830809 + 20 +183498.3053767629 + 30 +0.0 + 11 +535854.5755331281 + 21 +183470.8787938838 + 31 +0.0 + 0 +LINE + 5 +7AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535451.6689210649 + 20 +183755.4131482404 + 30 +0.0 + 11 +535684.6932673409 + 21 +183477.412754533 + 31 +0.0 + 0 +LINE + 5 +7AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535551.9427449507 + 20 +183521.0592219379 + 30 +0.0 + 11 +535767.5207965271 + 21 +183853.0110194557 + 31 +0.0 + 0 +LINE + 5 +7AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535647.9399360763 + 20 +183900.109968144 + 30 +0.0 + 11 +535635.1479909715 + 21 +183866.968455348 + 31 +0.0 + 0 +LINE + 5 +7AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535734.3941103009 + 20 +183709.4413871868 + 30 +0.0 + 11 +535818.1464496484 + 21 +183668.2420442983 + 31 +0.0 + 0 +LINE + 5 +7AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535784.997818753 + 20 +183679.9341086515 + 30 +0.0 + 11 +535867.701463327 + 21 +183690.5496357759 + 31 +0.0 + 0 +LINE + 5 +7AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535787.7353612302 + 20 +183692.7706530751 + 30 +0.0 + 11 +535836.7629337048 + 21 +183629.3636758962 + 31 +0.0 + 0 +LINE + 5 +7B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535759.317802778 + 20 +183481.1939545241 + 30 +0.0 + 11 +535836.8808525597 + 21 +183641.9872263462 + 31 +0.0 + 0 +LINE + 5 +7B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535229.0626630619 + 20 +183733.640242334 + 30 +0.0 + 11 +535319.1722889316 + 21 +183885.5502146886 + 31 +0.0 + 0 +LINE + 5 +7B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535277.5420608356 + 20 +183837.4780543974 + 30 +0.0 + 11 +535506.3174597182 + 21 +183707.0915593584 + 31 +0.0 + 0 +LINE + 5 +7B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535846.6805967275 + 20 +184089.7471852094 + 30 +0.0 + 11 +535843.7035839816 + 21 +184042.8297328804 + 31 +0.0 + 0 +LINE + 5 +7B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535781.8848576137 + 20 +184058.6656310285 + 30 +0.0 + 11 +535845.4122390982 + 21 +184043.6633162154 + 31 +0.0 + 0 +LINE + 5 +7B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535768.0352899427 + 20 +184106.2445656752 + 30 +0.0 + 11 +535732.7426991815 + 21 +184008.0744272857 + 31 +0.0 + 0 +LINE + 5 +7B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535598.6269255083 + 20 +184077.5419763038 + 30 +0.0 + 11 +535866.3924957366 + 21 +183945.4044315131 + 31 +0.0 + 0 +LINE + 5 +7B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535956.8819629148 + 20 +183984.4097522817 + 30 +0.0 + 11 +535942.9537047379 + 21 +183916.9889292629 + 31 +0.0 + 0 +LINE + 5 +7B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535911.9821283329 + 20 +183924.3855077801 + 30 +0.0 + 11 +535970.8072088518 + 21 +183912.0493066405 + 31 +0.0 + 0 +LINE + 5 +7B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535918.5935446724 + 20 +183929.8949118557 + 30 +0.0 + 11 +535903.1769200424 + 21 +183860.2472011814 + 31 +0.0 + 0 +LINE + 5 +7BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535900.9461733749 + 20 +183863.2209372202 + 30 +0.0 + 11 +535955.5830900649 + 21 +183850.3214360929 + 31 +0.0 + 0 +LINE + 5 +7BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535967.3854864592 + 20 +183920.4118218448 + 30 +0.0 + 11 +535951.4779899194 + 21 +183844.563029156 + 31 +0.0 + 0 +LINE + 5 +7BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535411.801821753 + 20 +183916.0150905535 + 30 +0.0 + 11 +535516.3892101873 + 21 +183873.9907080598 + 31 +0.0 + 0 +LINE + 5 +7BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535920.4534103485 + 20 +184270.4946846228 + 30 +0.0 + 11 +536183.9037860471 + 21 +184245.8441409534 + 31 +0.0 + 0 +LINE + 5 +7BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536459.1144204453 + 20 +184515.8449592403 + 30 +0.0 + 11 +537050.7840434664 + 21 +184508.4728549048 + 31 +0.0 + 0 +LINE + 5 +7BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536372.3224962037 + 20 +184615.45444566 + 30 +0.0 + 11 +536372.6473193558 + 21 +184370.2079044642 + 31 +0.0 + 0 +LINE + 5 +7C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535421.6860749543 + 20 +184433.5942901648 + 30 +0.0 + 11 +536741.1559099641 + 21 +184447.5844802925 + 31 +0.0 + 0 +LINE + 5 +7C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536368.8292361395 + 20 +184402.6300032422 + 30 +0.0 + 11 +536399.9528189172 + 21 +184326.7852878713 + 31 +0.0 + 0 +LINE + 5 +7C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536298.1860212753 + 20 +184365.686102428 + 30 +0.0 + 11 +536379.9031737661 + 21 +184397.9310317812 + 31 +0.0 + 0 +LINE + 5 +7C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536310.4646766277 + 20 +184378.1616925207 + 30 +0.0 + 11 +536259.6272821861 + 21 +184185.886337598 + 31 +0.0 + 0 +LINE + 5 +7C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536110.4724337224 + 20 +184422.0345196693 + 30 +0.0 + 11 +536584.8624347385 + 21 +184213.8110004394 + 31 +0.0 + 0 +LINE + 5 +7C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536311.9517120049 + 20 +184166.7925783813 + 30 +0.0 + 11 +536400.5693539809 + 21 +184331.069029192 + 31 +0.0 + 0 +LINE + 5 +7C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536256.9714743426 + 20 +184192.3031114103 + 30 +0.0 + 11 +536312.7462353251 + 21 +184167.0881016221 + 31 +0.0 + 0 +LINE + 5 +7C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536167.266059036 + 20 +183908.7451954644 + 30 +0.0 + 11 +536294.5367860616 + 21 +184177.349231537 + 31 +0.0 + 0 +LINE + 5 +7C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536193.2131911263 + 20 +183972.0572312018 + 30 +0.0 + 11 +536298.5135492011 + 21 +183930.7094875404 + 31 +0.0 + 0 +LINE + 5 +7C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536263.1452801746 + 20 +183857.3208601452 + 30 +0.0 + 11 +536574.4665492171 + 21 +184545.7616112611 + 31 +0.0 + 0 +LINE + 5 +7CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536543.7254387533 + 20 +184311.6130557499 + 30 +0.0 + 11 +536973.1077221413 + 21 +184219.3383446261 + 31 +0.0 + 0 +LINE + 5 +7CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536568.5464437036 + 20 +184376.5248785597 + 30 +0.0 + 11 +536505.9846746213 + 21 +184192.9614204287 + 31 +0.0 + 0 +LINE + 5 +7CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536636.9143777085 + 20 +184352.0662643937 + 30 +0.0 + 11 +536615.6670344794 + 21 +184291.3686853001 + 31 +0.0 + 0 +LINE + 5 +7CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536596.7010109462 + 20 +184388.6743258272 + 30 +0.0 + 11 +536642.3203501395 + 21 +184337.1366559674 + 31 +0.0 + 0 +LINE + 5 +7CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536623.9970331696 + 20 +184346.2096831239 + 30 +0.0 + 11 +537022.7126182932 + 21 +184286.0184883272 + 31 +0.0 + 0 +LINE + 5 +7CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536744.3381625373 + 20 +184514.6666443953 + 30 +0.0 + 11 +536710.4706398047 + 21 +184108.7544800689 + 31 +0.0 + 0 +LINE + 5 +7D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536697.8620519129 + 20 +184113.0347261562 + 30 +0.0 + 11 +536934.2693140616 + 21 +184079.16175616 + 31 +0.0 + 0 +LINE + 5 +7D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536582.3753302783 + 20 +183961.4807163454 + 30 +0.0 + 11 +536713.8444273649 + 21 +184121.5518205851 + 31 +0.0 + 0 +LINE + 5 +7D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536548.4851090295 + 20 +184041.8140054961 + 30 +0.0 + 11 +536625.517736707 + 21 +184004.9725338305 + 31 +0.0 + 0 +LINE + 5 +7D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536875.2099065892 + 20 +184517.34910723 + 30 +0.0 + 11 +536862.9984506618 + 21 +184428.0576107547 + 31 +0.0 + 0 +LINE + 5 +7D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537006.7836280222 + 20 +184543.4062176398 + 30 +0.0 + 11 +536931.8526886525 + 21 +184077.2158017846 + 31 +0.0 + 0 +LINE + 5 +7D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536542.8261128231 + 20 +184228.6996468251 + 30 +0.0 + 11 +536959.1089760015 + 21 +184147.8058635433 + 31 +0.0 + 0 +LINE + 5 +7D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536686.7698355978 + 20 +183683.7674240936 + 30 +0.0 + 11 +536958.3045855089 + 21 +184154.7345164754 + 31 +0.0 + 0 +LINE + 5 +7D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536629.1999098027 + 20 +183760.6787351024 + 30 +0.0 + 11 +536746.6080051664 + 21 +183758.472636195 + 31 +0.0 + 0 +LINE + 5 +7D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536659.7486756028 + 20 +183814.7322506615 + 30 +0.0 + 11 +536729.295575602 + 21 +183729.7097267011 + 31 +0.0 + 0 +LINE + 5 +7D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536742.0055517852 + 20 +183986.0129710593 + 30 +0.0 + 11 +536671.246055113 + 21 +183796.8032329595 + 31 +0.0 + 0 +LINE + 5 +7DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536492.5198274261 + 20 +183996.7623429372 + 30 +0.0 + 11 +536812.6378803514 + 21 +183897.694868372 + 31 +0.0 + 0 +LINE + 5 +7DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536515.3962938599 + 20 +184087.4997183867 + 30 +0.0 + 11 +536492.8736392421 + 21 +183968.1674278886 + 31 +0.0 + 0 +LINE + 5 +7DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536398.2457513548 + 20 +184006.5023126832 + 30 +0.0 + 11 +536468.666537428 + 21 +184104.6279660823 + 31 +0.0 + 0 +LINE + 5 +7DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536463.0869882278 + 20 +184100.8539433953 + 30 +0.0 + 11 +536516.8884232679 + 21 +184085.9198722496 + 31 +0.0 + 0 +LINE + 5 +7DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536128.598786307 + 20 +184149.630260731 + 30 +0.0 + 11 +536651.6601445378 + 21 +183942.4482538111 + 31 +0.0 + 0 +LINE + 5 +7DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536663.7753244765 + 20 +183947.3729040663 + 30 +0.0 + 11 +536654.6566654839 + 21 +183924.8650247745 + 31 +0.0 + 0 +LINE + 5 +7E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536838.0648295431 + 20 +184023.3759506626 + 30 +0.0 + 11 +536878.262014232 + 21 +184002.4397734485 + 31 +0.0 + 0 +LINE + 5 +7E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536830.40168072 + 20 +184036.8889753371 + 30 +0.0 + 11 +536843.8955740622 + 21 +184016.9625788967 + 31 +0.0 + 0 +LINE + 5 +7E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536849.7154321912 + 20 +184098.007294127 + 30 +0.0 + 11 +536830.0563265061 + 21 +184028.9031557928 + 31 +0.0 + 0 +LINE + 5 +7E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536611.0849587833 + 20 +184003.1556167623 + 30 +0.0 + 11 +536507.6239143502 + 21 +183663.5239624828 + 31 +0.0 + 0 +LINE + 5 +7E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536262.780621498 + 20 +183877.1500396689 + 30 +0.0 + 11 +536390.3878227272 + 21 +183717.9550317594 + 31 +0.0 + 0 +LINE + 5 +7E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536361.3818492996 + 20 +183706.7303072926 + 30 +0.0 + 11 +536578.6324969599 + 21 +183974.7479108842 + 31 +0.0 + 0 +LINE + 5 +7E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536459.0516365094 + 20 +184021.8468595721 + 30 +0.0 + 11 +536446.2596914044 + 21 +183988.7053467764 + 31 +0.0 + 0 +LINE + 5 +7E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536545.505810734 + 20 +183831.1782786151 + 30 +0.0 + 11 +536629.2581500811 + 21 +183789.9789357268 + 31 +0.0 + 0 +LINE + 5 +7E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536596.1095191861 + 20 +183801.67100008 + 30 +0.0 + 11 +536678.81316376 + 21 +183812.2865272042 + 31 +0.0 + 0 +LINE + 5 +7E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536598.8470616633 + 20 +183814.5075445035 + 30 +0.0 + 11 +536647.8746341377 + 21 +183751.1005673246 + 31 +0.0 + 0 +LINE + 5 +7EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536590.7903098636 + 20 +183651.4745657494 + 30 +0.0 + 11 +536647.9925529926 + 21 +183763.7241177747 + 31 +0.0 + 0 +LINE + 5 +7EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536092.1118655931 + 20 +183976.7515162437 + 30 +0.0 + 11 +536317.4291601512 + 21 +183828.8284507869 + 31 +0.0 + 0 +LINE + 5 +7EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536657.7922971604 + 20 +184211.4840766378 + 30 +0.0 + 11 +536654.8152844146 + 21 +184164.5666243088 + 31 +0.0 + 0 +LINE + 5 +7ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536592.9965580466 + 20 +184180.4025224566 + 30 +0.0 + 11 +536656.5239395312 + 21 +184165.4002076438 + 31 +0.0 + 0 +LINE + 5 +7EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536579.1469903754 + 20 +184227.9814571035 + 30 +0.0 + 11 +536543.8543996145 + 21 +184129.8113187139 + 31 +0.0 + 0 +LINE + 5 +7EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536409.7386259413 + 20 +184199.2788677323 + 30 +0.0 + 11 +536677.5041961697 + 21 +184067.1413229414 + 31 +0.0 + 0 +LINE + 5 +7F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536767.9936633479 + 20 +184106.1466437101 + 30 +0.0 + 11 +536754.0654051708 + 21 +184038.7258206911 + 31 +0.0 + 0 +LINE + 5 +7F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536723.0938287659 + 20 +184046.1223992084 + 30 +0.0 + 11 +536781.9189092848 + 21 +184033.786198069 + 31 +0.0 + 0 +LINE + 5 +7F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536729.7052451053 + 20 +184051.6318032842 + 30 +0.0 + 11 +536714.2886204753 + 21 +183981.9840926098 + 31 +0.0 + 0 +LINE + 5 +7F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536712.0578738078 + 20 +183984.9578286487 + 30 +0.0 + 11 +536766.6947904981 + 21 +183972.0583275212 + 31 +0.0 + 0 +LINE + 5 +7F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536778.4971868923 + 20 +184042.148713273 + 30 +0.0 + 11 +536762.5896903524 + 21 +183966.2999205845 + 31 +0.0 + 0 +LINE + 5 +7F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536222.9135221859 + 20 +184037.7519819821 + 30 +0.0 + 11 +536327.5009106202 + 21 +183995.7275994882 + 31 +0.0 + 0 +LINE + 5 +7F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536731.5651107815 + 20 +184392.2315760508 + 30 +0.0 + 11 +536995.0154864801 + 21 +184367.5810323819 + 31 +0.0 + 0 +LINE + 5 +7F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536695.8355699313 + 20 +183725.3801674254 + 30 +0.0 + 11 +536789.8996370914 + 21 +183158.1987582552 + 31 +0.0 + 0 +LINE + 5 +7F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536467.2987365435 + 20 +183735.5527801813 + 30 +0.0 + 11 +536424.7170935654 + 21 +183571.1760746548 + 31 +0.0 + 0 +LINE + 5 +7F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536021.4904705762 + 20 +183831.9354238264 + 30 +0.0 + 11 +536750.7631994243 + 21 +183634.3679990988 + 31 +0.0 + 0 +LINE + 5 +7FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536514.7086588478 + 20 +183627.3811690832 + 30 +0.0 + 11 +536502.1850618724 + 21 +183188.349851915 + 31 +0.0 + 0 +LINE + 5 +7FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536582.7476885168 + 20 +183613.2278136884 + 30 +0.0 + 11 +536391.5573141017 + 21 +183645.7202565448 + 31 +0.0 + 0 +LINE + 5 +7FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536569.5031594619 + 20 +183541.8346721609 + 30 +0.0 + 11 +536506.194272646 + 21 +183553.1320414237 + 31 +0.0 + 0 +LINE + 5 +7FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536599.2309034192 + 20 +183587.3706608673 + 30 +0.0 + 11 +536555.6265312794 + 21 +183534.1173581218 + 31 +0.0 + 0 +LINE + 5 +7FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536561.6618541108 + 20 +183553.6529319524 + 30 +0.0 + 11 +536565.8153502428 + 21 +183150.4410196515 + 31 +0.0 + 0 +LINE + 5 +7FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536747.1518353845 + 20 +183461.7116351087 + 30 +0.0 + 11 +536341.0326863496 + 21 +183430.4237615611 + 31 +0.0 + 0 +LINE + 5 +800 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536343.2477510256 + 20 +183443.5535172205 + 30 +0.0 + 11 +536347.5029372484 + 21 +183204.7697969143 + 31 +0.0 + 0 +LINE + 5 +801 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536175.2184971649 + 20 +183533.3976634438 + 30 +0.0 + 11 +536354.2042462857 + 21 +183429.1336547311 + 31 +0.0 + 0 +LINE + 5 +802 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536249.1202751502 + 20 +183579.663327307 + 30 +0.0 + 11 +536225.0328846765 + 21 +183497.7419175195 + 31 +0.0 + 0 +LINE + 5 +803 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536777.2915141768 + 20 +183276.9074759882 + 30 +0.0 + 11 +536687.1952927396 + 21 +183274.7253024385 + 31 +0.0 + 0 +LINE + 5 +804 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536432.7126278959 + 20 +183615.0485669723 + 30 +0.0 + 11 +536419.2294763712 + 21 +183191.193130562 + 31 +0.0 + 0 +LINE + 5 +805 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535973.3551159433 + 20 +183363.2330692008 + 30 +0.0 + 11 +536390.3861526087 + 21 +183209.9348118807 + 31 +0.0 + 0 +LINE + 5 +806 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535765.9509262584 + 20 +183422.3573275007 + 30 +0.0 + 11 +536242.9275657301 + 21 +183266.7582370015 + 31 +0.0 + 0 +LINE + 5 +807 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535984.4516391039 + 20 +183455.1545628895 + 30 +0.0 + 11 +536000.9943142841 + 21 +183338.8967991611 + 31 +0.0 + 0 +LINE + 5 +808 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536042.6845632144 + 20 +183433.6153849628 + 30 +0.0 + 11 +535969.8389488495 + 21 +183351.4015336484 + 31 +0.0 + 0 +LINE + 5 +809 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536224.8896984233 + 20 +183379.7213448218 + 30 +0.0 + 11 +536026.8181654621 + 21 +183419.4063443993 + 31 +0.0 + 0 +LINE + 5 +80A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536190.3202068777 + 20 +183593.9325871916 + 30 +0.0 + 11 +536148.9637381762 + 21 +183295.9104764247 + 31 +0.0 + 0 +LINE + 5 +80B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536123.5626722017 + 20 +183656.0761439899 + 30 +0.0 + 11 +536235.0531643094 + 21 +183607.9374309185 + 31 +0.0 + 0 +LINE + 5 +80C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536256.2599631653 + 20 +183707.8087092746 + 30 +0.0 + 11 +536135.528785634 + 21 +183704.3861753978 + 31 +0.0 + 0 +LINE + 5 +80D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536141.7794635759 + 20 +183706.8968808336 + 30 +0.0 + 11 +536124.0364940552 + 21 +183653.9553288545 + 31 +0.0 + 0 +LINE + 5 +80E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536288.6068926312 + 20 +184011.3688704059 + 30 +0.0 + 11 +536288.6042152567 + 21 +184011.3567267488 + 31 +0.0 + 0 +LINE + 5 +80F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536257.0943731896 + 20 +183868.4388440262 + 30 +0.0 + 11 +536167.4768940855 + 21 +183461.9645639813 + 31 +0.0 + 0 +LINE + 5 +810 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536174.2702873457 + 20 +183450.7896110464 + 30 +0.0 + 11 +536150.5964115458 + 21 +183456.202759544 + 31 +0.0 + 0 +LINE + 5 +811 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536277.091176984 + 20 +183290.848499001 + 30 +0.0 + 11 +536262.8322347262 + 21 +183247.8273444499 + 31 +0.0 + 0 +LINE + 5 +812 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536289.2094413577 + 20 +183300.5682394452 + 30 +0.0 + 11 +536271.6895600724 + 21 +183284.0697488365 + 31 +0.0 + 0 +LINE + 5 +813 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536352.6253766384 + 20 +183291.2468103648 + 30 +0.0 + 11 +536281.2707242392 + 21 +183299.6358479864 + 31 +0.0 + 0 +LINE + 5 +814 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536220.9379273907 + 20 +183511.7003411787 + 30 +0.0 + 11 +535874.6134005037 + 21 +183570.4289235953 + 31 +0.0 + 0 +LINE + 5 +815 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535920.839662087 + 20 +183659.1692777822 + 30 +0.0 + 11 +536187.7191650914 + 21 +183539.2080466986 + 31 +0.0 + 0 +LINE + 5 +816 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536215.1485471566 + 20 +183664.7688771879 + 30 +0.0 + 11 +536180.3913818786 + 21 +183672.1127992867 + 31 +0.0 + 0 +LINE + 5 +817 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536040.7043262499 + 20 +183549.0189493377 + 30 +0.0 + 11 +536013.3862663467 + 21 +183459.7689420341 + 31 +0.0 + 0 +LINE + 5 +818 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536019.6432443323 + 20 +183494.3577599607 + 30 +0.0 + 11 +536043.3099346213 + 21 +183414.4048362322 + 31 +0.0 + 0 +LINE + 5 +819 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536032.7520582591 + 20 +183493.7020092531 + 30 +0.0 + 11 +535977.9736696914 + 21 +183435.1915335789 + 31 +0.0 + 0 +LINE + 5 +81A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535819.3510827251 + 20 +183488.0204039051 + 30 +0.0 + 11 +535990.454519467 + 21 +183437.0879300813 + 31 +0.0 + 0 +LINE + 5 +81B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536434.0485002005 + 20 +183498.8082347155 + 30 +0.0 + 11 +536387.2566181096 + 21 +183494.2662408433 + 31 +0.0 + 0 +LINE + 5 +81C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536393.0330097161 + 20 +183557.8190842093 + 30 +0.0 + 11 +536388.3519793497 + 21 +183492.7123594973 + 31 +0.0 + 0 +LINE + 5 +81D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536437.7949375415 + 20 +183579.0778556736 + 30 +0.0 + 11 +536335.2534120668 + 21 +183598.2658359574 + 31 +0.0 + 0 +LINE + 5 +81E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536382.4476452358 + 20 +183741.7422642311 + 30 +0.0 + 11 +536294.6954665122 + 21 +183456.3332831664 + 31 +0.0 + 0 +LINE + 5 +81F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536347.6301763369 + 20 +183373.220858017 + 30 +0.0 + 11 +536278.8510786098 + 21 +183376.2207693881 + 31 +0.0 + 0 +LINE + 5 +820 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536281.2146543384 + 20 +183407.9754765754 + 30 +0.0 + 11 +536278.4158529892 + 21 +183347.936000665 + 31 +0.0 + 0 +LINE + 5 +821 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536287.7077531305 + 20 +183402.327111559 + 30 +0.0 + 11 +536216.4929401491 + 21 +183406.4412735882 + 31 +0.0 + 0 +LINE + 5 +822 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536219.0729416188 + 20 +183409.1176385002 + 30 +0.0 + 11 +536215.050250384 + 21 +183353.1229266965 + 31 +0.0 + 0 +LINE + 5 +823 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536286.1257915368 + 20 +183352.6473372339 + 30 +0.0 + 11 +536208.7109628799 + 21 +183356.2573375812 + 31 +0.0 + 0 +LINE + 5 +824 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536624.2465273168 + 20 +183454.7991782079 + 30 +0.0 + 11 +536641.9181354303 + 21 +183190.7888298772 + 31 +0.0 + 0 +LINE + 5 +832 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535735.2534055224 + 20 +184715.4109906729 + 30 +0.0 + 11 +536165.5409591916 + 21 +184803.3677343476 + 31 +0.0 + 0 +LINE + 5 +836 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535509.6257709515 + 20 +184600.3551137814 + 30 +0.0 + 11 +536214.4735245573 + 21 +184667.7356093472 + 31 +0.0 + 0 +LINE + 5 +837 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535933.8162550799 + 20 +184510.3524146965 + 30 +0.0 + 11 +535889.0382171611 + 21 +185121.0044603166 + 31 +0.0 + 0 +LINE + 5 +838 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535891.3770378981 + 20 +184912.4309386843 + 30 +0.0 + 11 +536128.1126389638 + 21 +184943.9273969149 + 31 +0.0 + 0 +LINE + 5 +83A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535720.2179529596 + 20 +184854.8705574998 + 30 +0.0 + 11 +535798.7532048145 + 21 +185134.6910814056 + 31 +0.0 + 0 +LINE + 5 +83B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536189.9053794 + 20 +184532.9956358863 + 30 +0.0 + 11 +536125.7156833548 + 21 +184945.8975290452 + 31 +0.0 + 0 +LINE + 5 +83C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535735.1870223283 + 20 +184798.3292501815 + 30 +0.0 + 11 +536152.2614908992 + 21 +184875.0372290103 + 31 +0.0 + 0 +LINE + 5 +83D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535789.271791806 + 20 +185515.9908257694 + 30 +0.0 + 11 +536151.3875399865 + 21 +184868.1170060862 + 31 +0.0 + 0 +LINE + 5 +842 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535694.3790202402 + 20 +185135.4241570543 + 30 +0.0 + 11 +536071.6732173155 + 21 +185063.2439938016 + 31 +0.0 + 0 +LINE + 5 +845 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536032.473398615 + 20 +185000.676799044 + 30 +0.0 + 11 +536072.8788671299 + 21 +185021.2081235834 + 31 +0.0 + 0 +LINE + 5 +846 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536024.6748928699 + 20 +184987.2414354884 + 30 +0.0 + 11 +536038.3682737447 + 21 +185007.031275125 + 31 +0.0 + 0 +LINE + 5 +847 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536043.3737126193 + 20 +184925.9321863689 + 30 +0.0 + 11 +536024.4097767367 + 21 +184995.2303213156 + 31 +0.0 + 0 +LINE + 5 +851 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535850.3203429926 + 20 +184814.3890718129 + 30 +0.0 + 11 +535847.8147844659 + 21 +184861.3340621145 + 31 +0.0 + 0 +LINE + 5 +852 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535785.8400994945 + 20 +184846.119956075 + 30 +0.0 + 11 +535849.5149797025 + 21 +184860.4833567355 + 31 +0.0 + 0 +LINE + 5 +853 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535771.5132817625 + 20 +184389.55211422 + 30 +0.0 + 11 +535737.208628857 + 21 +184897.2022592253 + 31 +0.0 + 0 +LINE + 5 +854 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535602.4017936732 + 20 +184829.0854602525 + 30 +0.0 + 11 +535923.2220377361 + 21 +184983.4165245147 + 31 +0.0 + 0 +LINE + 5 +85A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536367.6458885368 + 20 +184582.1864207075 + 30 +0.0 + 11 +536587.2186660103 + 21 +184682.9161934223 + 31 +0.0 + 0 +LINE + 5 +85B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536172.7078649907 + 20 +184992.1615235455 + 30 +0.0 + 11 +536390.8634053164 + 21 +184519.5335550324 + 31 +0.0 + 0 +LINE + 5 +85C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536269.0988258286 + 20 +185042.6201202157 + 30 +0.0 + 11 +536573.4887323567 + 21 +184351.0867622647 + 31 +0.0 + 0 +LINE + 5 +85D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536545.101286052 + 20 +184585.5323099143 + 30 +0.0 + 11 +536975.3888397213 + 21 +184673.4890535888 + 31 +0.0 + 0 +LINE + 5 +85E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536569.2689741861 + 20 +184520.3744256831 + 30 +0.0 + 11 +536508.5543278837 + 21 +184704.5570791448 + 31 +0.0 + 0 +LINE + 5 +85F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536637.8791548743 + 20 +184544.1450233398 + 30 +0.0 + 11 +536617.2426144353 + 21 +184605.0529776709 + 31 +0.0 + 0 +LINE + 5 +860 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536597.3000749455 + 20 +184507.9427678797 + 30 +0.0 + 11 +536643.4348282493 + 21 +184559.0195733847 + 31 +0.0 + 0 +LINE + 5 +861 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536625.0212937263 + 20 +184550.1310688461 + 30 +0.0 + 11 +537024.321405087 + 21 +184606.3139738869 + 31 +0.0 + 0 +LINE + 5 +862 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536735.5056521489 + 20 +184490.2048948725 + 30 +0.0 + 11 +536713.875866871 + 21 +184786.7056298909 + 31 +0.0 + 0 +LINE + 5 +863 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536701.2249184277 + 20 +184782.5522579256 + 30 +0.0 + 11 +536937.9605194933 + 21 +184814.0487161564 + 31 +0.0 + 0 +LINE + 5 +864 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536587.2664426376 + 20 +184935.2587298225 + 30 +0.0 + 11 +536717.1209299521 + 21 +184773.8750440749 + 31 +0.0 + 0 +LINE + 5 +865 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536552.5709523043 + 20 +184855.2699344034 + 30 +0.0 + 11 +536629.9697800855 + 21 +184891.3357245587 + 31 +0.0 + 0 +LINE + 5 +866 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536985.3667351677 + 20 +184480.2953076949 + 30 +0.0 + 11 +536935.5635638845 + 21 +184816.0188482864 + 31 +0.0 + 0 +LINE + 5 +867 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536545.0349028581 + 20 +184668.4505694229 + 30 +0.0 + 11 +536962.1093714287 + 21 +184745.1585482518 + 31 +0.0 + 0 +LINE + 5 +868 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536694.4454183708 + 20 +185211.9093264152 + 30 +0.0 + 11 +536961.235420516 + 21 +184738.2383253276 + 31 +0.0 + 0 +LINE + 5 +869 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536636.1057933771 + 20 +185135.5802082968 + 30 +0.0 + 11 +536753.5301258957 + 21 +185136.6067860254 + 31 +0.0 + 0 +LINE + 5 +86A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536666.1100292685 + 20 +185081.2225458677 + 30 +0.0 + 11 +536736.5075044353 + 21 +185165.5421543244 + 31 +0.0 + 0 +LINE + 5 +86B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536746.6421737969 + 20 +184909.1241654075 + 30 +0.0 + 11 +536677.7869326034 + 21 +185099.0351633024 + 31 +0.0 + 0 +LINE + 5 +86C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536497.061055924 + 20 +184900.8815167933 + 30 +0.0 + 11 +536818.1581281305 + 21 +184996.7282827578 + 31 +0.0 + 0 +LINE + 5 +86D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536519.0248759599 + 20 +184809.918916625 + 30 +0.0 + 11 +536497.7020969032 + 21 +184929.4714348748 + 31 +0.0 + 0 +LINE + 5 +86E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536466.5840612846 + 20 +184797.0908326885 + 30 +0.0 + 11 +536520.5328002478 + 21 +184811.4836940305 + 31 +0.0 + 0 +LINE + 5 +86F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536131.6227593306 + 20 +184751.6770401758 + 30 +0.0 + 11 +536656.7389495195 + 21 +184953.5942392125 + 31 +0.0 + 0 +LINE + 5 +870 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536668.8040481505 + 20 +184948.548135754 + 30 +0.0 + 11 +536659.91194963 + 21 +184971.1464798513 + 31 +0.0 + 0 +LINE + 5 +871 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536842.3212791448 + 20 +184870.7981182857 + 30 +0.0 + 11 +536882.7267476596 + 21 +184891.3294428248 + 31 +0.0 + 0 +LINE + 5 +872 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536834.5227733995 + 20 +184857.3627547297 + 30 +0.0 + 11 +536848.2161542742 + 21 +184877.1525943664 + 31 +0.0 + 0 +LINE + 5 +873 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536853.2215931489 + 20 +184796.0535056102 + 30 +0.0 + 11 +536834.2576572664 + 21 +184865.3516405568 + 31 +0.0 + 0 +LINE + 5 +874 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536615.5559820213 + 20 +184893.2975328055 + 30 +0.0 + 11 +536515.5118895682 + 21 +185233.9513568983 + 31 +0.0 + 0 +LINE + 5 +875 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536268.5349937502 + 20 +185022.7956043346 + 30 +0.0 + 11 +536397.7349320228 + 21 +185180.7007160287 + 31 +0.0 + 0 +LINE + 5 +876 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536368.8431788377 + 20 +185192.2162503954 + 30 +0.0 + 11 +536583.390524052 + 21 +184922.0298029087 + 31 +0.0 + 0 +LINE + 5 +877 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536463.342569983 + 20 +184876.1344667894 + 30 +0.0 + 11 +536450.8841896643 + 21 +184909.4028074425 + 31 +0.0 + 0 +LINE + 5 +878 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536551.7077219273 + 20 +185065.9249616169 + 30 +0.0 + 11 +536635.8696988342 + 21 +185106.2809010026 + 31 +0.0 + 0 +LINE + 5 +879 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536602.6052891701 + 20 +185094.9224174441 + 30 +0.0 + 11 +536685.1981237456 + 21 +185083.4766357432 + 31 +0.0 + 0 +LINE + 5 +87A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536605.2137454526 + 20 +185082.0590210273 + 30 +0.0 + 11 +536654.875791868 + 21 +185144.9702979461 + 31 +0.0 + 0 +LINE + 5 +87B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536598.7951296876 + 20 +185245.1647069569 + 30 +0.0 + 11 +536654.8668963114 + 21 +185132.3461998914 + 31 +0.0 + 0 +LINE + 5 +87C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536096.8743136659 + 20 +184924.9135871356 + 30 +0.0 + 11 +536323.666184154 + 21 +185070.5657893215 + 31 +0.0 + 0 +LINE + 5 +87D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536660.1682235223 + 20 +184684.5103910543 + 30 +0.0 + 11 +536657.6626649958 + 21 +184731.455381356 + 31 +0.0 + 0 +LINE + 5 +87E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536595.6879800242 + 20 +184716.2412753165 + 30 +0.0 + 11 +536659.362860232 + 21 +184730.6046759769 + 31 +0.0 + 0 +LINE + 5 +87F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536581.3611622921 + 20 +184668.8038656017 + 30 +0.0 + 11 +536547.0565093866 + 21 +184767.3235784669 + 31 +0.0 + 0 +LINE + 5 +880 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536412.2496742029 + 20 +184699.2067794937 + 30 +0.0 + 11 +536681.3291069041 + 21 +184828.6478480936 + 31 +0.0 + 0 +LINE + 5 +881 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536771.4221847498 + 20 +184788.7354935804 + 30 +0.0 + 11 +536758.1718976634 + 21 +184856.292829559 + 31 +0.0 + 0 +LINE + 5 +882 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536727.1275824649 + 20 +184849.2077457455 + 30 +0.0 + 11 +536786.0736168213 + 21 +184860.9524036919 + 31 +0.0 + 0 +LINE + 5 +883 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536733.6833211163 + 20 +184843.6322054112 + 30 +0.0 + 11 +536718.9671126245 + 21 +184913.4312679034 + 31 +0.0 + 0 +LINE + 5 +884 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536716.7066061798 + 20 +184910.4800906235 + 30 +0.0 + 11 +536771.4703465928 + 21 +184922.8300918665 + 31 +0.0 + 0 +LINE + 5 +885 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536782.5680623663 + 20 +184852.6246829575 + 30 +0.0 + 11 +536767.4232990065 + 21 +184928.6294455796 + 31 +0.0 + 0 +LINE + 5 +886 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536227.0565971623 + 20 +184862.6022458617 + 30 +0.0 + 11 +536332.060859742 + 21 +184903.5738870732 + 31 +0.0 + 0 +LINE + 5 +887 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536703.092679131 + 20 +185170.207613885 + 30 +0.0 + 11 +536802.8495574758 + 21 +185736.4154951988 + 31 +0.0 + 0 +LINE + 5 +888 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536653.0321400727 + 20 +185217.3556704263 + 30 +0.0 + 11 +536690.4029275054 + 21 +185441.5719254414 + 31 +0.0 + 0 +LINE + 5 +889 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536474.4651889979 + 20 +185162.3312555545 + 30 +0.0 + 11 +536433.5369223055 + 21 +185327.1274163836 + 31 +0.0 + 0 +LINE + 5 +88A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536027.7112157658 + 20 +185070.4317919967 + 30 +0.0 + 11 +536758.9317897254 + 21 +185260.6634207374 + 31 +0.0 + 0 +LINE + 5 +88B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536522.959344978 + 20 +185270.0211576637 + 30 +0.0 + 11 +536455.699115787 + 21 +185786.0925192186 + 31 +0.0 + 0 +LINE + 5 +88C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536591.1371176031 + 20 +185283.4903204848 + 30 +0.0 + 11 +536399.6299907303 + 21 +185252.9200985578 + 31 +0.0 + 0 +LINE + 5 +88D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536578.6104286209 + 20 +185355.0129062195 + 30 +0.0 + 11 +536515.1912496727 + 21 +185344.3520693082 + 31 +0.0 + 0 +LINE + 5 +88E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536607.879245957 + 20 +185309.1805883639 + 30 +0.0 + 11 +536564.8120240138 + 21 +185362.8692269859 + 31 +0.0 + 0 +LINE + 5 +88F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536570.6507999075 + 20 +185343.2740116868 + 30 +0.0 + 11 +536630.0084509401 + 21 +185657.4002796109 + 31 +0.0 + 0 +LINE + 5 +890 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536331.3764837016 + 20 +185274.9186586766 + 30 +0.0 + 11 +536360.0073551307 + 21 +185694.2908528184 + 31 +0.0 + 0 +LINE + 5 +891 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536131.5448419101 + 20 +185245.2568437803 + 30 +0.0 + 11 +536243.5132806817 + 21 +185292.273162709 + 31 +0.0 + 0 +LINE + 5 +892 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536263.7157637863 + 20 +185192.1938929543 + 30 +0.0 + 11 +536143.0250585699 + 21 +185196.8290456603 + 31 +0.0 + 0 +LINE + 5 +893 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536149.2502001165 + 20 +185194.2556764203 + 30 +0.0 + 11 +536132.0399442671 + 21 +185247.3727921829 + 31 +0.0 + 0 +LINE + 5 +894 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536293.0116815622 + 20 +184888.3241108541 + 30 +0.0 + 11 +536293.0091263105 + 21 +184888.3362807939 + 31 +0.0 + 0 +LINE + 5 +895 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536262.9365396879 + 20 +185031.563481014 + 30 +0.0 + 11 +536186.7930930003 + 21 +185659.8411021697 + 31 +0.0 + 0 +LINE + 5 +896 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536368.966370536 + 20 +185451.3462593905 + 30 +0.0 + 11 +535883.4684907984 + 21 +185333.4005347594 + 31 +0.0 + 0 +LINE + 5 +897 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535705.8904213834 + 20 +185192.8603974879 + 30 +0.0 + 11 +536236.2722789427 + 21 +185347.2694557663 + 31 +0.0 + 0 +LINE + 5 +898 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536223.0387739137 + 20 +185235.6445335389 + 30 +0.0 + 11 +536188.2095898026 + 21 +185228.6501311959 + 31 +0.0 + 0 +LINE + 5 +899 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536545.7749020496 + 20 +185506.3403822074 + 30 +0.0 + 11 +536396.8509260806 + 21 +185404.4096746278 + 31 +0.0 + 0 +LINE + 5 +89A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536401.9886132652 + 20 +185340.8020118011 + 30 +0.0 + 11 +536397.9618413939 + 21 +185405.9524742422 + 31 +0.0 + 0 +LINE + 5 +89B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536389.5562031839 + 20 +185156.9944459336 + 30 +0.0 + 11 +536322.8218062403 + 21 +185382.0687006323 + 31 +0.0 + 0 +LINE + 5 +89E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536074.9532183286 + 20 +185122.5485679805 + 30 +0.0 + 11 +536236.5382793906 + 21 +184989.6285783852 + 31 +0.0 + 0 +LINE + 5 +89F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536414.0357339334 + 20 +185353.9101287031 + 30 +0.0 + 11 +536297.5220622345 + 21 +185341.469954668 + 31 +0.0 + 0 +LINE + 5 +8A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535933.5172575562 + 20 +184514.429937026 + 30 +0.0 + 11 +536060.3141642157 + 21 +184362.1580201859 + 31 +0.0 + 0 +LINE + 5 +8A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537477.0561138507 + 20 +187928.2588438897 + 30 +0.0 + 11 +537648.2829715595 + 21 +185028.8175773283 + 31 +0.0 + 0 +LINE + 5 +8A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537726.5507136519 + 20 +187131.1942189549 + 30 +0.0 + 11 +537653.7532900338 + 21 +187419.2442196735 + 31 +0.0 + 0 +LINE + 5 +8A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537192.3049867737 + 20 +187262.0692319707 + 30 +0.0 + 11 +537721.8503967186 + 21 +187225.0229891532 + 31 +0.0 + 0 +LINE + 5 +8A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537344.6652379133 + 20 +187445.065864851 + 30 +0.0 + 11 +537395.6850929626 + 21 +187218.5848226858 + 31 +0.0 + 0 +LINE + 5 +8A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537340.5091686917 + 20 +187073.0513562111 + 30 +0.0 + 11 +537659.2540033284 + 21 +187059.0562025004 + 31 +0.0 + 0 +LINE + 5 +8A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537460.6349338569 + 20 +186643.1579815403 + 30 +0.0 + 11 +537687.0150856387 + 21 +186633.5398320825 + 31 +0.0 + 0 +LINE + 5 +8A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537391.191286337 + 20 +187276.4319337291 + 30 +0.0 + 11 +537350.1318901424 + 21 +187036.2308251472 + 31 +0.0 + 0 +LINE + 5 +8A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537591.6890055485 + 20 +187284.1217651576 + 30 +0.0 + 11 +537594.5541466836 + 21 +186994.0394027349 + 31 +0.0 + 0 +LINE + 5 +8A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537644.0726228921 + 20 +185220.5275972164 + 30 +0.0 + 11 +537601.0638613992 + 21 +181721.5800113643 + 31 +0.0 + 0 +LINE + 5 +8AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536779.5233751413 + 20 +185481.8898698351 + 30 +0.0 + 11 +536524.1838228082 + 21 +185503.1272773228 + 31 +0.0 + 0 +LINE + 5 +8AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537442.3737651119 + 20 +185653.3438155586 + 30 +0.0 + 11 +537504.9645686496 + 21 +185218.641435863 + 31 +0.0 + 0 +LINE + 5 +8AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537682.705819199 + 20 +185657.090434018 + 30 +0.0 + 11 +537318.0003070827 + 21 +185647.5284239513 + 31 +0.0 + 0 +LINE + 5 +8AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537512.6729933498 + 20 +185580.0044745308 + 30 +0.0 + 11 +537448.3743816385 + 21 +185578.8493840094 + 31 +0.0 + 0 +LINE + 5 +8AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537702.4601705908 + 20 +185535.7373255553 + 30 +0.0 + 11 +537310.0515201883 + 21 +185426.5258548515 + 31 +0.0 + 0 +LINE + 5 +8AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537309.6864577988 + 20 +185439.8361412739 + 30 +0.0 + 11 +537360.0247466008 + 21 +185206.3798747624 + 31 +0.0 + 0 +LINE + 5 +8B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537127.4578714785 + 20 +185495.5006999384 + 30 +0.0 + 11 +537323.2240027454 + 21 +185427.806507056 + 31 +0.0 + 0 +LINE + 5 +8B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537191.0210346118 + 20 +185555.1807530092 + 30 +0.0 + 11 +537183.2257022997 + 21 +185470.1480971908 + 31 +0.0 + 0 +LINE + 5 +8B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537751.9121436832 + 20 +185436.0956015051 + 30 +0.0 + 11 +537663.9375196824 + 21 +185416.53654911 + 31 +0.0 + 0 +LINE + 5 +8B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537820.5566786869 + 20 +185299.6085467093 + 30 +0.0 + 11 +537357.3606357392 + 21 +185207.9702615446 + 31 +0.0 + 0 +LINE + 5 +8B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537364.3088697837 + 20 +185625.3918159156 + 30 +0.0 + 11 +537433.0228561571 + 21 +185206.9260294692 + 31 +0.0 + 0 +LINE + 5 +8B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536962.3002130862 + 20 +185289.5206968154 + 30 +0.0 + 11 +537439.2408833411 + 21 +185210.0866328064 + 31 +0.0 + 0 +LINE + 5 +8B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536709.953957186 + 20 +185311.975009698 + 30 +0.0 + 11 +537245.4382083907 + 21 +185246.98160248 + 31 +0.0 + 0 +LINE + 5 +8B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536955.4164714151 + 20 +185381.8532908917 + 30 +0.0 + 11 +536994.1228419815 + 21 +185270.9869542205 + 31 +0.0 + 0 +LINE + 5 +8B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537016.7149015927 + 20 +185371.9784696792 + 30 +0.0 + 11 +536961.1377379927 + 21 +185277.2326002901 + 31 +0.0 + 0 +LINE + 5 +8B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537205.9017999561 + 20 +185354.3263778232 + 30 +0.0 + 11 +537003.8948273027 + 21 +185354.9700862593 + 31 +0.0 + 0 +LINE + 5 +8BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537121.0637200125 + 20 +185778.5458884923 + 30 +0.0 + 11 +537147.6111499923 + 21 +185257.4181055872 + 31 +0.0 + 0 +LINE + 5 +8BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537142.4979307457 + 20 +185414.2677876428 + 30 +0.0 + 11 +537118.2241694152 + 21 +185415.0020102937 + 31 +0.0 + 0 +LINE + 5 +8BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537274.2999987925 + 20 +185277.2221400399 + 30 +0.0 + 11 +537268.6272185847 + 21 +185232.2559667765 + 31 +0.0 + 0 +LINE + 5 +8BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537284.3105543463 + 20 +185289.1013009212 + 30 +0.0 + 11 +537270.3108034533 + 21 +185269.5269961427 + 31 +0.0 + 0 +LINE + 5 +8BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537348.3321920717 + 20 +185292.2157496004 + 30 +0.0 + 11 +537276.7018629033 + 21 +185286.6517299696 + 31 +0.0 + 0 +LINE + 5 +8BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537176.5094565962 + 20 +185483.0515196001 + 30 +0.0 + 11 +536742.5172056709 + 21 +185465.5012760965 + 31 +0.0 + 0 +LINE + 5 +8C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536766.9536079009 + 20 +185485.7875121864 + 30 +0.0 + 11 +536810.4861386002 + 21 +185289.2697495361 + 31 +0.0 + 0 +LINE + 5 +8C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536752.440527201 + 20 +185590.4929007661 + 30 +0.0 + 11 +537138.5994012306 + 21 +185503.6181851989 + 31 +0.0 + 0 +LINE + 5 +8C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536992.4613792804 + 20 +185484.8220369056 + 30 +0.0 + 11 +536982.9131431991 + 21 +185391.9744661871 + 31 +0.0 + 0 +LINE + 5 +8C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536982.365121138 + 20 +185427.1203873002 + 30 +0.0 + 11 +537021.0423958639 + 21 +185353.2512417675 + 31 +0.0 + 0 +LINE + 5 +8C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536995.3534031598 + 20 +185429.011297577 + 30 +0.0 + 11 +536952.9201089633 + 21 +185361.0145097018 + 31 +0.0 + 0 +LINE + 5 +8C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536787.0767849401 + 20 +185382.1806740374 + 30 +0.0 + 11 +536964.7988744056 + 21 +185365.2880167373 + 31 +0.0 + 0 +LINE + 5 +8C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537388.0919537572 + 20 +185511.6026937876 + 30 +0.0 + 11 +537343.0609218514 + 21 +185498.100245733 + 31 +0.0 + 0 +LINE + 5 +8C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537336.4418470921 + 20 +185561.5708566427 + 30 +0.0 + 11 +537344.4360258606 + 21 +185496.7874424549 + 31 +0.0 + 0 +LINE + 5 +8C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537376.2494139416 + 20 +185591.0822640697 + 30 +0.0 + 11 +537271.932843452 + 21 +185590.0841882765 + 31 +0.0 + 0 +LINE + 5 +8C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537290.498835642 + 20 +185739.9777673537 + 30 +0.0 + 11 +537259.5794679108 + 21 +185442.9883331271 + 31 +0.0 + 0 +LINE + 5 +8CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537327.5834193336 + 20 +185371.6775954408 + 30 +0.0 + 11 +537259.5219198117 + 21 +185361.3240436236 + 31 +0.0 + 0 +LINE + 5 +8CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537255.7018576593 + 20 +185392.9366209298 + 30 +0.0 + 11 +537264.5631191268 + 21 +185333.4887445855 + 31 +0.0 + 0 +LINE + 5 +8CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537263.1644422948 + 20 +185388.65010838 + 30 +0.0 + 11 +537192.497763957 + 21 +185378.918896233 + 31 +0.0 + 0 +LINE + 5 +8CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537194.511677977 + 20 +185382.0435541413 + 30 +0.0 + 11 +537201.3901762668 + 21 +185326.3275236292 + 31 +0.0 + 0 +LINE + 5 +8CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537271.2167753149 + 20 +185339.6017392693 + 30 +0.0 + 11 +537194.5645167913 + 21 +185328.1772453325 + 31 +0.0 + 0 +LINE + 5 +8CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537929.3346989562 + 20 +185271.5668162964 + 30 +0.0 + 11 +538198.9327271872 + 21 +184527.868208749 + 31 +0.0 + 0 +LINE + 5 +8D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537979.076304023 + 20 +185143.0004105447 + 30 +0.0 + 11 +537833.7609421401 + 21 +185115.7765183631 + 31 +0.0 + 0 +LINE + 5 +8D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537864.912350873 + 20 +185261.6115672493 + 30 +0.0 + 11 +538034.3022126254 + 21 +184797.0777347585 + 31 +0.0 + 0 +LINE + 5 +8D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537862.8389685585 + 20 +185130.6169573129 + 30 +0.0 + 11 +537802.5241558244 + 21 +185075.0901924201 + 31 +0.0 + 0 +LINE + 5 +8D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537803.6606153359 + 20 +185184.0326677696 + 30 +0.0 + 11 +537862.278393451 + 21 +185118.6003778122 + 31 +0.0 + 0 +LINE + 5 +8D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537791.3098488985 + 20 +185379.6317312794 + 30 +0.0 + 11 +537760.7998573019 + 21 +184862.4547331083 + 31 +0.0 + 0 +LINE + 5 +8D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537398.0762367352 + 20 +185145.7665578626 + 30 +0.0 + 11 +537395.8723393784 + 21 +185032.6606599039 + 31 +0.0 + 0 +LINE + 5 +8D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537314.7685022459 + 20 +185040.3400275386 + 30 +0.0 + 11 +538068.478175064 + 21 +184987.488069622 + 31 +0.0 + 0 +LINE + 5 +8D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537838.2277014728 + 20 +184934.9972958472 + 30 +0.0 + 11 +537936.9033700488 + 21 +184444.3422736906 + 31 +0.0 + 0 +LINE + 5 +8D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537907.7193585047 + 20 +184934.2647453819 + 30 +0.0 + 11 +537713.8542434436 + 21 +184929.1819042397 + 31 +0.0 + 0 +LINE + 5 +8D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537908.5269297106 + 20 +184861.6579548194 + 30 +0.0 + 11 +537844.2283179992 + 21 +184860.5028642978 + 31 +0.0 + 0 +LINE + 5 +8DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537928.8904968241 + 20 +184912.0820578129 + 30 +0.0 + 11 +537896.4040596111 + 21 +184851.4035037743 + 31 +0.0 + 0 +LINE + 5 +8DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537898.5487650536 + 20 +184871.7373181024 + 30 +0.0 + 11 +537927.1449354257 + 21 +184734.1017373799 + 31 +0.0 + 0 +LINE + 5 +8DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538098.3141069516 + 20 +184817.3908058439 + 30 +0.0 + 11 +537329.9835135775 + 21 +184606.5084133261 + 31 +0.0 + 0 +LINE + 5 +8DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537705.5403941596 + 20 +184721.4896215623 + 30 +0.0 + 11 +537772.8875289665 + 21 +184417.2423231482 + 31 +0.0 + 0 +LINE + 5 +8DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538148.8034751078 + 20 +184702.7591116822 + 30 +0.0 + 11 +538060.8288511072 + 21 +184683.2000592873 + 31 +0.0 + 0 +LINE + 5 +8DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537760.1628061444 + 20 +184907.0452962041 + 30 +0.0 + 11 +537836.5749717135 + 21 +184441.6978662771 + 31 +0.0 + 0 +LINE + 5 +8E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537525.1910752361 + 20 +184873.6698417635 + 30 +0.0 + 11 +537539.4957322885 + 21 +184445.6458203916 + 31 +0.0 + 0 +LINE + 5 +8E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537542.1562393378 + 20 +185268.0292053734 + 30 +0.0 + 11 +537529.5262136854 + 21 +184705.572050634 + 31 +0.0 + 0 +LINE + 5 +8E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537572.3633929569 + 20 +184764.7049998887 + 30 +0.0 + 11 +537044.7432192317 + 21 +184733.545769042 + 31 +0.0 + 0 +LINE + 5 +8E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537333.2367947538 + 20 +185047.5685480215 + 30 +0.0 + 11 +537228.2679305992 + 21 +184872.616594883 + 31 +0.0 + 0 +LINE + 5 +8E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537207.6682683828 + 20 +184895.9188447834 + 30 +0.0 + 11 +537534.4533375916 + 21 +184785.2716654875 + 31 +0.0 + 0 +LINE + 5 +8E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537388.3153156413 + 20 +184766.4755171942 + 30 +0.0 + 11 +537367.4725160221 + 21 +184552.8193007415 + 31 +0.0 + 0 +LINE + 5 +8E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537235.5240868724 + 20 +184661.5996348834 + 30 +0.0 + 11 +537393.7310076131 + 21 +184610.9278129846 + 31 +0.0 + 0 +LINE + 5 +8E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537367.36642518 + 20 +185242.2052524351 + 30 +0.0 + 11 +537306.9020463016 + 21 +184979.539732414 + 31 +0.0 + 0 +LINE + 5 +8E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537783.945890118 + 20 +184793.256174076 + 30 +0.0 + 11 +537738.9148582124 + 21 +184779.7537260216 + 31 +0.0 + 0 +LINE + 5 +8E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537732.2957834531 + 20 +184843.2243369311 + 30 +0.0 + 11 +537740.2899622214 + 21 +184778.4409227434 + 31 +0.0 + 0 +LINE + 5 +8EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537772.1033503026 + 20 +184872.7357443583 + 30 +0.0 + 11 +537667.7867798128 + 21 +184871.7376685649 + 31 +0.0 + 0 +LINE + 5 +8EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537469.9966511197 + 20 +185140.7302953704 + 30 +0.0 + 11 +537466.9106212527 + 21 +185028.057996365 + 31 +0.0 + 0 +LINE + 5 +8EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537979.0638534152 + 20 +184786.8478223103 + 30 +0.0 + 11 +538083.7178428379 + 21 +184458.7717046499 + 31 +0.0 + 0 +LINE + 5 +8ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537280.0222161629 + 20 +184619.9473564593 + 30 +0.0 + 11 +536956.2067911491 + 21 +184481.6762675277 + 31 +0.0 + 0 +LINE + 5 +8EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537207.0378316328 + 20 +185258.1371119735 + 30 +0.0 + 11 +537278.2416384539 + 21 +184470.2140828968 + 31 +0.0 + 0 +LINE + 5 +8EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536980.4710469725 + 20 +185010.2972592024 + 30 +0.0 + 11 +536927.8955659535 + 21 +184779.1685527982 + 31 +0.0 + 0 +LINE + 5 +8F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537049.5226215949 + 20 +184957.0632054001 + 30 +0.0 + 11 +536964.3348987111 + 21 +184951.2004729965 + 31 +0.0 + 0 +LINE + 5 +8F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536840.8458648577 + 20 +185162.016689198 + 30 +0.0 + 11 +536737.5695998013 + 21 +185106.128042719 + 31 +0.0 + 0 +LINE + 5 +8F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536840.8713251344 + 20 +185099.9279705128 + 30 +0.0 + 11 +536738.4759137944 + 21 +185139.6870024007 + 31 +0.0 + 0 +LINE + 5 +8F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537041.7635251898 + 20 +185000.2299248898 + 30 +0.0 + 11 +536793.6735813123 + 21 +184993.7955770673 + 31 +0.0 + 0 +LINE + 5 +8F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537077.5737849831 + 20 +185101.3433580342 + 30 +0.0 + 11 +537071.1514116518 + 21 +184980.0741589464 + 31 +0.0 + 0 +LINE + 5 +8F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537172.1713225316 + 20 +184994.8720697461 + 30 +0.0 + 11 +537127.032579336 + 21 +185106.8998557143 + 31 +0.0 + 0 +LINE + 5 +8F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537131.5578333191 + 20 +185101.9101971182 + 30 +0.0 + 11 +537075.7495330001 + 21 +185100.162481796 + 31 +0.0 + 0 +LINE + 5 +8F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537468.0706524365 + 20 +185069.9632265745 + 30 +0.0 + 11 +537468.0583348098 + 21 +185069.9615198771 + 31 +0.0 + 0 +LINE + 5 +8F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537323.0930156879 + 20 +185049.8755147771 + 30 +0.0 + 11 +536910.7955998639 + 21 +184992.7486926704 + 31 +0.0 + 0 +LINE + 5 +8F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536976.0023422475 + 20 +184959.8882245781 + 30 +0.0 + 11 +536910.7989271889 + 21 +185305.0523000277 + 31 +0.0 + 0 +LINE + 5 +8FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537010.069859664 + 20 +185292.5223484414 + 30 +0.0 + 11 +536990.2611797721 + 21 +185000.592592699 + 31 +0.0 + 0 +LINE + 5 +8FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537117.5326950717 + 20 +185018.477070521 + 30 +0.0 + 11 +537112.3485408801 + 21 +185053.6213200548 + 31 +0.0 + 0 +LINE + 5 +8FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536948.4040101366 + 20 +185141.8639415291 + 30 +0.0 + 11 +536855.2218565389 + 21 +185136.4856098683 + 31 +0.0 + 0 +LINE + 5 +8FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536889.8307478832 + 20 +185142.6305865953 + 30 +0.0 + 11 +536823.0737015237 + 21 +185092.6698119482 + 31 +0.0 + 0 +LINE + 5 +8FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536893.7684289591 + 20 +185130.1099764146 + 30 +0.0 + 11 +536819.8756486581 + 21 +185161.1584004829 + 31 +0.0 + 0 +LINE + 5 +8FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536814.3275417369 + 20 +185328.2548790376 + 30 +0.0 + 11 +536825.9885333216 + 21 +185150.1130135764 + 31 +0.0 + 0 +LINE + 5 +900 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537247.8169779245 + 20 +184888.3237141581 + 30 +0.0 + 11 +536949.6971068369 + 21 +184871.492974252 + 31 +0.0 + 0 +LINE + 5 +901 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537488.5795058766 + 20 +185910.915399177 + 30 +0.0 + 11 +537918.0019126186 + 21 +186216.2516944803 + 31 +0.0 + 0 +LINE + 5 +902 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537649.7421860449 + 20 +186032.3074633412 + 30 +0.0 + 11 +537922.143169518 + 21 +185289.6309389398 + 31 +0.0 + 0 +LINE + 5 +903 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537694.4341605217 + 20 +185901.8997358865 + 30 +0.0 + 11 +537823.164857351 + 21 +185974.605323007 + 31 +0.0 + 0 +LINE + 5 +904 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537705.4513987788 + 20 +186066.1575672213 + 30 +0.0 + 11 +537874.8412605314 + 21 +185601.6237347305 + 31 +0.0 + 0 +LINE + 5 +905 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537791.3592910779 + 20 +185967.24487447 + 30 +0.0 + 11 +537873.2594627485 + 21 +185963.5760688097 + 31 +0.0 + 0 +LINE + 5 +906 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537802.2635272968 + 20 +186046.215839047 + 30 +0.0 + 11 +537799.5233544297 + 21 +185958.4096893029 + 31 +0.0 + 0 +LINE + 5 +907 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537793.0742666434 + 20 +186029.5641904967 + 30 +0.0 + 11 +537956.8676222774 + 21 +186142.3737177295 + 31 +0.0 + 0 +LINE + 5 +908 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537744.3345605741 + 20 +186142.0599034011 + 30 +0.0 + 11 +538042.0635214961 + 21 +185827.7086871679 + 31 +0.0 + 0 +LINE + 5 +909 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537994.112465099 + 20 +186100.4570891543 + 30 +0.0 + 11 +537869.4359160997 + 21 +185961.5484973036 + 31 +0.0 + 0 +LINE + 5 +90A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537951.5265775774 + 20 +186143.5854558382 + 30 +0.0 + 11 +537994.1027542618 + 21 +186099.6094412371 + 31 +0.0 + 0 +LINE + 5 +90B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538188.1030446081 + 20 +186323.8178848796 + 30 +0.0 + 11 +537978.2928211513 + 21 +186113.281341056 + 31 +0.0 + 0 +LINE + 5 +90C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538137.2803173881 + 20 +186278.0061185872 + 30 +0.0 + 11 +538211.7731332879 + 21 +186192.8672808224 + 31 +0.0 + 0 +LINE + 5 +90D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538268.8969313724 + 20 +186250.9506414111 + 30 +0.0 + 11 +537642.7016945823 + 21 +185646.7766129888 + 31 +0.0 + 0 +LINE + 5 +90E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537936.1140565315 + 20 +185833.3836616485 + 30 +0.0 + 11 +538168.0324223031 + 21 +185460.4257025991 + 31 +0.0 + 0 +LINE + 5 +90F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537883.405144088 + 20 +185788.0913049394 + 30 +0.0 + 11 +538035.0377262333 + 21 +185908.9924138828 + 31 +0.0 + 0 +LINE + 5 +910 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537929.5240893575 + 20 +185732.0070728036 + 30 +0.0 + 11 +537979.4739508218 + 21 +185772.5120976989 + 31 +0.0 + 0 +LINE + 5 +911 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537881.4823191293 + 20 +185757.4875229886 + 30 +0.0 + 11 +537945.4022444065 + 21 +185731.9630508963 + 31 +0.0 + 0 +LINE + 5 +912 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537930.6720798144 + 20 +185746.1435310593 + 30 +0.0 + 11 +538122.0325711219 + 21 +185391.209367984 + 31 +0.0 + 0 +LINE + 5 +913 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537812.7788332458 + 20 +185575.9644558714 + 30 +0.0 + 11 +538183.3800251802 + 21 +185744.9805816725 + 31 +0.0 + 0 +LINE + 5 +914 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538175.0915734619 + 20 +185755.4016451168 + 30 +0.0 + 11 +538286.8444801435 + 21 +185544.3399016834 + 31 +0.0 + 0 +LINE + 5 +915 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538278.7158961651 + 20 +185915.3009900432 + 30 +0.0 + 11 +538172.4750552428 + 21 +185737.4815152343 + 31 +0.0 + 0 +LINE + 5 +916 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538191.6563625952 + 20 +185920.0572550347 + 30 +0.0 + 11 +538252.3574474437 + 21 +185860.0014638102 + 31 +0.0 + 0 +LINE + 5 +917 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537875.7705432734 + 20 +185399.632320588 + 30 +0.0 + 11 +537955.6857652751 + 21 +185441.2934330443 + 31 +0.0 + 0 +LINE + 5 +918 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537874.3981423898 + 20 +185319.2415582475 + 30 +0.0 + 11 +538287.8595349536 + 21 +185547.2718772174 + 31 +0.0 + 0 +LINE + 5 +919 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538013.8481153227 + 20 +185862.2429456056 + 30 +0.0 + 11 +538230.6290537816 + 21 +185497.7690081691 + 31 +0.0 + 0 +LINE + 5 +91A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538469.9074596536 + 20 +185747.2320719628 + 30 +0.0 + 11 +538270.6231049247 + 21 +185542.5828923688 + 31 +0.0 + 0 +LINE + 5 +91B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538579.1173669532 + 20 +186074.6315486046 + 30 +0.0 + 11 +538414.9811071633 + 21 +185898.6873731377 + 31 +0.0 + 0 +LINE + 5 +91C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537948.318605483 + 20 +186278.8268257429 + 30 +0.0 + 11 +538320.0375345342 + 21 +185856.5205313893 + 31 +0.0 + 0 +LINE + 5 +91D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538306.8466288651 + 20 +185653.7349334854 + 30 +0.0 + 11 +538351.7220665163 + 21 +185610.3568952985 + 31 +0.0 + 0 +LINE + 5 +91E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538291.5391571618 + 20 +185656.3820065465 + 30 +0.0 + 11 +538314.8528344023 + 21 +185650.4138505369 + 31 +0.0 + 0 +LINE + 5 +91F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538240.5400198092 + 20 +185617.5547239104 + 30 +0.0 + 11 +538298.9387112047 + 21 +185659.4051147633 + 31 +0.0 + 0 +LINE + 5 +920 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538419.1352779886 + 20 +186314.8277945895 + 30 +0.0 + 11 +538630.0002317273 + 21 +186229.2174081527 + 31 +0.0 + 0 +LINE + 5 +921 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538250.1105527468 + 20 +186244.5944385616 + 30 +0.0 + 11 +538448.8635819237 + 21 +186327.1805350029 + 31 +0.0 + 0 +LINE + 5 +922 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538068.8934503017 + 20 +185759.8534417735 + 30 +0.0 + 11 +538112.0462407692 + 21 +185778.5067688979 + 31 +0.0 + 0 +LINE + 5 +923 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538076.2556680476 + 20 +185831.3401438057 + 30 +0.0 + 11 +538111.8389544994 + 21 +185776.6169551807 + 31 +0.0 + 0 +LINE + 5 +924 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538026.7953211405 + 20 +185828.3004677325 + 30 +0.0 + 11 +538107.2689864418 + 21 +185894.6851966017 + 31 +0.0 + 0 +LINE + 5 +925 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537996.5743993786 + 20 +185997.4445733489 + 30 +0.0 + 11 +538211.4082992304 + 21 +185790.0677983291 + 31 +0.0 + 0 +LINE + 5 +926 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538205.2690463632 + 20 +185691.7211242995 + 30 +0.0 + 11 +538264.0196099377 + 21 +185727.6089360475 + 31 +0.0 + 0 +LINE + 5 +927 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538246.5940171504 + 20 +185754.2603269081 + 30 +0.0 + 11 +538278.0792604868 + 21 +185703.0621686534 + 31 +0.0 + 0 +LINE + 5 +928 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538243.6422897201 + 20 +185746.1762892745 + 30 +0.0 + 11 +538303.985940229 + 21 +185784.2173166059 + 31 +0.0 + 0 +LINE + 5 +929 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538300.4333945551 + 20 +185785.3121937489 + 30 +0.0 + 11 +538331.0338157953 + 21 +185738.2462398686 + 31 +0.0 + 0 +LINE + 5 +92A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538269.0524297824 + 20 +185703.4573548131 + 30 +0.0 + 11 +538335.0666795332 + 21 +185744.0554659552 + 31 +0.0 + 0 +LINE + 5 +92B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537950.820243172 + 20 +185162.6988744979 + 30 +0.0 + 11 +538032.7204148425 + 21 +185159.0300688376 + 31 +0.0 + 0 +LINE + 5 +92C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537961.7244793911 + 20 +185241.6698390747 + 30 +0.0 + 11 +537958.9843065237 + 21 +185153.8636893305 + 31 +0.0 + 0 +LINE + 5 +92D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537954.1309083346 + 20 +185225.8982378864 + 30 +0.0 + 11 +538117.9242639685 + 21 +185338.7077651193 + 31 +0.0 + 0 +LINE + 5 +92E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537845.2692138033 + 20 +185399.3077348817 + 30 +0.0 + 11 +538201.5244735902 + 21 +185023.1626871957 + 31 +0.0 + 0 +LINE + 5 +92F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538153.573417193 + 20 +185295.9110891822 + 30 +0.0 + 11 +538028.8968681939 + 21 +185157.0024973315 + 31 +0.0 + 0 +LINE + 5 +930 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538110.9875296714 + 20 +185339.0394558662 + 30 +0.0 + 11 +538153.563706356 + 21 +185295.063441265 + 31 +0.0 + 0 +LINE + 5 +931 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538347.5639967021 + 20 +185519.2718849074 + 30 +0.0 + 11 +538137.7537732455 + 21 +185308.7353410838 + 31 +0.0 + 0 +LINE + 5 +932 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538350.7571299851 + 20 +185375.1291508186 + 30 +0.0 + 11 +537885.5810351296 + 21 +184920.7955725819 + 31 +0.0 + 0 +LINE + 5 +933 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538095.5750086255 + 20 +185028.8376616764 + 30 +0.0 + 11 +538235.7333668089 + 21 +184803.4429412633 + 31 +0.0 + 0 +LINE + 5 +934 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538042.8660961822 + 20 +184983.5453049674 + 30 +0.0 + 11 +538194.4986783272 + 21 +185104.4464139107 + 31 +0.0 + 0 +LINE + 5 +935 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538088.9850414515 + 20 +184927.4610728313 + 30 +0.0 + 11 +538138.9349029161 + 21 +184967.9660977267 + 31 +0.0 + 0 +LINE + 5 +936 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538040.9432712235 + 20 +184952.9415230164 + 30 +0.0 + 11 +538104.8631965004 + 21 +184927.417050924 + 31 +0.0 + 0 +LINE + 5 +937 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538090.1330319084 + 20 +184941.5975310872 + 30 +0.0 + 11 +538281.4935232161 + 21 +184586.6633680119 + 31 +0.0 + 0 +LINE + 5 +938 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538072.307469424 + 20 +184817.178123014 + 30 +0.0 + 11 +538342.8409772741 + 21 +184940.4345817006 + 31 +0.0 + 0 +LINE + 5 +939 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538334.5525255559 + 20 +184950.8556451446 + 30 +0.0 + 11 +538446.3054322376 + 21 +184739.793901711 + 31 +0.0 + 0 +LINE + 5 +93A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538438.1768482592 + 20 +185110.754990071 + 30 +0.0 + 11 +538331.9360073368 + 21 +184932.9355152621 + 31 +0.0 + 0 +LINE + 5 +93B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538192.79221278 + 20 +185254.3631671886 + 30 +0.0 + 11 +538411.8183995378 + 21 +185055.4554638381 + 31 +0.0 + 0 +LINE + 5 +93C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538173.3090674167 + 20 +185057.6969456334 + 30 +0.0 + 11 +538411.6300655914 + 21 +184662.8555463364 + 31 +0.0 + 0 +LINE + 5 +93D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538605.9235865892 + 20 +185128.2845935083 + 30 +0.0 + 11 +538286.2399475104 + 21 +184954.0946146965 + 31 +0.0 + 0 +LINE + 5 +93E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538505.7505698988 + 20 +185165.5577566305 + 30 +0.0 + 11 +538547.4940421457 + 21 +185055.7988833945 + 31 +0.0 + 0 +LINE + 5 +93F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538465.1966319189 + 20 +185118.542995645 + 30 +0.0 + 11 +538568.7165055024 + 21 +185081.811038804 + 31 +0.0 + 0 +LINE + 5 +940 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538107.7795575772 + 20 +185474.2808257707 + 30 +0.0 + 11 +538314.4841544041 + 21 +185231.6328740587 + 31 +0.0 + 0 +LINE + 5 +941 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538229.1246635165 + 20 +185284.572763438 + 30 +0.0 + 11 +538556.1171595886 + 21 +185312.809171415 + 31 +0.0 + 0 +LINE + 5 +942 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538443.4888289444 + 20 +185324.8896968279 + 30 +0.0 + 11 +538459.6365313105 + 21 +185158.8469818409 + 31 +0.0 + 0 +LINE + 5 +943 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538455.9889421318 + 20 +185182.8528467175 + 30 +0.0 + 11 +538473.9396036967 + 21 +185101.4258487909 + 31 +0.0 + 0 +LINE + 5 +944 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538444.8321139844 + 20 +185175.9393673298 + 30 +0.0 + 11 +538521.074896924 + 21 +185151.2171977781 + 31 +0.0 + 0 +LINE + 5 +945 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538595.5563366735 + 20 +185238.6041270096 + 30 +0.0 + 11 +538509.233481124 + 21 +185146.8412632869 + 31 +0.0 + 0 +LINE + 5 +946 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538258.1652718431 + 20 +185567.0304490767 + 30 +0.0 + 11 +538377.4093335351 + 21 +185477.2768007374 + 31 +0.0 + 0 +LINE + 5 +947 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538228.3544023958 + 20 +184955.3074418012 + 30 +0.0 + 11 +538271.5071928632 + 21 +184973.9607689259 + 31 +0.0 + 0 +LINE + 5 +948 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538235.7166201418 + 20 +185026.7941438338 + 30 +0.0 + 11 +538271.2999065937 + 21 +184972.0709552085 + 31 +0.0 + 0 +LINE + 5 +949 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538186.2562732346 + 20 +185023.7544677603 + 30 +0.0 + 11 +538266.7299385358 + 21 +185090.1391966294 + 31 +0.0 + 0 +LINE + 5 +94A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538156.0353514726 + 20 +185192.8985733767 + 30 +0.0 + 11 +538370.8692513245 + 21 +184985.521798357 + 31 +0.0 + 0 +LINE + 5 +94B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538364.7299984572 + 20 +184887.1751243276 + 30 +0.0 + 11 +538423.4805620318 + 21 +184923.0629360754 + 31 +0.0 + 0 +LINE + 5 +94C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538406.0549692446 + 20 +184949.7143269358 + 30 +0.0 + 11 +538437.5402125808 + 21 +184898.5161686812 + 31 +0.0 + 0 +LINE + 5 +94D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538244.943979526 + 20 +185423.3108344892 + 30 +0.0 + 11 +538319.8327647924 + 21 +185339.0716489233 + 31 +0.0 + 0 +LINE + 5 +94E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538561.4867933374 + 20 +185114.7662861104 + 30 +0.0 + 11 +539127.0967414929 + 21 +185217.8593808671 + 31 +0.0 + 0 +LINE + 5 +94F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538588.3144403077 + 20 +185178.0851155726 + 30 +0.0 + 11 +538811.5532858948 + 21 +185220.909437952 + 31 +0.0 + 0 +LINE + 5 +950 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538474.6996822701 + 20 +185326.427722413 + 30 +0.0 + 11 +538615.0241558182 + 21 +185422.04121394 + 31 +0.0 + 0 +LINE + 5 +951 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538414.3673936683 + 20 +185453.1652775622 + 30 +0.0 + 11 +539150.8013019747 + 21 +184398.8570169071 + 31 +0.0 + 0 +LINE + 5 +952 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538592.5282977311 + 20 +185318.3521073253 + 30 +0.0 + 11 +538997.6937680966 + 21 +185487.835762065 + 31 +0.0 + 0 +LINE + 5 +953 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538628.8368356242 + 20 +185259.0957397071 + 30 +0.0 + 11 +538533.6601007033 + 21 +185428.0658768367 + 31 +0.0 + 0 +LINE + 5 +954 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538691.5571382496 + 20 +185295.6821011772 + 30 +0.0 + 11 +538659.5347575402 + 21 +185351.4513833656 + 31 +0.0 + 0 +LINE + 5 +955 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538658.7424885215 + 20 +185252.317786453 + 30 +0.0 + 11 +538694.1323456457 + 21 +185311.3500957061 + 31 +0.0 + 0 +LINE + 5 +956 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538677.7845838421 + 20 +185299.0694421985 + 30 +0.0 + 11 +539058.6899563309 + 21 +185431.387978166 + 31 +0.0 + 0 +LINE + 5 +957 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538826.9885224897 + 20 +185155.5496877736 + 30 +0.0 + 11 +538719.2265685296 + 21 +185548.3588723946 + 31 +0.0 + 0 +LINE + 5 +958 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538707.6172481076 + 20 +185541.838084518 + 30 +0.0 + 11 +538933.7975566249 + 21 +185618.5077638701 + 31 +0.0 + 0 +LINE + 5 +959 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538566.286364202 + 20 +185669.632380236 + 30 +0.0 + 11 +538724.8909121459 + 21 +185536.3977027955 + 31 +0.0 + 0 +LINE + 5 +95A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538547.7094339019 + 20 +185584.4450448938 + 30 +0.0 + 11 +538616.6755853611 + 21 +185634.7937262498 + 31 +0.0 + 0 +LINE + 5 +95B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +539011.1086433176 + 20 +185189.6195949093 + 30 +0.0 + 11 +538982.7228988433 + 21 +185275.1552045073 + 31 +0.0 + 0 +LINE + 5 +95C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +539090.2520782862 + 20 +185175.4465622335 + 30 +0.0 + 11 +538931.0649410907 + 21 +185619.9773315418 + 31 +0.0 + 0 +LINE + 5 +95D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538576.4328149488 + 20 +185399.6932260825 + 30 +0.0 + 11 +538970.8091654945 + 21 +185555.5858829968 + 31 +0.0 + 0 +LINE + 5 +95E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538658.2440018568 + 20 +185917.1169387221 + 30 +0.0 + 11 +538971.2895693079 + 21 +185548.6272561428 + 31 +0.0 + 0 +LINE + 5 +95F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538553.7271723706 + 20 +186089.1058411073 + 30 +0.0 + 11 +538840.1227081429 + 21 +185695.9906509777 + 31 +0.0 + 0 +LINE + 5 +960 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538575.4767454062 + 20 +185875.6166364597 + 30 +0.0 + 11 +538690.4873259018 + 21 +185899.3251603142 + 31 +0.0 + 0 +LINE + 5 +961 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538615.4237445238 + 20 +185828.0851006367 + 30 +0.0 + 11 +538668.1918546128 + 21 +185924.4237088775 + 31 +0.0 + 0 +LINE + 5 +962 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538727.7078894064 + 20 +185674.8025195414 + 30 +0.0 + 11 +538623.4366926458 + 21 +185847.8191340247 + 31 +0.0 + 0 +LINE + 5 +963 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538514.4132508551 + 20 +185634.9665650709 + 30 +0.0 + 11 +538780.9383930338 + 21 +185774.579904677 + 31 +0.0 + 0 +LINE + 5 +964 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538455.918930015 + 20 +185720.009259043 + 30 +0.0 + 11 +538305.634055489 + 21 +185742.7299976086 + 31 +0.0 + 0 +LINE + 5 +965 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538291.9706382603 + 20 +185370.3940992804 + 30 +0.0 + 11 +538291.9811632725 + 21 +185370.4007220331 + 31 +0.0 + 0 +LINE + 5 +966 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538407.4697143141 + 20 +185573.9977691916 + 30 +0.0 + 11 +538630.9034748751 + 21 +185701.0529010041 + 31 +0.0 + 0 +LINE + 5 +967 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538643.7165064174 + 20 +185698.4345068811 + 30 +0.0 + 11 +538630.6232893641 + 21 +185718.8874342814 + 31 +0.0 + 0 +LINE + 5 +968 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538828.9914119887 + 20 +185655.6968883955 + 30 +0.0 + 11 +538864.6653422267 + 21 +185683.6523507348 + 31 +0.0 + 0 +LINE + 5 +969 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538823.9374508764 + 20 +185641.007328742 + 30 +0.0 + 11 +538833.5465836131 + 21 +185663.0711226288 + 31 +0.0 + 0 +LINE + 5 +96A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538854.1362484448 + 20 +185584.4697084079 + 30 +0.0 + 11 +538822.132867692 + 21 +185648.7942448745 + 31 +0.0 + 0 +LINE + 5 +96B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538602.1544421794 + 20 +185633.9319450027 + 30 +0.0 + 11 +538429.8712217547 + 21 +185940.049922711 + 31 +0.0 + 0 +LINE + 5 +96C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538426.6473692368 + 20 +185796.1398550403 + 30 +0.0 + 11 +538565.0410782722 + 21 +185655.9037053136 + 31 +0.0 + 0 +LINE + 5 +96D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538447.7259734861 + 20 +185262.5988138148 + 30 +0.0 + 11 +538438.3876748164 + 21 +185962.9560360679 + 31 +0.0 + 0 +LINE + 5 +96E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538506.1371499462 + 20 +185790.9590416683 + 30 +0.0 + 11 +538580.909456926 + 21 +185846.8244362297 + 31 +0.0 + 0 +LINE + 5 +96F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538550.468505471 + 20 +185829.2493238951 + 30 +0.0 + 11 +538633.7159528389 + 21 +185833.9869128063 + 31 +0.0 + 0 +LINE + 5 +970 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538555.5145954715 + 20 +185817.1328893014 + 30 +0.0 + 11 +538592.0772762257 + 21 +185888.4583265156 + 31 +0.0 + 0 +LINE + 5 +971 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538488.7631856539 + 20 +186019.9049442931 + 30 +0.0 + 11 +538594.5091295639 + 21 +185876.0706705564 + 31 +0.0 + 0 +LINE + 5 +972 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538686.2892706148 + 20 +185437.7084670585 + 30 +0.0 + 11 +538674.7552392485 + 21 +185483.2834169584 + 31 +0.0 + 0 +LINE + 5 +973 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538616.8910471252 + 20 +185456.3749448757 + 30 +0.0 + 11 +538676.5878236505 + 21 +185482.7774546147 + 31 +0.0 + 0 +LINE + 5 +974 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538440.206655419 + 20 +185404.1982085089 + 30 +0.0 + 11 +538679.1852543343 + 21 +185583.2176504797 + 31 +0.0 + 0 +LINE + 5 +975 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538775.2948097776 + 20 +185561.4757078123 + 30 +0.0 + 11 +538708.736655484 + 21 +185714.3325515911 + 31 +0.0 + 0 +LINE + 5 +976 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538791.9701436699 + 20 +185273.5632884998 + 30 +0.0 + 11 +539046.4265204657 + 21 +185346.1284458889 + 31 +0.0 + 0 +LINE + 5 +977 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538162.3788787743 + 20 +186053.3999999256 + 30 +0.0 + 11 +538044.7831239762 + 21 +185935.7459723394 + 31 +0.0 + 0 +LINE + 5 +978 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538212.0529438026 + 20 +186139.58135618 + 30 +0.0 + 11 +538044.4452423011 + 21 +186216.7745436283 + 31 +0.0 + 0 +LINE + 5 +979 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538633.3671606733 + 20 +185449.6300558871 + 30 +0.0 + 11 +538581.2367847845 + 21 +185554.5710751908 + 31 +0.0 + 0 +LINE + 5 +97A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537816.4987150436 + 20 +185577.6609426168 + 30 +0.0 + 11 +537717.7406119495 + 21 +185405.8731977982 + 31 +0.0 + 0 +LINE + 5 +97B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536377.950798813 + 20 +183242.8256182219 + 30 +0.0 + 11 +536229.3811899697 + 21 +182702.1611796888 + 31 +0.0 + 0 +LINE + 5 +97C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536365.4089121279 + 20 +183226.3197876327 + 30 +0.0 + 11 +537156.4467427117 + 21 +183220.8547826734 + 31 +0.0 + 0 +LINE + 5 +97D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536503.2478305164 + 20 +183228.3149166955 + 30 +0.0 + 11 +536478.3100186013 + 21 +183082.589832233 + 31 +0.0 + 0 +LINE + 5 +97E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536474.4919353847 + 20 +183115.0119310109 + 30 +0.0 + 11 +536505.6155181625 + 21 +183039.1672156401 + 31 +0.0 + 0 +LINE + 5 +97F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536403.8487205204 + 20 +183078.0680301967 + 30 +0.0 + 11 +536485.5658730114 + 21 +183110.3129595501 + 31 +0.0 + 0 +LINE + 5 +980 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536416.4165601175 + 20 +183092.3428093075 + 30 +0.0 + 11 +536365.5791656758 + 21 +182900.0674543847 + 31 +0.0 + 0 +LINE + 5 +981 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536294.0688341979 + 20 +183100.2090874555 + 30 +0.0 + 11 +536690.5251339838 + 21 +182926.1929282078 + 31 +0.0 + 0 +LINE + 5 +982 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536417.6144112501 + 20 +182879.17450615 + 30 +0.0 + 11 +536506.2320532261 + 21 +183043.4509569607 + 31 +0.0 + 0 +LINE + 5 +983 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536362.6341735878 + 20 +182904.685039179 + 30 +0.0 + 11 +536418.4089345704 + 21 +182879.4700293907 + 31 +0.0 + 0 +LINE + 5 +984 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536272.9287582812 + 20 +182621.1271232333 + 30 +0.0 + 11 +536400.1994853068 + 21 +182889.7311593058 + 31 +0.0 + 0 +LINE + 5 +985 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536298.8758903715 + 20 +182684.4391589704 + 30 +0.0 + 11 +536404.1762484465 + 21 +182643.0914153091 + 31 +0.0 + 0 +LINE + 5 +986 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536368.8079794198 + 20 +182569.702787914 + 30 +0.0 + 11 +536644.0003308036 + 21 +183243.9299080776 + 31 +0.0 + 0 +LINE + 5 +987 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536649.3881379984 + 20 +183023.9949835186 + 30 +0.0 + 11 +537078.7704213867 + 21 +182931.720272395 + 31 +0.0 + 0 +LINE + 5 +988 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536674.2091429489 + 20 +183088.9068063282 + 30 +0.0 + 11 +536611.6473738665 + 21 +182905.3433481972 + 31 +0.0 + 0 +LINE + 5 +989 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536742.5770769539 + 20 +183064.4481921625 + 30 +0.0 + 11 +536721.3297337248 + 21 +183003.7506130688 + 31 +0.0 + 0 +LINE + 5 +98A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536702.3637101915 + 20 +183101.0562535959 + 30 +0.0 + 11 +536747.9830493849 + 21 +183049.5185837362 + 31 +0.0 + 0 +LINE + 5 +98B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536729.6597324148 + 20 +183058.5916108926 + 30 +0.0 + 11 +537128.3753175386 + 21 +182998.4004160958 + 31 +0.0 + 0 +LINE + 5 +98C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536850.0008617826 + 20 +183227.0485721637 + 30 +0.0 + 11 +536816.1333390501 + 21 +182821.1364078377 + 31 +0.0 + 0 +LINE + 5 +98D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536803.5247511583 + 20 +182825.4166539249 + 30 +0.0 + 11 +537039.9320133069 + 21 +182791.5436839286 + 31 +0.0 + 0 +LINE + 5 +98E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536688.0380295237 + 20 +182673.8626441143 + 30 +0.0 + 11 +536819.5071266102 + 21 +182833.9337483539 + 31 +0.0 + 0 +LINE + 5 +98F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536654.1478082748 + 20 +182754.1959332648 + 30 +0.0 + 11 +536731.1804359523 + 21 +182717.354461599 + 31 +0.0 + 0 +LINE + 5 +990 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536960.6148925918 + 20 +183238.8174719675 + 30 +0.0 + 11 +536948.4034366646 + 21 +183149.5259754921 + 31 +0.0 + 0 +LINE + 5 +991 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537112.4463272675 + 20 +183255.7881454086 + 30 +0.0 + 11 +537037.5153878978 + 21 +182789.5977295533 + 31 +0.0 + 0 +LINE + 5 +992 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536648.4888120684 + 20 +182941.0815745938 + 30 +0.0 + 11 +537064.7716752467 + 21 +182860.1877913121 + 31 +0.0 + 0 +LINE + 5 +993 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536823.8387568325 + 20 +182447.4493576788 + 30 +0.0 + 11 +537063.9672847543 + 21 +182867.1164442443 + 31 +0.0 + 0 +LINE + 5 +994 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536715.143687881 + 20 +182218.6083407707 + 30 +0.0 + 11 +536962.0622477265 + 21 +182698.1901910048 + 31 +0.0 + 0 +LINE + 5 +995 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536734.862609048 + 20 +182473.0606628711 + 30 +0.0 + 11 +536852.2707044117 + 21 +182470.854563964 + 31 +0.0 + 0 +LINE + 5 +996 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536765.411374848 + 20 +182527.1141784302 + 30 +0.0 + 11 +536834.9582748474 + 21 +182442.0916544697 + 31 +0.0 + 0 +LINE + 5 +997 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536847.6682510308 + 20 +182698.3948988279 + 30 +0.0 + 11 +536776.9087543582 + 21 +182509.1851607281 + 31 +0.0 + 0 +LINE + 5 +998 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536598.1825266714 + 20 +182709.144270706 + 30 +0.0 + 11 +536918.3005795967 + 21 +182610.0767961406 + 31 +0.0 + 0 +LINE + 5 +999 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536621.0589931053 + 20 +182799.8816461554 + 30 +0.0 + 11 +536598.5363384874 + 21 +182680.5493556573 + 31 +0.0 + 0 +LINE + 5 +99A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536503.9084506 + 20 +182718.8842404519 + 30 +0.0 + 11 +536574.3292366733 + 21 +182817.0098938511 + 31 +0.0 + 0 +LINE + 5 +99B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536568.7496874731 + 20 +182813.2358711641 + 30 +0.0 + 11 +536622.5511225131 + 21 +182798.3018000183 + 31 +0.0 + 0 +LINE + 5 +99C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536234.2614855521 + 20 +182862.0121884998 + 30 +0.0 + 11 +536757.322843783 + 21 +182654.8301815798 + 31 +0.0 + 0 +LINE + 5 +99D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536769.4380237217 + 20 +182659.7548318349 + 30 +0.0 + 11 +536760.3193647292 + 21 +182637.2469525432 + 31 +0.0 + 0 +LINE + 5 +99E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536943.7275287886 + 20 +182735.7578784313 + 30 +0.0 + 11 +536983.9247134773 + 21 +182714.8217012172 + 31 +0.0 + 0 +LINE + 5 +99F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536936.0643799653 + 20 +182749.2709031056 + 30 +0.0 + 11 +536949.5582733074 + 21 +182729.3445066654 + 31 +0.0 + 0 +LINE + 5 +9A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536955.3781314365 + 20 +182810.3892218956 + 30 +0.0 + 11 +536935.7190257515 + 21 +182741.2850835613 + 31 +0.0 + 0 +LINE + 5 +9A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536716.7476580286 + 20 +182715.5375445312 + 30 +0.0 + 11 +536582.4825053728 + 21 +182302.4635152185 + 31 +0.0 + 0 +LINE + 5 +9A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536571.9455827591 + 20 +182332.4241959598 + 30 +0.0 + 11 +536771.3499328064 + 21 +182304.9976130809 + 31 +0.0 + 0 +LINE + 5 +9A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536368.4433207431 + 20 +182589.5319674376 + 30 +0.0 + 11 +536601.4676670191 + 21 +182311.5315737302 + 31 +0.0 + 0 +LINE + 5 +9A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536468.717144629 + 20 +182355.1780411351 + 30 +0.0 + 11 +536684.2951962053 + 21 +182687.1298386529 + 31 +0.0 + 0 +LINE + 5 +9A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536564.7143357547 + 20 +182734.2287873409 + 30 +0.0 + 11 +536551.9223906497 + 21 +182701.0872745451 + 31 +0.0 + 0 +LINE + 5 +9A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536651.1685099792 + 20 +182543.560206384 + 30 +0.0 + 11 +536734.9208493266 + 21 +182502.3608634954 + 31 +0.0 + 0 +LINE + 5 +9A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536701.7722184314 + 20 +182514.0529278487 + 30 +0.0 + 11 +536784.4758630052 + 21 +182524.6684549728 + 31 +0.0 + 0 +LINE + 5 +9A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536704.5097609086 + 20 +182526.8894722722 + 30 +0.0 + 11 +536753.5373333831 + 21 +182463.4824950933 + 31 +0.0 + 0 +LINE + 5 +9A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536676.0922024562 + 20 +182315.3127737212 + 30 +0.0 + 11 +536753.655252238 + 21 +182476.1060455431 + 31 +0.0 + 0 +LINE + 5 +9AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536145.8370627403 + 20 +182567.7590615311 + 30 +0.0 + 11 +536235.94668861 + 21 +182719.6690338856 + 31 +0.0 + 0 +LINE + 5 +9AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536194.3164605139 + 20 +182671.5968735944 + 30 +0.0 + 11 +536423.0918593966 + 21 +182541.2103785556 + 31 +0.0 + 0 +LINE + 5 +9AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536763.4549964057 + 20 +182923.8660044065 + 30 +0.0 + 11 +536760.47798366 + 21 +182876.9485520774 + 31 +0.0 + 0 +LINE + 5 +9AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536698.659257292 + 20 +182892.7844502254 + 30 +0.0 + 11 +536762.1866387764 + 21 +182877.7821354124 + 31 +0.0 + 0 +LINE + 5 +9AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536684.8096896209 + 20 +182940.3633848721 + 30 +0.0 + 11 +536649.5170988597 + 21 +182842.1932464827 + 31 +0.0 + 0 +LINE + 5 +9AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536515.4013251864 + 20 +182911.6607955009 + 30 +0.0 + 11 +536783.1668954148 + 21 +182779.5232507103 + 31 +0.0 + 0 +LINE + 5 +9B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536873.6563625932 + 20 +182818.5285714787 + 30 +0.0 + 11 +536859.7281044162 + 21 +182751.1077484599 + 31 +0.0 + 0 +LINE + 5 +9B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536828.7565280112 + 20 +182758.5043269772 + 30 +0.0 + 11 +536887.58160853 + 21 +182746.1681258376 + 31 +0.0 + 0 +LINE + 5 +9B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536835.3679443507 + 20 +182764.0137310528 + 30 +0.0 + 11 +536819.9513197208 + 21 +182694.3660203783 + 31 +0.0 + 0 +LINE + 5 +9B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536817.7205730532 + 20 +182697.3397564173 + 30 +0.0 + 11 +536872.3574897433 + 21 +182684.44025529 + 31 +0.0 + 0 +LINE + 5 +9B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536884.1598861377 + 20 +182754.5306410416 + 30 +0.0 + 11 +536868.2523895976 + 21 +182678.6818483531 + 31 +0.0 + 0 +LINE + 5 +9B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536328.5762214313 + 20 +182750.1339097506 + 30 +0.0 + 11 +536433.1636098655 + 21 +182708.109527257 + 31 +0.0 + 0 +LINE + 5 +9B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536837.2278100268 + 20 +183104.6135038196 + 30 +0.0 + 11 +537100.6781857253 + 21 +183079.9629601505 + 31 +0.0 + 0 +LINE + 5 +9B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536668.1832728364 + 20 +183351.5686047555 + 30 +0.0 + 11 +537967.5584431446 + 21 +183342.5916741019 + 31 +0.0 + 0 +LINE + 5 +9B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537314.3595309493 + 20 +183350.051808124 + 30 +0.0 + 11 +537289.4217190342 + 21 +183204.3267236614 + 31 +0.0 + 0 +LINE + 5 +9B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537163.4826997652 + 20 +183284.1868211775 + 30 +0.0 + 11 +537657.9303096423 + 21 +183281.7032994896 + 31 +0.0 + 0 +LINE + 5 +9BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537285.6036358177 + 20 +183236.7488224393 + 30 +0.0 + 11 +537316.7272185955 + 21 +183160.9041070683 + 31 +0.0 + 0 +LINE + 5 +9BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537214.9604209535 + 20 +183199.8049216252 + 30 +0.0 + 11 +537296.6775734443 + 21 +183232.0498509783 + 31 +0.0 + 0 +LINE + 5 +9BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537227.239076306 + 20 +183212.280511718 + 30 +0.0 + 11 +537176.4016818643 + 21 +183020.0051567952 + 31 +0.0 + 0 +LINE + 5 +9BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537027.2468334006 + 20 +183256.1533388664 + 30 +0.0 + 11 +537501.6368344167 + 21 +183047.9298196365 + 31 +0.0 + 0 +LINE + 5 +9BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537228.7261116832 + 20 +183000.9113975783 + 30 +0.0 + 11 +537317.3437536592 + 21 +183165.187848389 + 31 +0.0 + 0 +LINE + 5 +9BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537173.7458740209 + 20 +183026.4219306075 + 30 +0.0 + 11 +537229.5206350034 + 21 +183001.206920819 + 31 +0.0 + 0 +LINE + 5 +9C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537084.0404587141 + 20 +182742.8640146615 + 30 +0.0 + 11 +537211.3111857398 + 21 +183011.4680507342 + 31 +0.0 + 0 +LINE + 5 +9C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537109.9875908043 + 20 +182806.1760503987 + 30 +0.0 + 11 +537215.2879488794 + 21 +182764.8283067376 + 31 +0.0 + 0 +LINE + 5 +9C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537179.9196798528 + 20 +182691.4396793422 + 30 +0.0 + 11 +537491.2409488954 + 21 +183379.880430458 + 31 +0.0 + 0 +LINE + 5 +9C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537460.4998384315 + 20 +183145.7318749472 + 30 +0.0 + 11 +537889.8821218196 + 21 +183053.4571638233 + 31 +0.0 + 0 +LINE + 5 +9C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537485.3208433818 + 20 +183210.643697757 + 30 +0.0 + 11 +537422.7590742995 + 21 +183027.0802396259 + 31 +0.0 + 0 +LINE + 5 +9C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537553.6887773869 + 20 +183186.1850835907 + 30 +0.0 + 11 +537532.4414341579 + 21 +183125.4875044973 + 31 +0.0 + 0 +LINE + 5 +9C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537513.4754106245 + 20 +183222.7931450241 + 30 +0.0 + 11 +537559.0947498179 + 21 +183171.2554751645 + 31 +0.0 + 0 +LINE + 5 +9C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537540.7714328479 + 20 +183180.328502321 + 30 +0.0 + 11 +537939.4870179715 + 21 +183120.1373075241 + 31 +0.0 + 0 +LINE + 5 +9C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537737.9508085389 + 20 +183602.3443691874 + 30 +0.0 + 11 +537692.0225814107 + 21 +182912.5622043346 + 31 +0.0 + 0 +LINE + 5 +9C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537614.6364515911 + 20 +182947.1535453535 + 30 +0.0 + 11 +537851.0437137399 + 21 +182913.2805753571 + 31 +0.0 + 0 +LINE + 5 +9CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537499.1497299565 + 20 +182795.5995355427 + 30 +0.0 + 11 +537630.6188270431 + 21 +182955.6706397822 + 31 +0.0 + 0 +LINE + 5 +9CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537465.2595087079 + 20 +182875.9328246934 + 30 +0.0 + 11 +537542.2921363853 + 21 +182839.0913530274 + 31 +0.0 + 0 +LINE + 5 +9CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537848.3581093194 + 20 +183349.0727886068 + 30 +0.0 + 11 +537836.146653392 + 21 +183259.7812921317 + 31 +0.0 + 0 +LINE + 5 +9CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537923.5580277004 + 20 +183377.525036837 + 30 +0.0 + 11 +537848.6270883307 + 21 +182911.3346209815 + 31 +0.0 + 0 +LINE + 5 +9CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537459.6005125013 + 20 +183062.8184660221 + 30 +0.0 + 11 +537875.8833756796 + 21 +182981.9246827404 + 31 +0.0 + 0 +LINE + 5 +9CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537698.132007023 + 20 +182681.9452738537 + 30 +0.0 + 11 +537875.0789851874 + 21 +182988.8533356727 + 31 +0.0 + 0 +LINE + 5 +9D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537409.2942271043 + 20 +182830.8811621344 + 30 +0.0 + 11 +537729.4122800297 + 21 +182731.8136875691 + 31 +0.0 + 0 +LINE + 5 +9D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537432.1706935382 + 20 +182921.6185375839 + 30 +0.0 + 11 +537409.6480389204 + 21 +182802.2862470857 + 31 +0.0 + 0 +LINE + 5 +9D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537315.020151033 + 20 +182840.6211318802 + 30 +0.0 + 11 +537385.4409371062 + 21 +182938.7467852796 + 31 +0.0 + 0 +LINE + 5 +9D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537379.8613879062 + 20 +182934.9727625926 + 30 +0.0 + 11 +537433.662822946 + 21 +182920.0386914467 + 31 +0.0 + 0 +LINE + 5 +9D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537045.3731859852 + 20 +182983.7490799281 + 30 +0.0 + 11 +537568.434544216 + 21 +182776.567073008 + 31 +0.0 + 0 +LINE + 5 +9D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537580.5497241547 + 20 +182781.4917232632 + 30 +0.0 + 11 +537571.4310651623 + 21 +182758.9838439715 + 31 +0.0 + 0 +LINE + 5 +9D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537754.8392292213 + 20 +182857.4947698596 + 30 +0.0 + 11 +537795.0364139103 + 21 +182836.5585926457 + 31 +0.0 + 0 +LINE + 5 +9D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537747.1760803985 + 20 +182871.0077945341 + 30 +0.0 + 11 +537760.6699737404 + 21 +182851.0813980939 + 31 +0.0 + 0 +LINE + 5 +9D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537766.4898318695 + 20 +182932.1261133241 + 30 +0.0 + 11 +537746.8307261844 + 21 +182863.0219749897 + 31 +0.0 + 0 +LINE + 5 +9D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537527.8593584616 + 20 +182837.2744359597 + 30 +0.0 + 11 +537424.3983140284 + 21 +182497.6427816799 + 31 +0.0 + 0 +LINE + 5 +9DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537179.5550211762 + 20 +182711.268858866 + 30 +0.0 + 11 +537307.1622224056 + 21 +182552.0738509563 + 31 +0.0 + 0 +LINE + 5 +9DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537278.1562489779 + 20 +182540.8491264896 + 30 +0.0 + 11 +537495.4068966384 + 21 +182808.8667300813 + 31 +0.0 + 0 +LINE + 5 +9DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537375.8260361876 + 20 +182855.9656787693 + 30 +0.0 + 11 +537363.0340910828 + 21 +182822.8241659735 + 31 +0.0 + 0 +LINE + 5 +9DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537008.8862652714 + 20 +182810.8703354409 + 30 +0.0 + 11 +537234.2035598295 + 21 +182662.9472699839 + 31 +0.0 + 0 +LINE + 5 +9DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537574.5666968386 + 20 +183045.6028958351 + 30 +0.0 + 11 +537571.5896840929 + 21 +182998.685443506 + 31 +0.0 + 0 +LINE + 5 +9DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537509.770957725 + 20 +183014.5213416539 + 30 +0.0 + 11 +537573.2983392094 + 21 +182999.5190268409 + 31 +0.0 + 0 +LINE + 5 +9E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537495.9213900537 + 20 +183062.1002763007 + 30 +0.0 + 11 +537460.6287992928 + 21 +182963.930137911 + 31 +0.0 + 0 +LINE + 5 +9E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537326.5130256195 + 20 +183033.3976869292 + 30 +0.0 + 11 +537594.2785958478 + 21 +182901.2601421385 + 31 +0.0 + 0 +LINE + 5 +9E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537139.6879218641 + 20 +182871.870801179 + 30 +0.0 + 11 +537244.2753102984 + 21 +182829.8464186852 + 31 +0.0 + 0 +LINE + 5 +9E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537686.437641938 + 20 +183224.7317307152 + 30 +0.0 + 11 +537911.7898861585 + 21 +183201.699851579 + 31 +0.0 + 0 +LINE + 5 +9E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537384.0731362219 + 20 +182569.6715993786 + 30 +0.0 + 11 +537341.4914932436 + 21 +182405.2948938519 + 31 +0.0 + 0 +LINE + 5 +9E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536938.2648702544 + 20 +182666.0542430234 + 30 +0.0 + 11 +537667.5375991025 + 21 +182468.4868182959 + 31 +0.0 + 0 +LINE + 5 +9E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537431.4830585261 + 20 +182461.4999882802 + 30 +0.0 + 11 +537408.8532674805 + 21 +182022.8980501202 + 31 +0.0 + 0 +LINE + 5 +9E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537499.522088195 + 20 +182447.3466328855 + 30 +0.0 + 11 +537308.3317137799 + 21 +182479.8390757421 + 31 +0.0 + 0 +LINE + 5 +9E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537486.27755914 + 20 +182375.9534913579 + 30 +0.0 + 11 +537422.9686723243 + 21 +182387.250860621 + 31 +0.0 + 0 +LINE + 5 +9E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537516.0053030976 + 20 +182421.4894800645 + 30 +0.0 + 11 +537472.4009309577 + 21 +182368.2361773191 + 31 +0.0 + 0 +LINE + 5 +9EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537478.4362537891 + 20 +182387.7717511494 + 30 +0.0 + 11 +537482.5897499209 + 21 +181984.5598388484 + 31 +0.0 + 0 +LINE + 5 +9EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537663.9262350628 + 20 +182295.8304543059 + 30 +0.0 + 11 +537257.8070860278 + 21 +182264.5425807582 + 31 +0.0 + 0 +LINE + 5 +9EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537260.0221507038 + 20 +182277.6723364173 + 30 +0.0 + 11 +537264.2773369267 + 21 +182038.8886161115 + 31 +0.0 + 0 +LINE + 5 +9ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537091.9928968431 + 20 +182367.516482641 + 30 +0.0 + 11 +537270.978645964 + 21 +182263.2524739281 + 31 +0.0 + 0 +LINE + 5 +9EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537165.8946748286 + 20 +182413.7821465039 + 30 +0.0 + 11 +537141.8072843549 + 21 +182331.8607367166 + 31 +0.0 + 0 +LINE + 5 +9EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537734.1446683246 + 20 +182041.325135984 + 30 +0.0 + 11 +537261.9709512213 + 21 +182040.9640442066 + 31 +0.0 + 0 +LINE + 5 +9F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537349.4870275742 + 20 +182449.1673861692 + 30 +0.0 + 11 +537336.0038760495 + 21 +182025.3119497591 + 31 +0.0 + 0 +LINE + 5 +9F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536890.1295156216 + 20 +182197.3518883977 + 30 +0.0 + 11 +537342.7156265724 + 21 +182027.2108126912 + 31 +0.0 + 0 +LINE + 5 +9F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536682.7253259366 + 20 +182256.4761466977 + 30 +0.0 + 11 +537159.7019654085 + 21 +182100.8770561987 + 31 +0.0 + 0 +LINE + 5 +9F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536901.2260387822 + 20 +182289.2733820865 + 30 +0.0 + 11 +536917.7687139625 + 21 +182173.0156183581 + 31 +0.0 + 0 +LINE + 5 +9F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536959.4589628925 + 20 +182267.73420416 + 30 +0.0 + 11 +536886.6133485277 + 21 +182185.5203528457 + 31 +0.0 + 0 +LINE + 5 +9F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537141.6640981017 + 20 +182213.8401640188 + 30 +0.0 + 11 +536943.5925651405 + 21 +182253.5251635965 + 31 +0.0 + 0 +LINE + 5 +9F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537107.0946065559 + 20 +182428.0514063887 + 30 +0.0 + 11 +537065.7381378544 + 21 +182130.0292956218 + 31 +0.0 + 0 +LINE + 5 +9F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537040.3370718799 + 20 +182490.194963187 + 30 +0.0 + 11 +537151.8275639878 + 21 +182442.0562501154 + 31 +0.0 + 0 +LINE + 5 +9F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537173.0343628435 + 20 +182541.9275284717 + 30 +0.0 + 11 +537052.3031853124 + 21 +182538.504994595 + 31 +0.0 + 0 +LINE + 5 +9F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537058.5538632543 + 20 +182541.0157000306 + 30 +0.0 + 11 +537040.8108937336 + 21 +182488.0741480516 + 31 +0.0 + 0 +LINE + 5 +9FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537205.3812923094 + 20 +182845.4876896032 + 30 +0.0 + 11 +537205.378614935 + 21 +182845.4755459459 + 31 +0.0 + 0 +LINE + 5 +9FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537173.8687728678 + 20 +182702.5576632234 + 30 +0.0 + 11 +537084.2512937638 + 21 +182296.0833831784 + 31 +0.0 + 0 +LINE + 5 +9FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537091.0446870241 + 20 +182284.9084302434 + 30 +0.0 + 11 +537067.3708112243 + 21 +182290.3215787412 + 31 +0.0 + 0 +LINE + 5 +9FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537193.8655766623 + 20 +182124.9673181983 + 30 +0.0 + 11 +537179.6066344044 + 21 +182081.9461636468 + 31 +0.0 + 0 +LINE + 5 +9FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537205.983841036 + 20 +182134.6870586424 + 30 +0.0 + 11 +537188.4639597507 + 21 +182118.1885680334 + 31 +0.0 + 0 +LINE + 5 +9FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537269.3997763168 + 20 +182125.365629562 + 30 +0.0 + 11 +537198.0451239174 + 21 +182133.7546671835 + 31 +0.0 + 0 +LINE + 5 +A00 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537137.7123270689 + 20 +182345.8191603759 + 30 +0.0 + 11 +536791.3878001819 + 21 +182404.5477427922 + 31 +0.0 + 0 +LINE + 5 +A01 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536837.6140617653 + 20 +182493.2880969794 + 30 +0.0 + 11 +537104.4935647696 + 21 +182373.3268658957 + 31 +0.0 + 0 +LINE + 5 +A02 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537131.9229468348 + 20 +182498.8876963849 + 30 +0.0 + 11 +537097.1657815568 + 21 +182506.2316184839 + 31 +0.0 + 0 +LINE + 5 +A03 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536957.4787259281 + 20 +182383.1377685347 + 30 +0.0 + 11 +536930.1606660249 + 21 +182293.8877612312 + 31 +0.0 + 0 +LINE + 5 +A04 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536936.4176440107 + 20 +182328.4765791578 + 30 +0.0 + 11 +536960.0843342996 + 21 +182248.5236554292 + 31 +0.0 + 0 +LINE + 5 +A05 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536949.5264579374 + 20 +182327.82082845 + 30 +0.0 + 11 +536894.7480693696 + 21 +182269.3103527759 + 31 +0.0 + 0 +LINE + 5 +A06 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536736.1254824033 + 20 +182322.1392231021 + 30 +0.0 + 11 +536907.2289191453 + 21 +182271.2067492784 + 31 +0.0 + 0 +LINE + 5 +A07 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537350.8228998787 + 20 +182332.9270539126 + 30 +0.0 + 11 +537304.0310177877 + 21 +182328.3850600403 + 31 +0.0 + 0 +LINE + 5 +A08 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537309.8074093944 + 20 +182391.9379034063 + 30 +0.0 + 11 +537305.126379028 + 21 +182326.8311786943 + 31 +0.0 + 0 +LINE + 5 +A09 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537354.5693372198 + 20 +182413.1966748707 + 30 +0.0 + 11 +537252.0278117451 + 21 +182432.3846551545 + 31 +0.0 + 0 +LINE + 5 +A0A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537299.2220449141 + 20 +182575.8610834282 + 30 +0.0 + 11 +537211.4698661906 + 21 +182290.4521023634 + 31 +0.0 + 0 +LINE + 5 +A0B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537264.4045760152 + 20 +182207.3396772141 + 30 +0.0 + 11 +537195.625478288 + 21 +182210.3395885852 + 31 +0.0 + 0 +LINE + 5 +A0C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537197.9890540169 + 20 +182242.0942957727 + 30 +0.0 + 11 +537195.1902526674 + 21 +182182.054819862 + 31 +0.0 + 0 +LINE + 5 +A0D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537204.4821528088 + 20 +182236.4459307558 + 30 +0.0 + 11 +537133.2673398275 + 21 +182240.5600927853 + 31 +0.0 + 0 +LINE + 5 +A0E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537135.8473412971 + 20 +182243.2364576972 + 30 +0.0 + 11 +537131.8246500621 + 21 +182187.2417458936 + 31 +0.0 + 0 +LINE + 5 +A0F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537202.9001912149 + 20 +182186.7661564309 + 30 +0.0 + 11 +537125.4853625582 + 21 +182190.3761567784 + 31 +0.0 + 0 +LINE + 5 +A10 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537541.020926995 + 20 +182288.917997405 + 30 +0.0 + 11 +537558.6925351086 + 21 +182024.9076490744 + 31 +0.0 + 0 +LINE + 5 +A11 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536709.6910170015 + 20 +183412.2770954969 + 30 +0.0 + 11 +536848.0824291129 + 21 +183411.5819802481 + 31 +0.0 + 0 +LINE + 5 +A12 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536652.0278052007 + 20 +183549.5298098701 + 30 +0.0 + 11 +537082.31535887 + 21 +183637.4865535445 + 31 +0.0 + 0 +LINE + 5 +A13 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536731.9478128749 + 20 +183514.1285688017 + 30 +0.0 + 11 +537131.2479242355 + 21 +183570.3114738424 + 31 +0.0 + 0 +LINE + 5 +A14 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536850.5906547582 + 20 +183344.4712338936 + 30 +0.0 + 11 +536824.9151047095 + 21 +183694.6167044956 + 31 +0.0 + 0 +LINE + 5 +A15 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537037.8238678751 + 20 +183342.3029692122 + 30 +0.0 + 11 +537026.5099958148 + 21 +183431.7126291917 + 31 +0.0 + 0 +LINE + 5 +A16 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537112.7341780836 + 20 +183313.0967442194 + 30 +0.0 + 11 +537042.4900830331 + 21 +183780.0163482421 + 31 +0.0 + 0 +LINE + 5 +A17 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536651.9614220067 + 20 +183632.4480693786 + 30 +0.0 + 11 +537069.0358905775 + 21 +183709.1560482073 + 31 +0.0 + 0 +LINE + 5 +A18 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536878.5293577574 + 20 +184041.5140416933 + 30 +0.0 + 11 +537068.1619396648 + 21 +183702.2358252833 + 31 +0.0 + 0 +LINE + 5 +A19 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536767.0947426709 + 20 +183648.50789101 + 30 +0.0 + 11 +536764.5891841443 + 21 +183695.4528813116 + 31 +0.0 + 0 +LINE + 5 +A1A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536702.6144991729 + 20 +183680.2387752721 + 30 +0.0 + 11 +536766.2893793806 + 21 +183694.6021759327 + 31 +0.0 + 0 +LINE + 5 +A1B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537027.5353145481 + 20 +183313.5874311575 + 30 +0.0 + 11 +537503.9930656886 + 21 +183517.0350126194 + 31 +0.0 + 0 +LINE + 5 +A1C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537089.482264669 + 20 +183826.2803427426 + 30 +0.0 + 11 +537251.0272936064 + 21 +183476.297487684 + 31 +0.0 + 0 +LINE + 5 +A1D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537185.8732255069 + 20 +183876.7389394128 + 30 +0.0 + 11 +537490.2631320349 + 21 +183185.2055814617 + 31 +0.0 + 0 +LINE + 5 +A1E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537461.8756857302 + 20 +183419.6511291113 + 30 +0.0 + 11 +537892.1632393996 + 21 +183507.607872786 + 31 +0.0 + 0 +LINE + 5 +A1F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537486.0433738643 + 20 +183354.4932448803 + 30 +0.0 + 11 +537425.3287275618 + 21 +183538.6758983417 + 31 +0.0 + 0 +LINE + 5 +A20 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537554.6535545524 + 20 +183378.2638425367 + 30 +0.0 + 11 +537534.0170141136 + 21 +183439.1717968681 + 31 +0.0 + 0 +LINE + 5 +A21 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537514.0744746237 + 20 +183342.0615870769 + 30 +0.0 + 11 +537560.2092279274 + 21 +183393.1383925819 + 31 +0.0 + 0 +LINE + 5 +A22 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537705.0470616232 + 20 +183407.2199194994 + 30 +0.0 + 11 +537941.0958047653 + 21 +183440.4327930841 + 31 +0.0 + 0 +LINE + 5 +A23 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537469.3453519826 + 20 +183689.3887536004 + 30 +0.0 + 11 +537546.7441797636 + 21 +183725.4545437557 + 31 +0.0 + 0 +LINE + 5 +A24 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537902.141134846 + 20 +183314.4141268921 + 30 +0.0 + 11 +537846.9844232049 + 21 +183524.1326304348 + 31 +0.0 + 0 +LINE + 5 +A25 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537461.8093025364 + 20 +183502.5693886199 + 30 +0.0 + 11 +537878.883771107 + 21 +183579.2773674488 + 31 +0.0 + 0 +LINE + 5 +A26 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537413.8354556022 + 20 +183735.0003359903 + 30 +0.0 + 11 +537734.9325278087 + 21 +183830.847101955 + 31 +0.0 + 0 +LINE + 5 +A27 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537435.7992756382 + 20 +183644.037735822 + 30 +0.0 + 11 +537414.4764965815 + 21 +183763.5902540719 + 31 +0.0 + 0 +LINE + 5 +A28 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537383.3584609629 + 20 +183631.2096518854 + 30 +0.0 + 11 +537437.3071999261 + 21 +183645.6025132274 + 31 +0.0 + 0 +LINE + 5 +A29 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537048.3971590088 + 20 +183585.795859373 + 30 +0.0 + 11 +537573.5133491979 + 21 +183787.7130584098 + 31 +0.0 + 0 +LINE + 5 +A2A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537585.5784478287 + 20 +183782.666954951 + 30 +0.0 + 11 +537576.6863493082 + 21 +183805.2652990483 + 31 +0.0 + 0 +LINE + 5 +A2B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537532.3303816995 + 20 +183727.4163520024 + 30 +0.0 + 11 +537432.2862892464 + 21 +184068.0701760955 + 31 +0.0 + 0 +LINE + 5 +A2C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537185.3093934284 + 20 +183856.9144235318 + 30 +0.0 + 11 +537314.5093317011 + 21 +184014.8195352259 + 31 +0.0 + 0 +LINE + 5 +A2D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537285.6175785159 + 20 +184026.3350695925 + 30 +0.0 + 11 +537500.1649237304 + 21 +183756.1486221057 + 31 +0.0 + 0 +LINE + 5 +A2E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537013.6487133441 + 20 +183759.0324063326 + 30 +0.0 + 11 +537240.4405838322 + 21 +183904.6846085185 + 31 +0.0 + 0 +LINE + 5 +A2F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537576.9426232004 + 20 +183518.6292102514 + 30 +0.0 + 11 +537574.4370646741 + 21 +183565.574200553 + 31 +0.0 + 0 +LINE + 5 +A30 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537512.4623797024 + 20 +183550.3600945134 + 30 +0.0 + 11 +537576.1372599103 + 21 +183564.723495174 + 31 +0.0 + 0 +LINE + 5 +A31 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537498.1355619702 + 20 +183502.9226847985 + 30 +0.0 + 11 +537463.8309090649 + 21 +183601.4423976639 + 31 +0.0 + 0 +LINE + 5 +A32 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537143.8309968407 + 20 +183696.7210650589 + 30 +0.0 + 11 +537248.8352594203 + 21 +183737.6927062702 + 31 +0.0 + 0 +LINE + 5 +A33 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537391.2395886763 + 20 +183996.4500747515 + 30 +0.0 + 11 +537350.3113219837 + 21 +184161.2462355808 + 31 +0.0 + 0 +LINE + 5 +A34 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536944.4856154441 + 20 +183904.550611194 + 30 +0.0 + 11 +537675.7061894037 + 21 +184094.7822399344 + 31 +0.0 + 0 +LINE + 5 +A35 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537439.7337446563 + 20 +184104.1399768607 + 30 +0.0 + 11 +537372.4735154652 + 21 +184620.2113384158 + 31 +0.0 + 0 +LINE + 5 +A36 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537507.9115172814 + 20 +184117.6091396818 + 30 +0.0 + 11 +537316.4043904086 + 21 +184087.038917755 + 31 +0.0 + 0 +LINE + 5 +A37 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537530.3843034036 + 20 +184042.9295421691 + 30 +0.0 + 11 +537481.5864236921 + 21 +184196.9880461829 + 31 +0.0 + 0 +LINE + 5 +A38 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537487.4251995858 + 20 +184177.3928308839 + 30 +0.0 + 11 +537546.7828506184 + 21 +184491.519098808 + 31 +0.0 + 0 +LINE + 5 +A39 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537248.15088338 + 20 +184109.0374778735 + 30 +0.0 + 11 +537276.7817548089 + 21 +184528.4096720155 + 31 +0.0 + 0 +LINE + 5 +A3A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537048.3192415882 + 20 +184079.3756629772 + 30 +0.0 + 11 +537160.2876803599 + 21 +184126.3919819062 + 31 +0.0 + 0 +LINE + 5 +A3B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537180.4901634646 + 20 +184026.3127121513 + 30 +0.0 + 11 +537059.7994582482 + 21 +184030.9478648575 + 31 +0.0 + 0 +LINE + 5 +A3C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537066.0245997946 + 20 +184028.3744956174 + 30 +0.0 + 11 +537048.8143439454 + 21 +184081.4916113799 + 31 +0.0 + 0 +LINE + 5 +A3D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537209.7860812404 + 20 +183722.4429300512 + 30 +0.0 + 11 +537209.7835259888 + 21 +183722.4550999909 + 31 +0.0 + 0 +LINE + 5 +A3E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537179.7109393662 + 20 +183865.6823002111 + 30 +0.0 + 11 +537053.7451530563 + 21 +184905.0558512203 + 31 +0.0 + 0 +LINE + 5 +A3F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537285.7407702143 + 20 +184285.4650785877 + 30 +0.0 + 11 +536927.6087474007 + 21 +184218.7015045664 + 31 +0.0 + 0 +LINE + 5 +A40 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536902.8055636038 + 20 +184075.8875942751 + 30 +0.0 + 11 +537153.0466786208 + 21 +184181.3882749635 + 31 +0.0 + 0 +LINE + 5 +A41 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537139.813173592 + 20 +184069.7633527361 + 30 +0.0 + 11 +537104.983989481 + 21 +184062.768950393 + 31 +0.0 + 0 +LINE + 5 +A42 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537462.5493017278 + 20 +184340.4592014045 + 30 +0.0 + 11 +537313.6253257588 + 21 +184238.528493825 + 31 +0.0 + 0 +LINE + 5 +A43 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537318.7630129435 + 20 +184174.9208309981 + 30 +0.0 + 11 +537314.7362410721 + 21 +184240.0712934394 + 31 +0.0 + 0 +LINE + 5 +A44 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537306.3306028621 + 20 +183991.1132651308 + 30 +0.0 + 11 +537239.5962059187 + 21 +184216.1875198294 + 31 +0.0 + 0 +LINE + 5 +A45 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536991.7276180069 + 20 +183956.6673871777 + 30 +0.0 + 11 +537153.3126790687 + 21 +183823.7473975823 + 31 +0.0 + 0 +LINE + 5 +A46 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537330.8101336117 + 20 +184188.0289479002 + 30 +0.0 + 11 +537214.2964619126 + 21 +184175.5887738653 + 31 +0.0 + 0 +LINE + 5 +A47 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536850.2916572344 + 20 +183348.5487562232 + 30 +0.0 + 11 +536977.0885638939 + 21 +183196.2768393831 + 31 +0.0 + 0 +LINE + 5 +A48 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538506.0844988089 + 20 +185996.3447167731 + 30 +0.0 + 11 +538433.2870751908 + 21 +186284.3947174916 + 31 +0.0 + 0 +LINE + 5 +A49 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538236.611476903 + 20 +186108.6966083801 + 30 +0.0 + 11 +538501.3841818756 + 21 +186090.1734869714 + 31 +0.0 + 0 +LINE + 5 +A4A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538247.6415314158 + 20 +186382.4893745176 + 30 +0.0 + 11 +538312.4594926409 + 21 +186052.7036418829 + 31 +0.0 + 0 +LINE + 5 +A4B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538263.2903968339 + 20 +185969.8818847871 + 30 +0.0 + 11 +538438.7877884853 + 21 +185924.2067003186 + 31 +0.0 + 0 +LINE + 5 +A4C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538302.4828347366 + 20 +185505.6609571547 + 30 +0.0 + 11 +538466.5488707956 + 21 +185498.6903299007 + 31 +0.0 + 0 +LINE + 5 +A4D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538307.9656860152 + 20 +186110.5507529264 + 30 +0.0 + 11 +538266.9062898205 + 21 +185870.3496443443 + 31 +0.0 + 0 +LINE + 5 +A4E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538508.4634052267 + 20 +186118.2405843548 + 30 +0.0 + 11 +538511.3285463617 + 21 +185828.1582219318 + 31 +0.0 + 0 +LINE + 5 +A4F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537396.4745148345 + 20 +184361.1420230591 + 30 +0.0 + 11 +536955.6363053342 + 21 +184369.5511270819 + 31 +0.0 + 0 +LINE + 5 +A50 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536878.220237347 + 20 +184474.6403155652 + 30 +0.0 + 11 +536764.0290457257 + 21 +184811.8648697378 + 31 +0.0 + 0 +LINE + 5 +A51 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536952.1839728251 + 20 +183640.2609312836 + 30 +0.0 + 11 +536790.915974635 + 21 +183915.5375969097 + 31 +0.0 + 0 +LINE + 5 +A52 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537476.9348578087 + 20 +186223.2748301299 + 30 +0.0 + 11 +537711.5158275844 + 21 +186252.9584421817 + 31 +0.0 + 0 +LINE + 5 +A53 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538395.4387740356 + 20 +184744.9613180355 + 30 +0.0 + 11 +538432.9385039107 + 21 +184349.3462321565 + 31 +0.0 + 0 +LINE + 5 +A54 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +539877.8866788756 + 20 +184891.7611603959 + 30 +0.0 + 11 +537310.6239412522 + 21 +184351.3091305436 + 31 +0.0 + 0 +LINE + 5 +A55 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537814.5552439405 + 20 +183508.1585503803 + 30 +0.0 + 11 +537814.8800670928 + 21 +183262.9120091844 + 31 +0.0 + 0 +LINE + 5 +A56 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537809.8786362737 + 20 +183474.8905254279 + 30 +0.0 + 11 +538029.4514137471 + 21 +183575.6202981426 + 31 +0.0 + 0 +LINE + 5 +A57 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537711.3315735654 + 20 +183935.324224936 + 30 +0.0 + 11 +538015.7214800934 + 21 +183243.7908669849 + 31 +0.0 + 0 +LINE + 5 +A58 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537987.3340337887 + 20 +183478.2364146344 + 30 +0.0 + 11 +538417.6215874582 + 21 +183566.1931583092 + 31 +0.0 + 0 +LINE + 5 +A59 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538011.5017219228 + 20 +183413.0785304034 + 30 +0.0 + 11 +537950.7870756203 + 21 +183597.2611838649 + 31 +0.0 + 0 +LINE + 5 +A5A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538080.1119026109 + 20 +183436.8491280599 + 30 +0.0 + 11 +538059.475362172 + 21 +183497.7570823913 + 31 +0.0 + 0 +LINE + 5 +A5B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538067.254041463 + 20 +183442.8351735665 + 30 +0.0 + 11 +538466.5541528236 + 21 +183499.0180786073 + 31 +0.0 + 0 +LINE + 5 +A5C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538177.7383998855 + 20 +183382.9089995929 + 30 +0.0 + 11 +538156.1086146076 + 21 +183679.4097346112 + 31 +0.0 + 0 +LINE + 5 +A5D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538143.4576661646 + 20 +183675.2563626459 + 30 +0.0 + 11 +538380.1932672301 + 21 +183706.7528208766 + 31 +0.0 + 0 +LINE + 5 +A5E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538029.4991903743 + 20 +183827.9628345427 + 30 +0.0 + 11 +538159.3536776889 + 21 +183666.5791487954 + 31 +0.0 + 0 +LINE + 5 +A5F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537994.8037000412 + 20 +183747.9740391237 + 30 +0.0 + 11 +538072.202527822 + 21 +183784.0398292791 + 31 +0.0 + 0 +LINE + 5 +A60 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538427.5994829046 + 20 +183372.9994124152 + 30 +0.0 + 11 +538377.7963116212 + 21 +183708.7229530068 + 31 +0.0 + 0 +LINE + 5 +A61 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537987.2676505948 + 20 +183561.1546741433 + 30 +0.0 + 11 +538404.3421191655 + 21 +183637.8626529719 + 31 +0.0 + 0 +LINE + 5 +A62 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538136.6781661074 + 20 +184104.6134311353 + 30 +0.0 + 11 +538403.4681682527 + 21 +183630.9424300478 + 31 +0.0 + 0 +LINE + 5 +A63 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538078.3385411136 + 20 +184028.2843130171 + 30 +0.0 + 11 +538195.7628736324 + 21 +184029.3108907458 + 31 +0.0 + 0 +LINE + 5 +A64 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538108.3427770053 + 20 +183973.9266505879 + 30 +0.0 + 11 +538178.740252172 + 21 +184058.2462590448 + 31 +0.0 + 0 +LINE + 5 +A65 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538188.8749215336 + 20 +183801.8282701278 + 30 +0.0 + 11 +538120.0196803401 + 21 +183991.7392680226 + 31 +0.0 + 0 +LINE + 5 +A66 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537939.2938036606 + 20 +183793.5856215137 + 30 +0.0 + 11 +538260.3908758672 + 21 +183889.432387478 + 31 +0.0 + 0 +LINE + 5 +A67 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537961.2576236966 + 20 +183702.6230213453 + 30 +0.0 + 11 +537939.9348446399 + 21 +183822.175539595 + 31 +0.0 + 0 +LINE + 5 +A68 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537908.8168090213 + 20 +183689.7949374087 + 30 +0.0 + 11 +537962.7655479845 + 21 +183704.1877987506 + 31 +0.0 + 0 +LINE + 5 +A69 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537206.4826825364 + 20 +183499.6604219087 + 30 +0.0 + 11 +538098.9716972564 + 21 +183846.2983439329 + 31 +0.0 + 0 +LINE + 5 +A6A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538111.0367958871 + 20 +183841.2522404741 + 30 +0.0 + 11 +538102.1446973668 + 21 +183863.8505845716 + 31 +0.0 + 0 +LINE + 5 +A6B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538284.5540268816 + 20 +183763.5022230059 + 30 +0.0 + 11 +538324.9594953962 + 21 +183784.0335475451 + 31 +0.0 + 0 +LINE + 5 +A6C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538276.7555211362 + 20 +183750.06685945 + 30 +0.0 + 11 +538290.4489020112 + 21 +183769.8566990866 + 31 +0.0 + 0 +LINE + 5 +A6D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538295.4543408857 + 20 +183688.7576103305 + 30 +0.0 + 11 +538276.4904050032 + 21 +183758.0557452773 + 31 +0.0 + 0 +LINE + 5 +A6E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538057.7887297581 + 20 +183786.0016375257 + 30 +0.0 + 11 +537957.7446373048 + 21 +184126.6554616186 + 31 +0.0 + 0 +LINE + 5 +A6F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537710.7677414869 + 20 +183915.499709055 + 30 +0.0 + 11 +537839.9676797596 + 21 +184073.4048207491 + 31 +0.0 + 0 +LINE + 5 +A70 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537811.0759265745 + 20 +184084.9203551157 + 30 +0.0 + 11 +538025.6232717888 + 21 +183814.7339076289 + 31 +0.0 + 0 +LINE + 5 +A71 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537905.5753177196 + 20 +183768.8385715097 + 30 +0.0 + 11 +537893.116937401 + 21 +183802.1069121628 + 31 +0.0 + 0 +LINE + 5 +A72 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537993.940469664 + 20 +183958.6290663373 + 30 +0.0 + 11 +538078.1024465711 + 21 +183998.9850057228 + 31 +0.0 + 0 +LINE + 5 +A73 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538044.8380369068 + 20 +183987.6265221644 + 30 +0.0 + 11 +538127.4308714822 + 21 +183976.1807404638 + 31 +0.0 + 0 +LINE + 5 +A74 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538047.4464931892 + 20 +183974.7631257476 + 30 +0.0 + 11 +538097.1085396048 + 21 +184037.6744026663 + 31 +0.0 + 0 +LINE + 5 +A75 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538041.0278774243 + 20 +184137.8688116774 + 30 +0.0 + 11 +538097.0996440481 + 21 +184025.0503046117 + 31 +0.0 + 0 +LINE + 5 +A76 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537463.9253455385 + 20 +183879.6009256452 + 30 +0.0 + 11 +537765.8989318906 + 21 +183963.2698940417 + 31 +0.0 + 0 +LINE + 5 +A77 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538102.4009712589 + 20 +183577.2144957746 + 30 +0.0 + 11 +538099.8954127324 + 21 +183624.1594860762 + 31 +0.0 + 0 +LINE + 5 +A78 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538037.9207277609 + 20 +183608.9453800368 + 30 +0.0 + 11 +538101.5956079687 + 21 +183623.3087806971 + 31 +0.0 + 0 +LINE + 5 +A79 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538023.5939100288 + 20 +183561.5079703217 + 30 +0.0 + 11 +537989.2892571234 + 21 +183660.0276831871 + 31 +0.0 + 0 +LINE + 5 +A7A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537854.4824219396 + 20 +183591.9108842141 + 30 +0.0 + 11 +538123.5618546408 + 21 +183721.3519528138 + 31 +0.0 + 0 +LINE + 5 +A7B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538213.6549324865 + 20 +183681.4395983006 + 30 +0.0 + 11 +538200.4046453999 + 21 +183748.9969342792 + 31 +0.0 + 0 +LINE + 5 +A7C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538169.3603302017 + 20 +183741.9118504657 + 30 +0.0 + 11 +538228.306364558 + 21 +183753.6565084122 + 31 +0.0 + 0 +LINE + 5 +A7D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538175.916068853 + 20 +183736.3363101316 + 30 +0.0 + 11 +538161.1998603613 + 21 +183806.1353726237 + 31 +0.0 + 0 +LINE + 5 +A7E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538158.9393539165 + 20 +183803.1841953439 + 30 +0.0 + 11 +538213.7030943297 + 21 +183815.5341965869 + 31 +0.0 + 0 +LINE + 5 +A7F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538224.8008101031 + 20 +183745.3287876775 + 30 +0.0 + 11 +538209.6560467433 + 21 +183821.3335502998 + 31 +0.0 + 0 +LINE + 5 +A80 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537669.289344899 + 20 +183755.306350582 + 30 +0.0 + 11 +537774.2936074787 + 21 +183796.2779917936 + 31 +0.0 + 0 +LINE + 5 +A81 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538145.3254268677 + 20 +184062.9117186055 + 30 +0.0 + 11 +538200.5195342072 + 21 +184558.2110496839 + 31 +0.0 + 0 +LINE + 5 +A82 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538095.2648878094 + 20 +184110.0597751467 + 30 +0.0 + 11 +538132.635675242 + 21 +184334.2760301617 + 31 +0.0 + 0 +LINE + 5 +A83 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537916.6979367347 + 20 +184055.0353602746 + 30 +0.0 + 11 +537875.7696700422 + 21 +184219.831521104 + 31 +0.0 + 0 +LINE + 5 +A84 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537591.4353194408 + 20 +183994.7426366546 + 30 +0.0 + 11 +538201.1645374622 + 21 +184153.3675254576 + 31 +0.0 + 0 +LINE + 5 +A85 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538033.3698653398 + 20 +184176.194425205 + 30 +0.0 + 11 +537841.8627384671 + 21 +184145.6242032781 + 31 +0.0 + 0 +LINE + 5 +A86 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538020.8431763577 + 20 +184247.7170109398 + 30 +0.0 + 11 +537957.4239974094 + 21 +184237.0561740283 + 31 +0.0 + 0 +LINE + 5 +A87 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538050.1119936939 + 20 +184201.8846930842 + 30 +0.0 + 11 +538007.0447717504 + 21 +184255.5733317061 + 31 +0.0 + 0 +LINE + 5 +A88 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538012.8835476444 + 20 +184235.978116407 + 30 +0.0 + 11 +538072.241198677 + 21 +184550.104384331 + 31 +0.0 + 0 +LINE + 5 +A89 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537773.6092314384 + 20 +184167.6227633967 + 30 +0.0 + 11 +537765.0484060659 + 21 +184477.7323845723 + 31 +0.0 + 0 +LINE + 5 +A8A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537735.2444292989 + 20 +183781.0282155746 + 30 +0.0 + 11 +537735.2418740472 + 21 +183781.0403855143 + 31 +0.0 + 0 +LINE + 5 +A8B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537469.4126087932 + 20 +184179.279231093 + 30 +0.0 + 11 +537866.2284132929 + 21 +184257.6630007943 + 31 +0.0 + 0 +LINE + 5 +A8C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537988.0076497864 + 20 +184399.0444869277 + 30 +0.0 + 11 +537839.0836738173 + 21 +184297.1137793482 + 31 +0.0 + 0 +LINE + 5 +A8D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537844.221361002 + 20 +184233.5061165213 + 30 +0.0 + 11 +537840.1945891305 + 21 +184298.6565789625 + 31 +0.0 + 0 +LINE + 5 +A8E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +537831.7889509204 + 20 +184049.6985506539 + 30 +0.0 + 11 +537765.0545539771 + 21 +184274.7728053526 + 31 +0.0 + 0 +LINE + 5 +A8F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538221.7561228781 + 20 +184374.5939745554 + 30 +0.0 + 11 +537966.4165705449 + 21 +184395.8313820429 + 31 +0.0 + 0 +LINE + 5 +A90 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538569.6906192152 + 20 +184388.2048046587 + 30 +0.0 + 11 +538765.456750482 + 21 +184320.5106117761 + 31 +0.0 + 0 +LINE + 5 +A91 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538404.532960823 + 20 +184182.2248015356 + 30 +0.0 + 11 +538881.4736310778 + 21 +184102.7907375266 + 31 +0.0 + 0 +LINE + 5 +A92 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538152.1867049226 + 20 +184204.6791144183 + 30 +0.0 + 11 +538687.6709561274 + 21 +184139.6857072004 + 31 +0.0 + 0 +LINE + 5 +A93 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538397.6492191518 + 20 +184274.5573956118 + 30 +0.0 + 11 +538436.3555897182 + 21 +184163.6910589407 + 31 +0.0 + 0 +LINE + 5 +A94 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538458.9476493293 + 20 +184264.6825743995 + 30 +0.0 + 11 +538403.3704857294 + 21 +184169.9367050105 + 31 +0.0 + 0 +LINE + 5 +A95 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538648.1345476928 + 20 +184247.0304825434 + 30 +0.0 + 11 +538446.1275750394 + 21 +184247.6741909795 + 31 +0.0 + 0 +LINE + 5 +A96 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538563.296467749 + 20 +184671.2499932127 + 30 +0.0 + 11 +538589.843897729 + 21 +184150.1222103075 + 31 +0.0 + 0 +LINE + 5 +A97 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538584.7306784826 + 20 +184306.9718923631 + 30 +0.0 + 11 +538560.4569171519 + 21 +184307.7061150138 + 31 +0.0 + 0 +LINE + 5 +A98 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538618.7422043328 + 20 +184375.7556243205 + 30 +0.0 + 11 +538184.7499534075 + 21 +184358.2053808167 + 31 +0.0 + 0 +LINE + 5 +A99 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538209.1863556376 + 20 +184378.4916169066 + 30 +0.0 + 11 +538252.7188863369 + 21 +184181.9738542562 + 31 +0.0 + 0 +LINE + 5 +A9A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538177.4047095581 + 20 +184483.9306901377 + 30 +0.0 + 11 +538580.8321489674 + 21 +184396.3222899192 + 31 +0.0 + 0 +LINE + 5 +A9B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538434.6941270173 + 20 +184377.5261416259 + 30 +0.0 + 11 +538425.1458909358 + 21 +184284.6785709076 + 31 +0.0 + 0 +LINE + 5 +A9C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538424.5978688746 + 20 +184319.8244920206 + 30 +0.0 + 11 +538463.2751436005 + 21 +184245.9553464877 + 31 +0.0 + 0 +LINE + 5 +A9D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538437.5861508965 + 20 +184321.7154022971 + 30 +0.0 + 11 +538395.1528567 + 21 +184253.718614422 + 31 +0.0 + 0 +LINE + 5 +A9E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538229.3095326769 + 20 +184274.8847787577 + 30 +0.0 + 11 +538407.0316221425 + 21 +184257.9921214577 + 31 +0.0 + 0 +LINE + 5 +A9F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538422.7037947091 + 20 +183903.0013639225 + 30 +0.0 + 11 +538370.1283136902 + 21 +183671.8726575186 + 31 +0.0 + 0 +LINE + 5 +AA0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538491.7553693318 + 20 +183849.7673101204 + 30 +0.0 + 11 +538406.5676464476 + 21 +183843.9045777167 + 31 +0.0 + 0 +LINE + 5 +AA1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538283.0786125945 + 20 +184054.7207939183 + 30 +0.0 + 11 +538179.8023475381 + 21 +183998.8321474391 + 31 +0.0 + 0 +LINE + 5 +AA2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538283.104072871 + 20 +183992.6320752329 + 30 +0.0 + 11 +538180.7086615311 + 21 +184032.3911071209 + 31 +0.0 + 0 +LINE + 5 +AA3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538483.9962729265 + 20 +183892.9340296101 + 30 +0.0 + 11 +538235.9063290492 + 21 +183886.4996817873 + 31 +0.0 + 0 +LINE + 5 +AA4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538519.8065327198 + 20 +183994.0474627546 + 30 +0.0 + 11 +538513.3841593884 + 21 +183872.7782636668 + 31 +0.0 + 0 +LINE + 5 +AA5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538614.4040702685 + 20 +183887.5761744664 + 30 +0.0 + 11 +538569.2653270726 + 21 +183999.6039604346 + 31 +0.0 + 0 +LINE + 5 +AA6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538573.7905810559 + 20 +183994.6143018384 + 30 +0.0 + 11 +538517.9822807369 + 21 +183992.8665865164 + 31 +0.0 + 0 +LINE + 5 +AA7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538765.3257634245 + 20 +183942.5796194973 + 30 +0.0 + 11 +538353.0283476007 + 21 +183885.4527973906 + 31 +0.0 + 0 +LINE + 5 +AA8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538418.2350899841 + 20 +183852.5923292984 + 30 +0.0 + 11 +538353.0316749258 + 21 +184197.756404748 + 31 +0.0 + 0 +LINE + 5 +AA9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538452.3026074006 + 20 +184185.2264531618 + 30 +0.0 + 11 +538432.4939275087 + 21 +183893.2966974193 + 31 +0.0 + 0 +LINE + 5 +AAA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538559.7654428084 + 20 +183911.1811752413 + 30 +0.0 + 11 +538554.581288617 + 21 +183946.3254247748 + 31 +0.0 + 0 +LINE + 5 +AAB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538390.6367578734 + 20 +184034.5680462495 + 30 +0.0 + 11 +538297.4546042756 + 21 +184029.1897145885 + 31 +0.0 + 0 +LINE + 5 +AAC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538332.0634956199 + 20 +184035.3346913154 + 30 +0.0 + 11 +538265.3064492604 + 21 +183985.3739166687 + 31 +0.0 + 0 +LINE + 5 +AAD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538336.0011766956 + 20 +184022.814081135 + 30 +0.0 + 11 +538262.108396395 + 21 +184053.8625052031 + 31 +0.0 + 0 +LINE + 5 +AAE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538256.5602894736 + 20 +184220.9589837579 + 30 +0.0 + 11 +538268.2212810583 + 21 +184042.8171182967 + 31 +0.0 + 0 +LINE + 5 +AAF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538690.0497256613 + 20 +183781.0278188786 + 30 +0.0 + 11 +538391.9298545738 + 21 +183764.1970789722 + 31 +0.0 + 0 +LINE + 5 +AB0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +538320.4529850837 + 20 +183367.3444202856 + 30 +0.0 + 11 +538206.2617934625 + 21 +183704.568974458 + 31 +0.0 + 0 +LINE + 5 +AB8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535649.0581230556 + 20 +184628.1294401782 + 30 +0.0 + 11 +535631.7063125931 + 21 +184416.4013498721 + 31 +0.0 + 0 +LINE + 5 +ABA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536044.1049790082 + 20 +186337.1683777391 + 30 +0.0 + 11 +535278.8738929772 + 21 +186537.6480541799 + 31 +0.0 + 0 +LINE + 5 +ABC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536072.4992580615 + 20 +186395.8464045735 + 30 +0.0 + 11 +535593.9523860775 + 21 +186520.2549979555 + 31 +0.0 + 0 +LINE + 5 +AC0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535947.4422199873 + 20 +186595.5290238438 + 30 +0.0 + 11 +535803.0955322193 + 21 +186708.2359403478 + 31 +0.0 + 0 +LINE + 5 +AC5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536202.8271529145 + 20 +186974.3219773433 + 30 +0.0 + 11 +535694.707314849 + 21 +186335.5423163722 + 31 +0.0 + 0 +LINE + 5 +AC6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535818.8285570935 + 20 +186603.307553388 + 30 +0.0 + 11 +535425.4906564561 + 21 +186798.6765978215 + 31 +0.0 + 0 +LINE + 5 +AC7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535778.7584118029 + 20 +186546.5271828044 + 30 +0.0 + 11 +535884.678955602 + 21 +186708.9782724068 + 31 +0.0 + 0 +LINE + 5 +AC8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535718.5393726928 + 20 +186587.098916015 + 30 +0.0 + 11 +535754.1065128451 + 21 +186640.6771228112 + 31 +0.0 + 0 +LINE + 5 +AC9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535748.4765621386 + 20 +186541.7003508794 + 30 +0.0 + 11 +535716.9843364775 + 21 +186602.9008022333 + 31 +0.0 + 0 +LINE + 5 +ACA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535732.5023976116 + 20 +186589.5871421354 + 30 +0.0 + 11 +535360.9665969115 + 21 +186746.2978518829 + 31 +0.0 + 0 +LINE + 5 +ACB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535574.3164212192 + 20 +186456.0321643507 + 30 +0.0 + 11 +535707.2930778238 + 21 +186841.0372332034 + 31 +0.0 + 0 +LINE + 5 +ACC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535718.4556937626 + 20 +186833.7782387417 + 30 +0.0 + 11 +535497.7159083774 + 21 +186924.9358979981 + 31 +0.0 + 0 +LINE + 5 +ACD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535867.7666592935 + 20 +186952.1506862782 + 30 +0.0 + 11 +535700.8659413488 + 21 +186829.4680377467 + 31 +0.0 + 0 +LINE + 5 +ACE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535880.7872831714 + 20 +186865.9390409171 + 30 +0.0 + 11 +535815.2268489009 + 21 +186920.6487221414 + 31 +0.0 + 0 +LINE + 5 +ACF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535464.218589661 + 20 +186471.9204713913 + 30 +0.0 + 11 +535498.0845958487 + 21 +186555.4380421386 + 31 +0.0 + 0 +LINE + 5 +AD0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535312.8942598835 + 20 +186492.9379767162 + 30 +0.0 + 11 +535500.5379656564 + 21 +186926.2253977131 + 31 +0.0 + 0 +LINE + 5 +AD1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535840.1584424718 + 20 +186683.4354396475 + 30 +0.0 + 11 +535456.7067650441 + 21 +186864.5432457396 + 31 +0.0 + 0 +LINE + 5 +AD2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535792.0308519474 + 20 +187205.0714274164 + 30 +0.0 + 11 +535455.7766825467 + 21 +186857.6303431607 + 31 +0.0 + 0 +LINE + 5 +AD3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535953.8302439406 + 20 +187400.0170244034 + 30 +0.0 + 11 +535596.2123914296 + 21 +186996.1890934282 + 31 +0.0 + 0 +LINE + 5 +AD4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535871.9364952116 + 20 +187158.2976954422 + 30 +0.0 + 11 +535758.7029100819 + 21 +187189.4052978565 + 31 +0.0 + 0 +LINE + 5 +AD5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535828.9949065974 + 20 +187113.4531907232 + 30 +0.0 + 11 +535782.5771207934 + 21 +187213.0071461503 + 31 +0.0 + 0 +LINE + 5 +AD6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535707.0189022852 + 20 +186967.7647106319 + 30 +0.0 + 11 +535822.2768904915 + 21 +187133.664763422 + 31 +0.0 + 0 +LINE + 5 +AD7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535946.1383772131 + 20 +186895.7886565231 + 30 +0.0 + 11 +535660.3624120137 + 21 +187070.7801707167 + 31 +0.0 + 0 +LINE + 5 +ADB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536093.3785918208 + 20 +186779.22303751 + 30 +0.0 + 11 +535805.3202201372 + 21 +186987.6902748207 + 31 +0.0 + 0 +LINE + 5 +ADC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535792.3645056573 + 20 +186985.9072360099 + 30 +0.0 + 11 +535806.7549013131 + 21 +187005.4692166076 + 31 +0.0 + 0 +LINE + 5 +ADD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535604.7106224969 + 20 +186955.2589929417 + 30 +0.0 + 11 +535570.922175215 + 21 +186985.4662437851 + 31 +0.0 + 0 +LINE + 5 +ADE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535608.8025781208 + 20 +186940.2729466015 + 30 +0.0 + 11 +535600.642619605 + 21 +186962.912767927 + 31 +0.0 + 0 +LINE + 5 +ADF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535575.0054296454 + 20 +186885.809907368 + 30 +0.0 + 11 +535611.107705352 + 21 +186947.9266366771 + 31 +0.0 + 0 +LINE + 5 +AE0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535829.6616892381 + 20 +186918.8482636828 + 30 +0.0 + 11 +536061.6989027946 + 21 +187286.0212698194 + 31 +0.0 + 0 +LINE + 5 +AE1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536064.5174208748 + 20 +187254.3870307029 + 30 +0.0 + 11 +535878.0458398946 + 21 +187330.167382727 + 31 +0.0 + 0 +LINE + 5 +AE2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536198.2878103921 + 20 +186955.0159237332 + 30 +0.0 + 11 +536041.0632611067 + 21 +187281.9180588759 + 31 +0.0 + 0 +LINE + 5 +AE3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536158.9397449123 + 20 +187206.8657446049 + 30 +0.0 + 11 +535868.1201696403 + 21 +186938.3701825645 + 31 +0.0 + 0 +LINE + 5 +AE5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535935.6475141795 + 20 +187069.3269479096 + 30 +0.0 + 11 +535864.6504141312 + 21 +187129.9178051844 + 31 +0.0 + 0 +LINE + 5 +AE6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535893.8891706733 + 20 +187110.4080328917 + 30 +0.0 + 11 +535811.1233449206 + 21 +187120.5273376794 + 31 +0.0 + 0 +LINE + 5 +AE7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535888.0689337474 + 20 +187098.643856181 + 30 +0.0 + 11 +535856.2025322552 + 21 +187172.1875851703 + 31 +0.0 + 0 +LINE + 5 +AE8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535967.8130721198 + 20 +187296.6669088628 + 30 +0.0 + 11 +535852.9734771124 + 21 +187159.9834410502 + 31 +0.0 + 0 +LINE + 5 +AEB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535732.9947596506 + 20 +186728.4859055958 + 30 +0.0 + 11 +535747.4563138236 + 21 +186773.2181466402 + 31 +0.0 + 0 +LINE + 5 +AEC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535803.4562431559 + 20 +186742.6184977095 + 30 +0.0 + 11 +535745.5948075422 + 21 +186772.8319370493 + 31 +0.0 + 0 +LINE + 5 +AED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535805.1377876865 + 20 +186693.0933732292 + 30 +0.0 + 11 +535863.5620270077 + 21 +186779.5199391322 + 31 +0.0 + 0 +LINE + 5 +AEE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535976.3903589083 + 20 +186679.1080442436 + 30 +0.0 + 11 +535749.5080107486 + 21 +186873.2294790124 + 31 +0.0 + 0 +LINE + 5 +AEF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535652.1920898013 + 20 +186857.7578841165 + 30 +0.0 + 11 +535682.3253639074 + 21 +186919.6573957788 + 31 +0.0 + 0 +LINE + 5 +AF0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535710.5142631384 + 20 +186904.8474707648 + 30 +0.0 + 11 +535656.5518900161 + 21 +186931.3169672393 + 31 +0.0 + 0 +LINE + 5 +AF1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535702.7478557151 + 20 +186901.1397389758 + 30 +0.0 + 11 +535734.8729477382 + 21 +186964.8300394907 + 31 +0.0 + 0 +LINE + 5 +AF2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535736.3009706147 + 20 +186961.3978262998 + 30 +0.0 + 11 +535686.5362572322 + 21 +186987.3798026816 + 31 +0.0 + 0 +LINE + 5 +AF3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535657.8044169427 + 20 +186922.3687260173 + 30 +0.0 + 11 +535691.9352817553 + 21 +186991.9472562233 + 31 +0.0 + 0 +LINE + 5 +AF5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535616.9046285221 + 20 +186571.529962643 + 30 +0.0 + 11 +535367.6823060016 + 21 +186660.4230653926 + 31 +0.0 + 0 +LINE + 5 +AF6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535093.9650888768 + 20 +186451.4096970502 + 30 +0.0 + 11 +535154.0885972468 + 21 +186586.4758232478 + 31 +0.0 + 0 +LINE + 5 +AF7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535256.4286973283 + 20 +186478.0102726568 + 30 +0.0 + 11 +534777.8818253441 + 21 +186602.4188660389 + 31 +0.0 + 0 +LINE + 5 +AF8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535149.7886778084 + 20 +186554.1141029375 + 30 +0.0 + 11 +535138.3416224898 + 21 +186635.2933070427 + 31 +0.0 + 0 +LINE + 5 +AF9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535227.3633349829 + 20 +186572.484954252 + 30 +0.0 + 11 +535140.2165797861 + 21 +186561.4002107324 + 31 +0.0 + 0 +LINE + 5 +AFA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535212.3860523695 + 20 +186563.4247814637 + 30 +0.0 + 11 +535309.0943364181 + 21 +186737.2113188613 + 31 +0.0 + 0 +LINE + 5 +AFB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535395.3693409279 + 20 +186471.5616316553 + 30 +0.0 + 11 +534987.024971486 + 21 +186790.399808431 + 31 +0.0 + 0 +LINE + 5 +AFC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535263.0990040753 + 20 +186768.6254398828 + 30 +0.0 + 11 +535136.6871637996 + 21 +186631.2941419262 + 31 +0.0 + 0 +LINE + 5 +AFD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535310.0847298305 + 20 +186730.337642818 + 30 +0.0 + 11 +535262.2561282982 + 21 +186768.5350976643 + 31 +0.0 + 0 +LINE + 5 +AFE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535466.9826670145 + 20 +186982.9939123589 + 30 +0.0 + 11 +535277.370685492 + 21 +186754.098166188 + 31 +0.0 + 0 +LINE + 5 +AFF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535426.2159510503 + 20 +186928.0417294869 + 30 +0.0 + 11 +535334.3736976055 + 21 +186994.0932381661 + 31 +0.0 + 0 +LINE + 5 +B00 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535386.7565921814 + 20 +187056.4858454265 + 30 +0.0 + 11 +534915.1926836778 + 21 +186466.1477384471 + 31 +0.0 + 0 +LINE + 5 +B01 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535002.7579963602 + 20 +186685.4714214713 + 30 +0.0 + 11 +534433.1757887198 + 21 +186994.3605355972 + 31 +0.0 + 0 +LINE + 5 +B02 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534962.6878510696 + 20 +186628.6910508876 + 30 +0.0 + 11 +535068.6083948688 + 21 +186791.1421404901 + 31 +0.0 + 0 +LINE + 5 +B03 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534902.4688119596 + 20 +186669.2627840982 + 30 +0.0 + 11 +534938.0359521117 + 21 +186722.8409908944 + 31 +0.0 + 0 +LINE + 5 +B04 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534932.4060014054 + 20 +186623.8642189625 + 30 +0.0 + 11 +534900.9137757443 + 21 +186685.0646703165 + 31 +0.0 + 0 +LINE + 5 +B05 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534916.4318368784 + 20 +186671.7510102187 + 30 +0.0 + 11 +534786.9073252073 + 21 +186726.3833716639 + 31 +0.0 + 0 +LINE + 5 +B06 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534758.2458604859 + 20 +186538.196032434 + 30 +0.0 + 11 +534891.2225170906 + 21 +186923.2011012866 + 31 +0.0 + 0 +LINE + 5 +B07 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534902.3851330294 + 20 +186915.9421068249 + 30 +0.0 + 11 +534681.6453476442 + 21 +187007.0997660814 + 31 +0.0 + 0 +LINE + 5 +B08 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535051.6960985602 + 20 +187034.3145543616 + 30 +0.0 + 11 +534884.7953806155 + 21 +186911.63190583 + 31 +0.0 + 0 +LINE + 5 +B09 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535064.716722438 + 20 +186948.1029090003 + 30 +0.0 + 11 +534999.1562881677 + 21 +187002.8125902247 + 31 +0.0 + 0 +LINE + 5 +B0A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534635.2210719854 + 20 +186561.7439201856 + 30 +0.0 + 11 +534669.0870781731 + 21 +186645.2614909329 + 31 +0.0 + 0 +LINE + 5 +B0B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535024.0878817386 + 20 +186765.5993077308 + 30 +0.0 + 11 +534640.636204311 + 21 +186946.7071138229 + 31 +0.0 + 0 +LINE + 5 +B0C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535055.8659344782 + 20 +187240.4615635254 + 30 +0.0 + 11 +534942.6323493486 + 21 +187271.5691659399 + 31 +0.0 + 0 +LINE + 5 +B0D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535012.9243458644 + 20 +187195.6170588064 + 30 +0.0 + 11 +534966.5065600603 + 21 +187295.1710142336 + 31 +0.0 + 0 +LINE + 5 +B0E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534890.9483415519 + 20 +187049.9285787151 + 30 +0.0 + 11 +535006.2063297581 + 21 +187215.8286315053 + 31 +0.0 + 0 +LINE + 5 +B0F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535130.06781648 + 20 +186977.9525246064 + 30 +0.0 + 11 +534769.6503777293 + 21 +187209.2714730936 + 31 +0.0 + 0 +LINE + 5 +B10 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535085.5097921989 + 20 +186895.6653051118 + 30 +0.0 + 11 +535136.7805609917 + 21 +187005.7506074639 + 31 +0.0 + 0 +LINE + 5 +B11 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535219.0237330307 + 20 +186945.2521677223 + 30 +0.0 + 11 +535126.5684119001 + 21 +186867.5363742124 + 31 +0.0 + 0 +LINE + 5 +B12 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535132.9066622104 + 20 +186869.8169880601 + 30 +0.0 + 11 +535084.4536154681 + 21 +186897.5644772211 + 31 +0.0 + 0 +LINE + 5 +B13 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535445.0174913342 + 20 +186740.0159221909 + 30 +0.0 + 11 +534989.2496594038 + 21 +187069.854142904 + 31 +0.0 + 0 +LINE + 5 +B14 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534976.2939449241 + 20 +187068.0711040932 + 30 +0.0 + 11 +534990.68434058 + 21 +187087.6330846908 + 31 +0.0 + 0 +LINE + 5 +B15 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534788.6400617637 + 20 +187037.422861025 + 30 +0.0 + 11 +534729.1827484464 + 21 +187087.0008624204 + 31 +0.0 + 0 +LINE + 5 +B16 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534792.7320173874 + 20 +187022.4368146847 + 30 +0.0 + 11 +534784.5720588717 + 21 +187045.0766360102 + 31 +0.0 + 0 +LINE + 5 +B17 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534758.9348689123 + 20 +186967.9737754513 + 30 +0.0 + 11 +534795.0371446187 + 21 +187030.0905047604 + 31 +0.0 + 0 +LINE + 5 +B18 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535013.5911285049 + 20 +187001.0121317661 + 30 +0.0 + 11 +535197.6552260111 + 21 +187304.6142666616 + 31 +0.0 + 0 +LINE + 5 +B19 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535382.2172496589 + 20 +187037.1797918165 + 30 +0.0 + 11 +535297.8359402907 + 21 +187222.9388911312 + 31 +0.0 + 0 +LINE + 5 +B1A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535328.7147017309 + 20 +187226.6595128224 + 30 +0.0 + 11 +535052.049608907 + 21 +187020.5340506478 + 31 +0.0 + 0 +LINE + 5 +B1B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535156.3117485155 + 20 +186945.3855350409 + 30 +0.0 + 11 +535176.8856377365 + 21 +186974.3460048628 + 31 +0.0 + 0 +LINE + 5 +B1C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535119.5769534462 + 20 +187151.4908159928 + 30 +0.0 + 11 +535048.579853398 + 21 +187212.0816732677 + 31 +0.0 + 0 +LINE + 5 +B1D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535077.8186099403 + 20 +187192.5719009749 + 30 +0.0 + 11 +534995.0527841873 + 21 +187202.6912057627 + 31 +0.0 + 0 +LINE + 5 +B1E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535071.9983730142 + 20 +187180.8077242643 + 30 +0.0 + 11 +535040.1319715219 + 21 +187254.3514532537 + 31 +0.0 + 0 +LINE + 5 +B1F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535120.0333856632 + 20 +187336.8118939866 + 30 +0.0 + 11 +535036.9029163791 + 21 +187242.1473091334 + 31 +0.0 + 0 +LINE + 5 +B20 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535523.0330148909 + 20 +186898.5464673954 + 30 +0.0 + 11 +535341.1814526257 + 21 +187097.4914995595 + 31 +0.0 + 0 +LINE + 5 +B21 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534916.9241989173 + 20 +186810.649773679 + 30 +0.0 + 11 +534931.3857530902 + 21 +186855.3820147234 + 31 +0.0 + 0 +LINE + 5 +B22 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534987.3856824226 + 20 +186824.7823657927 + 30 +0.0 + 11 +534929.5242468087 + 21 +186854.9958051326 + 31 +0.0 + 0 +LINE + 5 +B23 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534989.0672269532 + 20 +186775.2572413124 + 30 +0.0 + 11 +535047.4914662743 + 21 +186861.6838072155 + 31 +0.0 + 0 +LINE + 5 +B24 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535160.319798175 + 20 +186761.2719123269 + 30 +0.0 + 11 +534933.4374500154 + 21 +186955.3933470955 + 31 +0.0 + 0 +LINE + 5 +B25 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534836.1215290681 + 20 +186939.9217521998 + 30 +0.0 + 11 +534866.254803174 + 21 +187001.821263862 + 31 +0.0 + 0 +LINE + 5 +B26 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534894.4437024051 + 20 +186987.011338848 + 30 +0.0 + 11 +534840.4813292829 + 21 +187013.4808353226 + 31 +0.0 + 0 +LINE + 5 +B27 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534886.6772949818 + 20 +186983.3036070591 + 30 +0.0 + 11 +534918.8023870048 + 21 +187046.9939075741 + 31 +0.0 + 0 +LINE + 5 +B28 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534920.2304098814 + 20 +187043.5616943832 + 30 +0.0 + 11 +534870.465696499 + 21 +187069.5436707649 + 31 +0.0 + 0 +LINE + 5 +B29 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534841.7338562095 + 20 +187004.5325941006 + 30 +0.0 + 11 +534875.864721022 + 21 +187074.1111243065 + 31 +0.0 + 0 +LINE + 5 +B2A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535381.2241621185 + 20 +186871.7065817206 + 30 +0.0 + 11 +535290.2397902417 + 21 +186938.2378872666 + 31 +0.0 + 0 +LINE + 5 +B2B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534800.8340677889 + 20 +186653.6938307262 + 30 +0.0 + 11 +534551.6117452683 + 21 +186742.5869334758 + 31 +0.0 + 0 +LINE + 5 +B2C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534315.9374838286 + 20 +186110.7368073677 + 30 +0.0 + 11 +535072.5823581115 + 21 +187921.5456161805 + 31 +0.0 + 0 +LINE + 5 +B2D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535060.4783531628 + 20 +187323.8429344235 + 30 +0.0 + 11 +535081.8613660606 + 21 +187550.1442192757 + 31 +0.0 + 0 +LINE + 5 +B2E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535218.9609189549 + 20 +187224.8625394553 + 30 +0.0 + 11 +535300.7848955697 + 21 +187373.6500876221 + 31 +0.0 + 0 +LINE + 5 +B2F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535627.2033165716 + 20 +187021.4595680193 + 30 +0.0 + 11 +534938.2488278624 + 21 +187410.3482337611 + 31 +0.0 + 0 +LINE + 5 +B30 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535199.7075450184 + 20 +187341.3876688161 + 30 +0.0 + 11 +535329.8599296329 + 21 +187760.8446086559 + 31 +0.0 + 0 +LINE + 5 +B31 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535137.264482519 + 20 +187371.8916189357 + 30 +0.0 + 11 +535314.5260884354 + 21 +187293.2287866729 + 31 +0.0 + 0 +LINE + 5 +B32 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535167.7153126758 + 20 +187437.8093339281 + 30 +0.0 + 11 +535226.2791814901 + 21 +187411.2401982319 + 31 +0.0 + 0 +LINE + 5 +B33 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535127.6710070983 + 20 +187401.0164185898 + 30 +0.0 + 11 +535183.0670851085 + 21 +187441.8640631253 + 31 +0.0 + 0 +LINE + 5 +B34 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535172.3980890155 + 20 +187424.4216926175 + 30 +0.0 + 11 +535267.8630374448 + 21 +187816.1914481792 + 31 +0.0 + 0 +LINE + 5 +B35 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535011.5144413881 + 20 +187559.0584404998 + 30 +0.0 + 11 +535416.6115988639 + 21 +187489.4018411997 + 31 +0.0 + 0 +LINE + 5 +B36 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535411.2253370809 + 20 +187477.224600987 + 30 +0.0 + 11 +535466.0201099505 + 21 +187709.6752507155 + 31 +0.0 + 0 +LINE + 5 +B37 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535551.890772004 + 20 +187348.698198324 + 30 +0.0 + 11 +535404.165619358 + 21 +187493.9020590748 + 31 +0.0 + 0 +LINE + 5 +B38 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535468.8582171794 + 20 +187322.0978358947 + 30 +0.0 + 11 +535512.4144401708 + 21 +187395.5428847416 + 31 +0.0 + 0 +LINE + 5 +B39 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534761.5383226473 + 20 +187886.4093640894 + 30 +0.0 + 11 +535467.7430850394 + 21 +187707.0949070089 + 31 +0.0 + 0 +LINE + 5 +B3A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535282.211313556 + 20 +187333.1069476038 + 30 +0.0 + 11 +535399.8612585677 + 21 +187740.5302125117 + 31 +0.0 + 0 +LINE + 5 +B3B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535789.4997419352 + 20 +187463.7929037642 + 30 +0.0 + 11 +535392.8884976999 + 21 +187740.3461435108 + 31 +0.0 + 0 +LINE + 5 +B3C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535975.9026101069 + 20 +187355.3210338819 + 30 +0.0 + 11 +535552.0668299141 + 21 +187623.8001261673 + 31 +0.0 + 0 +LINE + 5 +B3D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535756.0652602497 + 20 +187377.4515506207 + 30 +0.0 + 11 +535768.7199492786 + 21 +187494.1965144302 + 31 +0.0 + 0 +LINE + 5 +B3E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535704.9475115667 + 20 +187412.6933639361 + 30 +0.0 + 11 +535795.8265493328 + 21 +187474.3910249521 + 31 +0.0 + 0 +LINE + 5 +B3F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535541.6740385804 + 20 +187509.8790206878 + 30 +0.0 + 11 +535723.8293243902 + 21 +187422.5481371889 + 31 +0.0 + 0 +LINE + 5 +B40 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535522.3193812402 + 20 +187293.7612209985 + 30 +0.0 + 11 +535635.9322342677 + 21 +187572.3642641195 + 31 +0.0 + 0 +LINE + 5 +B41 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535571.6792890632 + 20 +187217.0670909279 + 30 +0.0 + 11 +535475.5139251245 + 21 +187291.2269743228 + 31 +0.0 + 0 +LINE + 5 +B42 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535430.3202100606 + 20 +187199.6762852104 + 30 +0.0 + 11 +535548.1629601752 + 21 +187173.2033327564 + 31 +0.0 + 0 +LINE + 5 +B43 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535541.4860475573 + 20 +187172.3125721767 + 30 +0.0 + 11 +535571.743415313 + 21 +187219.2392446545 + 31 +0.0 + 0 +LINE + 5 +B44 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535324.0718488141 + 20 +186913.4833764857 + 30 +0.0 + 11 +535324.0774397778 + 21 +186913.4944840446 + 31 +0.0 + 0 +LINE + 5 +B45 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535389.8771166202 + 20 +187044.2185976446 + 30 +0.0 + 11 +535577.0186818464 + 21 +187416.0124484055 + 31 +0.0 + 0 +LINE + 5 +B46 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535573.1926850023 + 20 +187428.5181076536 + 30 +0.0 + 11 +535594.7989219584 + 21 +187417.4309485659 + 31 +0.0 + 0 +LINE + 5 +B47 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535513.0154098396 + 20 +187608.8843745172 + 30 +0.0 + 11 +535537.4486776886 + 21 +187647.0570426904 + 31 +0.0 + 0 +LINE + 5 +B48 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535498.8735477308 + 20 +187602.4552671278 + 30 +0.0 + 11 +535519.9226271356 + 21 +187614.120715633 + 31 +0.0 + 0 +LINE + 5 +B49 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535439.7183894071 + 20 +187627.1359707509 + 30 +0.0 + 11 +535506.7968675183 + 21 +187601.4000008731 + 31 +0.0 + 0 +LINE + 5 +B4A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535512.9386306098 + 20 +187381.005639796 + 30 +0.0 + 11 +535834.0641552604 + 21 +187238.6394860438 + 31 +0.0 + 0 +LINE + 5 +B4B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535767.3710462818 + 20 +187164.0489575836 + 30 +0.0 + 11 +535538.3429394452 + 21 +187346.1519294588 + 31 +0.0 + 0 +LINE + 5 +B4C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535480.7803021392 + 20 +187231.2413731987 + 30 +0.0 + 11 +535512.650735354 + 21 +187215.5484060904 + 31 +0.0 + 0 +LINE + 5 +B4D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535678.3914122045 + 20 +187300.3693789839 + 30 +0.0 + 11 +535726.886700457 + 21 +187380.1192831711 + 31 +0.0 + 0 +LINE + 5 +B4E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535712.2886086333 + 20 +187348.143795463 + 30 +0.0 + 11 +535709.0815591129 + 21 +187431.4642435856 + 31 +0.0 + 0 +LINE + 5 +B4F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535699.7469116659 + 20 +187352.0137888389 + 30 +0.0 + 11 +535767.2686885993 + 21 +187395.19893973 + 31 +0.0 + 0 +LINE + 5 +B50 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535907.9515918173 + 20 +187304.8643650759 + 30 +0.0 + 11 +535754.7058132201 + 21 +187396.4407501155 + 31 +0.0 + 0 +LINE + 5 +B51 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535309.5983215623 + 20 +187446.0828352542 + 30 +0.0 + 11 +535356.0641428375 + 21 +187438.9387893999 + 31 +0.0 + 0 +LINE + 5 +B52 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535334.7850856074 + 20 +187378.7762402243 + 30 +0.0 + 11 +535355.3860598539 + 21 +187440.7148994615 + 31 +0.0 + 0 +LINE + 5 +B53 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535286.161693467 + 20 +187369.219500009 + 30 +0.0 + 11 +535380.7981985624 + 21 +187325.3233163779 + 31 +0.0 + 0 +LINE + 5 +B54 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535299.6612624473 + 20 +187197.9279525986 + 30 +0.0 + 11 +535455.1230943988 + 21 +187452.8600026617 + 31 +0.0 + 0 +LINE + 5 +B55 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535424.3325575165 + 20 +187546.4639638863 + 30 +0.0 + 11 +535490.2448484002 + 21 +187526.585994603 + 31 +0.0 + 0 +LINE + 5 +B56 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535480.1190769222 + 20 +187496.3963163875 + 30 +0.0 + 11 +535497.6457072415 + 21 +187553.8888305634 + 31 +0.0 + 0 +LINE + 5 +B57 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535475.2204386095 + 20 +187503.472169832 + 30 +0.0 + 11 +535543.2181998905 + 21 +187481.9134041444 + 31 +0.0 + 0 +LINE + 5 +B58 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535540.0575937758 + 20 +187479.9563896547 + 30 +0.0 + 11 +535557.7722519484 + 21 +187533.2272135696 + 31 +0.0 + 0 +LINE + 5 +B59 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535489.0116612563 + 20 +187551.2255441356 + 30 +0.0 + 11 +535563.1421371856 + 21 +187528.6255366802 + 31 +0.0 + 0 +LINE + 5 +B5A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535136.1400328259 + 20 +187535.6613407249 + 30 +0.0 + 11 +535184.1577223208 + 21 +187795.8690486325 + 31 +0.0 + 0 +LINE + 5 +B5C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536619.1422674942 + 20 +186063.4384918894 + 30 +0.0 + 11 +534385.6388024107 + 21 +186630.7233926483 + 31 +0.0 + 0 +LINE + 5 +B5E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536009.1899432151 + 20 +186152.3224343746 + 30 +0.0 + 11 +535530.6430712309 + 21 +186276.7310277567 + 31 +0.0 + 0 +LINE + 5 +B62 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535789.7596570048 + 20 +186038.0820289988 + 30 +0.0 + 11 +535621.7540618088 + 21 +186010.6925386679 + 31 +0.0 + 0 +LINE + 5 +B67 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535841.2831803683 + 20 +185583.6162998391 + 30 +0.0 + 11 +535707.9985295088 + 21 +186382.4418322399 + 31 +0.0 + 0 +LINE + 5 +B68 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535686.5980695482 + 20 +186094.6731859741 + 30 +0.0 + 11 +535247.9119028322 + 21 +186115.6067650437 + 31 +0.0 + 0 +LINE + 5 +B69 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535679.254929043 + 20 +186163.7796640695 + 30 +0.0 + 11 +535692.6464049468 + 21 +185970.3108384543 + 31 +0.0 + 0 +LINE + 5 +B6A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535606.9008764697 + 20 +186157.6731688996 + 30 +0.0 + 11 +535611.8706933489 + 21 +186093.5565047453 + 31 +0.0 + 0 +LINE + 5 +B6B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535655.1579625586 + 20 +186182.7434435389 + 30 +0.0 + 11 +535597.8467779507 + 21 +186144.6293563551 + 31 +0.0 + 0 +LINE + 5 +B6C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535617.8841629698 + 20 +186148.6996104211 + 30 +0.0 + 11 +535217.06732667 + 21 +186192.7786472781 + 31 +0.0 + 0 +LINE + 5 +B6D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535544.7715556255 + 20 +186342.3856498398 + 30 +0.0 + 11 +535473.4036100022 + 21 +185941.3640661544 + 31 +0.0 + 0 +LINE + 5 +B6E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535486.6882193292 + 20 +185942.2674764811 + 30 +0.0 + 11 +535249.5007487831 + 21 +185970.1578961421 + 31 +0.0 + 0 +LINE + 5 +B6F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535559.443817224 + 20 +185766.1640303519 + 30 +0.0 + 11 +535473.4247487389 + 21 +185954.5986390577 + 31 +0.0 + 0 +LINE + 5 +B70 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535612.8032851592 + 20 +185835.1187373975 + 30 +0.0 + 11 +535528.8985618088 + 21 +185819.265751531 + 31 +0.0 + 0 +LINE + 5 +B71 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535363.8624569724 + 20 +186390.6854996359 + 30 +0.0 + 11 +535352.7652373983 + 21 +186301.2486911264 + 31 +0.0 + 0 +LINE + 5 +B72 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535298.4747702867 + 20 +186437.4723416302 + 30 +0.0 + 11 +535251.3374745445 + 21 +185967.6572451714 + 31 +0.0 + 0 +LINE + 5 +B73 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535666.2028374502 + 20 +186014.3023164108 + 30 +0.0 + 11 +535243.0967797666 + 21 +186042.8766108213 + 31 +0.0 + 0 +LINE + 5 +B74 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535312.5258796923 + 20 +185704.2535522482 + 30 +0.0 + 11 +535245.6512305763 + 21 +186049.3672237799 + 31 +0.0 + 0 +LINE + 5 +B75 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535416.487460791 + 20 +185333.088196827 + 30 +0.0 + 11 +535364.8931120207 + 21 +185568.1096593225 + 31 +0.0 + 0 +LINE + 5 +B76 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +536046.2969796299 + 20 +185831.6422799202 + 30 +0.0 + 11 +535487.5951750196 + 21 +185765.5373482527 + 31 +0.0 + 0 +LINE + 5 +B77 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535477.148214591 + 20 +185773.4044177763 + 30 +0.0 + 11 +535480.189375884 + 21 +185749.310727523 + 31 +0.0 + 0 +LINE + 5 +B78 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535328.1803358655 + 20 +185891.5647570459 + 30 +0.0 + 11 +535266.9905951748 + 21 +185879.2653775681 + 31 +0.0 + 0 +LINE + 5 +B79 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535339.0528098024 + 20 +185902.6604767717 + 30 +0.0 + 11 +535320.899798502 + 21 +185886.861280167 + 31 +0.0 + 0 +LINE + 5 +B7A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535336.0598177444 + 20 +185966.6879075037 + 30 +0.0 + 11 +535337.3385210526 + 21 +185894.8531854739 + 31 +0.0 + 0 +LINE + 5 +B7F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535550.6666908782 + 20 +186027.1474802185 + 30 +0.0 + 11 +535541.5113962165 + 21 +185981.0357624278 + 31 +0.0 + 0 +LINE + 5 +B80 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535605.323856681 + 20 +185980.4875933348 + 30 +0.0 + 11 +535540.0736759655 + 21 +185982.279677201 + 31 +0.0 + 0 +LINE + 5 +B81 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535630.9125847318 + 20 +186022.9232215679 + 30 +0.0 + 11 +535639.8474398627 + 21 +185918.985204472 + 31 +0.0 + 0 +LINE + 5 +B82 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535787.2935449371 + 20 +185951.7331389566 + 30 +0.0 + 11 +535494.595068434 + 21 +185892.687959679 + 31 +0.0 + 0 +LINE + 5 +B83 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535417.1357243587 + 20 +185953.5961589125 + 30 +0.0 + 11 +535413.306971826 + 21 +185884.8582188327 + 31 +0.0 + 0 +LINE + 5 +B84 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535445.1396205757 + 20 +185884.0642463102 + 30 +0.0 + 11 +535385.1182318035 + 21 +185887.2272901695 + 31 +0.0 + 0 +LINE + 5 +B85 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535440.162310145 + 20 +185891.0849827503 + 30 +0.0 + 11 +535437.201021822 + 21 +185819.8129216839 + 31 +0.0 + 0 +LINE + 5 +B86 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535440.1198196912 + 20 +185822.1150849543 + 30 +0.0 + 11 +535384.0020468323 + 21 +185823.6595473568 + 31 +0.0 + 0 +LINE + 5 +B87 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535390.570210269 + 20 +185894.4325504339 + 30 +0.0 + 11 +535386.493008466 + 21 +185817.0409215329 + 31 +0.0 + 0 +LINE + 5 +B88 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535176.3899097375 + 20 +186455.1643532043 + 30 +0.0 + 11 +535176.1881728044 + 21 +186225.9779133883 + 31 +0.0 + 0 +LINE + 5 +B89 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535193.3728299822 + 20 +186389.7491184667 + 30 +0.0 + 11 +534868.9928159219 + 21 +186336.3803769501 + 31 +0.0 + 0 +LINE + 5 +B8A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535120.7169243895 + 20 +186220.9422211613 + 30 +0.0 + 11 +535077.1945969464 + 21 +186402.45157567 + 31 +0.0 + 0 +LINE + 5 +B8B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535180.4008373886 + 20 +186231.4989421477 + 30 +0.0 + 11 +535120.0247670033 + 21 +186221.4316283989 + 31 +0.0 + 0 +LINE + 5 +B8C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535194.3829037004 + 20 +185934.4187256195 + 30 +0.0 + 11 +535140.2568009018 + 21 +186226.6794502267 + 31 +0.0 + 0 +LINE + 5 +B8D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535073.9299995649 + 20 +186013.6552183236 + 30 +0.0 + 11 +534964.1750705812 + 21 +186654.5621188186 + 31 +0.0 + 0 +LINE + 5 +B8E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534933.8368236612 + 20 +186420.3610242562 + 30 +0.0 + 11 +534668.7196878103 + 21 +186433.0120968159 + 31 +0.0 + 0 +LINE + 5 +B8F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534926.4936831563 + 20 +186489.4675023514 + 30 +0.0 + 11 +534939.8851590602 + 21 +186295.9986767365 + 31 +0.0 + 0 +LINE + 5 +B90 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534854.1396305828 + 20 +186483.3610071817 + 30 +0.0 + 11 +534859.1094474623 + 21 +186419.2443430274 + 31 +0.0 + 0 +LINE + 5 +B91 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534902.3967166717 + 20 +186508.4312818211 + 30 +0.0 + 11 +534845.0855320638 + 21 +186470.3171946374 + 31 +0.0 + 0 +LINE + 5 +B92 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534865.122917083 + 20 +186474.3874487032 + 30 +0.0 + 11 +534464.3060807833 + 21 +186518.4664855602 + 31 +0.0 + 0 +LINE + 5 +B93 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534772.8410603143 + 20 +186559.7220764609 + 30 +0.0 + 11 +534720.6423641154 + 21 +186267.0519044365 + 31 +0.0 + 0 +LINE + 5 +B94 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534733.9269734424 + 20 +186267.9553147632 + 30 +0.0 + 11 +534496.7395028962 + 21 +186295.8457344243 + 31 +0.0 + 0 +LINE + 5 +B95 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534861.5969108653 + 20 +185960.9438478748 + 30 +0.0 + 11 +534720.663502852 + 21 +186280.2864773399 + 31 +0.0 + 0 +LINE + 5 +B96 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535064.2461378692 + 20 +186212.2592482234 + 30 +0.0 + 11 +534776.1373159221 + 21 +186144.9535898132 + 31 +0.0 + 0 +LINE + 5 +B97 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534913.4415915634 + 20 +186339.9901546929 + 30 +0.0 + 11 +534490.33553388 + 21 +186368.5644491034 + 31 +0.0 + 0 +LINE + 5 +B98 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534622.3544160384 + 20 +185848.4946772513 + 30 +0.0 + 11 +534660.5457259393 + 21 +186210.5460571149 + 31 +0.0 + 0 +LINE + 5 +B9B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535293.5357337432 + 20 +186157.3301182024 + 30 +0.0 + 11 +534976.4236209976 + 21 +186125.0078848395 + 31 +0.0 + 0 +LINE + 5 +B9C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535001.4616769477 + 20 +186133.8790524274 + 30 +0.0 + 11 +534802.517987515 + 21 +185784.6896027268 + 31 +0.0 + 0 +LINE + 5 +B9D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534876.4274104778 + 20 +185870.5294370419 + 30 +0.0 + 11 +534730.5918755537 + 21 +185951.5413389166 + 31 +0.0 + 0 +LINE + 5 +BA1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535284.4647476339 + 20 +185980.8759516614 + 30 +0.0 + 11 +535142.8676494943 + 21 +185933.7047163851 + 31 +0.0 + 0 +LINE + 5 +BA2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534797.9054449913 + 20 +186352.8353185006 + 30 +0.0 + 11 +534788.7501503297 + 21 +186306.7236007099 + 31 +0.0 + 0 +LINE + 5 +BA3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534852.5626107943 + 20 +186306.1754316169 + 30 +0.0 + 11 +534787.3124300786 + 21 +186307.9675154832 + 31 +0.0 + 0 +LINE + 5 +BA4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534878.151338845 + 20 +186348.61105985 + 30 +0.0 + 11 +534887.086193976 + 21 +186244.6730427542 + 31 +0.0 + 0 +LINE + 5 +BA5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535034.5322990501 + 20 +186277.4209772388 + 30 +0.0 + 11 +534741.8338225472 + 21 +186218.3757979611 + 31 +0.0 + 0 +LINE + 5 +BA6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534664.374478472 + 20 +186279.2839971947 + 30 +0.0 + 11 +534660.5457259393 + 21 +186210.5460571149 + 31 +0.0 + 0 +LINE + 5 +BA8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535173.6825358063 + 20 +186073.3823391721 + 30 +0.0 + 11 +535061.815428612 + 21 +186059.5866560993 + 31 +0.0 + 0 +LINE + 5 +BBE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535194.578432252 + 20 +185635.8937551822 + 30 +0.0 + 11 +535401.461030561 + 21 +185836.6217479292 + 31 +0.0 + 0 +LINE + 5 +BBF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535103.4200229305 + 20 +186064.72977994 + 30 +0.0 + 11 +535103.419496319 + 21 +186064.7173557932 + 31 +0.0 + 0 +LINE + 5 +BC0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535101.9172540151 + 20 +185758.6967996004 + 30 +0.0 + 11 +535079.5950350825 + 21 +185502.6355365788 + 31 +0.0 + 0 +LINE + 5 +BC5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534987.1535696143 + 20 +185571.4007763362 + 30 +0.0 + 11 +535390.4806209565 + 21 +185532.3625558564 + 31 +0.0 + 0 +LINE + 5 +BC6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535273.8636907524 + 20 +185616.7485285761 + 30 +0.0 + 11 +535079.8401373477 + 21 +185582.4869303215 + 31 +0.0 + 0 +LINE + 5 +BC7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534822.7512757593 + 20 +185902.4195618786 + 30 +0.0 + 11 +535404.497080421 + 21 +185512.3435931971 + 31 +0.0 + 0 +LINE + 5 +BC8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535224.4539681542 + 20 +185554.265367827 + 30 +0.0 + 11 +535175.1006113234 + 21 +185446.6389761997 + 31 +0.0 + 0 +LINE + 5 +BD1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535739.1814437658 + 20 +185783.4852240454 + 30 +0.0 + 11 +535709.1316076679 + 21 +185947.0952454507 + 31 +0.0 + 0 +LINE + 5 +BD4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535544.0552051991 + 20 +186338.3604256307 + 30 +0.0 + 11 +535458.7509072162 + 21 +186517.2105554664 + 31 +0.0 + 0 +LINE + 5 +BD5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534557.5132893847 + 20 +188709.4671073466 + 30 +0.0 + 11 +534078.7111282838 + 21 +189277.7834406533 + 31 +0.0 + 0 +LINE + 5 +BD6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534356.231596675 + 20 +188753.5477289792 + 30 +0.0 + 11 +534250.4530444998 + 21 +188856.8366083633 + 31 +0.0 + 0 +LINE + 5 +BD7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534387.7094145916 + 20 +188915.137214011 + 30 +0.0 + 11 +534104.8479175942 + 21 +188509.583296129 + 31 +0.0 + 0 +LINE + 5 +BD8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534279.3071116973 + 20 +188841.5652935944 + 30 +0.0 + 11 +534199.2053122115 + 21 +188859.023815117 + 31 +0.0 + 0 +LINE + 5 +BD9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534289.0209621512 + 20 +188920.691501156 + 30 +0.0 + 11 +534269.1501844531 + 21 +188835.1194223341 + 31 +0.0 + 0 +LINE + 5 +BDA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534293.6322883562 + 20 +188902.2400626908 + 30 +0.0 + 11 +534164.2491112132 + 21 +189053.2839180996 + 31 +0.0 + 0 +LINE + 5 +BDB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534369.5931450922 + 20 +188998.4730747685 + 30 +0.0 + 11 +534001.2018272664 + 21 +188770.9932772706 + 31 +0.0 + 0 +LINE + 5 +BDC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534117.4997940166 + 20 +189022.3213050065 + 30 +0.0 + 11 +534202.3809702101 + 21 +188856.0834492446 + 31 +0.0 + 0 +LINE + 5 +BDD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534169.7222849479 + 20 +189053.0853305843 + 30 +0.0 + 11 +534117.2917871034 + 21 +189021.4995176764 + 31 +0.0 + 0 +LINE + 5 +BDE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533987.2820451778 + 20 +189287.9634099007 + 30 +0.0 + 11 +534136.0793077706 + 21 +189030.6594247062 + 31 +0.0 + 0 +LINE + 5 +BDF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534024.6557512186 + 20 +189230.6495928087 + 30 +0.0 + 11 +533930.8192540997 + 21 +189167.463256271 + 31 +0.0 + 0 +LINE + 5 +BE0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533890.5024755896 + 20 +189238.254233489 + 30 +0.0 + 11 +534313.0549878999 + 21 +188539.9172092332 + 31 +0.0 + 0 +LINE + 5 +BE1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534105.0630630806 + 20 +188749.3059962787 + 30 +0.0 + 11 +533785.2505457025 + 21 +188448.3014758329 + 31 +0.0 + 0 +LINE + 5 +BE2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534144.393078485 + 20 +188692.0104736309 + 30 +0.0 + 11 +534028.8391525893 + 21 +188847.7564473246 + 31 +0.0 + 0 +LINE + 5 +BE3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534085.4329589249 + 20 +188649.6300240285 + 30 +0.0 + 11 +534047.5419248361 + 21 +188701.5907326242 + 31 +0.0 + 0 +LINE + 5 +BE4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534138.4027586058 + 20 +188661.9371500156 + 30 +0.0 + 11 +534070.0745867984 + 21 +188653.6596829845 + 31 +0.0 + 0 +LINE + 5 +BE5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534087.9488873361 + 20 +188663.5880840061 + 30 +0.0 + 11 +533811.9602070268 + 21 +188369.6028019041 + 31 +0.0 + 0 +LINE + 5 +BE6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534158.2538218248 + 20 +188468.8653287749 + 30 +0.0 + 11 +533843.3949501841 + 21 +188727.2750522629 + 31 +0.0 + 0 +LINE + 5 +BE7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533854.0788294193 + 20 +188735.2218578901 + 30 +0.0 + 11 +533691.9335150255 + 21 +188559.8802806386 + 31 +0.0 + 0 +LINE + 5 +BE8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533794.9291670263 + 20 +188916.3492114355 + 30 +0.0 + 11 +533852.0119277566 + 21 +188717.2300503069 + 31 +0.0 + 0 +LINE + 5 +BE9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533880.2966608565 + 20 +188898.6185758231 + 30 +0.0 + 11 +533806.2235569675 + 21 +188856.1392274093 + 31 +0.0 + 0 +LINE + 5 +BEA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534192.1061369314 + 20 +188120.0411750974 + 30 +0.0 + 11 +534038.560469262 + 21 +188431.9015479835 + 31 +0.0 + 0 +LINE + 5 +BEB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534032.8547598519 + 20 +188236.5322474452 + 30 +0.0 + 11 +533691.7043628487 + 21 +188562.9745181988 + 31 +0.0 + 0 +LINE + 5 +BEC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534037.3303856688 + 20 +188797.1361810715 + 30 +0.0 + 11 +533734.3248614275 + 21 +188500.4496821728 + 31 +0.0 + 0 +LINE + 5 +BED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533531.4485612727 + 20 +188933.1654001786 + 30 +0.0 + 11 +533740.4844665125 + 21 +188497.1766803831 + 31 +0.0 + 0 +LINE + 5 +BEE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533404.8291103822 + 20 +189152.5972658912 + 30 +0.0 + 11 +533659.3226478687 + 21 +188676.9917932062 + 31 +0.0 + 0 +LINE + 5 +BEF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533603.0616876657 + 20 +188991.8531668461 + 30 +0.0 + 11 +533534.5649698983 + 21 +188896.4711591908 + 31 +0.0 + 0 +LINE + 5 +BF0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533630.2015349752 + 20 +188936.0101876615 + 30 +0.0 + 11 +533520.7235654619 + 21 +188927.0561343128 + 31 +0.0 + 0 +LINE + 5 +BF1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533724.4602508802 + 20 +188771.0296635525 + 30 +0.0 + 11 +533608.9148788381 + 21 +188936.7296887813 + 31 +0.0 + 0 +LINE + 5 +BF2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533875.0010558523 + 20 +188970.2685696257 + 30 +0.0 + 11 +533611.6533331736 + 21 +188763.0539241843 + 31 +0.0 + 0 +LINE + 5 +BF3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533936.6916629213 + 20 +188899.906129223 + 30 +0.0 + 11 +533851.2645282592 + 21 +188986.217601172 + 31 +0.0 + 0 +LINE + 5 +BF4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533936.5598949222 + 20 +189042.3308882265 + 30 +0.0 + 11 +533977.3291642509 + 21 +188928.6400898097 + 31 +0.0 + 0 +LINE + 5 +BF5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533977.39174217 + 20 +188935.3758674577 + 30 +0.0 + 11 +533934.5438983906 + 21 +188899.5752644348 + 31 +0.0 + 0 +LINE + 5 +BF6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534207.5077871861 + 20 +189182.9805769916 + 30 +0.0 + 11 +533739.9144092359 + 21 +188870.1323688091 + 31 +0.0 + 0 +LINE + 5 +BF7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533737.0870201404 + 20 +188857.3638279377 + 30 +0.0 + 11 +533723.7403525454 + 21 +188877.652273816 + 31 +0.0 + 0 +LINE + 5 +BF8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533700.6564906054 + 20 +188670.7462746741 + 30 +0.0 + 11 +533660.5949207275 + 21 +188649.5517519813 + 31 +0.0 + 0 +LINE + 5 +BF9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533716.1308612756 + 20 +188669.3789641419 + 30 +0.0 + 11 +533692.0663216224 + 21 +188669.5895915292 + 31 +0.0 + 0 +LINE + 5 +BFA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533755.4663603712 + 20 +188618.7707790478 + 30 +0.0 + 11 +533709.7541232065 + 21 +188674.198693898 + 31 +0.0 + 0 +LINE + 5 +BFB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533812.9250847721 + 20 +188869.0502998399 + 30 +0.0 + 11 +533549.1915001816 + 21 +189214.1617039826 + 31 +0.0 + 0 +LINE + 5 +BFC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533579.8355596115 + 20 +189205.818398264 + 30 +0.0 + 11 +533444.0115601664 + 21 +189057.2715927079 + 31 +0.0 + 0 +LINE + 5 +BFD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533907.0303599279 + 20 +189227.2925558879 + 30 +0.0 + 11 +533545.8726725557 + 21 +189193.3854812484 + 31 +0.0 + 0 +LINE + 5 +BFE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533657.1912689352 + 20 +189277.8596513352 + 30 +0.0 + 11 +533807.9746921486 + 21 +188911.8948285983 + 31 +0.0 + 0 +LINE + 5 +BFF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533914.6553188072 + 20 +188983.5686526164 + 30 +0.0 + 11 +533894.642651127 + 21 +189012.9197490576 + 31 +0.0 + 0 +LINE + 5 +C00 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533708.6210282044 + 20 +189020.69954408 + 30 +0.0 + 11 +533627.1446922855 + 21 +188975.1644270182 + 31 +0.0 + 0 +LINE + 5 +C01 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533655.5945538338 + 20 +188995.8076214645 + 30 +0.0 + 11 +533617.3610195242 + 21 +188921.7078299929 + 31 +0.0 + 0 +LINE + 5 +C02 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533664.6051489978 + 20 +188986.2640274697 + 30 +0.0 + 11 +533584.572042754 + 21 +188981.9224237718 + 31 +0.0 + 0 +LINE + 5 +C03 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533506.6024791567 + 20 +189129.8168516188 + 30 +0.0 + 11 +533594.8951225617 + 21 +188974.6559284607 + 31 +0.0 + 0 +LINE + 5 +C04 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534015.5371236648 + 20 +189422.8785670367 + 30 +0.0 + 11 +534089.3924771831 + 21 +189262.4361439317 + 31 +0.0 + 0 +LINE + 5 +C05 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534073.4693208243 + 20 +189324.0028685315 + 30 +0.0 + 11 +533836.2211857393 + 21 +189209.7568899539 + 31 +0.0 + 0 +LINE + 5 +C06 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533957.8667029707 + 20 +188712.2885380282 + 30 +0.0 + 11 +533920.9411801206 + 21 +188741.3851993519 + 31 +0.0 + 0 +LINE + 5 +C07 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533969.0846431969 + 20 +188783.2723998186 + 30 +0.0 + 11 +533920.6568601831 + 21 +188739.5054319043 + 31 +0.0 + 0 +LINE + 5 +C08 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534016.1111272417 + 20 +188767.6494889127 + 30 +0.0 + 11 +533955.3544787583 + 21 +188852.4526297691 + 31 +0.0 + 0 +LINE + 5 +C09 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534088.7009854969 + 20 +188923.3856281208 + 30 +0.0 + 11 +533827.8674739919 + 21 +188778.0425491007 + 31 +0.0 + 0 +LINE + 5 +C0A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533808.5788008996 + 20 +188681.410743732 + 30 +0.0 + 11 +533760.9972611464 + 21 +188731.1657517926 + 31 +0.0 + 0 +LINE + 5 +C0B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533784.675202312 + 20 +188752.4566658391 + 30 +0.0 + 11 +533741.112446881 + 21 +188711.0458182762 + 31 +0.0 + 0 +LINE + 5 +C0C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533785.4549223951 + 20 +188743.8859951609 + 30 +0.0 + 11 +533736.8858061241 + 21 +188796.1307734819 + 31 +0.0 + 0 +LINE + 5 +C0D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533740.600329478 + 20 +188796.2779229899 + 30 +0.0 + 11 +533698.9525720323 + 21 +188758.6341440286 + 31 +0.0 + 0 +LINE + 5 +C0E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533749.9387110799 + 20 +188709.1127106841 + 30 +0.0 + 11 +533696.5444641208 + 21 +188765.2833630762 + 31 +0.0 + 0 +LINE + 5 +C0F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534061.8589977427 + 20 +189168.8933915557 + 30 +0.0 + 11 +533967.8705054438 + 21 +189106.6781694724 + 31 +0.0 + 0 +LINE + 5 +C10 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534064.7356819831 + 20 +188548.9144032987 + 30 +0.0 + 11 +533894.8221488595 + 21 +188346.0766823975 + 31 +0.0 + 0 +LINE + 5 +C11 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533960.747825353 + 20 +187966.2146806913 + 30 +0.0 + 11 +533618.6462585406 + 21 +187483.4167843487 + 31 +0.0 + 0 +LINE + 5 +C12 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534092.0260363118 + 20 +187981.0780324602 + 30 +0.0 + 11 +533889.9867732282 + 21 +188120.0964040922 + 31 +0.0 + 0 +LINE + 5 +C13 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534482.2486223949 + 20 +188866.8031900984 + 30 +0.0 + 11 +533744.3816463227 + 21 +187772.8430918578 + 31 +0.0 + 0 +LINE + 5 +C14 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533918.8408404258 + 20 +188104.8250893232 + 30 +0.0 + 11 +533838.7390409401 + 21 +188122.2836108459 + 31 +0.0 + 0 +LINE + 5 +C15 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533928.5546908797 + 20 +188183.9512968847 + 30 +0.0 + 11 +533908.6839131813 + 21 +188098.379218063 + 31 +0.0 + 0 +LINE + 5 +C16 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533931.8494004686 + 20 +188166.7597113222 + 30 +0.0 + 11 +533802.4662233257 + 21 +188317.803566731 + 31 +0.0 + 0 +LINE + 5 +C17 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534081.5436796952 + 20 +188306.4498861776 + 30 +0.0 + 11 +533640.7355559948 + 21 +188034.2530729997 + 31 +0.0 + 0 +LINE + 5 +C18 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533757.033522745 + 20 +188285.5811007354 + 30 +0.0 + 11 +533841.9146989385 + 21 +188119.3432449735 + 31 +0.0 + 0 +LINE + 5 +C19 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533809.2560136765 + 20 +188316.345126313 + 30 +0.0 + 11 +533756.825515832 + 21 +188284.759313405 + 31 +0.0 + 0 +LINE + 5 +C1A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533626.8157739061 + 20 +188551.2232056296 + 30 +0.0 + 11 +533775.613036499 + 21 +188293.9192204351 + 31 +0.0 + 0 +LINE + 5 +C1B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533664.1894799472 + 20 +188493.9093885375 + 30 +0.0 + 11 +533570.3529828282 + 21 +188430.723052 + 31 +0.0 + 0 +LINE + 5 +C1C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533530.0362043181 + 20 +188501.5140292179 + 30 +0.0 + 11 +533919.8580114896 + 21 +187854.2810271168 + 31 +0.0 + 0 +LINE + 5 +C1D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533744.5967918091 + 20 +188012.5657920076 + 30 +0.0 + 11 +533424.7842744307 + 21 +187711.5612715618 + 31 +0.0 + 0 +LINE + 5 +C1E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533783.9268072136 + 20 +187955.2702693596 + 30 +0.0 + 11 +533668.372881318 + 21 +188111.0162430533 + 31 +0.0 + 0 +LINE + 5 +C1F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533724.9666876536 + 20 +187912.8898197572 + 30 +0.0 + 11 +533687.0756535645 + 21 +187964.8505283531 + 31 +0.0 + 0 +LINE + 5 +C20 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533777.9364873344 + 20 +187925.1969457444 + 30 +0.0 + 11 +533709.6083155268 + 21 +187916.9194787134 + 31 +0.0 + 0 +LINE + 5 +C21 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533727.4826160646 + 20 +187926.8478797349 + 30 +0.0 + 11 +533451.4939357553 + 21 +187632.8625976329 + 31 +0.0 + 0 +LINE + 5 +C22 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533797.7875505533 + 20 +187732.1251245037 + 30 +0.0 + 11 +533482.9286789124 + 21 +187990.5348479918 + 31 +0.0 + 0 +LINE + 5 +C23 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533493.6125581479 + 20 +187998.481653619 + 30 +0.0 + 11 +533331.4672437539 + 21 +187823.1400763673 + 31 +0.0 + 0 +LINE + 5 +C24 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533434.4628957546 + 20 +188179.6090071645 + 30 +0.0 + 11 +533491.5456564852 + 21 +187980.4898460357 + 31 +0.0 + 0 +LINE + 5 +C25 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533519.8303895849 + 20 +188161.878371552 + 30 +0.0 + 11 +533445.757285696 + 21 +188119.3990231381 + 31 +0.0 + 0 +LINE + 5 +C26 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533725.6678888035 + 20 +187622.8851895573 + 30 +0.0 + 11 +533659.1102360578 + 21 +187683.6484174145 + 31 +0.0 + 0 +LINE + 5 +C27 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533672.3884885803 + 20 +187499.7920431741 + 30 +0.0 + 11 +533331.2380915771 + 21 +187826.2343139276 + 31 +0.0 + 0 +LINE + 5 +C28 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533676.8641143972 + 20 +188060.3959768004 + 30 +0.0 + 11 +533373.8585901557 + 21 +187763.7094779017 + 31 +0.0 + 0 +LINE + 5 +C29 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533146.5957557968 + 20 +188251.4100877043 + 30 +0.0 + 11 +533380.0181952408 + 21 +187760.4364761121 + 31 +0.0 + 0 +LINE + 5 +C2A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533242.5954163944 + 20 +188255.1129625749 + 30 +0.0 + 11 +533174.0986986265 + 21 +188159.7309549197 + 31 +0.0 + 0 +LINE + 5 +C2B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533269.7352637037 + 20 +188199.2699833903 + 30 +0.0 + 11 +533160.2572941904 + 21 +188190.3159300416 + 31 +0.0 + 0 +LINE + 5 +C2C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533363.9939796087 + 20 +188034.2894592814 + 30 +0.0 + 11 +533248.4486075667 + 21 +188199.9894845101 + 31 +0.0 + 0 +LINE + 5 +C2D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533514.5347845807 + 20 +188233.5283653546 + 30 +0.0 + 11 +533251.187061902 + 21 +188026.3137199132 + 31 +0.0 + 0 +LINE + 5 +C2E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533576.2253916496 + 20 +188163.1659249519 + 30 +0.0 + 11 +533490.7982569877 + 21 +188249.4773969008 + 31 +0.0 + 0 +LINE + 5 +C2F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533576.0936236506 + 20 +188305.5906839552 + 30 +0.0 + 11 +533616.8628929792 + 21 +188191.8998855386 + 31 +0.0 + 0 +LINE + 5 +C30 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533616.9254708984 + 20 +188198.6356631866 + 30 +0.0 + 11 +533574.077627119 + 21 +188162.8350601635 + 31 +0.0 + 0 +LINE + 5 +C31 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533847.0415159145 + 20 +188446.2403727204 + 30 +0.0 + 11 +533379.4481379644 + 21 +188133.3921645379 + 31 +0.0 + 0 +LINE + 5 +C32 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533376.620748869 + 20 +188120.6236236665 + 30 +0.0 + 11 +533363.2740812741 + 21 +188140.9120695446 + 31 +0.0 + 0 +LINE + 5 +C33 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533340.1902193338 + 20 +187934.006070403 + 30 +0.0 + 11 +533300.128649456 + 21 +187912.8115477102 + 31 +0.0 + 0 +LINE + 5 +C34 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533355.6645900042 + 20 +187932.6387598706 + 30 +0.0 + 11 +533331.6000503509 + 21 +187932.8493872581 + 31 +0.0 + 0 +LINE + 5 +C35 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533395.0000890999 + 20 +187882.0305747765 + 30 +0.0 + 11 +533349.2878519349 + 21 +187937.4584896269 + 31 +0.0 + 0 +LINE + 5 +C36 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533452.4588135006 + 20 +188132.3100955687 + 30 +0.0 + 11 +533231.6784224093 + 21 +188410.3566154416 + 31 +0.0 + 0 +LINE + 5 +C37 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533546.5640886565 + 20 +188490.5523516167 + 30 +0.0 + 11 +533343.0621970856 + 21 +188475.9363167254 + 31 +0.0 + 0 +LINE + 5 +C38 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533350.297176501 + 20 +188506.1852176427 + 30 +0.0 + 11 +533447.508420877 + 21 +188175.1546243272 + 31 +0.0 + 0 +LINE + 5 +C39 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533554.1890475354 + 20 +188246.8284483454 + 30 +0.0 + 11 +533534.1763798556 + 21 +188276.1795447865 + 31 +0.0 + 0 +LINE + 5 +C3A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533348.1547569327 + 20 +188283.9593398089 + 30 +0.0 + 11 +533266.6784210141 + 21 +188238.4242227471 + 31 +0.0 + 0 +LINE + 5 +C3B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533295.1282825622 + 20 +188259.0674171934 + 30 +0.0 + 11 +533256.8947482528 + 21 +188184.9676257218 + 31 +0.0 + 0 +LINE + 5 +C3C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533304.1388777264 + 20 +188249.5238231985 + 30 +0.0 + 11 +533224.1057714826 + 21 +188245.1822195005 + 31 +0.0 + 0 +LINE + 5 +C3D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533174.5272803235 + 20 +188348.7483021824 + 30 +0.0 + 11 +533234.4288512903 + 21 +188237.9157241895 + 31 +0.0 + 0 +LINE + 5 +C3E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533725.4728525103 + 20 +188574.456657789 + 30 +0.0 + 11 +533475.7549144679 + 21 +188473.0166856827 + 31 +0.0 + 0 +LINE + 5 +C3F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533597.4004316991 + 20 +187975.548333757 + 30 +0.0 + 11 +533560.4749088491 + 21 +188004.6449950807 + 31 +0.0 + 0 +LINE + 5 +C40 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533608.6183719253 + 20 +188046.5321955475 + 30 +0.0 + 11 +533560.1905889117 + 21 +188002.7652276331 + 31 +0.0 + 0 +LINE + 5 +C41 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533655.6448559702 + 20 +188030.9092846418 + 30 +0.0 + 11 +533594.8882074865 + 21 +188115.712425498 + 31 +0.0 + 0 +LINE + 5 +C42 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533728.2347142254 + 20 +188186.6454238496 + 30 +0.0 + 11 +533467.4012027203 + 21 +188041.3023448295 + 31 +0.0 + 0 +LINE + 5 +C43 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533448.112529628 + 20 +187944.6705394609 + 30 +0.0 + 11 +533400.5309898749 + 21 +187994.4255475215 + 31 +0.0 + 0 +LINE + 5 +C44 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533424.2089310404 + 20 +188015.7164615679 + 30 +0.0 + 11 +533380.6461756096 + 21 +187974.305614005 + 31 +0.0 + 0 +LINE + 5 +C45 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533424.9886511237 + 20 +188007.1457908898 + 30 +0.0 + 11 +533376.4195348527 + 21 +188059.3905692107 + 31 +0.0 + 0 +LINE + 5 +C46 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533380.1340582064 + 20 +188059.5377187187 + 30 +0.0 + 11 +533338.4863007607 + 21 +188021.8939397574 + 31 +0.0 + 0 +LINE + 5 +C47 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533389.4724398083 + 20 +187972.3725064129 + 30 +0.0 + 11 +533336.0781928492 + 21 +188028.543158805 + 31 +0.0 + 0 +LINE + 5 +C48 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533701.3927264713 + 20 +188432.1531872845 + 30 +0.0 + 11 +533607.4042341724 + 21 +188369.9379652012 + 31 +0.0 + 0 +LINE + 5 +C49 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533704.2694107114 + 20 +187812.1741990278 + 30 +0.0 + 11 +533534.3558775881 + 21 +187609.3364781263 + 31 +0.0 + 0 +LINE + 5 +C4A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533175.6970995059 + 20 +188220.3147545992 + 30 +0.0 + 11 +532655.4448627076 + 21 +188465.0194945314 + 31 +0.0 + 0 +LINE + 5 +C4B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533313.8654444766 + 20 +188402.6388471191 + 30 +0.0 + 11 +533202.7559908635 + 21 +188531.0428461079 + 31 +0.0 + 0 +LINE + 5 +C4C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533646.388072575 + 20 +188714.8300158017 + 30 +0.0 + 11 +533069.5921329468 + 21 +188226.7951355077 + 31 +0.0 + 0 +LINE + 5 +C4D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533197.9066944875 + 20 +188425.0523805634 + 30 +0.0 + 11 +532843.6663763799 + 21 +188684.704330224 + 31 +0.0 + 0 +LINE + 5 +C4E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533147.6153106242 + 20 +188377.0898562728 + 30 +0.0 + 11 +533282.943802676 + 21 +188515.9988817203 + 31 +0.0 + 0 +LINE + 5 +C4F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533096.3759611031 + 20 +188428.5381533069 + 30 +0.0 + 11 +533141.6302267151 + 21 +188474.2294779323 + 31 +0.0 + 0 +LINE + 5 +C50 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533116.9715900882 + 20 +188378.2083897967 + 30 +0.0 + 11 +533097.9051955084 + 21 +188444.3425573709 + 31 +0.0 + 0 +LINE + 5 +C51 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533110.5566061437 + 20 +188428.28000541 + 30 +0.0 + 11 +532776.3265078583 + 21 +188653.8622280066 + 31 +0.0 + 0 +LINE + 5 +C52 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532929.5351063394 + 20 +188327.8262756299 + 30 +0.0 + 11 +533134.4350096063 + 21 +188679.8599727173 + 31 +0.0 + 0 +LINE + 5 +C53 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533143.9836746984 + 20 +188670.5798870416 + 30 +0.0 + 11 +532945.0315411522 + 21 +188802.6927942477 + 31 +0.0 + 0 +LINE + 5 +C54 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533313.3624009986 + 20 +188757.8532955949 + 30 +0.0 + 11 +533125.8924855081 + 21 +188669.7515777499 + 31 +0.0 + 0 +LINE + 5 +C55 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533309.4703294126 + 20 +188670.7508488964 + 30 +0.0 + 11 +533255.7236030304 + 21 +188737.1030091067 + 31 +0.0 + 0 +LINE + 5 +C56 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532760.3109855633 + 20 +188407.9772233068 + 30 +0.0 + 11 +532809.6843025367 + 21 +188483.3719616491 + 31 +0.0 + 0 +LINE + 5 +C57 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533234.3250746628 + 20 +188499.5449557109 + 30 +0.0 + 11 +532893.1205218853 + 21 +188751.3676701617 + 31 +0.0 + 0 +LINE + 5 +C58 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533287.9518486706 + 20 +189020.6443107427 + 30 +0.0 + 11 +532924.927540181 + 21 +188764.4635294863 + 31 +0.0 + 0 +LINE + 5 +C59 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533454.4086586428 + 20 +189157.773105065 + 30 +0.0 + 11 +533055.445001969 + 21 +188853.5597059197 + 31 +0.0 + 0 +LINE + 5 +C5A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533357.3073868794 + 20 +188959.3050643503 + 30 +0.0 + 11 +533252.2239717797 + 21 +189011.7169294218 + 31 +0.0 + 0 +LINE + 5 +C5B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533306.5062584413 + 20 +188923.6083560199 + 30 +0.0 + 11 +533280.2106583208 + 21 +189030.2579799969 + 31 +0.0 + 0 +LINE + 5 +C5C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533158.6658703738 + 20 +188804.2496591633 + 30 +0.0 + 11 +533303.8224281221 + 21 +188944.7373992113 + 31 +0.0 + 0 +LINE + 5 +C5D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533354.609919737 + 20 +188711.0432451002 + 30 +0.0 + 11 +533132.8052719798 + 21 +188914.3416323113 + 31 +0.0 + 0 +LINE + 5 +C5E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533443.6727279084 + 20 +188730.6953770002 + 30 +0.0 + 11 +533340.7311606862 + 21 +188666.2710084394 + 31 +0.0 + 0 +LINE + 5 +C5F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533410.8878722348 + 20 +188592.0952955483 + 30 +0.0 + 11 +533476.6391545755 + 21 +188693.4091634875 + 31 +0.0 + 0 +LINE + 5 +C60 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533475.1556176507 + 20 +188686.8384911694 + 30 +0.0 + 11 +533441.6580479251 + 21 +188731.5098882355 + 31 +0.0 + 0 +LINE + 5 +C61 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533642.3676091107 + 20 +188393.0670897887 + 30 +0.0 + 11 +533642.3591346374 + 21 +188393.0761903409 + 31 +0.0 + 0 +LINE + 5 +C62 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533542.6236322993 + 20 +188500.1799760925 + 30 +0.0 + 11 +533258.9648225294 + 21 +188804.7949995876 + 31 +0.0 + 0 +LINE + 5 +C63 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533245.9088162212 + 20 +188805.550290505 + 30 +0.0 + 11 +533263.8095899025 + 21 +188821.9611671926 + 31 +0.0 + 0 +LINE + 5 +C64 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533055.8700081143 + 20 +188811.7588395784 + 30 +0.0 + 11 +533028.5588840766 + 21 +188847.9284356091 + 31 +0.0 + 0 +LINE + 5 +C65 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533056.9875564872 + 20 +188796.2644286064 + 30 +0.0 + 11 +533053.3584333629 + 21 +188820.0546765659 + 31 +0.0 + 0 +LINE + 5 +C66 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533013.2988283583 + 20 +188749.362777014 + 30 +0.0 + 11 +533060.7288621851 + 21 +188803.3280831137 + 31 +0.0 + 0 +LINE + 5 +C67 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533269.5380431569 + 20 +188732.5458707275 + 30 +0.0 + 11 +533514.5678291421 + 21 +188984.2403845657 + 31 +0.0 + 0 +LINE + 5 +C68 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533561.3534292562 + 20 +188895.7936472422 + 30 +0.0 + 11 +533311.0450964412 + 21 +188744.2644269236 + 31 +0.0 + 0 +LINE + 5 +C69 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533398.812013349 + 20 +188650.3769333467 + 30 +0.0 + 11 +533424.5966082207 + 21 +188674.8135533515 + 31 +0.0 + 0 +LINE + 5 +C6A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533402.6159936026 + 20 +188859.6957374214 + 30 +0.0 + 11 +533344.6721587765 + 21 +188932.869176634 + 31 +0.0 + 0 +LINE + 5 +C6B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533369.5875381494 + 20 +188908.0748230476 + 30 +0.0 + 11 +533290.3394802066 + 21 +188934.0041029116 + 31 +0.0 + 0 +LINE + 5 +C6C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533361.6027688713 + 20 +188897.6577951062 + 30 +0.0 + 11 +533344.5555483907 + 21 +188975.9747146804 + 31 +0.0 + 0 +LINE + 5 +C6D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533478.1257172051 + 20 +189076.5283055594 + 30 +0.0 + 11 +533339.0280189092 + 21 +188964.6250737764 + 31 +0.0 + 0 +LINE + 5 +C6E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533137.8925834676 + 20 +188564.4631660981 + 30 +0.0 + 11 +533160.729268282 + 21 +188605.555692969 + 31 +0.0 + 0 +LINE + 5 +C6F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533209.7569790573 + 20 +188564.7070188652 + 30 +0.0 + 11 +533158.8282157264 + 21 +188605.536649204 + 31 +0.0 + 0 +LINE + 5 +C70 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533201.8322482928 + 20 +188515.7911299423 + 30 +0.0 + 11 +533275.8628790885 + 21 +188589.2922097849 + 31 +0.0 + 0 +LINE + 5 +C71 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533367.1502840121 + 20 +188468.961869401 + 30 +0.0 + 11 +533182.077165856 + 21 +188703.2835975423 + 31 +0.0 + 0 +LINE + 5 +C72 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533083.6060937013 + 20 +188706.9176953847 + 30 +0.0 + 11 +533125.1377409663 + 21 +188761.8238519414 + 31 +0.0 + 0 +LINE + 5 +C73 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533149.9316774165 + 20 +188741.8436458843 + 30 +0.0 + 11 +533102.1046123628 + 21 +188778.24617059 + 31 +0.0 + 0 +LINE + 5 +C74 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533141.594983066 + 20 +188739.7073203964 + 30 +0.0 + 11 +533185.4270794335 + 21 +188795.9854088964 + 31 +0.0 + 0 +LINE + 5 +C75 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533186.1646216841 + 20 +188792.3418710342 + 30 +0.0 + 11 +533142.361773903 + 21 +188827.4545513793 + 31 +0.0 + 0 +LINE + 5 +C76 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533101.6035714538 + 20 +188769.2245962995 + 30 +0.0 + 11 +533148.5419551448 + 21 +188830.8920588301 + 31 +0.0 + 0 +LINE + 5 +C77 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532993.6487211053 + 20 +188432.9116752496 + 30 +0.0 + 11 +532766.313591787 + 21 +188568.3091964116 + 31 +0.0 + 0 +LINE + 5 +C78 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534342.418987797 + 20 +188859.4888269258 + 30 +0.0 + 11 +535041.1571359639 + 21 +188606.5066843258 + 31 +0.0 + 0 +LINE + 5 +C79 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534534.3741274379 + 20 +188797.3384682259 + 30 +0.0 + 11 +534222.6936299359 + 21 +188332.6906515765 + 31 +0.0 + 0 +LINE + 5 +C7A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534453.323294102 + 20 +188685.8292292451 + 30 +0.0 + 11 +534586.7963206439 + 21 +188622.2474245328 + 31 +0.0 + 0 +LINE + 5 +C7B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534594.0885719828 + 20 +188771.1940418831 + 30 +0.0 + 11 +534034.5871467995 + 21 +187956.3988856886 + 31 +0.0 + 0 +LINE + 5 +C7C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534562.4969298503 + 20 +188644.0490266683 + 30 +0.0 + 11 +534606.5536739899 + 21 +188574.9107481938 + 31 +0.0 + 0 +LINE + 5 +C7D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534633.395276966 + 20 +188680.5009126278 + 30 +0.0 + 11 +534559.9569102708 + 21 +188632.2905944648 + 31 +0.0 + 0 +LINE + 5 +C7E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534614.4868337088 + 20 +188678.4537965122 + 30 +0.0 + 11 +534800.9292733384 + 21 +188609.2189101521 + 31 +0.0 + 0 +LINE + 5 +C7F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534678.5519897104 + 20 +188782.9836972875 + 30 +0.0 + 11 +534592.3486427728 + 21 +188358.6863907961 + 31 +0.0 + 0 +LINE + 5 +C80 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534788.0238202058 + 20 +188554.6512333887 + 30 +0.0 + 11 +534602.6972417204 + 21 +188576.8750509549 + 31 +0.0 + 0 +LINE + 5 +C81 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534798.8520678092 + 20 +188614.2864820481 + 30 +0.0 + 11 +534787.3244932632 + 21 +188554.1721268046 + 31 +0.0 + 0 +LINE + 5 +C82 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535082.2967784591 + 20 +188524.2240079788 + 30 +0.0 + 11 +534789.4297842628 + 21 +188574.967380576 + 31 +0.0 + 0 +LINE + 5 +C83 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535015.6002069867 + 20 +188539.4960375335 + 30 +0.0 + 11 +534988.7225627527 + 21 +188429.6079419225 + 31 +0.0 + 0 +LINE + 5 +C84 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535069.0832357024 + 20 +188416.2300748297 + 30 +0.0 + 11 +534273.6906374572 + 21 +188568.6690594344 + 31 +0.0 + 0 +LINE + 5 +C85 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534536.1152181576 + 20 +188448.6602559888 + 30 +0.0 + 11 +534364.1314518119 + 21 +188044.5496873147 + 31 +0.0 + 0 +LINE + 5 +C86 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534468.7599584501 + 20 +188465.7744611111 + 30 +0.0 + 11 +534654.8373345632 + 21 +188411.1417949609 + 31 +0.0 + 0 +LINE + 5 +C87 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534449.3582176149 + 20 +188395.8032480332 + 30 +0.0 + 11 +534511.2100066913 + 21 +188378.1963774951 + 31 +0.0 + 0 +LINE + 5 +C88 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534442.607819061 + 20 +188449.7633920994 + 30 +0.0 + 11 +534458.44569778 + 21 +188382.7826700915 + 31 +0.0 + 0 +LINE + 5 +C89 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534461.5876598364 + 20 +188402.9864281824 + 30 +0.0 + 11 +534281.0508963453 + 21 +188042.4263433427 + 31 +0.0 + 0 +LINE + 5 +C8A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534254.5657860476 + 20 +188401.6906691855 + 30 +0.0 + 11 +534605.8405935904 + 21 +188195.4924542807 + 31 +0.0 + 0 +LINE + 5 +C8B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534609.6070830462 + 20 +188208.2639284466 + 30 +0.0 + 11 +534501.0788297879 + 21 +187995.5260852271 + 31 +0.0 + 0 +LINE + 5 +C8C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534800.0167833604 + 20 +188215.3312327294 + 30 +0.0 + 11 +534593.4371319426 + 21 +188200.108568007 + 31 +0.0 + 0 +LINE + 5 +C8D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534753.8855132741 + 20 +188289.3169770472 + 30 +0.0 + 11 +534739.6121234155 + 21 +188205.1291507104 + 31 +0.0 + 0 +LINE + 5 +C8E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534127.7590375945 + 20 +188178.051666309 + 30 +0.0 + 11 +534504.061715031 + 21 +187996.3800245856 + 31 +0.0 + 0 +LINE + 5 +C8F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534604.40035436 + 20 +188401.6221614216 + 30 +0.0 + 11 +534430.6623416044 + 21 +188014.7755131572 + 31 +0.0 + 0 +LINE + 5 +C90 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534906.8235633151 + 20 +187973.8832557906 + 30 +0.0 + 11 +534425.4628749706 + 21 +188019.4251176826 + 31 +0.0 + 0 +LINE + 5 +C91 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535156.488421269 + 20 +187930.8682847123 + 30 +0.0 + 11 +534622.2457847449 + 21 +188005.3822538067 + 31 +0.0 + 0 +LINE + 5 +C92 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534937.1572461826 + 20 +188061.3621761767 + 30 +0.0 + 11 +534871.3120220185 + 21 +187964.1308325468 + 31 +0.0 + 0 +LINE + 5 +C93 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534875.3764938226 + 20 +188067.5386050841 + 30 +0.0 + 11 +534904.7956771976 + 21 +187961.70802099 + 31 +0.0 + 0 +LINE + 5 +C94 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534687.9901235956 + 20 +188098.9969443977 + 30 +0.0 + 11 +534883.405704264 + 21 +188047.8111827726 + 31 +0.0 + 0 +LINE + 5 +C95 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534822.953366526 + 20 +188309.1007252122 + 30 +0.0 + 11 +534719.4774529505 + 21 +187990.380365594 + 31 +0.0 + 0 +LINE + 5 +C96 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534907.6954397033 + 20 +188694.6210301165 + 30 +0.0 + 11 +534775.6518398568 + 21 +188147.7370788022 + 31 +0.0 + 0 +LINE + 5 +C97 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534764.6462774784 + 20 +188140.6725645359 + 30 +0.0 + 11 +534788.2964630404 + 21 +188135.1568329503 + 31 +0.0 + 0 +LINE + 5 +C98 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534602.1050007739 + 20 +188042.0134137412 + 30 +0.0 + 11 +534596.0557457803 + 21 +187997.0963380654 + 31 +0.0 + 0 +LINE + 5 +C99 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534595.4758680417 + 20 +188056.0626231478 + 30 +0.0 + 11 +534603.9872268712 + 21 +188033.5525542118 + 31 +0.0 + 0 +LINE + 5 +C9A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534534.3942980067 + 20 +188075.4922831983 + 30 +0.0 + 11 +534602.2018414045 + 21 +188051.743611033 + 31 +0.0 + 0 +LINE + 5 +C9B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534749.4130227723 + 20 +188215.8785059482 + 30 +0.0 + 11 +535164.3885908858 + 21 +188087.6109622003 + 31 +0.0 + 0 +LINE + 5 +C9C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535053.0865184272 + 20 +188427.9533155489 + 30 +0.0 + 11 +535146.0381762112 + 21 +188077.3188132905 + 31 +0.0 + 0 +LINE + 5 +C9D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535186.8532867293 + 20 +188210.9670159163 + 30 +0.0 + 11 +534791.3297615979 + 21 +188226.0346389663 + 31 +0.0 + 0 +LINE + 5 +C9E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534927.7593634743 + 20 +188170.3877128874 + 30 +0.0 + 11 +534913.1759876781 + 21 +188078.1967949456 + 31 +0.0 + 0 +LINE + 5 +C9F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534922.7194174261 + 20 +188112.0266493305 + 30 +0.0 + 11 +534866.3908411974 + 21 +188050.5475980855 + 31 +0.0 + 0 +LINE + 5 +CA0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534910.6505059065 + 20 +188117.1853687731 + 30 +0.0 + 11 +534934.2256724622 + 21 +188040.5801526349 + 31 +0.0 + 0 +LINE + 5 +CA1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535213.9468003766 + 20 +187999.5703161947 + 30 +0.0 + 11 +534923.8402230674 + 21 +188047.7572252753 + 31 +0.0 + 0 +LINE + 5 +CA2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535199.1434991289 + 20 +188597.3491948433 + 30 +0.0 + 11 +535023.064663989 + 21 +188611.2282506775 + 31 +0.0 + 0 +LINE + 5 +CA3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535086.3416508714 + 20 +188617.5552892779 + 30 +0.0 + 11 +535061.093369618 + 21 +188355.4458741167 + 31 +0.0 + 0 +LINE + 5 +CA4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534552.2296856262 + 20 +188297.7384729914 + 30 +0.0 + 11 +534592.291654657 + 21 +188273.1387052013 + 31 +0.0 + 0 +LINE + 5 +CA5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534614.9674026566 + 20 +188332.7888607126 + 30 +0.0 + 11 +534590.6258539049 + 21 +188272.2224785161 + 31 +0.0 + 0 +LINE + 5 +CA6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534584.0599459788 + 20 +188371.5224981418 + 30 +0.0 + 11 +534684.631491202 + 21 +188343.804140949 + 31 +0.0 + 0 +LINE + 5 +CA7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534705.1290929152 + 20 +188493.4458110767 + 30 +0.0 + 11 +534658.8465861588 + 21 +188198.4599454638 + 31 +0.0 + 0 +LINE + 5 +CA8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534574.828360812 + 20 +188146.9750299248 + 30 +0.0 + 11 +534637.9580877661 + 21 +188119.5123037841 + 31 +0.0 + 0 +LINE + 5 +CA9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534649.7579355233 + 20 +188149.0878259552 + 30 +0.0 + 11 +534625.9466897634 + 21 +188093.9009023957 + 31 +0.0 + 0 +LINE + 5 +CAA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534641.4456051139 + 20 +188146.8585833822 + 30 +0.0 + 11 +534707.2529850864 + 21 +188119.3292416115 + 31 +0.0 + 0 +LINE + 5 +CAB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534706.1077988136 + 20 +188122.8658904667 + 30 +0.0 + 11 +534685.170091141 + 21 +188070.7774830026 + 31 +0.0 + 0 +LINE + 5 +CAC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534621.083352799 + 20 +188101.5158743744 + 30 +0.0 + 11 +534692.2418452411 + 21 +188070.8147872303 + 31 +0.0 + 0 +LINE + 5 +CAD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534067.3002023453 + 20 +188003.8214991741 + 30 +0.0 + 11 +534025.5032141101 + 21 +187765.8893586528 + 31 +0.0 + 0 +LINE + 5 +CAE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534515.4513497963 + 20 +187931.4269758353 + 30 +0.0 + 11 +534002.546387197 + 21 +188020.2950563631 + 31 +0.0 + 0 +LINE + 5 +CAF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534502.2378070394 + 20 +187823.4330426864 + 30 +0.0 + 11 +533760.1825551896 + 21 +187965.6497911978 + 31 +0.0 + 0 +LINE + 5 +CB0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533969.2697894947 + 20 +187855.8632238454 + 30 +0.0 + 11 +533797.2860231489 + 21 +187451.7526551713 + 31 +0.0 + 0 +LINE + 5 +CB1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533901.9145297874 + 20 +187872.9774289677 + 30 +0.0 + 11 +534087.9919059005 + 21 +187818.3447628175 + 31 +0.0 + 0 +LINE + 5 +CB2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533882.512788952 + 20 +187803.0062158899 + 30 +0.0 + 11 +533944.3645780285 + 21 +187785.3993453517 + 31 +0.0 + 0 +LINE + 5 +CB3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533875.7623903983 + 20 +187856.9663599559 + 30 +0.0 + 11 +533891.6002691171 + 21 +187789.9856379482 + 31 +0.0 + 0 +LINE + 5 +CB4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533894.7422311735 + 20 +187810.1893960391 + 30 +0.0 + 11 +533714.2054676827 + 21 +187449.6293111992 + 31 +0.0 + 0 +LINE + 5 +CB5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533782.6701975751 + 20 +187753.2877346548 + 30 +0.0 + 11 +534038.9951649274 + 21 +187602.6954221372 + 31 +0.0 + 0 +LINE + 5 +CB6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534042.7616543834 + 20 +187615.4668963031 + 30 +0.0 + 11 +533934.233401125 + 21 +187402.7290530838 + 31 +0.0 + 0 +LINE + 5 +CB7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534233.1713546975 + 20 +187622.5342005861 + 30 +0.0 + 11 +534026.5917032798 + 21 +187607.3115358635 + 31 +0.0 + 0 +LINE + 5 +CB8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534187.0400846114 + 20 +187696.519944904 + 30 +0.0 + 11 +534172.7666947527 + 21 +187612.332118567 + 31 +0.0 + 0 +LINE + 5 +CB9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533632.607411396 + 20 +187553.2629338686 + 30 +0.0 + 11 +533937.2162863679 + 21 +187403.5829924421 + 31 +0.0 + 0 +LINE + 5 +CBA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534037.5549256969 + 20 +187808.8251292782 + 30 +0.0 + 11 +533863.8169129417 + 21 +187421.9784810139 + 31 +0.0 + 0 +LINE + 5 +CBB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534400.0024326341 + 20 +187377.1971327206 + 30 +0.0 + 11 +533858.6174463078 + 21 +187426.6280855392 + 31 +0.0 + 0 +LINE + 5 +CBC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534370.3118175198 + 20 +187468.5651440334 + 30 +0.0 + 11 +534304.4665933558 + 21 +187371.3338004034 + 31 +0.0 + 0 +LINE + 5 +CBD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534308.5310651599 + 20 +187474.7415729406 + 30 +0.0 + 11 +534337.9502485348 + 21 +187368.9109888465 + 31 +0.0 + 0 +LINE + 5 +CBE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534121.1446949326 + 20 +187506.1999122544 + 30 +0.0 + 11 +534316.5602756013 + 21 +187455.0141506292 + 31 +0.0 + 0 +LINE + 5 +CBF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534256.1079378633 + 20 +187716.303693069 + 30 +0.0 + 11 +534152.6320242878 + 21 +187397.5833334506 + 31 +0.0 + 0 +LINE + 5 +CC0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534168.7652893984 + 20 +187749.8874060726 + 30 +0.0 + 11 +534279.2753342777 + 21 +187699.5386671871 + 31 +0.0 + 0 +LINE + 5 +CC1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534187.9902158508 + 20 +187800.3354088496 + 30 +0.0 + 11 +534169.1967959018 + 21 +187747.7575783508 + 31 +0.0 + 0 +LINE + 5 +CC2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534340.8500110405 + 20 +188101.8239979731 + 30 +0.0 + 11 +534208.8064111941 + 21 +187554.9400466588 + 31 +0.0 + 0 +LINE + 5 +CC3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534197.8008488156 + 20 +187547.8755323925 + 30 +0.0 + 11 +534221.4510343777 + 21 +187542.3598008071 + 31 +0.0 + 0 +LINE + 5 +CC4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534035.2595721112 + 20 +187449.2163815976 + 30 +0.0 + 11 +534029.2103171174 + 21 +187404.2993059221 + 31 +0.0 + 0 +LINE + 5 +CC5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534028.6304393789 + 20 +187463.2655910044 + 30 +0.0 + 11 +534037.1417982083 + 21 +187440.7555220685 + 31 +0.0 + 0 +LINE + 5 +CC6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533967.5488693438 + 20 +187482.695251055 + 30 +0.0 + 11 +534035.3564127415 + 21 +187458.9465788896 + 31 +0.0 + 0 +LINE + 5 +CC7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534182.5675941095 + 20 +187623.0814738048 + 30 +0.0 + 11 +534519.7683430233 + 21 +187511.9531550208 + 31 +0.0 + 0 +LINE + 5 +CC8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534486.2410897645 + 20 +187835.1562834054 + 30 +0.0 + 11 +534542.8298393397 + 21 +187639.1349535193 + 31 +0.0 + 0 +LINE + 5 +CC9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534568.7167464405 + 20 +187656.3747033612 + 30 +0.0 + 11 +534224.4843329351 + 21 +187633.2376068228 + 31 +0.0 + 0 +LINE + 5 +CCA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534254.8895447855 + 20 +187758.1112079001 + 30 +0.0 + 11 +534289.3473118174 + 21 +187749.4708363137 + 31 +0.0 + 0 +LINE + 5 +CCB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534360.9139348114 + 20 +187577.5906807442 + 30 +0.0 + 11 +534346.3305590152 + 21 +187485.3997628022 + 31 +0.0 + 0 +LINE + 5 +CCC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534355.8739887633 + 20 +187519.2296171871 + 30 +0.0 + 11 +534299.5454125343 + 21 +187457.7505659422 + 31 +0.0 + 0 +LINE + 5 +CCD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534343.8050772437 + 20 +187524.3883366297 + 30 +0.0 + 11 +534367.3802437997 + 21 +187447.7831204914 + 31 +0.0 + 0 +LINE + 5 +CCE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534481.6976816879 + 20 +187437.0367879853 + 30 +0.0 + 11 +534356.9947944047 + 21 +187454.9601931319 + 31 +0.0 + 0 +LINE + 5 +CCF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534503.1707014955 + 20 +188032.0361112815 + 30 +0.0 + 11 +534494.2479409549 + 21 +187762.6488419732 + 31 +0.0 + 0 +LINE + 5 +CD0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533985.3842569635 + 20 +187704.941440848 + 30 +0.0 + 11 +534025.4462259941 + 21 +187680.3416730576 + 31 +0.0 + 0 +LINE + 5 +CD1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534048.121973994 + 20 +187739.9918285693 + 30 +0.0 + 11 +534023.7804252421 + 21 +187679.4254463728 + 31 +0.0 + 0 +LINE + 5 +CD2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534017.2145173163 + 20 +187778.7254659985 + 30 +0.0 + 11 +534117.7860625391 + 21 +187751.0071088056 + 31 +0.0 + 0 +LINE + 5 +CD3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534138.2836642524 + 20 +187900.6487789333 + 30 +0.0 + 11 +534092.0011574961 + 21 +187605.6629133204 + 31 +0.0 + 0 +LINE + 5 +CD4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534007.9829321491 + 20 +187554.1779977815 + 30 +0.0 + 11 +534071.1126591032 + 21 +187526.7152716407 + 31 +0.0 + 0 +LINE + 5 +CD5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534082.9125068603 + 20 +187556.2907938117 + 30 +0.0 + 11 +534059.1012611005 + 21 +187501.103870252 + 31 +0.0 + 0 +LINE + 5 +CD6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534074.6001764511 + 20 +187554.0615512388 + 30 +0.0 + 11 +534140.4075564234 + 21 +187526.5322094681 + 31 +0.0 + 0 +LINE + 5 +CD7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534139.2623701508 + 20 +187530.0688583234 + 30 +0.0 + 11 +534118.3246624784 + 21 +187477.9804508591 + 31 +0.0 + 0 +LINE + 5 +CD8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534054.2379241361 + 20 +187508.718842231 + 30 +0.0 + 11 +534125.3964165783 + 21 +187478.0177550869 + 31 +0.0 + 0 +LINE + 5 +CD9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534377.9482391282 + 20 +187960.2763376868 + 30 +0.0 + 11 +534352.0344263502 + 21 +187850.5811014604 + 31 +0.0 + 0 +LINE + 5 +CDA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534360.7679136229 + 20 +187393.7639810799 + 30 +0.0 + 11 +534770.1398838371 + 21 +186990.0841702868 + 31 +0.0 + 0 +LINE + 5 +CDB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534428.0054739007 + 20 +187408.1899054635 + 30 +0.0 + 11 +534591.3264570555 + 21 +187250.0894271984 + 31 +0.0 + 0 +LINE + 5 +CDC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534484.1322009104 + 20 +187586.4134526264 + 30 +0.0 + 11 +534643.0156503759 + 21 +187526.5056307297 + 31 +0.0 + 0 +LINE + 5 +CDD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534662.2228028087 + 20 +188006.316252708 + 30 +0.0 + 11 +534403.5059120892 + 21 +187296.4309304117 + 31 +0.0 + 0 +LINE + 5 +CDE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534545.2265514975 + 20 +187485.3378447537 + 30 +0.0 + 11 +535008.1886856977 + 21 +187247.5992257941 + 31 +0.0 + 0 +LINE + 5 +CDF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534517.5916033422 + 20 +187421.5731470936 + 30 +0.0 + 11 +534601.1950789026 + 21 +187596.5587950364 + 31 +0.0 + 0 +LINE + 5 +CE0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534583.5740422579 + 20 +187391.2628194515 + 30 +0.0 + 11 +534610.8178324108 + 21 +187449.5159017755 + 31 +0.0 + 0 +LINE + 5 +CE1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534529.2279100611 + 20 +187393.2026502444 + 30 +0.0 + 11 +534597.8770235372 + 21 +187398.1579243974 + 31 +0.0 + 0 +LINE + 5 +CE2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534578.4327287344 + 20 +187404.4811487468 + 30 +0.0 + 11 +534803.2685851388 + 21 +187177.2203280783 + 31 +0.0 + 0 +LINE + 5 +CE3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534658.0654168236 + 20 +187640.2422304982 + 30 +0.0 + 11 +534986.9769317319 + 21 +187378.4981200029 + 31 +0.0 + 0 +LINE + 5 +CE4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534747.144412568 + 20 +187821.5636049725 + 30 +0.0 + 11 +534722.2505399106 + 21 +187702.7033482393 + 31 +0.0 + 0 +LINE + 5 +CE5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534628.4045815115 + 20 +187742.9144990611 + 30 +0.0 + 11 +534700.7649085668 + 21 +187839.6187597465 + 31 +0.0 + 0 +LINE + 5 +CE6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534695.1113314549 + 20 +187835.9565633617 + 30 +0.0 + 11 +534748.6047944875 + 21 +187819.9543664458 + 31 +0.0 + 0 +LINE + 5 +CE7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534361.6604653533 + 20 +187891.3822456155 + 30 +0.0 + 11 +534361.6719332852 + 21 +187891.3774369479 + 31 +0.0 + 0 +LINE + 5 +CE8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534496.6372509165 + 20 +187834.7845541287 + 30 +0.0 + 11 +535056.9980084965 + 21 +187540.6308271714 + 31 +0.0 + 0 +LINE + 5 +CE9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534781.928612762 + 20 +187509.102585166 + 30 +0.0 + 11 +534960.5856270645 + 21 +187975.6870431467 + 31 +0.0 + 0 +LINE + 5 +CEA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534861.4214791478 + 20 +187989.0358067275 + 30 +0.0 + 11 +534771.6287406363 + 21 +187677.4285060179 + 31 +0.0 + 0 +LINE + 5 +CEB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534687.2696056447 + 20 +187751.7170331342 + 30 +0.0 + 11 +534701.2936751604 + 21 +187784.3562611305 + 31 +0.0 + 0 +LINE + 5 +CEC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534726.7756330002 + 20 +187332.3435424447 + 30 +0.0 + 11 +534727.4597728151 + 21 +187512.8089178462 + 31 +0.0 + 0 +LINE + 5 +CED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534672.1883820148 + 20 +187544.7056881982 + 30 +0.0 + 11 +534728.0986680131 + 21 +187511.0183379375 + 31 +0.0 + 0 +LINE + 5 +CEE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534527.9629881593 + 20 +187659.3303882316 + 30 +0.0 + 11 +534751.1158335205 + 21 +187586.4283479941 + 31 +0.0 + 0 +LINE + 5 +CEF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534846.1955660799 + 20 +188389.8968598512 + 30 +0.0 + 11 +534682.3331169241 + 21 +188418.5382548995 + 31 +0.0 + 0 +LINE + 5 +CF0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534945.2721225843 + 20 +188398.7611056485 + 30 +0.0 + 11 +534912.1433930747 + 21 +188580.2924171957 + 31 +0.0 + 0 +LINE + 5 +CF1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534678.2877958446 + 20 +187937.8335458117 + 30 +0.0 + 11 +534477.114611199 + 21 +187880.3287166929 + 31 +0.0 + 0 +LINE + 5 +CF2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534676.1352028901 + 20 +187527.3454333013 + 30 +0.0 + 11 +534732.0690495518 + 21 +187630.3094970343 + 31 +0.0 + 0 +LINE + 5 +CF3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534258.091680705 + 20 +188399.6209699965 + 30 +0.0 + 11 +534060.7481695947 + 21 +188381.7399515909 + 31 +0.0 + 0 +LINE + 5 +CF4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535780.3901278204 + 20 +185439.4290383135 + 30 +0.0 + 11 +533707.5812551458 + 21 +186696.108607327 + 31 +0.0 + 0 +LINE + 5 +CF6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535804.6699560423 + 20 +185803.0532584575 + 30 +0.0 + 11 +535577.8025029244 + 21 +185518.9490408467 + 31 +0.0 + 0 +LINE + 5 +CF8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535564.9239086284 + 20 +185788.4221394258 + 30 +0.0 + 11 +535372.3764689632 + 21 +185534.021633504 + 31 +0.0 + 0 +LINE + 5 +CF9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535142.8676494943 + 20 +185933.7047163851 + 30 +0.0 + 11 +535006.3805352725 + 21 +185752.840818464 + 31 +0.0 + 0 +LINE + 5 +CFA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535703.5356364426 + 20 +185631.1989691456 + 30 +0.0 + 11 +535529.1529331644 + 21 +185801.4138902812 + 31 +0.0 + 0 +LINE + 5 +CFB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +535595.9938929793 + 20 +185461.8081714932 + 30 +0.0 + 11 +535355.6089108344 + 21 +185624.1998165417 + 31 +0.0 + 0 +LINE + 5 +CFC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533867.7630282873 + 20 +186590.6939104643 + 30 +0.0 + 11 +531012.3148168298 + 21 +188613.2911204371 + 31 +0.0 + 0 +LINE + 5 +CFD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534573.8956867553 + 20 +187153.838925518 + 30 +0.0 + 11 +534736.3934995475 + 21 +187351.9393427316 + 31 +0.0 + 0 +LINE + 5 +CFE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534338.5537451374 + 20 +186510.8915983567 + 30 +0.0 + 11 +533945.2158445 + 21 +186706.2606427902 + 31 +0.0 + 0 +LINE + 5 +CFF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534205.142888429 + 20 +186310.9539163557 + 30 +0.0 + 11 +534404.4041436459 + 21 +186616.5623173755 + 31 +0.0 + 0 +LINE + 5 +D00 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534238.2645607369 + 20 +186494.6829609836 + 30 +0.0 + 11 +534273.831700889 + 21 +186548.2611677799 + 31 +0.0 + 0 +LINE + 5 +D01 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534094.0416092633 + 20 +186363.6162093194 + 30 +0.0 + 11 +534227.0182658679 + 21 +186748.621278172 + 31 +0.0 + 0 +LINE + 5 +D02 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534238.1808818067 + 20 +186741.3622837103 + 30 +0.0 + 11 +534017.4410964214 + 21 +186832.5199429668 + 31 +0.0 + 0 +LINE + 5 +D03 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534387.4918473375 + 20 +186859.734731247 + 30 +0.0 + 11 +534220.5911293927 + 21 +186737.0520827154 + 31 +0.0 + 0 +LINE + 5 +D04 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534400.5124712154 + 20 +186773.5230858858 + 30 +0.0 + 11 +534334.9520369448 + 21 +186828.2327671101 + 31 +0.0 + 0 +LINE + 5 +D05 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533983.943777705 + 20 +186379.5045163599 + 30 +0.0 + 11 +534017.8097838926 + 21 +186463.0220871074 + 31 +0.0 + 0 +LINE + 5 +D06 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533832.6194479275 + 20 +186400.5220216849 + 30 +0.0 + 11 +534020.2631537003 + 21 +186833.8094426817 + 31 +0.0 + 0 +LINE + 5 +D07 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534359.8836305158 + 20 +186591.0194846162 + 30 +0.0 + 11 +533976.4319530882 + 21 +186772.1272907083 + 31 +0.0 + 0 +LINE + 5 +D08 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534311.7560399915 + 20 +187112.655472385 + 30 +0.0 + 11 +533975.5018705906 + 21 +186765.2143881295 + 31 +0.0 + 0 +LINE + 5 +D09 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534473.5554319845 + 20 +187307.601069372 + 30 +0.0 + 11 +534115.9375794735 + 21 +186903.7731383969 + 31 +0.0 + 0 +LINE + 5 +D0A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534391.6616832556 + 20 +187065.8817404109 + 30 +0.0 + 11 +534278.4280981259 + 21 +187096.9893428252 + 31 +0.0 + 0 +LINE + 5 +D0B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534348.7200946414 + 20 +187021.0372356918 + 30 +0.0 + 11 +534302.3023088374 + 21 +187120.591191119 + 31 +0.0 + 0 +LINE + 5 +D0C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534226.7440903293 + 20 +186875.3487556006 + 30 +0.0 + 11 +534342.0020785355 + 21 +187041.2488083907 + 31 +0.0 + 0 +LINE + 5 +D0D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534624.0890229793 + 20 +186704.244408671 + 30 +0.0 + 11 +534180.0876000576 + 21 +186978.3642156855 + 31 +0.0 + 0 +LINE + 5 +D0E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534312.0896937012 + 20 +186893.4912809786 + 30 +0.0 + 11 +534326.4800893573 + 21 +186913.0532615762 + 31 +0.0 + 0 +LINE + 5 +D0F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534124.4358105409 + 20 +186862.8430379104 + 30 +0.0 + 11 +534090.647363259 + 21 +186893.0502887538 + 31 +0.0 + 0 +LINE + 5 +D10 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534128.5277661647 + 20 +186847.8569915702 + 30 +0.0 + 11 +534120.367807649 + 21 +186870.4968128956 + 31 +0.0 + 0 +LINE + 5 +D11 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534094.7306176895 + 20 +186793.3939523367 + 30 +0.0 + 11 +534130.8328933959 + 21 +186855.5106816458 + 31 +0.0 + 0 +LINE + 5 +D12 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534349.3868772822 + 20 +186826.4323086515 + 30 +0.0 + 11 +534581.4240908384 + 21 +187193.605314788 + 31 +0.0 + 0 +LINE + 5 +D13 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534584.2426089188 + 20 +187161.9710756716 + 30 +0.0 + 11 +534397.7710279386 + 21 +187237.7514276956 + 31 +0.0 + 0 +LINE + 5 +D14 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534678.6649329562 + 20 +187114.4497895736 + 30 +0.0 + 11 +534387.8453576843 + 21 +186845.9542275332 + 31 +0.0 + 0 +LINE + 5 +D15 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534455.3727022235 + 20 +186976.9109928783 + 30 +0.0 + 11 +534384.375602175 + 21 +187037.5018501531 + 31 +0.0 + 0 +LINE + 5 +D16 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534413.6143587174 + 20 +187017.9920778603 + 30 +0.0 + 11 +534330.8485329645 + 21 +187028.1113826482 + 31 +0.0 + 0 +LINE + 5 +D17 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534407.7941217914 + 20 +187006.2279011498 + 30 +0.0 + 11 +534375.9277202994 + 21 +187079.771630139 + 31 +0.0 + 0 +LINE + 5 +D18 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534487.5382601636 + 20 +187204.2509538315 + 30 +0.0 + 11 +534372.6986651564 + 21 +187067.5674860189 + 31 +0.0 + 0 +LINE + 5 +D19 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534252.7199476946 + 20 +186636.0699505644 + 30 +0.0 + 11 +534267.1815018675 + 21 +186680.8021916089 + 31 +0.0 + 0 +LINE + 5 +D1A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534323.1814311998 + 20 +186650.2025426782 + 30 +0.0 + 11 +534265.3199955861 + 21 +186680.415982018 + 31 +0.0 + 0 +LINE + 5 +D1B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534324.8629757305 + 20 +186600.6774181978 + 30 +0.0 + 11 +534383.2872150517 + 21 +186687.1039841008 + 31 +0.0 + 0 +LINE + 5 +D1C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534496.1155469523 + 20 +186586.6920892123 + 30 +0.0 + 11 +534269.2331987927 + 21 +186780.813523981 + 31 +0.0 + 0 +LINE + 5 +D1D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534171.9172778454 + 20 +186765.3419290852 + 30 +0.0 + 11 +534202.0505519514 + 21 +186827.2414407475 + 31 +0.0 + 0 +LINE + 5 +D1E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534230.2394511825 + 20 +186812.4315157334 + 30 +0.0 + 11 +534176.27707806 + 21 +186838.901012208 + 31 +0.0 + 0 +LINE + 5 +D1F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534222.4730437592 + 20 +186808.7237839446 + 30 +0.0 + 11 +534254.5981357822 + 21 +186872.4140844594 + 31 +0.0 + 0 +LINE + 5 +D20 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534256.0261586587 + 20 +186868.9818712686 + 30 +0.0 + 11 +534206.2614452762 + 21 +186894.9638476503 + 31 +0.0 + 0 +LINE + 5 +D21 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534177.5296049868 + 20 +186829.9527709859 + 30 +0.0 + 11 +534211.6604697993 + 21 +186899.531301192 + 31 +0.0 + 0 +LINE + 5 +D22 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534302.1858237155 + 20 +186200.0906309843 + 30 +0.0 + 11 +532982.5285202879 + 21 +186527.3959672318 + 31 +0.0 + 0 +LINE + 5 +D23 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533613.6902769207 + 20 +186358.993742019 + 30 +0.0 + 11 +533673.8137852908 + 21 +186494.0598682165 + 31 +0.0 + 0 +LINE + 5 +D24 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533776.1538853722 + 20 +186385.5943176254 + 30 +0.0 + 11 +533297.6070133881 + 21 +186510.0029110075 + 31 +0.0 + 0 +LINE + 5 +D25 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533669.5138658524 + 20 +186461.6981479062 + 30 +0.0 + 11 +533658.0668105337 + 21 +186542.8773520114 + 31 +0.0 + 0 +LINE + 5 +D26 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533747.0885230267 + 20 +186480.0689992206 + 30 +0.0 + 11 +533659.94176783 + 21 +186468.984255701 + 31 +0.0 + 0 +LINE + 5 +D27 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533915.0945289718 + 20 +186379.145676624 + 30 +0.0 + 11 +533506.7501595299 + 21 +186697.9838533997 + 31 +0.0 + 0 +LINE + 5 +D28 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533945.9411390942 + 20 +186835.6257744556 + 30 +0.0 + 11 +533854.0988856495 + 21 +186901.6772831347 + 31 +0.0 + 0 +LINE + 5 +D29 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533906.4817802253 + 20 +186964.0698903952 + 30 +0.0 + 11 +533434.9178717218 + 21 +186373.7317834158 + 31 +0.0 + 0 +LINE + 5 +D2A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533522.483184404 + 20 +186593.0554664399 + 30 +0.0 + 11 +533062.5983105609 + 21 +186790.5020190729 + 31 +0.0 + 0 +LINE + 5 +D2B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533482.4130391135 + 20 +186536.2750958563 + 30 +0.0 + 11 +533588.3335829126 + 21 +186698.7261854587 + 31 +0.0 + 0 +LINE + 5 +D2C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533422.1940000035 + 20 +186576.8468290668 + 30 +0.0 + 11 +533457.7611401558 + 21 +186630.4250358631 + 31 +0.0 + 0 +LINE + 5 +D2D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533452.1311894492 + 20 +186531.4482639312 + 30 +0.0 + 11 +533420.6389637881 + 21 +186592.6487152852 + 31 +0.0 + 0 +LINE + 5 +D2E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533436.1570249224 + 20 +186579.3350551873 + 30 +0.0 + 11 +533306.6325132512 + 21 +186633.9674166327 + 31 +0.0 + 0 +LINE + 5 +D2F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533277.9710485301 + 20 +186445.7800774027 + 30 +0.0 + 11 +533540.7672647548 + 21 +187197.9379284728 + 31 +0.0 + 0 +LINE + 5 +D30 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533422.1103210733 + 20 +186823.5261517935 + 30 +0.0 + 11 +533238.7604418549 + 21 +186898.0710717438 + 31 +0.0 + 0 +LINE + 5 +D31 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533154.9462600293 + 20 +186469.3279651543 + 30 +0.0 + 11 +533188.812266217 + 21 +186552.8455359016 + 31 +0.0 + 0 +LINE + 5 +D32 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533543.8130697824 + 20 +186673.1833526995 + 30 +0.0 + 11 +533159.1539992682 + 21 +186854.8614218153 + 31 +0.0 + 0 +LINE + 5 +D33 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533649.7930045239 + 20 +186885.536569575 + 30 +0.0 + 11 +533289.3755657732 + 21 +187116.8555180623 + 31 +0.0 + 0 +LINE + 5 +D34 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533964.7426793781 + 20 +186647.5999671596 + 30 +0.0 + 11 +533508.9748474477 + 21 +186977.4381878725 + 31 +0.0 + 0 +LINE + 5 +D35 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533533.3163165489 + 20 +186908.5961767348 + 30 +0.0 + 11 +533807.3275931497 + 21 +187360.5605178996 + 31 +0.0 + 0 +LINE + 5 +D36 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533901.9424377028 + 20 +186944.7638367852 + 30 +0.0 + 11 +533817.5611283347 + 21 +187130.5229360999 + 31 +0.0 + 0 +LINE + 5 +D37 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533848.4398897749 + 20 +187134.243557791 + 30 +0.0 + 11 +533571.7747969511 + 21 +186928.1180956163 + 31 +0.0 + 0 +LINE + 5 +D38 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533639.3021414902 + 20 +187059.0748609615 + 30 +0.0 + 11 +533475.2858643194 + 21 +187197.5741820712 + 31 +0.0 + 0 +LINE + 5 +D39 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533639.7585737072 + 20 +187244.3959389553 + 30 +0.0 + 11 +533508.199878366 + 21 +187142.9593923612 + 31 +0.0 + 0 +LINE + 5 +D3A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534042.758202935 + 20 +186806.130512364 + 30 +0.0 + 11 +533860.9066406696 + 21 +187005.0755445281 + 31 +0.0 + 0 +LINE + 5 +D3B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533436.6493869612 + 20 +186718.2338186477 + 30 +0.0 + 11 +533451.1109411342 + 21 +186762.966059692 + 31 +0.0 + 0 +LINE + 5 +D3C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533507.1108704664 + 20 +186732.3664107614 + 30 +0.0 + 11 +533449.2494348529 + 21 +186762.5798501013 + 31 +0.0 + 0 +LINE + 5 +D3D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533508.7924149971 + 20 +186682.8412862811 + 30 +0.0 + 11 +533567.2166543183 + 21 +186769.2678521841 + 31 +0.0 + 0 +LINE + 5 +D3E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533900.9493501624 + 20 +186779.2906266893 + 30 +0.0 + 11 +533809.9649782856 + 21 +186845.8219322354 + 31 +0.0 + 0 +LINE + 5 +D3F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533320.5592558329 + 20 +186561.2778756949 + 30 +0.0 + 11 +532991.0926725162 + 21 +186707.4178168395 + 31 +0.0 + 0 +LINE + 5 +D40 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533580.2035412068 + 20 +187231.4269793923 + 30 +0.0 + 11 +533650.3051828861 + 21 +187576.4792701323 + 31 +0.0 + 0 +LINE + 5 +D41 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534146.9285046155 + 20 +186929.0436129879 + 30 +0.0 + 11 +533457.9740159064 + 21 +187317.9322787298 + 31 +0.0 + 0 +LINE + 5 +D42 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534071.615960048 + 20 +187256.2822432926 + 30 +0.0 + 11 +533911.2409323012 + 21 +187430.823099838 + 31 +0.0 + 0 +LINE + 5 +D43 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533988.5834052235 + 20 +187229.6818808633 + 30 +0.0 + 11 +534032.1396282146 + 21 +187303.1269297103 + 31 +0.0 + 0 +LINE + 5 +D44 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534275.7904482939 + 20 +187285.0355955895 + 30 +0.0 + 11 +534288.4451373226 + 21 +187401.7805593987 + 31 +0.0 + 0 +LINE + 5 +D45 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534224.6726996108 + 20 +187320.2774089048 + 30 +0.0 + 11 +534315.5517373769 + 21 +187381.9750699207 + 31 +0.0 + 0 +LINE + 5 +D46 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534028.5193002688 + 20 +187211.5519736528 + 30 +0.0 + 11 +534164.1239993988 + 21 +187419.4014063171 + 31 +0.0 + 0 +LINE + 5 +D47 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534091.4044771071 + 20 +187124.6511358966 + 30 +0.0 + 11 +533995.2391131685 + 21 +187198.8110192915 + 31 +0.0 + 0 +LINE + 5 +D48 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533950.0453981045 + 20 +187107.2603301792 + 30 +0.0 + 11 +534067.888148219 + 21 +187080.787377725 + 31 +0.0 + 0 +LINE + 5 +D49 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534061.2112356012 + 20 +187079.8966171456 + 30 +0.0 + 11 +534091.4686033571 + 21 +187126.8232896232 + 31 +0.0 + 0 +LINE + 5 +D4A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533843.797036858 + 20 +186821.0674214544 + 30 +0.0 + 11 +533843.8026278218 + 21 +186821.0785290134 + 31 +0.0 + 0 +LINE + 5 +D4B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533909.6023046641 + 20 +186951.8026426131 + 30 +0.0 + 11 +534096.7438698906 + 21 +187323.5964933741 + 31 +0.0 + 0 +LINE + 5 +D4C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534032.6638186539 + 20 +187288.5896847648 + 30 +0.0 + 11 +534353.7893433044 + 21 +187146.2235310125 + 31 +0.0 + 0 +LINE + 5 +D4D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534287.0962343258 + 20 +187071.6330025523 + 30 +0.0 + 11 +534058.0681274892 + 21 +187253.7359744275 + 31 +0.0 + 0 +LINE + 5 +D4E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534000.5054901832 + 20 +187138.8254181675 + 30 +0.0 + 11 +534032.3759233981 + 21 +187123.1324510591 + 31 +0.0 + 0 +LINE + 5 +D4F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534198.1166002486 + 20 +187207.9534239526 + 30 +0.0 + 11 +534246.6118885009 + 21 +187287.7033281399 + 31 +0.0 + 0 +LINE + 5 +D50 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534232.0137966773 + 20 +187255.7278404318 + 30 +0.0 + 11 +534228.8067471569 + 21 +187339.0482885543 + 31 +0.0 + 0 +LINE + 5 +D51 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534219.4720997099 + 20 +187259.5978338077 + 30 +0.0 + 11 +534286.9938766432 + 21 +187302.7829846988 + 31 +0.0 + 0 +LINE + 5 +D52 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534427.6767798613 + 20 +187212.4484100446 + 30 +0.0 + 11 +534274.4310012642 + 21 +187304.0247950843 + 31 +0.0 + 0 +LINE + 5 +D53 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533819.3864504914 + 20 +187105.5119975673 + 30 +0.0 + 11 +533974.8482824426 + 21 +187360.4440476305 + 31 +0.0 + 0 +LINE + 5 +D54 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534524.3107215045 + 20 +186326.5754653182 + 30 +0.0 + 11 +534531.7366402564 + 21 +185799.7180724953 + 31 +0.0 + 0 +LINE + 5 +D57 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534573.6321587367 + 20 +186048.281322406 + 30 +0.0 + 11 +534050.3682592749 + 21 +186184.3150727255 + 31 +0.0 + 0 +LINE + 5 +D5A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534302.7168493062 + 20 +186154.8844698029 + 30 +0.0 + 11 +534471.8062822185 + 21 +185786.7375415203 + 31 +0.0 + 0 +LINE + 5 +D60 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534361.0083684124 + 20 +185491.2003448077 + 30 +0.0 + 11 +534219.3739121182 + 21 +186349.7377126543 + 31 +0.0 + 0 +LINE + 5 +DB8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533623.1452109745 + 20 +185972.3138249086 + 30 +0.0 + 11 +533623.1446843631 + 21 +185972.3014007619 + 31 +0.0 + 0 +LINE + 5 +DCD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534063.780393243 + 20 +186245.9444705994 + 30 +0.0 + 11 +533978.4760952603 + 21 +186424.7946004351 + 31 +0.0 + 0 +LINE + 5 +DCE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532959.0614927691 + 20 +188756.0186229439 + 30 +0.0 + 11 +532598.4363163279 + 21 +189185.367485622 + 31 +0.0 + 0 +LINE + 5 +DCF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532952.5991179057 + 20 +188775.7158074176 + 30 +0.0 + 11 +532498.8377178559 + 21 +188127.7410335887 + 31 +0.0 + 0 +LINE + 5 +DD0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532875.956784719 + 20 +188661.1317739479 + 30 +0.0 + 11 +532770.1782325437 + 21 +188764.4206533319 + 31 +0.0 + 0 +LINE + 5 +DD1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532799.0322997413 + 20 +188749.1493385631 + 30 +0.0 + 11 +532718.9305002555 + 21 +188766.6078600857 + 31 +0.0 + 0 +LINE + 5 +DD2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532808.7461501953 + 20 +188828.2755461247 + 30 +0.0 + 11 +532788.875372497 + 21 +188742.7034673028 + 31 +0.0 + 0 +LINE + 5 +DD3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532813.3574764001 + 20 +188809.8241076595 + 30 +0.0 + 11 +532683.9742992572 + 21 +188960.8679630683 + 31 +0.0 + 0 +LINE + 5 +DD4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532889.3183331362 + 20 +188906.0571197371 + 30 +0.0 + 11 +532520.9270153102 + 21 +188678.5773222394 + 31 +0.0 + 0 +LINE + 5 +DD5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532637.2249820604 + 20 +188929.9053499753 + 30 +0.0 + 11 +532722.1061582541 + 21 +188763.6674942133 + 31 +0.0 + 0 +LINE + 5 +DD6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532689.4474729919 + 20 +188960.6693755529 + 30 +0.0 + 11 +532637.0169751474 + 21 +188929.0835626449 + 31 +0.0 + 0 +LINE + 5 +DD7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532507.0072332216 + 20 +189195.5474548694 + 30 +0.0 + 11 +532655.8044958146 + 21 +188938.243469675 + 31 +0.0 + 0 +LINE + 5 +DD8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532544.3809392626 + 20 +189138.2336377773 + 30 +0.0 + 11 +532450.5444421437 + 21 +189075.0473012399 + 31 +0.0 + 0 +LINE + 5 +DD9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532410.2276636336 + 20 +189145.8382784577 + 30 +0.0 + 11 +532808.8697911184 + 21 +188536.4143750713 + 31 +0.0 + 0 +LINE + 5 +DDA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532624.7882511244 + 20 +188656.8900412475 + 30 +0.0 + 11 +532304.9757337464 + 21 +188355.8855208015 + 31 +0.0 + 0 +LINE + 5 +DDB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532664.118266529 + 20 +188599.5945185996 + 30 +0.0 + 11 +532548.5643406334 + 21 +188755.3404922934 + 31 +0.0 + 0 +LINE + 5 +DDC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532605.1581469689 + 20 +188557.2140689971 + 30 +0.0 + 11 +532567.26711288 + 21 +188609.174777593 + 31 +0.0 + 0 +LINE + 5 +DDD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532658.1279466498 + 20 +188569.5211949843 + 30 +0.0 + 11 +532589.7997748422 + 21 +188561.2437279531 + 31 +0.0 + 0 +LINE + 5 +DDE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532607.6740753801 + 20 +188571.1721289748 + 30 +0.0 + 11 +532331.6853950706 + 21 +188277.1868468728 + 31 +0.0 + 0 +LINE + 5 +DDF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532677.9790098687 + 20 +188376.4493737437 + 30 +0.0 + 11 +532363.1201382281 + 21 +188634.8590972316 + 31 +0.0 + 0 +LINE + 5 +DE0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532373.8040174633 + 20 +188642.8059028588 + 30 +0.0 + 11 +532211.6587030695 + 21 +188467.4643256072 + 31 +0.0 + 0 +LINE + 5 +DE1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532314.6543550703 + 20 +188823.9332564042 + 30 +0.0 + 11 +532371.7371158007 + 21 +188624.8140952755 + 31 +0.0 + 0 +LINE + 5 +DE2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532400.0218489002 + 20 +188806.2026207918 + 30 +0.0 + 11 +532325.9487450115 + 21 +188763.723272378 + 31 +0.0 + 0 +LINE + 5 +DE3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532624.8433100517 + 20 +188278.722365095 + 30 +0.0 + 11 +532558.2856573059 + 21 +188339.4855929523 + 31 +0.0 + 0 +LINE + 5 +DE4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532552.579947896 + 20 +188144.1162924139 + 30 +0.0 + 11 +532211.4295508927 + 21 +188470.5585631675 + 31 +0.0 + 0 +LINE + 5 +DE5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532557.0555737129 + 20 +188704.7202260402 + 30 +0.0 + 11 +532254.0500494715 + 21 +188408.0337271415 + 31 +0.0 + 0 +LINE + 5 +DE6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532051.1737493166 + 20 +188840.7494451472 + 30 +0.0 + 11 +532260.2096545565 + 21 +188404.7607253519 + 31 +0.0 + 0 +LINE + 5 +DE7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531924.5542984262 + 20 +189060.1813108598 + 30 +0.0 + 11 +532179.0478359127 + 21 +188584.5758381749 + 31 +0.0 + 0 +LINE + 5 +DE8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532122.7868757098 + 20 +188899.4372118148 + 30 +0.0 + 11 +532054.2901579421 + 21 +188804.0552041594 + 31 +0.0 + 0 +LINE + 5 +DE9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532149.9267230192 + 20 +188843.5942326302 + 30 +0.0 + 11 +532040.4487535058 + 21 +188834.6401792815 + 31 +0.0 + 0 +LINE + 5 +DEA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532244.1854389241 + 20 +188678.6137085213 + 30 +0.0 + 11 +532128.6400668821 + 21 +188844.31373375 + 31 +0.0 + 0 +LINE + 5 +DEB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532394.7262438962 + 20 +188877.8526145944 + 30 +0.0 + 11 +532131.3785212176 + 21 +188670.6379691531 + 31 +0.0 + 0 +LINE + 5 +DEC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532456.4168509652 + 20 +188807.4901741918 + 30 +0.0 + 11 +532370.9897163031 + 21 +188893.8016461407 + 31 +0.0 + 0 +LINE + 5 +DED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532456.2850829661 + 20 +188949.9149331953 + 30 +0.0 + 11 +532497.0543522947 + 21 +188836.2241347784 + 31 +0.0 + 0 +LINE + 5 +DEE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532497.116930214 + 20 +188842.9599124264 + 30 +0.0 + 11 +532454.2690864345 + 21 +188807.1593094035 + 31 +0.0 + 0 +LINE + 5 +DEF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532727.23297523 + 20 +189090.5646219603 + 30 +0.0 + 11 +532259.6395972801 + 21 +188777.7164137778 + 31 +0.0 + 0 +LINE + 5 +DF0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532256.8122081843 + 20 +188764.9478729063 + 30 +0.0 + 11 +532243.4655405895 + 21 +188785.2363187846 + 31 +0.0 + 0 +LINE + 5 +DF1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532220.3816786492 + 20 +188578.3303196427 + 30 +0.0 + 11 +532180.3201087714 + 21 +188557.1357969501 + 31 +0.0 + 0 +LINE + 5 +DF2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532235.8560493197 + 20 +188576.9630091105 + 30 +0.0 + 11 +532211.7915096664 + 21 +188577.1736364979 + 31 +0.0 + 0 +LINE + 5 +DF3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532275.1915484151 + 20 +188526.3548240165 + 30 +0.0 + 11 +532229.4793112505 + 21 +188581.7827388668 + 31 +0.0 + 0 +LINE + 5 +DF4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532332.6502728161 + 20 +188776.6343448085 + 30 +0.0 + 11 +532068.9166882257 + 21 +189121.7457489512 + 31 +0.0 + 0 +LINE + 5 +DF5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532426.7555479719 + 20 +189134.8766008566 + 30 +0.0 + 11 +532065.5978605995 + 21 +189100.9695262171 + 31 +0.0 + 0 +LINE + 5 +DF6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532176.9164569791 + 20 +189185.4436963039 + 30 +0.0 + 11 +532327.6998801924 + 21 +188819.4788735671 + 31 +0.0 + 0 +LINE + 5 +DF7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532434.3805068511 + 20 +188891.152697585 + 30 +0.0 + 11 +532414.3678391711 + 21 +188920.5037940263 + 31 +0.0 + 0 +LINE + 5 +DF8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532228.3462162483 + 20 +188928.2835890487 + 30 +0.0 + 11 +532146.8698803295 + 21 +188882.7484719869 + 31 +0.0 + 0 +LINE + 5 +DF9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532175.3197418778 + 20 +188903.3916664333 + 30 +0.0 + 11 +532137.0862075681 + 21 +188829.2918749616 + 31 +0.0 + 0 +LINE + 5 +DFA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532184.3303370418 + 20 +188893.8480724385 + 30 +0.0 + 11 +532104.2972307981 + 21 +188889.5064687405 + 31 +0.0 + 0 +LINE + 5 +DFB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532413.3284184004 + 20 +189411.3057914018 + 30 +0.0 + 11 +532609.1176652272 + 21 +189170.0201889003 + 31 +0.0 + 0 +LINE + 5 +DFC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532593.1945088682 + 20 +189231.5869135002 + 30 +0.0 + 11 +532355.9463737834 + 21 +189117.3409349225 + 31 +0.0 + 0 +LINE + 5 +DFD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532477.5918910147 + 20 +188619.8725829968 + 30 +0.0 + 11 +532440.6663681646 + 21 +188648.9692443206 + 31 +0.0 + 0 +LINE + 5 +DFE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532488.8098312406 + 20 +188690.8564447874 + 30 +0.0 + 11 +532440.3820482271 + 21 +188647.0894768731 + 31 +0.0 + 0 +LINE + 5 +DFF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532535.8363152857 + 20 +188675.2335338815 + 30 +0.0 + 11 +532475.0796668022 + 21 +188760.0366747378 + 31 +0.0 + 0 +LINE + 5 +E00 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532608.426173541 + 20 +188830.9696730895 + 30 +0.0 + 11 +532347.592662036 + 21 +188685.6265940694 + 31 +0.0 + 0 +LINE + 5 +E01 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532328.3039889435 + 20 +188588.9947887008 + 30 +0.0 + 11 +532280.7224491903 + 21 +188638.7497967613 + 31 +0.0 + 0 +LINE + 5 +E02 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532304.400390356 + 20 +188660.0407108078 + 30 +0.0 + 11 +532260.8376349251 + 21 +188618.629863245 + 31 +0.0 + 0 +LINE + 5 +E03 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532305.1801104391 + 20 +188651.4700401296 + 30 +0.0 + 11 +532256.6109941681 + 21 +188703.7148184506 + 31 +0.0 + 0 +LINE + 5 +E04 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532260.325517522 + 20 +188703.8619679585 + 30 +0.0 + 11 +532218.6777600764 + 21 +188666.2181889972 + 31 +0.0 + 0 +LINE + 5 +E05 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532269.6638991237 + 20 +188616.6967556528 + 30 +0.0 + 11 +532216.2696521647 + 21 +188672.8674080448 + 31 +0.0 + 0 +LINE + 5 +E06 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532581.5841857867 + 20 +189076.4774365243 + 30 +0.0 + 11 +532487.5956934878 + 21 +189014.2622144411 + 31 +0.0 + 0 +LINE + 5 +E07 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532584.4608700269 + 20 +188456.4984482675 + 30 +0.0 + 11 +532414.5473369034 + 21 +188253.6607273663 + 31 +0.0 + 0 +LINE + 5 +E08 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532883.7293468934 + 20 +188455.3776511924 + 30 +0.0 + 11 +532138.3714465846 + 21 +187391.0008293174 + 31 +0.0 + 0 +LINE + 5 +E09 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532515.4905134476 + 20 +187924.3915696767 + 30 +0.0 + 11 +532409.7119612722 + 21 +188027.6804490609 + 31 +0.0 + 0 +LINE + 5 +E0A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532546.9683313642 + 20 +188085.9810547085 + 30 +0.0 + 11 +532264.1068343666 + 21 +187680.4271368265 + 31 +0.0 + 0 +LINE + 5 +E0B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532438.5660284698 + 20 +188012.4091342919 + 30 +0.0 + 11 +532358.464228984 + 21 +188029.8676558145 + 31 +0.0 + 0 +LINE + 5 +E0C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532448.2798789237 + 20 +188091.5353418534 + 30 +0.0 + 11 +532428.4091012255 + 21 +188005.9632630317 + 31 +0.0 + 0 +LINE + 5 +E0D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532451.5745885126 + 20 +188074.3437562909 + 30 +0.0 + 11 +532322.1914113697 + 21 +188225.3876116995 + 31 +0.0 + 0 +LINE + 5 +E0E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532601.2688677392 + 20 +188214.0339311463 + 30 +0.0 + 11 +532160.4607440389 + 21 +187941.8371179683 + 31 +0.0 + 0 +LINE + 5 +E0F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532276.758710789 + 20 +188193.1651457041 + 30 +0.0 + 11 +532361.6398869824 + 21 +188026.9272899421 + 31 +0.0 + 0 +LINE + 5 +E10 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532328.9812017204 + 20 +188223.9291712816 + 30 +0.0 + 11 +532276.5507038758 + 21 +188192.3433583738 + 31 +0.0 + 0 +LINE + 5 +E11 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532146.5409619501 + 20 +188458.8072505983 + 30 +0.0 + 11 +532295.338224543 + 21 +188201.5032654037 + 31 +0.0 + 0 +LINE + 5 +E12 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532183.9146679911 + 20 +188401.4934335063 + 30 +0.0 + 11 +532090.0781708722 + 21 +188338.3070969686 + 31 +0.0 + 0 +LINE + 5 +E13 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532049.761392362 + 20 +188409.0980741865 + 30 +0.0 + 11 +532439.5831995335 + 21 +187761.8650720854 + 31 +0.0 + 0 +LINE + 5 +E14 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532264.3219798531 + 20 +187920.1498369762 + 30 +0.0 + 11 +531944.5094624748 + 21 +187619.1453165304 + 31 +0.0 + 0 +LINE + 5 +E15 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532303.6519952577 + 20 +187862.8543143283 + 30 +0.0 + 11 +532188.098069362 + 21 +188018.6002880221 + 31 +0.0 + 0 +LINE + 5 +E16 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532244.6918756974 + 20 +187820.473864726 + 30 +0.0 + 11 +532206.8008416085 + 21 +187872.4345733218 + 31 +0.0 + 0 +LINE + 5 +E17 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532297.6616753782 + 20 +187832.7809907131 + 30 +0.0 + 11 +532229.3335035706 + 21 +187824.503523682 + 31 +0.0 + 0 +LINE + 5 +E18 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532247.2078041085 + 20 +187834.4319247036 + 30 +0.0 + 11 +531971.2191237991 + 21 +187540.4466426017 + 31 +0.0 + 0 +LINE + 5 +E19 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532482.5695292557 + 20 +187432.4593430259 + 30 +0.0 + 11 +531940.9158861035 + 21 +187862.0174506855 + 31 +0.0 + 0 +LINE + 5 +E1A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532013.337746192 + 20 +187906.0656985876 + 30 +0.0 + 11 +531851.1924317979 + 21 +187730.7241213361 + 31 +0.0 + 0 +LINE + 5 +E1B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531954.1880837988 + 20 +188087.193052133 + 30 +0.0 + 11 +532011.2708445293 + 21 +187888.0738910043 + 31 +0.0 + 0 +LINE + 5 +E1C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532039.5555776289 + 20 +188069.4624165206 + 30 +0.0 + 11 +531965.48247374 + 21 +188026.9830681068 + 31 +0.0 + 0 +LINE + 5 +E1D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532211.4046832727 + 20 +187485.430013197 + 30 +0.0 + 11 +532144.847030527 + 21 +187546.1932410541 + 31 +0.0 + 0 +LINE + 5 +E1E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532192.1136766243 + 20 +187407.3760881427 + 30 +0.0 + 11 +531850.963279621 + 21 +187733.8183588964 + 31 +0.0 + 0 +LINE + 5 +E1F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532196.5893024412 + 20 +187967.980021769 + 30 +0.0 + 11 +531893.5837781998 + 21 +187671.2935228705 + 31 +0.0 + 0 +LINE + 5 +E20 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531747.632482898 + 20 +187987.965931228 + 30 +0.0 + 11 +531899.7433832848 + 21 +187668.0205210807 + 31 +0.0 + 0 +LINE + 5 +E21 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532034.2599726247 + 20 +188141.1124103233 + 30 +0.0 + 11 +531770.9122499461 + 21 +187933.8977648818 + 31 +0.0 + 0 +LINE + 5 +E22 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532095.9505796936 + 20 +188070.7499699206 + 30 +0.0 + 11 +532010.5234450315 + 21 +188157.0614418696 + 31 +0.0 + 0 +LINE + 5 +E23 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532095.8188116946 + 20 +188213.1747289239 + 30 +0.0 + 11 +532136.5880810233 + 21 +188099.4839305072 + 31 +0.0 + 0 +LINE + 5 +E24 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532136.6506589425 + 20 +188106.2197081552 + 30 +0.0 + 11 +532093.8028151631 + 21 +188070.4191051323 + 31 +0.0 + 0 +LINE + 5 +E25 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532366.7667039584 + 20 +188353.8244176891 + 30 +0.0 + 11 +531899.1733260084 + 21 +188040.9762095067 + 31 +0.0 + 0 +LINE + 5 +E26 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531896.3459369127 + 20 +188028.2076686353 + 30 +0.0 + 11 +531882.999269318 + 21 +188048.4961145133 + 31 +0.0 + 0 +LINE + 5 +E27 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531859.9154073778 + 20 +187841.5901153716 + 30 +0.0 + 11 +531819.8538374999 + 21 +187820.3955926789 + 31 +0.0 + 0 +LINE + 5 +E28 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531875.3897780482 + 20 +187840.2228048392 + 30 +0.0 + 11 +531851.3252383947 + 21 +187840.4334322268 + 31 +0.0 + 0 +LINE + 5 +E29 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531914.7252771438 + 20 +187789.6146197452 + 30 +0.0 + 11 +531869.0130399789 + 21 +187845.0425345955 + 31 +0.0 + 0 +LINE + 5 +E2A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531972.1840015447 + 20 +188039.8941405374 + 30 +0.0 + 11 +531751.4036104533 + 21 +188317.9406604103 + 31 +0.0 + 0 +LINE + 5 +E2B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532066.2892767004 + 20 +188398.1363965854 + 30 +0.0 + 11 +531862.7873851295 + 21 +188383.5203616941 + 31 +0.0 + 0 +LINE + 5 +E2C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531870.022364545 + 20 +188413.7692626113 + 30 +0.0 + 11 +531967.2336089209 + 21 +188082.7386692958 + 31 +0.0 + 0 +LINE + 5 +E2D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532073.9142355794 + 20 +188154.412493314 + 30 +0.0 + 11 +532053.9015678996 + 21 +188183.7635897552 + 31 +0.0 + 0 +LINE + 5 +E2E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532245.1980405545 + 20 +188482.0407027577 + 30 +0.0 + 11 +531995.480102512 + 21 +188380.6007306513 + 31 +0.0 + 0 +LINE + 5 +E2F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532117.1256197433 + 20 +187883.1323787257 + 30 +0.0 + 11 +532080.2000968932 + 21 +187912.2290400493 + 31 +0.0 + 0 +LINE + 5 +E30 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532128.3435599692 + 20 +187954.1162405161 + 30 +0.0 + 11 +532079.9157769556 + 21 +187910.3492726018 + 31 +0.0 + 0 +LINE + 5 +E31 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532175.3700440142 + 20 +187938.4933296104 + 30 +0.0 + 11 +532114.6133955306 + 21 +188023.2964704667 + 31 +0.0 + 0 +LINE + 5 +E32 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532247.9599022693 + 20 +188094.2294688184 + 30 +0.0 + 11 +531987.1263907643 + 21 +187948.8863897982 + 31 +0.0 + 0 +LINE + 5 +E33 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532221.1179145153 + 20 +188339.7372322532 + 30 +0.0 + 11 +532127.1294222164 + 21 +188277.52201017 + 31 +0.0 + 0 +LINE + 5 +E34 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532201.0248110695 + 20 +187689.3201666808 + 30 +0.0 + 11 +532054.0810656321 + 21 +187516.920523095 + 31 +0.0 + 0 +LINE + 5 +E35 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531833.5906325206 + 20 +188310.2228920877 + 30 +0.0 + 11 +531722.4811789076 + 21 +188438.6268910766 + 31 +0.0 + 0 +LINE + 5 +E36 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532166.1132606188 + 20 +188622.4140607703 + 30 +0.0 + 11 +531589.3173209907 + 21 +188134.3791804765 + 31 +0.0 + 0 +LINE + 5 +E37 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531717.6318825316 + 20 +188332.6364255321 + 30 +0.0 + 11 +531369.4847013599 + 21 +188600.3626062518 + 31 +0.0 + 0 +LINE + 5 +E38 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531667.3404986682 + 20 +188284.6739012414 + 30 +0.0 + 11 +531802.6689907199 + 21 +188423.5829266889 + 31 +0.0 + 0 +LINE + 5 +E39 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531616.1011491471 + 20 +188336.1221982756 + 30 +0.0 + 11 +531661.3554147592 + 21 +188381.813522901 + 31 +0.0 + 0 +LINE + 5 +E3A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531636.6967781323 + 20 +188285.7924347655 + 30 +0.0 + 11 +531617.6303835526 + 21 +188351.9266023396 + 31 +0.0 + 0 +LINE + 5 +E3B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531630.2817941878 + 20 +188335.8640503788 + 30 +0.0 + 11 +531296.0516959023 + 21 +188561.4462729754 + 31 +0.0 + 0 +LINE + 5 +E3C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531449.2602943833 + 20 +188235.4103205985 + 30 +0.0 + 11 +531654.1601976503 + 21 +188587.4440176861 + 31 +0.0 + 0 +LINE + 5 +E3D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531663.7088627422 + 20 +188578.1639320104 + 30 +0.0 + 11 +531480.7888713644 + 21 +188699.6307965083 + 31 +0.0 + 0 +LINE + 5 +E3E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531833.0875890426 + 20 +188665.4373405636 + 30 +0.0 + 11 +531645.617673552 + 21 +188577.3356227187 + 31 +0.0 + 0 +LINE + 5 +E3F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531829.1955174565 + 20 +188578.3348938651 + 30 +0.0 + 11 +531775.4487910742 + 21 +188644.6870540753 + 31 +0.0 + 0 +LINE + 5 +E40 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531199.9049287589 + 20 +188322.1598857742 + 30 +0.0 + 11 +531440.339198993 + 21 +188674.6404915461 + 31 +0.0 + 0 +LINE + 5 +E41 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531754.0502627065 + 20 +188407.1290006797 + 30 +0.0 + 11 +531412.845709929 + 21 +188658.9517151305 + 31 +0.0 + 0 +LINE + 5 +E42 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532549.8724364265 + 20 +189386.7313191874 + 30 +0.0 + 11 +531416.0773421576 + 21 +188643.2176930456 + 31 +0.0 + 0 +LINE + 5 +E43 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531678.3910584178 + 20 +188711.833704132 + 30 +0.0 + 11 +531823.547616166 + 21 +188852.3214441798 + 31 +0.0 + 0 +LINE + 5 +E44 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531874.3351077811 + 20 +188618.6272900689 + 30 +0.0 + 11 +531652.5304600238 + 21 +188821.9256772801 + 31 +0.0 + 0 +LINE + 5 +E45 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531963.3979159524 + 20 +188638.2794219689 + 30 +0.0 + 11 +531860.4563487301 + 21 +188573.8550534082 + 31 +0.0 + 0 +LINE + 5 +E46 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531930.6130602789 + 20 +188499.6793405171 + 30 +0.0 + 11 +531996.3643426193 + 21 +188600.9932084562 + 31 +0.0 + 0 +LINE + 5 +E47 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531994.8808056946 + 20 +188594.422536138 + 30 +0.0 + 11 +531961.383235969 + 21 +188639.0939332041 + 31 +0.0 + 0 +LINE + 5 +E48 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532162.0927971547 + 20 +188300.6511347574 + 30 +0.0 + 11 +532162.0843226814 + 21 +188300.6602353095 + 31 +0.0 + 0 +LINE + 5 +E49 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532062.3488203431 + 20 +188407.7640210612 + 30 +0.0 + 11 +531778.6900105733 + 21 +188712.3790445563 + 31 +0.0 + 0 +LINE + 5 +E4A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531765.6340042651 + 20 +188713.1343354736 + 30 +0.0 + 11 +531783.5347779464 + 21 +188729.5452121612 + 31 +0.0 + 0 +LINE + 5 +E4B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531789.263231201 + 20 +188640.1299156961 + 30 +0.0 + 11 +532034.293017186 + 21 +188891.8244295344 + 31 +0.0 + 0 +LINE + 5 +E4C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532081.0786173002 + 20 +188803.3776922108 + 30 +0.0 + 11 +531830.7702844852 + 21 +188651.8484718924 + 31 +0.0 + 0 +LINE + 5 +E4D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531918.5372013929 + 20 +188557.9609783154 + 30 +0.0 + 11 +531944.3217962647 + 21 +188582.3975983202 + 31 +0.0 + 0 +LINE + 5 +E4E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531922.3411816466 + 20 +188767.2797823902 + 30 +0.0 + 11 +531864.3973468203 + 21 +188840.4532216027 + 31 +0.0 + 0 +LINE + 5 +E4F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531889.3127261933 + 20 +188815.6588680163 + 30 +0.0 + 11 +531810.0646682506 + 21 +188841.5881478804 + 31 +0.0 + 0 +LINE + 5 +E50 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531881.3279569153 + 20 +188805.241840075 + 30 +0.0 + 11 +531864.2807364346 + 21 +188883.5587596492 + 31 +0.0 + 0 +LINE + 5 +E51 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531997.8509052491 + 20 +188984.1123505281 + 30 +0.0 + 11 +531858.7532069532 + 21 +188872.2091187451 + 31 +0.0 + 0 +LINE + 5 +E52 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531657.6177715115 + 20 +188472.0472110668 + 30 +0.0 + 11 +531680.4544563258 + 21 +188513.1397379377 + 31 +0.0 + 0 +LINE + 5 +E53 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531729.4821671011 + 20 +188472.2910638339 + 30 +0.0 + 11 +531678.5534037705 + 21 +188513.1206941728 + 31 +0.0 + 0 +LINE + 5 +E54 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531721.5574363368 + 20 +188423.3751749109 + 30 +0.0 + 11 +531795.5880671324 + 21 +188496.8762547536 + 31 +0.0 + 0 +LINE + 5 +E55 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531886.875472056 + 20 +188376.5459143697 + 30 +0.0 + 11 +531701.8023538999 + 21 +188610.867642511 + 31 +0.0 + 0 +LINE + 5 +E56 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531603.3312817452 + 20 +188614.5017403534 + 30 +0.0 + 11 +531644.8629290103 + 21 +188669.4078969101 + 31 +0.0 + 0 +LINE + 5 +E57 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531669.6568654605 + 20 +188649.4276908528 + 30 +0.0 + 11 +531621.8298004068 + 21 +188685.8302155587 + 31 +0.0 + 0 +LINE + 5 +E58 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531661.3201711099 + 20 +188647.2913653651 + 30 +0.0 + 11 +531705.1522674773 + 21 +188703.5694538651 + 31 +0.0 + 0 +LINE + 5 +E59 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531705.889809728 + 20 +188699.9259160029 + 30 +0.0 + 11 +531662.0869619471 + 21 +188735.038596348 + 31 +0.0 + 0 +LINE + 5 +E5A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531621.3287594976 + 20 +188676.8086412682 + 30 +0.0 + 11 +531668.2671431887 + 21 +188738.4761037986 + 31 +0.0 + 0 +LINE + 5 +E5B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532910.1226366329 + 20 +188386.7350410256 + 30 +0.0 + 11 +532830.9522630293 + 21 +188273.2241689699 + 31 +0.0 + 0 +LINE + 5 +E5C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533055.8404062017 + 20 +188356.2443009575 + 30 +0.0 + 11 +532883.8566398558 + 21 +187952.1337322834 + 31 +0.0 + 0 +LINE + 5 +E5D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532981.3128478802 + 20 +188310.5704731512 + 30 +0.0 + 11 +532800.7760843893 + 21 +187950.0103883114 + 31 +0.0 + 0 +LINE + 5 +E5E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532774.2909740916 + 20 +188309.2747141542 + 30 +0.0 + 11 +533077.067009216 + 21 +188131.5452652497 + 31 +0.0 + 0 +LINE + 5 +E5F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532666.1688044262 + 20 +188156.400341244 + 30 +0.0 + 11 +532746.1847272879 + 21 +188114.9329674759 + 31 +0.0 + 0 +LINE + 5 +E60 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532599.5853865142 + 20 +188111.3314316386 + 30 +0.0 + 11 +533023.7869030749 + 21 +187903.9640695543 + 31 +0.0 + 0 +LINE + 5 +E61 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533124.1255424038 + 20 +188309.2062063903 + 30 +0.0 + 11 +532950.3875296483 + 21 +187922.3595581259 + 31 +0.0 + 0 +LINE + 5 +E62 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533332.1376259856 + 20 +187890.3996014996 + 30 +0.0 + 11 +532945.1880630145 + 21 +187927.0091626512 + 31 +0.0 + 0 +LINE + 5 +E63 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533071.9548736702 + 20 +188205.32251796 + 30 +0.0 + 11 +533112.0168427009 + 21 +188180.7227501699 + 31 +0.0 + 0 +LINE + 5 +E64 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533134.6925907006 + 20 +188240.3729056813 + 30 +0.0 + 11 +533110.351041949 + 21 +188179.8065234848 + 31 +0.0 + 0 +LINE + 5 +E65 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532648.3772381376 + 20 +188181.1772785917 + 30 +0.0 + 11 +532545.2284021539 + 21 +187673.4734036214 + 31 +0.0 + 0 +LINE + 5 +E66 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533035.17653784 + 20 +187839.0110208041 + 30 +0.0 + 11 +532655.3684114847 + 21 +187904.8181812321 + 31 +0.0 + 0 +LINE + 5 +E67 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533021.9629950835 + 20 +187731.017087655 + 30 +0.0 + 11 +532279.9077432335 + 21 +187873.2338361666 + 31 +0.0 + 0 +LINE + 5 +E68 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532488.9949775387 + 20 +187763.4472688142 + 30 +0.0 + 11 +532317.0112111929 + 21 +187359.33670014 + 31 +0.0 + 0 +LINE + 5 +E69 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532421.6397178314 + 20 +187780.5614739364 + 30 +0.0 + 11 +532607.7170939442 + 21 +187725.9288077863 + 31 +0.0 + 0 +LINE + 5 +E6A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532402.237976996 + 20 +187710.5902608587 + 30 +0.0 + 11 +532464.0897660724 + 21 +187692.9833903204 + 31 +0.0 + 0 +LINE + 5 +E6B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532395.4875784423 + 20 +187764.5504049247 + 30 +0.0 + 11 +532411.3254571612 + 21 +187697.5696829169 + 31 +0.0 + 0 +LINE + 5 +E6C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532340.656085799 + 20 +187570.3606917988 + 30 +0.0 + 11 +532233.9306557266 + 21 +187357.2133561679 + 31 +0.0 + 0 +LINE + 5 +E6D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532706.7652726552 + 20 +187604.1039898727 + 30 +0.0 + 11 +532692.4918827968 + 21 +187519.9161635358 + 31 +0.0 + 0 +LINE + 5 +E6E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532152.33259944 + 20 +187460.8469788372 + 30 +0.0 + 11 +532356.271155133 + 21 +187387.1368772966 + 31 +0.0 + 0 +LINE + 5 +E6F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532557.2801137408 + 20 +187716.409174247 + 30 +0.0 + 11 +532383.5421009857 + 21 +187329.5625259826 + 31 +0.0 + 0 +LINE + 5 +E70 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532775.8331259071 + 20 +187623.8877380377 + 30 +0.0 + 11 +532672.357212332 + 21 +187305.1673784193 + 31 +0.0 + 0 +LINE + 5 +E71 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532688.4904774424 + 20 +187657.4714510412 + 30 +0.0 + 11 +532799.0005223217 + 21 +187607.1227121558 + 31 +0.0 + 0 +LINE + 5 +E72 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532707.7154038946 + 20 +187707.9194538183 + 30 +0.0 + 11 +532688.9219839458 + 21 +187655.3416233195 + 31 +0.0 + 0 +LINE + 5 +E73 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532860.5751990845 + 20 +188009.4080429418 + 30 +0.0 + 11 +532728.5315992382 + 21 +187462.5240916274 + 31 +0.0 + 0 +LINE + 5 +E74 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532717.5260368595 + 20 +187455.4595773613 + 30 +0.0 + 11 +532741.1762224215 + 21 +187449.9438457759 + 31 +0.0 + 0 +LINE + 5 +E75 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532702.2927821534 + 20 +187530.6655187736 + 30 +0.0 + 11 +533039.4935310675 + 21 +187419.5371999896 + 31 +0.0 + 0 +LINE + 5 +E76 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533005.9662778086 + 20 +187742.7403283741 + 30 +0.0 + 11 +533062.5550273837 + 21 +187546.7189984879 + 31 +0.0 + 0 +LINE + 5 +E77 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533088.4419344846 + 20 +187563.95874833 + 30 +0.0 + 11 +532744.2095209789 + 21 +187540.8216517915 + 31 +0.0 + 0 +LINE + 5 +E78 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533022.8958895394 + 20 +187939.6201562503 + 30 +0.0 + 11 +533013.973128999 + 21 +187670.232886942 + 31 +0.0 + 0 +LINE + 5 +E79 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532505.1094450074 + 20 +187612.5254858167 + 30 +0.0 + 11 +532545.1714140379 + 21 +187587.9257180264 + 31 +0.0 + 0 +LINE + 5 +E7A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532567.8471620379 + 20 +187647.5758735381 + 30 +0.0 + 11 +532543.5056132862 + 21 +187587.0094913414 + 31 +0.0 + 0 +LINE + 5 +E7B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532536.9397053601 + 20 +187686.3095109673 + 30 +0.0 + 11 +532637.5112505831 + 21 +187658.5911537743 + 31 +0.0 + 0 +LINE + 5 +E7C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532897.6734271721 + 20 +187867.8603826554 + 30 +0.0 + 11 +532871.7596143943 + 21 +187758.1651464291 + 31 +0.0 + 0 +LINE + 5 +E7D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533003.8573889543 + 20 +187493.997497595 + 30 +0.0 + 11 +533162.7408384199 + 21 +187434.0896756984 + 31 +0.0 + 0 +LINE + 5 +E7E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533181.9479908528 + 20 +187913.9002976766 + 30 +0.0 + 11 +532923.2311001333 + 21 +187204.0149753805 + 31 +0.0 + 0 +LINE + 5 +E7F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533064.9517395415 + 20 +187392.9218897224 + 30 +0.0 + 11 +533527.9138737417 + 21 +187155.1832707628 + 31 +0.0 + 0 +LINE + 5 +E80 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533037.3167913862 + 20 +187329.1571920623 + 30 +0.0 + 11 +533120.9202669467 + 21 +187504.1428400051 + 31 +0.0 + 0 +LINE + 5 +E81 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532963.087111749 + 20 +187353.074195673 + 30 +0.0 + 11 +533117.6022115812 + 21 +187305.7419693661 + 31 +0.0 + 0 +LINE + 5 +E82 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533098.1579167783 + 20 +187312.0651937155 + 30 +0.0 + 11 +533322.9937731828 + 21 +187084.8043730471 + 31 +0.0 + 0 +LINE + 5 +E83 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533177.7906048676 + 20 +187547.8262754669 + 30 +0.0 + 11 +533506.7021197757 + 21 +187286.0821649716 + 31 +0.0 + 0 +LINE + 5 +E84 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533266.8696006119 + 20 +187729.1476499413 + 30 +0.0 + 11 +533241.9757279544 + 21 +187610.2873932081 + 31 +0.0 + 0 +LINE + 5 +E85 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533148.1297695554 + 20 +187650.4985440298 + 30 +0.0 + 11 +533220.4900966108 + 21 +187747.2028047152 + 31 +0.0 + 0 +LINE + 5 +E86 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533214.8365194989 + 20 +187743.5406083304 + 30 +0.0 + 11 +533268.3299825314 + 21 +187727.5384114146 + 31 +0.0 + 0 +LINE + 5 +E87 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532881.3856533973 + 20 +187798.9662905841 + 30 +0.0 + 11 +532881.3971213293 + 21 +187798.9614819165 + 31 +0.0 + 0 +LINE + 5 +E88 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533016.3624389602 + 20 +187742.3685990975 + 30 +0.0 + 11 +533943.3796218751 + 21 +187255.7435890138 + 31 +0.0 + 0 +LINE + 5 +E89 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533301.653800806 + 20 +187416.6866301347 + 30 +0.0 + 11 +533450.1008736807 + 21 +187749.3717472283 + 31 +0.0 + 0 +LINE + 5 +E8A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533346.6419572953 + 20 +187850.8964413646 + 30 +0.0 + 11 +533291.3539286802 + 21 +187585.0125509866 + 31 +0.0 + 0 +LINE + 5 +E8B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533206.9947936887 + 20 +187659.3010781028 + 30 +0.0 + 11 +533221.0188632043 + 21 +187691.9403060992 + 31 +0.0 + 0 +LINE + 5 +E8C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533246.5008210441 + 20 +187239.9275874134 + 30 +0.0 + 11 +533247.1849608591 + 21 +187420.3929628149 + 31 +0.0 + 0 +LINE + 5 +E8D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533191.9135700587 + 20 +187452.2897331669 + 30 +0.0 + 11 +533247.8238560572 + 21 +187418.6023829063 + 31 +0.0 + 0 +LINE + 5 +E8E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533047.6881762032 + 20 +187566.9144332003 + 30 +0.0 + 11 +533270.8410215643 + 21 +187494.0123929628 + 31 +0.0 + 0 +LINE + 5 +E8F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533198.0129838886 + 20 +187845.4175907803 + 30 +0.0 + 11 +532996.8397992431 + 21 +187787.9127616617 + 31 +0.0 + 0 +LINE + 5 +E90 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533195.8603909342 + 20 +187434.92947827 + 30 +0.0 + 11 +533251.7942375957 + 21 +187537.893542003 + 31 +0.0 + 0 +LINE + 5 +E91 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532777.816868749 + 20 +188307.2050149652 + 30 +0.0 + 11 +532580.4733576386 + 21 +188289.3239965596 + 31 +0.0 + 0 +LINE + 5 +E99 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533301.0508297613 + 20 +187282.5650489181 + 30 +0.0 + 11 +533558.3424779411 + 21 +187640.6293556604 + 31 +0.0 + 0 +LINE + 5 +E9A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533688.8059216369 + 20 +187644.6635814481 + 30 +0.0 + 11 +534031.2188721263 + 21 +187547.1269241443 + 31 +0.0 + 0 +LINE + 5 +E9B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532960.0471768222 + 20 +188057.6651346364 + 30 +0.0 + 11 +533278.2096303262 + 21 +188034.0587147734 + 31 +0.0 + 0 +LINE + 5 +E9F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532361.5412691713 + 20 +187422.9006690331 + 30 +0.0 + 11 +532159.5020060875 + 21 +187561.9190406652 + 31 +0.0 + 0 +LINE + 5 +EA0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532336.8154352048 + 20 +187445.644135747 + 30 +0.0 + 11 +532295.0184469695 + 21 +187207.7119952258 + 31 +0.0 + 0 +LINE + 5 +EA1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532771.7530398989 + 20 +187265.2556792592 + 30 +0.0 + 11 +532029.6977880492 + 21 +187407.4724277708 + 31 +0.0 + 0 +LINE + 5 +EA2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532238.7850223542 + 20 +187297.6858604184 + 30 +0.0 + 11 +532066.8012560086 + 21 +186893.5752917443 + 31 +0.0 + 0 +LINE + 5 +EA3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532171.4297626468 + 20 +187314.8000655407 + 30 +0.0 + 11 +532357.5071387598 + 21 +187260.1673993905 + 31 +0.0 + 0 +LINE + 5 +EA4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532152.0280218115 + 20 +187244.8288524629 + 30 +0.0 + 11 +532213.8798108879 + 21 +187227.2219819246 + 31 +0.0 + 0 +LINE + 5 +EA5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532164.257464033 + 20 +187252.012032612 + 30 +0.0 + 11 +531983.7207005421 + 21 +186891.4519477722 + 31 +0.0 + 0 +LINE + 5 +EA6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532052.1854304346 + 20 +187195.1103712278 + 30 +0.0 + 11 +532308.5103977871 + 21 +187044.5180587102 + 31 +0.0 + 0 +LINE + 5 +EA7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532312.276887243 + 20 +187057.2895328762 + 30 +0.0 + 11 +532203.7486339846 + 21 +186844.5516896567 + 31 +0.0 + 0 +LINE + 5 +EA8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532502.6865875572 + 20 +187064.356837159 + 30 +0.0 + 11 +532296.1069361393 + 21 +187049.1341724364 + 31 +0.0 + 0 +LINE + 5 +EA9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532456.5553174708 + 20 +187138.342581477 + 30 +0.0 + 11 +532442.2819276124 + 21 +187054.1547551401 + 31 +0.0 + 0 +LINE + 5 +EAA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531902.1226442555 + 20 +186995.0855704415 + 30 +0.0 + 11 +532206.7315192275 + 21 +186845.4056290151 + 31 +0.0 + 0 +LINE + 5 +EAB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532307.0701585566 + 20 +187250.6477658511 + 30 +0.0 + 11 +532133.3321458012 + 21 +186863.8011175869 + 31 +0.0 + 0 +LINE + 5 +EAC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532669.5176654935 + 20 +186819.0197692934 + 30 +0.0 + 11 +532128.1326791673 + 21 +186868.4507221122 + 31 +0.0 + 0 +LINE + 5 +EAD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532639.8270503792 + 20 +186910.3877806064 + 30 +0.0 + 11 +532573.9818262154 + 21 +186813.1564369764 + 31 +0.0 + 0 +LINE + 5 +EAE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532578.0462980195 + 20 +186916.5642095136 + 30 +0.0 + 11 +532607.4654813943 + 21 +186810.7336254195 + 31 +0.0 + 0 +LINE + 5 +EAF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532390.6599277922 + 20 +186948.0225488274 + 30 +0.0 + 11 +532586.0755084608 + 21 +186896.8367872021 + 31 +0.0 + 0 +LINE + 5 +EB0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532525.6231707228 + 20 +187158.1263296419 + 30 +0.0 + 11 +532389.8328575555 + 21 +186741.9088822389 + 31 +0.0 + 0 +LINE + 5 +EB1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532438.280522258 + 20 +187191.7100426455 + 30 +0.0 + 11 +532548.7905671371 + 21 +187141.3613037601 + 31 +0.0 + 0 +LINE + 5 +EB2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532457.5054487103 + 20 +187242.1580454225 + 30 +0.0 + 11 +532438.7120287613 + 21 +187189.5802149239 + 31 +0.0 + 0 +LINE + 5 +EB3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532699.8964538836 + 20 +187928.212678685 + 30 +0.0 + 11 +532478.3216440537 + 21 +186996.7626832316 + 31 +0.0 + 0 +LINE + 5 +EB4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532467.316081675 + 20 +186989.6981689655 + 30 +0.0 + 11 +532490.9662672371 + 21 +186984.18243738 + 31 +0.0 + 0 +LINE + 5 +EB5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532304.7748049706 + 20 +186891.0390181706 + 30 +0.0 + 11 +532298.725549977 + 21 +186846.121942495 + 31 +0.0 + 0 +LINE + 5 +EB6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532298.1456722383 + 20 +186905.0882275774 + 30 +0.0 + 11 +532306.6570310679 + 21 +186882.5781586414 + 31 +0.0 + 0 +LINE + 5 +EB7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532237.0641022033 + 20 +186924.5178876279 + 30 +0.0 + 11 +532304.8716456011 + 21 +186900.7692154624 + 31 +0.0 + 0 +LINE + 5 +EB8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532452.0828269688 + 20 +187064.9041103778 + 30 +0.0 + 11 +532789.2835758827 + 21 +186953.7757915938 + 31 +0.0 + 0 +LINE + 5 +EB9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532755.7563226241 + 20 +187276.9789199783 + 30 +0.0 + 11 +532812.3450721992 + 21 +187080.9575900921 + 31 +0.0 + 0 +LINE + 5 +EBA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532838.2319793 + 20 +187098.1973399342 + 30 +0.0 + 11 +532493.9995657945 + 21 +187075.0602433957 + 31 +0.0 + 0 +LINE + 5 +EBB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532524.4047776451 + 20 +187199.933844473 + 30 +0.0 + 11 +532558.8625446769 + 21 +187191.2934728867 + 31 +0.0 + 0 +LINE + 5 +EBC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532630.429167671 + 20 +187019.4133173171 + 30 +0.0 + 11 +532615.8457918745 + 21 +186927.2223993751 + 31 +0.0 + 0 +LINE + 5 +EBD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532625.3892216226 + 20 +186961.05225376 + 30 +0.0 + 11 +532569.0606453941 + 21 +186899.5732025151 + 31 +0.0 + 0 +LINE + 5 +EBE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532613.3203101034 + 20 +186966.2109732026 + 30 +0.0 + 11 +532636.8954766592 + 21 +186889.6057570645 + 31 +0.0 + 0 +LINE + 5 +EBF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532751.2129145473 + 20 +186878.8594245582 + 30 +0.0 + 11 +532626.5100272641 + 21 +186896.7828297049 + 31 +0.0 + 0 +LINE + 5 +EC0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532866.401228957 + 20 +187500.5356147793 + 30 +0.0 + 11 +532763.7631738145 + 21 +187204.4714785462 + 31 +0.0 + 0 +LINE + 5 +EC1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532254.8994898229 + 20 +187146.7640774209 + 30 +0.0 + 11 +532294.9614588535 + 21 +187122.1643096307 + 31 +0.0 + 0 +LINE + 5 +EC2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532317.6372068535 + 20 +187181.8144651424 + 30 +0.0 + 11 +532293.2956581016 + 21 +187121.2480829457 + 31 +0.0 + 0 +LINE + 5 +EC3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532286.7297501757 + 20 +187220.5481025715 + 30 +0.0 + 11 +532387.3012953987 + 21 +187192.8297453785 + 31 +0.0 + 0 +LINE + 5 +EC4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532407.7988971119 + 20 +187342.4714155062 + 30 +0.0 + 11 +532361.5163903555 + 21 +187047.4855498933 + 31 +0.0 + 0 +LINE + 5 +EC5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532277.4981650085 + 20 +186996.0006343546 + 30 +0.0 + 11 +532340.6278919628 + 21 +186968.5379082136 + 31 +0.0 + 0 +LINE + 5 +EC6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532352.42773972 + 20 +186998.1134303847 + 30 +0.0 + 11 +532328.6164939601 + 21 +186942.9265068251 + 31 +0.0 + 0 +LINE + 5 +EC7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532344.1154093107 + 20 +186995.8841878118 + 30 +0.0 + 11 +532409.922789283 + 21 +186968.3548460411 + 31 +0.0 + 0 +LINE + 5 +EC8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532408.7776030103 + 20 +186971.8914948963 + 30 +0.0 + 11 +532387.8398953379 + 21 +186919.803087432 + 31 +0.0 + 0 +LINE + 5 +EC9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532323.7531569956 + 20 +186950.541478804 + 30 +0.0 + 11 +532394.9116494379 + 21 +186919.8403916598 + 31 +0.0 + 0 +LINE + 5 +ECA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532647.4634719876 + 20 +187402.0989742598 + 30 +0.0 + 11 +532621.5496592099 + 21 +187292.4037380333 + 31 +0.0 + 0 +LINE + 5 +ECB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532630.2831464825 + 20 +186835.5866176528 + 30 +0.0 + 11 +533006.6015529368 + 21 +186508.8569529216 + 31 +0.0 + 0 +LINE + 5 +ECC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532697.5207067601 + 20 +186850.0125420364 + 30 +0.0 + 11 +532860.8416899149 + 21 +186691.9120637713 + 31 +0.0 + 0 +LINE + 5 +ECD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532753.6474337698 + 20 +187028.2360891994 + 30 +0.0 + 11 +532868.0969839297 + 21 +187045.2654694289 + 31 +0.0 + 0 +LINE + 5 +ECE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532888.7525577194 + 20 +187354.0892509376 + 30 +0.0 + 11 +532600.956481905 + 21 +186546.2740326586 + 31 +0.0 + 0 +LINE + 5 +ED0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532853.0892751174 + 20 +186833.0854560245 + 30 +0.0 + 11 +532880.3330652703 + 21 +186891.3385383485 + 31 +0.0 + 0 +LINE + 5 +ED1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532798.7431429207 + 20 +186835.0252868174 + 30 +0.0 + 11 +532867.3922563968 + 21 +186839.9805609704 + 31 +0.0 + 0 +LINE + 5 +ED2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532847.9479615937 + 20 +186846.3037853197 + 30 +0.0 + 11 +533024.8768349366 + 21 +186688.6722408888 + 31 +0.0 + 0 +LINE + 5 +ED4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532631.1756982129 + 20 +187333.2048821884 + 30 +0.0 + 11 +532631.1871661447 + 21 +187333.2000735208 + 31 +0.0 + 0 +LINE + 5 +ED5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +533109.9406543836 + 20 +187325.8194304203 + 30 +0.0 + 11 +533029.5141630925 + 21 +187140.257367994 + 31 +0.0 + 0 +LINE + 5 +ED9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532767.8763670437 + 20 +186595.6615620909 + 30 +0.0 + 11 +532930.3741798359 + 21 +186793.7619793046 + 31 +0.0 + 0 +LINE + 5 +EE3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532826.7197102416 + 20 +186614.8899640539 + 30 +0.0 + 11 +532625.451864467 + 21 +186697.4888187418 + 31 +0.0 + 0 +LINE + 5 +EE9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532312.7807578225 + 20 +186709.8782579019 + 30 +0.0 + 11 +532180.7561651608 + 21 +186872.6457364109 + 31 +0.0 + 0 +LINE + 5 +EFA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531958.3211544966 + 20 +187086.486218021 + 30 +0.0 + 11 +532300.7341049858 + 21 +186988.9495607173 + 31 +0.0 + 0 +LINE + 5 +EFB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +534930.9326781594 + 20 +187726.3550681194 + 30 +0.0 + 11 +535449.6709668517 + 21 +188370.3442761802 + 31 +0.0 + 0 +LINE + 5 +EFC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529378.4635770085 + 20 +187735.7500589992 + 30 +0.0 + 11 +530008.689649875 + 21 +187341.9860925706 + 31 +0.0 + 0 +LINE + 5 +EFD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529545.8148094653 + 20 +187623.0424385107 + 30 +0.0 + 11 +529778.5966375779 + 21 +188379.0737448694 + 31 +0.0 + 0 +LINE + 5 +EFE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529583.5543794686 + 20 +187755.629288607 + 30 +0.0 + 11 +529715.9466170403 + 21 +187689.826628057 + 31 +0.0 + 0 +LINE + 5 +EFF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529603.2346550776 + 20 +187592.1829627211 + 30 +0.0 + 11 +529747.8446735596 + 21 +188065.0175525596 + 31 +0.0 + 0 +LINE + 5 +F00 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529683.7965904536 + 20 +187695.4963757663 + 30 +0.0 + 11 +529765.3885338919 + 21 +187703.4871842719 + 31 +0.0 + 0 +LINE + 5 +F01 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529698.8579615868 + 20 +187617.2118261202 + 30 +0.0 + 11 +529691.4824514415 + 21 +187704.7505622906 + 31 +0.0 + 0 +LINE + 5 +F02 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529688.8017596487 + 20 +187633.3547104158 + 30 +0.0 + 11 +529858.3265421476 + 21 +187529.3566291689 + 31 +0.0 + 0 +LINE + 5 +F03 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529646.0737452123 + 20 +187518.4409986492 + 30 +0.0 + 11 +529926.7783845801 + 21 +187848.0834212173 + 31 +0.0 + 0 +LINE + 5 +F04 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529893.3047350945 + 20 +187573.1825129142 + 30 +0.0 + 11 +529761.4632025456 + 21 +187705.3099099803 + 31 +0.0 + 0 +LINE + 5 +F05 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529853.056978453 + 20 +187527.8643938651 + 30 +0.0 + 11 +529893.2502530519 + 21 +187574.0284638578 + 31 +0.0 + 0 +LINE + 5 +F06 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530098.8254488125 + 20 +187360.3830151751 + 30 +0.0 + 11 +529878.1847450631 + 21 +187559.5403549869 + 31 +0.0 + 0 +LINE + 5 +F07 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530045.6532793329 + 20 +187403.4456199002 + 30 +0.0 + 11 +530115.5438118516 + 21 +187492.4013098859 + 31 +0.0 + 0 +LINE + 5 +F08 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530175.6566109118 + 20 +187437.4171624065 + 30 +0.0 + 11 +529559.0215932507 + 21 +187972.1942001524 + 31 +0.0 + 0 +LINE + 5 +F09 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529821.2767317422 + 20 +187836.8186216117 + 30 +0.0 + 11 +530033.1662553697 + 21 +188221.5088832217 + 31 +0.0 + 0 +LINE + 5 +F0A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529766.2484540445 + 20 +187879.2628871941 + 30 +0.0 + 11 +529924.0569599557 + 21 +187766.5420214515 + 31 +0.0 + 0 +LINE + 5 +F0B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529809.3398214984 + 20 +187937.7054423915 + 30 +0.0 + 11 +529861.3599671114 + 21 +187899.8960500067 + 31 +0.0 + 0 +LINE + 5 +F0C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529762.7113894739 + 20 +187909.7223340005 + 30 +0.0 + 11 +529825.1934736707 + 21 +187938.5883118542 + 31 +0.0 + 0 +LINE + 5 +F0D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529811.2330965048 + 20 +187923.6493816397 + 30 +0.0 + 11 +529983.5736650277 + 21 +188288.1981797348 + 31 +0.0 + 0 +LINE + 5 +F0E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529684.5132423182 + 20 +188087.3619766751 + 30 +0.0 + 11 +530063.5266412746 + 21 +187938.1623196526 + 31 +0.0 + 0 +LINE + 5 +F0F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530055.8003542056 + 20 +187927.3178978922 + 30 +0.0 + 11 +530156.2459049511 + 21 +188143.9892227795 + 31 +0.0 + 0 +LINE + 5 +F10 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530167.72809298 + 20 +187773.1167887638 + 30 +0.0 + 11 +530052.2406954039 + 21 +187945.0747571812 + 31 +0.0 + 0 +LINE + 5 +F11 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530081.0414487262 + 20 +187763.7674492108 + 30 +0.0 + 11 +530138.4847548853 + 21 +187826.9464515684 + 31 +0.0 + 0 +LINE + 5 +F12 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529705.0607078073 + 20 +188196.6861390384 + 30 +0.0 + 11 +529787.0654422633 + 21 +188159.3054685596 + 31 +0.0 + 0 +LINE + 5 +F13 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529732.4827482234 + 20 +188346.9819141357 + 30 +0.0 + 11 +530157.4144505093 + 21 +188141.1149719069 + 31 +0.0 + 0 +LINE + 5 +F14 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529900.4269755176 + 20 +187812.1066593871 + 30 +0.0 + 11 +530097.6484604593 + 21 +188187.5249757049 + 31 +0.0 + 0 +LINE + 5 +F15 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530423.635731933 + 20 +187838.048245992 + 30 +0.0 + 11 +530090.7812692937 + 21 +188188.7476616877 + 31 +0.0 + 0 +LINE + 5 +F16 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530611.5374876814 + 20 +187668.1195573589 + 30 +0.0 + 11 +530223.2538567075 + 21 +188042.5569328811 + 31 +0.0 + 0 +LINE + 5 +F17 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530373.5122905457 + 20 +187760.2000960348 + 30 +0.0 + 11 +530409.3984414326 + 21 +187872.0111505144 + 31 +0.0 + 0 +LINE + 5 +F18 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530330.5310086717 + 20 +187805.0065581208 + 30 +0.0 + 11 +530431.9655938526 + 21 +187847.1565973773 + 31 +0.0 + 0 +LINE + 5 +F19 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530190.1515324173 + 20 +187933.0568666163 + 30 +0.0 + 11 +530351.0095330452 + 21 +187810.8605696383 + 31 +0.0 + 0 +LINE + 5 +F1A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530108.0901088432 + 20 +187697.2081896732 + 30 +0.0 + 11 +530295.0546348895 + 21 +187975.2984597758 + 31 +0.0 + 0 +LINE + 5 +F1B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530027.7684759713 + 20 +187745.2190146273 + 30 +0.0 + 11 +530135.5781907513 + 21 +187689.321510876 + 31 +0.0 + 0 +LINE + 5 +F1C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530071.6431878232 + 20 +187609.7205312413 + 30 +0.0 + 11 +529997.9220251973 + 21 +187705.391431453 + 31 +0.0 + 0 +LINE + 5 +F1D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529999.9315347111 + 20 +187698.9620856049 + 30 +0.0 + 11 +530029.7107693157 + 21 +187746.1936225241 + 31 +0.0 + 0 +LINE + 5 +F1E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529856.9988515898 + 20 +187392.642425033 + 30 +0.0 + 11 +530205.8864010586 + 21 +187833.9983429626 + 31 +0.0 + 0 +LINE + 5 +F1F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530204.6549190094 + 20 +187847.0180671165 + 30 +0.0 + 11 +530223.5884180138 + 21 +187831.8102668979 + 31 +0.0 + 0 +LINE + 5 +F20 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530181.9999116782 + 20 +188035.803779794 + 30 +0.0 + 11 +530213.6142017748 + 21 +188068.2795220475 + 31 +0.0 + 0 +LINE + 5 +F21 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530166.8536758086 + 20 +188032.3516464356 + 30 +0.0 + 11 +530189.8194683097 + 21 +188039.5432253593 + 31 +0.0 + 0 +LINE + 5 +F22 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530113.8743619398 + 20 +188068.4302022495 + 30 +0.0 + 11 +530174.4026182898 + 21 +188029.7237098421 + 31 +0.0 + 0 +LINE + 5 +F23 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530136.0731830577 + 20 +187812.6010485576 + 30 +0.0 + 11 +530493.065627726 + 21 +187565.1870647974 + 31 +0.0 + 0 +LINE + 5 +F24 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530461.3402601847 + 20 +187563.7139106953 + 30 +0.0 + 11 +530544.9677326832 + 21 +187746.8006609251 + 31 +0.0 + 0 +LINE + 5 +F25 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530156.5606465565 + 20 +187442.7719249477 + 30 +0.0 + 11 +530489.8420656007 + 21 +187585.978281576 + 31 +0.0 + 0 +LINE + 5 +F26 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530409.853728282 + 20 +187471.3938969297 + 30 +0.0 + 11 +530153.9450042355 + 21 +187773.3485576881 + 31 +0.0 + 0 +LINE + 5 +F27 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530074.4384597199 + 20 +187672.3703296743 + 30 +0.0 + 11 +530102.4994971649 + 21 +187650.5856582863 + 31 +0.0 + 0 +LINE + 5 +F28 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530281.9173037256 + 20 +187700.3231702298 + 30 +0.0 + 11 +530345.4672628766 + 21 +187768.6842914354 + 31 +0.0 + 0 +LINE + 5 +F29 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530324.7339364529 + 20 +187740.3000480166 + 30 +0.0 + 11 +530338.357399006 + 21 +187822.5617250599 + 31 +0.0 + 0 +LINE + 5 +F2A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530313.2274231444 + 20 +187746.6144096657 + 30 +0.0 + 11 +530388.0575426544 + 21 +187775.3302734317 + 31 +0.0 + 0 +LINE + 5 +F2B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530507.6869767908 + 20 +187658.5363817937 + 30 +0.0 + 11 +530376.0014669189 + 21 +187779.0744647571 + 31 +0.0 + 0 +LINE + 5 +F2C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530113.378969668 + 20 +187223.3113400704 + 30 +0.0 + 11 +529993.8104067042 + 21 +187353.3103520891 + 31 +0.0 + 0 +LINE + 5 +F2D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530027.8754812543 + 20 +187299.6113839214 + 30 +0.0 + 11 +530218.5598977485 + 21 +187481.2105979304 + 31 +0.0 + 0 +LINE + 5 +F2E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529949.985764896 + 20 +187917.2614300507 + 30 +0.0 + 11 +529994.0638168057 + 21 +187900.9140976139 + 31 +0.0 + 0 +LINE + 5 +F2F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529961.1146399412 + 20 +187846.2635500974 + 30 +0.0 + 11 +529993.7569733256 + 21 +187902.7903200321 + 31 +0.0 + 0 +LINE + 5 +F30 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529911.5627755482 + 20 +187846.6857845978 + 30 +0.0 + 11 +529995.4314249195 + 21 +187784.6455340611 + 31 +0.0 + 0 +LINE + 5 +F31 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529890.3206506824 + 20 +187676.1812253975 + 30 +0.0 + 11 +530093.8979136191 + 21 +187894.6189267182 + 31 +0.0 + 0 +LINE + 5 +F32 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530082.5711711842 + 20 +187992.5038776773 + 30 +0.0 + 11 +530143.1357803735 + 21 +187959.7702273141 + 31 +0.0 + 0 +LINE + 5 +F33 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530127.1426298523 + 20 +187932.2353938265 + 30 +0.0 + 11 +530155.8788858883 + 21 +187985.0255401197 + 31 +0.0 + 0 +LINE + 5 +F34 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530123.7679117324 + 20 +187940.1521884365 + 30 +0.0 + 11 +530186.0371461363 + 21 +187905.3524993013 + 31 +0.0 + 0 +LINE + 5 +F35 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530182.5474092204 + 20 +187904.0714555937 + 30 +0.0 + 11 +530210.6184005529 + 21 +187952.6884201263 + 31 +0.0 + 0 +LINE + 5 +F36 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530146.8855422867 + 20 +187984.1539808663 + 30 +0.0 + 11 +530214.9525571921 + 21 +187947.1003807667 + 31 +0.0 + 0 +LINE + 5 +F37 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529991.2787391617 + 20 +187450.7881940411 + 30 +0.0 + 11 +530061.612220368 + 21 +187538.8664090824 + 31 +0.0 + 0 +LINE + 5 +F38 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529798.0991355714 + 20 +188039.9094565575 + 30 +0.0 + 11 +529897.4912097044 + 21 +188285.1337729669 + 31 +0.0 + 0 +LINE + 5 +F39 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529700.2850975303 + 20 +188567.4765653622 + 30 +0.0 + 11 +529832.6773351021 + 21 +188501.6739048121 + 31 +0.0 + 0 +LINE + 5 +F3A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529719.9653731394 + 20 +188404.0302394763 + 30 +0.0 + 11 +529864.5753916216 + 21 +188876.8648293147 + 31 +0.0 + 0 +LINE + 5 +F3B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529800.5273085154 + 20 +188507.3436525215 + 30 +0.0 + 11 +529882.1192519538 + 21 +188515.3344610271 + 31 +0.0 + 0 +LINE + 5 +F3C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529815.5886796486 + 20 +188429.0591028753 + 30 +0.0 + 11 +529808.2131695032 + 21 +188516.5978390456 + 31 +0.0 + 0 +LINE + 5 +F3D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529807.1724351745 + 20 +188444.4074758961 + 30 +0.0 + 11 +529976.6972176732 + 21 +188340.409394649 + 31 +0.0 + 0 +LINE + 5 +F3E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529707.6247334772 + 20 +188265.4885633374 + 30 +0.0 + 11 +530043.5091026421 + 21 +188659.9306979724 + 31 +0.0 + 0 +LINE + 5 +F3F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530010.0354531563 + 20 +188385.0297896692 + 30 +0.0 + 11 +529878.1939206073 + 21 +188517.1571867354 + 31 +0.0 + 0 +LINE + 5 +F40 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529969.7876965147 + 20 +188339.7116706202 + 30 +0.0 + 11 +530009.9809711138 + 21 +188385.875740613 + 31 +0.0 + 0 +LINE + 5 +F41 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530215.5561668745 + 20 +188172.2302919301 + 30 +0.0 + 11 +529994.9154631249 + 21 +188371.3876317421 + 31 +0.0 + 0 +LINE + 5 +F42 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530162.3839973947 + 20 +188215.2928966554 + 30 +0.0 + 11 +530232.2745299135 + 21 +188304.2485866411 + 31 +0.0 + 0 +LINE + 5 +F43 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530292.3873289736 + 20 +188249.2644391616 + 30 +0.0 + 11 +529722.5984614438 + 21 +188745.4622291548 + 31 +0.0 + 0 +LINE + 5 +F44 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529938.0074498041 + 20 +188648.6658983669 + 30 +0.0 + 11 +530270.7960156209 + 21 +189204.6228630211 + 31 +0.0 + 0 +LINE + 5 +F45 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529882.9791721063 + 20 +188691.1101639493 + 30 +0.0 + 11 +530040.7876780177 + 21 +188578.3892982067 + 31 +0.0 + 0 +LINE + 5 +F46 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529926.0705395602 + 20 +188749.5527191465 + 30 +0.0 + 11 +529978.090685173 + 21 +188711.7433267618 + 31 +0.0 + 0 +LINE + 5 +F47 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529879.4421075356 + 20 +188721.5696107556 + 30 +0.0 + 11 +529941.9241917324 + 21 +188750.4355886093 + 31 +0.0 + 0 +LINE + 5 +F48 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529927.9638145668 + 20 +188735.4966583948 + 30 +0.0 + 11 +529988.0450447927 + 21 +188862.5853668438 + 31 +0.0 + 0 +LINE + 5 +F49 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529801.2439603802 + 20 +188899.2092534301 + 30 +0.0 + 11 +530180.2573593365 + 21 +188750.0095964078 + 31 +0.0 + 0 +LINE + 5 +F4A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530172.5310722675 + 20 +188739.1651746473 + 30 +0.0 + 11 +530272.9766230131 + 21 +188955.8364995346 + 31 +0.0 + 0 +LINE + 5 +F4B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530284.4588110418 + 20 +188584.964065519 + 30 +0.0 + 11 +530168.9714134656 + 21 +188756.9220339363 + 31 +0.0 + 0 +LINE + 5 +F4C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530197.772166788 + 20 +188575.6147259658 + 30 +0.0 + 11 +530255.2154729472 + 21 +188638.7937283235 + 31 +0.0 + 0 +LINE + 5 +F4D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529829.9928316144 + 20 +189021.1235840313 + 30 +0.0 + 11 +529911.9975660703 + 21 +188983.7429135527 + 31 +0.0 + 0 +LINE + 5 +F4E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530017.1576935793 + 20 +188623.9539361422 + 30 +0.0 + 11 +530214.3791785211 + 21 +188999.3722524601 + 31 +0.0 + 0 +LINE + 5 +F4F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530490.2430086076 + 20 +188572.0473727899 + 30 +0.0 + 11 +530526.1291594945 + 21 +188683.8584272694 + 31 +0.0 + 0 +LINE + 5 +F50 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530447.2617267332 + 20 +188616.8538348757 + 30 +0.0 + 11 +530548.6963119143 + 21 +188659.0038741323 + 31 +0.0 + 0 +LINE + 5 +F51 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530306.882250479 + 20 +188744.9041433715 + 30 +0.0 + 11 +530467.7402511069 + 21 +188622.7078463936 + 31 +0.0 + 0 +LINE + 5 +F52 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530224.820826905 + 20 +188509.0554664283 + 30 +0.0 + 11 +530471.2304298216 + 21 +188859.3289219959 + 31 +0.0 + 0 +LINE + 5 +F53 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530144.4991940331 + 20 +188557.0662913824 + 30 +0.0 + 11 +530252.3089088132 + 21 +188501.1687876312 + 31 +0.0 + 0 +LINE + 5 +F54 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530188.3739058851 + 20 +188421.5678079964 + 30 +0.0 + 11 +530114.6527432591 + 21 +188517.238708208 + 31 +0.0 + 0 +LINE + 5 +F55 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530116.6622527729 + 20 +188510.8093623602 + 30 +0.0 + 11 +530146.4414873774 + 21 +188558.0408992791 + 31 +0.0 + 0 +LINE + 5 +F56 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529973.7295696518 + 20 +188204.4897017882 + 30 +0.0 + 11 +530322.6171191205 + 21 +188645.8456197177 + 31 +0.0 + 0 +LINE + 5 +F57 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530321.3856370711 + 20 +188658.8653438716 + 30 +0.0 + 11 +530340.3191360755 + 21 +188643.6575436529 + 31 +0.0 + 0 +LINE + 5 +F58 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530298.7306297399 + 20 +188847.6510565491 + 30 +0.0 + 11 +530350.7878136068 + 21 +188904.950270655 + 31 +0.0 + 0 +LINE + 5 +F59 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530283.5843938705 + 20 +188844.1989231907 + 30 +0.0 + 11 +530306.5501863716 + 21 +188851.3905021144 + 31 +0.0 + 0 +LINE + 5 +F5A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530230.6050800018 + 20 +188880.2774790045 + 30 +0.0 + 11 +530291.1333363518 + 21 +188841.5709865972 + 31 +0.0 + 0 +LINE + 5 +F5B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530252.8039011196 + 20 +188624.4483253126 + 30 +0.0 + 11 +530548.3191566242 + 21 +188427.6627006649 + 31 +0.0 + 0 +LINE + 5 +F5C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530273.2913646184 + 20 +188254.619201703 + 30 +0.0 + 11 +530462.4648851728 + 21 +188331.039274131 + 31 +0.0 + 0 +LINE + 5 +F5D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530464.8713986185 + 20 +188300.0304104486 + 30 +0.0 + 11 +530270.6757222974 + 21 +188585.1958344434 + 31 +0.0 + 0 +LINE + 5 +F5E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530191.1691777817 + 20 +188484.2176064294 + 30 +0.0 + 11 +530219.2302152268 + 21 +188462.4329350414 + 31 +0.0 + 0 +LINE + 5 +F5F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530398.6480217873 + 20 +188512.1704469851 + 30 +0.0 + 11 +530462.1979809385 + 21 +188580.5315681904 + 31 +0.0 + 0 +LINE + 5 +F60 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530441.4646545147 + 20 +188552.1473247715 + 30 +0.0 + 11 +530455.0881170677 + 21 +188634.4090018151 + 31 +0.0 + 0 +LINE + 5 +F61 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530429.9581412063 + 20 +188558.4616864207 + 30 +0.0 + 11 +530504.7882607162 + 21 +188587.177550187 + 31 +0.0 + 0 +LINE + 5 +F62 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530583.7826875651 + 20 +188503.8478388322 + 30 +0.0 + 11 +530492.7321849806 + 21 +188590.9217415122 + 31 +0.0 + 0 +LINE + 5 +F63 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530128.8055889876 + 20 +188119.8151252872 + 30 +0.0 + 11 +530335.2906158104 + 21 +188293.0578746854 + 31 +0.0 + 0 +LINE + 5 +F64 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530066.7164829579 + 20 +188729.1087068058 + 30 +0.0 + 11 +530110.7945348675 + 21 +188712.761374369 + 31 +0.0 + 0 +LINE + 5 +F65 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530077.8453580029 + 20 +188658.1108268526 + 30 +0.0 + 11 +530110.4876913875 + 21 +188714.6375967872 + 31 +0.0 + 0 +LINE + 5 +F66 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530028.2934936099 + 20 +188658.5330613529 + 30 +0.0 + 11 +530112.1621429813 + 21 +188596.4928108161 + 31 +0.0 + 0 +LINE + 5 +F67 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530007.0513687442 + 20 +188488.0285021525 + 30 +0.0 + 11 +530210.6286316809 + 21 +188706.4662034733 + 31 +0.0 + 0 +LINE + 5 +F68 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530199.301889246 + 20 +188804.3511544324 + 30 +0.0 + 11 +530259.8664984353 + 21 +188771.6175040693 + 31 +0.0 + 0 +LINE + 5 +F69 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530243.8733479142 + 20 +188744.0826705819 + 30 +0.0 + 11 +530272.6096039502 + 21 +188796.8728168748 + 31 +0.0 + 0 +LINE + 5 +F6A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530240.4986297941 + 20 +188751.9994651915 + 30 +0.0 + 11 +530302.7678641983 + 21 +188717.1997760565 + 31 +0.0 + 0 +LINE + 5 +F6B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530299.2781272823 + 20 +188715.9187323489 + 30 +0.0 + 11 +530327.3491186148 + 21 +188764.5356968813 + 31 +0.0 + 0 +LINE + 5 +F6C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530263.6162603486 + 20 +188796.0012576215 + 30 +0.0 + 11 +530331.6832752539 + 21 +188758.9476575219 + 31 +0.0 + 0 +LINE + 5 +F6D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530108.0094572235 + 20 +188262.6354707962 + 30 +0.0 + 11 +530178.3429384298 + 21 +188350.7136858376 + 31 +0.0 + 0 +LINE + 5 +F6E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529914.8298536334 + 20 +188851.7567333126 + 30 +0.0 + 11 +530014.2219277663 + 21 +189096.9810497221 + 31 +0.0 + 0 +LINE + 5 +F6F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529392.945314271 + 20 +189359.2639292472 + 30 +0.0 + 11 +531170.003586833 + 21 +188526.4350730158 + 31 +0.0 + 0 +LINE + 5 +F70 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530573.3534346061 + 20 +188563.8997038407 + 30 +0.0 + 11 +530798.5430697939 + 21 +188532.9298318643 + 31 +0.0 + 0 +LINE + 5 +F71 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530467.7349198311 + 20 +188409.7615463817 + 30 +0.0 + 11 +530612.9150610638 + 21 +188321.695524386 + 31 +0.0 + 0 +LINE + 5 +F72 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530247.1860381263 + 20 +188010.521249343 + 30 +0.0 + 11 +530664.9692136952 + 21 +188682.3470452653 + 31 +0.0 + 0 +LINE + 5 +F73 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530584.9722957194 + 20 +188424.0512586005 + 30 +0.0 + 11 +530998.5263986866 + 21 +188276.210900377 + 31 +0.0 + 0 +LINE + 5 +F74 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530618.0993608664 + 20 +188485.143194091 + 30 +0.0 + 11 +530531.9829551339 + 21 +188311.3804743395 + 31 +0.0 + 0 +LINE + 5 +F75 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530682.6650718633 + 20 +188451.9217075121 + 30 +0.0 + 11 +530653.6339401833 + 21 +188394.5384425692 + 31 +0.0 + 0 +LINE + 5 +F76 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530647.6051370533 + 20 +188493.4917207355 + 30 +0.0 + 11 +530686.0644878534 + 21 +188436.411655397 + 31 +0.0 + 0 +LINE + 5 +F77 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530669.0907209093 + 20 +188447.811436197 + 30 +0.0 + 11 +531056.4550221097 + 21 +188335.8025262527 + 31 +0.0 + 0 +LINE + 5 +F78 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530810.4353722193 + 20 +188602.8349553812 + 30 +0.0 + 11 +530723.6458221129 + 21 +188201.0597410968 + 31 +0.0 + 0 +LINE + 5 +F79 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530711.7081960532 + 20 +188206.9580526561 + 30 +0.0 + 11 +530941.6233769567 + 21 +188142.3455052437 + 31 +0.0 + 0 +LINE + 5 +F7A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530577.3266136871 + 20 +188071.87514817 + 30 +0.0 + 11 +530728.6702959506 + 21 +188213.3034753897 + 31 +0.0 + 0 +LINE + 5 +F7B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530554.2748281737 + 20 +188155.9620058036 + 30 +0.0 + 11 +530625.8047850881 + 21 +188109.327415367 + 31 +0.0 + 0 +LINE + 5 +F7C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531148.102332967 + 20 +188838.6902303597 + 30 +0.0 + 11 +530938.9722214446 + 21 +188140.7336146608 + 31 +0.0 + 0 +LINE + 5 +F7D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530573.1968834673 + 20 +188341.973357598 + 30 +0.0 + 11 +530975.258866774 + 21 +188207.1349805347 + 31 +0.0 + 0 +LINE + 5 +F7E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530682.2314537685 + 20 +187829.5947561866 + 30 +0.0 + 11 +530975.3709463781 + 21 +188214.1092700097 + 31 +0.0 + 0 +LINE + 5 +F7F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530565.94484635 + 20 +187647.9643601798 + 30 +0.0 + 11 +530852.1731076476 + 21 +188060.0216062034 + 31 +0.0 + 0 +LINE + 5 +F80 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530597.3871645713 + 20 +187866.6641562202 + 30 +0.0 + 11 +530713.4897298386 + 21 +187849.065233877 + 31 +0.0 + 0 +LINE + 5 +F81 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530634.7670807852 + 20 +187916.2398710416 + 30 +0.0 + 11 +530692.55145945 + 21 +187822.8237778752 + 31 +0.0 + 0 +LINE + 5 +F82 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530738.7958414644 + 20 +188075.2408012614 + 30 +0.0 + 11 +530643.8114683718 + 21 +187896.9567575858 + 31 +0.0 + 0 +LINE + 5 +F83 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530523.6944121592 + 20 +188103.751873043 + 30 +0.0 + 11 +530797.2236527434 + 21 +187978.4151643149 + 31 +0.0 + 0 +LINE + 5 +F84 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530444.9741594119 + 20 +188057.692000106 + 30 +0.0 + 11 +530523.1492674589 + 21 +188150.6227162792 + 31 +0.0 + 0 +LINE + 5 +F85 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530433.5994985798 + 20 +188199.6618787103 + 30 +0.0 + 11 +530402.148168475 + 21 +188083.0490800954 + 31 +0.0 + 0 +LINE + 5 +F86 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530401.5416351788 + 20 +188089.7577859227 + 30 +0.0 + 11 +530447.1416332303 + 21 +188057.5357271576 + 31 +0.0 + 0 +LINE + 5 +F87 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530152.1746223897 + 20 +188317.9629113906 + 30 +0.0 + 11 +530152.1854826093 + 21 +188317.9568539679 + 31 +0.0 + 0 +LINE + 5 +F88 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530279.9986768201 + 20 +188246.6674526891 + 30 +0.0 + 11 +530643.5135505878 + 21 +188043.9125034311 + 31 +0.0 + 0 +LINE + 5 +F89 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530656.1703455079 + 20 +188047.2042062475 + 30 +0.0 + 11 +530644.17602906 + 21 +188026.0880762758 + 31 +0.0 + 0 +LINE + 5 +F8A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530838.9284713299 + 20 +188099.6709777739 + 30 +0.0 + 11 +530876.0295792661 + 21 +188073.6393630881 + 31 +0.0 + 0 +LINE + 5 +F8B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530833.1054584868 + 20 +188114.0729987142 + 30 +0.0 + 11 +530843.8668922444 + 21 +188092.5477118147 + 31 +0.0 + 0 +LINE + 5 +F8C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530860.2749595206 + 20 +188172.1271811749 + 30 +0.0 + 11 +530831.7148109637 + 21 +188106.2016149227 + 31 +0.0 + 0 +LINE + 5 +F8D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530611.2583920929 + 20 +188109.420780511 + 30 +0.0 + 11 +530455.3892869106 + 21 +187794.6279178761 + 31 +0.0 + 0 +LINE + 5 +F8E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530383.6970071517 + 20 +187864.4271638903 + 30 +0.0 + 11 +530575.3577239918 + 21 +188085.5188546145 + 31 +0.0 + 0 +LINE + 5 +F8F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530462.9941843908 + 20 +188147.9073801776 + 30 +0.0 + 11 +530445.9625123882 + 21 +188116.7318147655 + 31 +0.0 + 0 +LINE + 5 +F90 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530523.6716025012 + 20 +187947.540010238 + 30 +0.0 + 11 +530601.2910764078 + 21 +187895.7031751591 + 31 +0.0 + 0 +LINE + 5 +F91 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530569.9640754642 + 20 +187911.6454181296 + 30 +0.0 + 11 +530653.3455576861 + 21 +187911.3127554578 + 31 +0.0 + 0 +LINE + 5 +F92 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530574.3629559046 + 20 +187924.0115356457 + 30 +0.0 + 11 +530614.6429893853 + 21 +187854.7174773109 + 31 +0.0 + 0 +LINE + 5 +F93 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530518.4180696863 + 20 +187717.9959374398 + 30 +0.0 + 11 +530616.4169547133 + 21 +187867.2163163705 + 31 +0.0 + 0 +LINE + 5 +F94 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530684.9084061024 + 20 +188309.815386448 + 30 +0.0 + 11 +530675.7983986727 + 21 +188263.694700172 + 31 +0.0 + 0 +LINE + 5 +F95 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530616.5933388403 + 20 +188287.5083830064 + 30 +0.0 + 11 +530677.6016914072 + 21 +188264.2967789023 + 31 +0.0 + 0 +LINE + 5 +F96 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530609.1091987736 + 20 +188336.4936174578 + 30 +0.0 + 11 +530561.2354102382 + 21 +188243.8057358047 + 31 +0.0 + 0 +LINE + 5 +F97 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530437.3990079661 + 20 +188330.2772720863 + 30 +0.0 + 11 +530685.5021679961 + 21 +188164.1341009169 + 31 +0.0 + 0 +LINE + 5 +F98 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530780.328769887 + 20 +188190.9235445889 + 30 +0.0 + 11 +530757.6708446792 + 21 +188125.9144515507 + 31 +0.0 + 0 +LINE + 5 +F99 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530727.9382006641 + 20 +188137.312600464 + 30 +0.0 + 11 +530784.6349167087 + 21 +188117.3613010984 + 31 +0.0 + 0 +LINE + 5 +F9A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530735.215615822 + 20 +188141.9064646223 + 30 +0.0 + 11 +530710.7898842521 + 21 +188074.8851280609 + 31 +0.0 + 0 +LINE + 5 +F9B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530708.9687964411 + 20 +188078.1259575703 + 30 +0.0 + 11 +530761.4396459194 + 21 +188058.1660039187 + 31 +0.0 + 0 +LINE + 5 +F9C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530782.340532437 + 20 +188126.1006171749 + 30 +0.0 + 11 +530756.6141735527 + 21 +188052.9962926993 + 31 +0.0 + 0 +LINE + 5 +F9D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530781.7692014918 + 20 +188479.3148639996 + 30 +0.0 + 11 +531039.7040985098 + 21 +188420.2950481815 + 31 +0.0 + 0 +LINE + 5 +F9E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529629.2416397601 + 20 +187659.0530045348 + 30 +0.0 + 11 +528886.575565366 + 21 +187685.1694001948 + 31 +0.0 + 0 +LINE + 5 +F9F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529247.9222219149 + 20 +187060.1428561345 + 30 +0.0 + 11 +529909.5045036059 + 21 +189267.5528252435 + 31 +0.0 + 0 +LINE + 5 +FA0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529470.3553425334 + 20 +187790.2496720883 + 30 +0.0 + 11 +529323.8045910156 + 21 +187809.7579250679 + 31 +0.0 + 0 +LINE + 5 +FA1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529362.617563407 + 20 +187665.7724225901 + 30 +0.0 + 11 +529507.2275818894 + 21 +188138.6070124287 + 31 +0.0 + 0 +LINE + 5 +FA2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529353.6260863388 + 20 +187796.4745269601 + 30 +0.0 + 11 +529290.4618051137 + 21 +187848.7370549503 + 31 +0.0 + 0 +LINE + 5 +FA3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529297.3525618934 + 20 +187740.0067834225 + 30 +0.0 + 11 +529352.4314082598 + 21 +187808.4447053898 + 31 +0.0 + 0 +LINE + 5 +FA4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529314.7180172402 + 20 +187747.7631273677 + 30 +0.0 + 11 +529116.0222761967 + 21 +187756.3802774495 + 31 +0.0 + 0 +LINE + 5 +FA5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529285.8591790829 + 20 +187628.6077169585 + 30 +0.0 + 11 +529237.5613662758 + 21 +188058.8710579453 + 31 +0.0 + 0 +LINE + 5 +FA6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529111.5419683684 + 20 +187812.2740061647 + 30 +0.0 + 11 +529294.735175274 + 21 +187848.0523194833 + 31 +0.0 + 0 +LINE + 5 +FA7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529119.5556862255 + 20 +187752.1957725445 + 30 +0.0 + 11 +529112.0603154724 + 21 +187812.9447651166 + 31 +0.0 + 0 +LINE + 5 +FA8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528822.1497234687 + 20 +187750.8368952536 + 30 +0.0 + 11 +529116.4445893118 + 21 +187792.5082054131 + 31 +0.0 + 0 +LINE + 5 +FA9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528890.3129050055 + 20 +187756.7907356661 + 30 +0.0 + 11 +528882.1362303199 + 21 +187869.6222175659 + 31 +0.0 + 0 +LINE + 5 +FAA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528801.5514038664 + 20 +187857.6685223063 + 30 +0.0 + 11 +529605.3146455969 + 21 +187956.9241549581 + 31 +0.0 + 0 +LINE + 5 +FAB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529318.7137926164 + 20 +187990.5206507724 + 30 +0.0 + 11 +529358.2500389636 + 21 +188427.9228144905 + 31 +0.0 + 0 +LINE + 5 +FAC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529388.0696869734 + 20 +187994.9237116579 + 30 +0.0 + 11 +529194.2067956202 + 21 +187989.7567523999 + 31 +0.0 + 0 +LINE + 5 +FAD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529385.0400111967 + 20 +188067.4717596795 + 30 +0.0 + 11 +529320.7701771024 + 21 +188065.2280735188 + 31 +0.0 + 0 +LINE + 5 +FAE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529408.0392518247 + 20 +188018.1939760562 + 30 +0.0 + 11 +529372.3922877637 + 21 +188077.0713866332 + 31 +0.0 + 0 +LINE + 5 +FAF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529375.6083177687 + 20 +188056.8792862579 + 30 +0.0 + 11 +529436.6616666444 + 21 +188455.4637645589 + 31 +0.0 + 0 +LINE + 5 +FB0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529572.2232949353 + 20 +188121.7043275001 + 30 +0.0 + 11 +529174.5926249127 + 21 +188210.0306797475 + 31 +0.0 + 0 +LINE + 5 +FB1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529174.9313102554 + 20 +188196.7196960337 + 30 +0.0 + 11 +529212.8648250112 + 21 +188432.5094756071 + 31 +0.0 + 0 +LINE + 5 +FB2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528995.8982329628 + 20 +188131.504989113 + 30 +0.0 + 11 +529187.8143716537 + 21 +188209.4477733275 + 31 +0.0 + 0 +LINE + 5 +FB3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529062.5257631239 + 20 +188075.2665977178 + 30 +0.0 + 11 +529050.2486893053 + 21 +188159.76862858 + 31 +0.0 + 0 +LINE + 5 +FB4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529628.1589158975 + 20 +188300.4001130504 + 30 +0.0 + 11 +529539.2737798636 + 21 +188315.283781647 + 31 +0.0 + 0 +LINE + 5 +FB5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529677.6791911395 + 20 +188363.7428355513 + 30 +0.0 + 11 +529210.288461868 + 21 +188430.7805540487 + 31 +0.0 + 0 +LINE + 5 +FB6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529239.2811099911 + 20 +188014.3091164152 + 30 +0.0 + 11 +529285.7898337491 + 21 +188435.8208777742 + 31 +0.0 + 0 +LINE + 5 +FB7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528944.5248341071 + 20 +188380.8283716183 + 30 +0.0 + 11 +529292.1661640495 + 21 +188432.9932131161 + 31 +0.0 + 0 +LINE + 5 +FB8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528569.2810199707 + 20 +188292.7158789641 + 30 +0.0 + 11 +528806.2807468023 + 21 +188334.287433425 + 31 +0.0 + 0 +LINE + 5 +FB9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529040.6513158122 + 20 +187642.311198794 + 30 +0.0 + 11 +528998.3219772069 + 21 +188203.3154728942 + 31 +0.0 + 0 +LINE + 5 +FBA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529006.6254128079 + 20 +188213.419072367 + 30 +0.0 + 11 +528982.4243466746 + 21 +188211.4033913288 + 31 +0.0 + 0 +LINE + 5 +FBB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529131.0027007718 + 20 +188357.2369603609 + 30 +0.0 + 11 +529121.3118151613 + 21 +188418.8936375129 + 31 +0.0 + 0 +LINE + 5 +FBC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529141.6269001136 + 20 +188345.903290431 + 30 +0.0 + 11 +529126.6125106496 + 21 +188364.7105906532 + 31 +0.0 + 0 +LINE + 5 +FBD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529205.7236681208 + 20 +188346.1757213804 + 30 +0.0 + 11 +529133.8994146958 + 21 +188347.9474412191 + 31 +0.0 + 0 +LINE + 5 +FBE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528643.1508068893 + 20 +187897.179310321 + 30 +0.0 + 11 +528526.4033827907 + 21 +188092.533363126 + 31 +0.0 + 0 +LINE + 5 +FBF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528820.3758145471 + 20 +187851.4258546835 + 30 +0.0 + 11 +528611.9802258696 + 21 +187905.2264917811 + 31 +0.0 + 0 +LINE + 5 +FC0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528733.4144066438 + 20 +187645.3547041817 + 30 +0.0 + 11 +528905.2436686549 + 21 +187686.2336607713 + 31 +0.0 + 0 +LINE + 5 +FC1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528846.9694373976 + 20 +187660.7754114646 + 30 +0.0 + 11 +528790.4836022626 + 21 +187917.9682800507 + 31 +0.0 + 0 +LINE + 5 +FC2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529257.0190230463 + 20 +188129.1958686471 + 30 +0.0 + 11 +529211.3374954253 + 21 +188140.3002809301 + 31 +0.0 + 0 +LINE + 5 +FC3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529208.0810821642 + 20 +188076.5686061319 + 30 +0.0 + 11 +529212.6413179638 + 21 +188141.6839030864 + 31 +0.0 + 0 +LINE + 5 +FC4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529249.3922603196 + 20 +188049.2016167797 + 30 +0.0 + 11 +529145.1686562638 + 21 +188044.6868198139 + 31 +0.0 + 0 +LINE + 5 +FC5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529171.6282192092 + 20 +187895.9835157372 + 30 +0.0 + 11 +529125.0608482104 + 21 +188190.9245459472 + 31 +0.0 + 0 +LINE + 5 +FC6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529189.2021753491 + 20 +188265.7286158319 + 30 +0.0 + 11 +529120.6887160605 + 21 +188272.4717344477 + 31 +0.0 + 0 +LINE + 5 +FC7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529118.5442134677 + 20 +188240.7014806336 + 30 +0.0 + 11 +529124.2522195913 + 21 +188300.534503478 + 31 +0.0 + 0 +LINE + 5 +FC8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529125.769900808 + 20 +188245.3762856292 + 30 +0.0 + 11 +529054.6877821515 + 21 +188251.3602913529 + 31 +0.0 + 0 +LINE + 5 +FC9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529056.8639720252 + 20 +188248.3464011163 + 30 +0.0 + 11 +529060.7891532491 + 21 +188304.3480327632 + 31 +0.0 + 0 +LINE + 5 +FCA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529131.21955758 + 20 +188294.7815871724 + 30 +0.0 + 11 +529054.0707556696 + 21 +188302.1402665566 + 31 +0.0 + 0 +LINE + 5 +FCB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529700.5375658763 + 20 +188484.9666580997 + 30 +0.0 + 11 +529471.5662644893 + 21 +188494.8968159285 + 31 +0.0 + 0 +LINE + 5 +FCC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529634.4603943709 + 20 +188470.7758187421 + 30 +0.0 + 11 +529594.9091760079 + 21 +188797.1288748313 + 31 +0.0 + 0 +LINE + 5 +FCD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529468.8897781007 + 20 +188550.5318230509 + 30 +0.0 + 11 +529652.0829850063 + 21 +188586.3101363694 + 31 +0.0 + 0 +LINE + 5 +FCE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529476.9034959577 + 20 +188490.4535894304 + 30 +0.0 + 11 +529469.4081252046 + 21 +188551.2025820028 + 31 +0.0 + 0 +LINE + 5 +FCF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529179.497533201 + 20 +188489.0947121396 + 30 +0.0 + 11 +529473.7923990441 + 21 +188530.7660222994 + 31 +0.0 + 0 +LINE + 5 +FD0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529263.7756425611 + 20 +188606.075583112 + 30 +0.0 + 11 +529908.763791275 + 21 +188688.5260989179 + 31 +0.0 + 0 +LINE + 5 +FD1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529676.0616023485 + 20 +188728.7784676585 + 30 +0.0 + 11 +529699.9550760643 + 21 +188993.1196246366 + 31 +0.0 + 0 +LINE + 5 +FD2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529745.4174967054 + 20 +188733.181528544 + 30 +0.0 + 11 +529551.5546053525 + 21 +188728.0145692858 + 31 +0.0 + 0 +LINE + 5 +FD3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529742.387820929 + 20 +188805.7295765657 + 30 +0.0 + 11 +529678.1179868345 + 21 +188803.4858904049 + 31 +0.0 + 0 +LINE + 5 +FD4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529765.3870615571 + 20 +188756.4517929425 + 30 +0.0 + 11 +529729.7400974962 + 21 +188815.3292035195 + 31 +0.0 + 0 +LINE + 5 +FD5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529732.9561275008 + 20 +188795.1371031438 + 30 +0.0 + 11 +529794.0094763765 + 21 +189193.721581445 + 31 +0.0 + 0 +LINE + 5 +FD6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529822.1310589099 + 20 +188883.713462244 + 30 +0.0 + 11 +529531.9404346449 + 21 +188948.2884966338 + 31 +0.0 + 0 +LINE + 5 +FD7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529532.2791199877 + 20 +188934.97751292 + 30 +0.0 + 11 +529570.2126347435 + 21 +189170.7672924934 + 31 +0.0 + 0 +LINE + 5 +FD8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529384.8240162092 + 20 +188882.5875490996 + 30 +0.0 + 11 +529545.1621813861 + 21 +188947.7055902138 + 31 +0.0 + 0 +LINE + 5 +FD9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529462.6117272585 + 20 +188607.3202886658 + 30 +0.0 + 11 +529407.5964990378 + 21 +188898.026445466 + 31 +0.0 + 0 +LINE + 5 +FDA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529596.6289197234 + 20 +188752.5669333013 + 30 +0.0 + 11 +529643.1376434814 + 21 +189174.0786946602 + 31 +0.0 + 0 +LINE + 5 +FDB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529117.932638334 + 20 +189064.2549476437 + 30 +0.0 + 11 +529478.0365257928 + 21 +189010.7295513338 + 31 +0.0 + 0 +LINE + 5 +FDC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529175.4404670244 + 20 +188974.1618202624 + 30 +0.0 + 11 +529208.2352462457 + 21 +189086.918328656 + 31 +0.0 + 0 +LINE + 5 +FDD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529236.1315537773 + 20 +188987.2615005996 + 30 +0.0 + 11 +529175.6261960312 + 21 +189078.9386655001 + 31 +0.0 + 0 +LINE + 5 +FDE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529397.9991255444 + 20 +188380.5690156801 + 30 +0.0 + 11 +529379.1669343232 + 21 +188698.7673302471 + 31 +0.0 + 0 +LINE + 5 +FDF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529386.967280002 + 20 +188673.3752750442 + 30 +0.0 + 11 +529046.5374145823 + 21 +188886.9621896196 + 31 +0.0 + 0 +LINE + 5 +FE0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529129.1625395999 + 20 +188809.4756186941 + 30 +0.0 + 11 +529216.2919105073 + 21 +188951.7408787446 + 31 +0.0 + 0 +LINE + 5 +FE1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529204.7431267487 + 20 +188930.3817577657 + 30 +0.0 + 11 +529239.4635664156 + 21 +189006.191211736 + 31 +0.0 + 0 +LINE + 5 +FE2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529217.8131727024 + 20 +188929.1797135396 + 30 +0.0 + 11 +529171.8465916677 + 21 +188994.8396027087 + 31 +0.0 + 0 +LINE + 5 +FE3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529059.7550470335 + 20 +188969.9509328124 + 30 +0.0 + 11 +529183.9345532104 + 21 +188991.1996691156 + 31 +0.0 + 0 +LINE + 5 +FE4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529222.0890533329 + 20 +188397.1220266792 + 30 +0.0 + 11 +529180.9709087853 + 21 +188540.5938421276 + 31 +0.0 + 0 +LINE + 5 +FE5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529614.3668327786 + 20 +188867.4536855333 + 30 +0.0 + 11 +529568.6853051575 + 21 +188878.5580978163 + 31 +0.0 + 0 +LINE + 5 +FE6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529565.4288918965 + 20 +188814.8264230181 + 30 +0.0 + 11 +529569.989127696 + 21 +188879.9417199727 + 31 +0.0 + 0 +LINE + 5 +FE7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529606.7400700518 + 20 +188787.4594336657 + 30 +0.0 + 11 +529502.5164659961 + 21 +188782.9446366999 + 31 +0.0 + 0 +LINE + 5 +FE8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529528.9760289416 + 20 +188634.2413326233 + 30 +0.0 + 11 +529482.4086579428 + 21 +188929.1823628333 + 31 +0.0 + 0 +LINE + 5 +FE9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529546.5499850815 + 20 +189003.9864327182 + 30 +0.0 + 11 +529478.0365257928 + 21 +189010.7295513338 + 31 +0.0 + 0 +LINE + 5 +FEA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529396.9533566374 + 20 +188869.3050320101 + 30 +0.0 + 11 +529481.6000293236 + 21 +189038.7923203641 + 31 +0.0 + 0 +LINE + 5 +FEB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529319.2145911773 + 20 +188503.8776358344 + 30 +0.0 + 11 +529310.1799248937 + 21 +188616.229517655 + 31 +0.0 + 0 +LINE + 5 +FEC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529161.5459109745 + 20 +189048.278224607 + 30 +0.0 + 11 +528647.9655036306 + 21 +189306.6925524445 + 31 +0.0 + 0 +LINE + 5 +FED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529101.9903625048 + 20 +189013.8960569484 + 30 +0.0 + 11 +528898.0009451259 + 21 +189114.1847520432 + 31 +0.0 + 0 +LINE + 5 +FEE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529103.3229948528 + 20 +188827.0483480004 + 30 +0.0 + 11 +528933.7188917285 + 21 +188835.2547992389 + 31 +0.0 + 0 +LINE + 5 +FEF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529075.138747387 + 20 +188689.541834962 + 30 +0.0 + 11 +529110.5648560599 + 21 +189653.1949148731 + 31 +0.0 + 0 +LINE + 5 +FF0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529014.134476429 + 20 +188904.4706081191 + 30 +0.0 + 11 +528588.6323275295 + 21 +189013.2441751404 + 31 +0.0 + 0 +LINE + 5 +FF1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529020.8464435756 + 20 +188973.6412415138 + 30 +0.0 + 11 +528995.036142355 + 21 +188781.4347211701 + 31 +0.0 + 0 +LINE + 5 +FF2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528948.7434804165 + 20 +188982.2180072632 + 30 +0.0 + 11 +528940.7107299657 + 21 +188918.4126734558 + 31 +0.0 + 0 +LINE + 5 +FF3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529001.0580113628 + 20 +188997.0657303256 + 30 +0.0 + 11 +528937.2500076989 + 21 +188971.2627422923 + 31 +0.0 + 0 +LINE + 5 +FF4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528957.6965665056 + 20 +188971.2180261912 + 30 +0.0 + 11 +528573.9463495623 + 21 +189095.0439877157 + 31 +0.0 + 0 +LINE + 5 +FF5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528925.0508529476 + 20 +189175.6538170998 + 30 +0.0 + 11 +528774.4528956277 + 21 +188797.1938463038 + 31 +0.0 + 0 +LINE + 5 +FF6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528787.6475847067 + 20 +188795.4057816234 + 30 +0.0 + 11 +528560.9228864532 + 21 +188870.450321031 + 31 +0.0 + 0 +LINE + 5 +FF7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528823.4813869797 + 20 +188608.2648203714 + 30 +0.0 + 11 +528777.1365327426 + 21 +188810.1534936224 + 31 +0.0 + 0 +LINE + 5 +FF8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528889.6239405762 + 20 +188665.0728043687 + 30 +0.0 + 11 +528804.2454468054 + 21 +188666.4265262114 + 31 +0.0 + 0 +LINE + 5 +FF9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528702.9237163125 + 20 +189318.3532235257 + 30 +0.0 + 11 +528562.2188912551 + 21 +188867.6312452332 + 31 +0.0 + 0 +LINE + 5 +FFA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528977.9849291424 + 20 +188829.8472042992 + 30 +0.0 + 11 +528569.281635989 + 21 +188942.9703430246 + 31 +0.0 + 0 +LINE + 5 +FFB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528601.002372018 + 20 +188466.1103209222 + 30 +0.0 + 11 +528573.0898207653 + 21 +188948.8142290799 + 31 +0.0 + 0 +LINE + 5 +FFC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528580.829102545 + 20 +188265.8679942571 + 30 +0.0 + 11 +528589.0227163259 + 21 +188752.1753253903 + 31 +0.0 + 0 +LINE + 5 +FFD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528692.0671885087 + 20 +188449.3803171656 + 30 +0.0 + 11 +528585.9823395023 + 21 +188499.7343889034 + 31 +0.0 + 0 +LINE + 5 +FFE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528688.812207707 + 20 +188511.3836617221 + 30 +0.0 + 11 +528588.6604472116 + 21 +188466.2701853558 + 31 +0.0 + 0 +LINE + 5 +FFF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528691.5173766687 + 20 +188701.3730322669 + 30 +0.0 + 11 +528670.5289779729 + 21 +188500.4583277746 + 31 +0.0 + 0 +LINE + 5 +1000 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528885.7690453813 + 20 +188604.6890351129 + 30 +0.0 + 11 +528588.9251168373 + 21 +188653.7931906997 + 31 +0.0 + 0 +LINE + 5 +1001 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528881.2333355238 + 20 +188501.5712737685 + 30 +0.0 + 11 +529072.9985641551 + 21 +188286.3545605624 + 31 +0.0 + 0 +LINE + 5 +1002 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529313.5523636491 + 20 +188574.4441057497 + 30 +0.0 + 11 +529313.5399730545 + 21 +188574.4451592718 + 31 +0.0 + 0 +LINE + 5 +1003 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529007.8590133908 + 20 +188588.9361372746 + 30 +0.0 + 11 +528752.9760917203 + 21 +188622.1076328554 + 31 +0.0 + 0 +LINE + 5 +1004 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528744.3257259774 + 20 +188631.9158405206 + 30 +0.0 + 11 +528742.4567941343 + 21 +188607.7029995927 + 31 +0.0 + 0 +LINE + 5 +1005 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528622.1795868 + 20 +188777.6334281767 + 30 +0.0 + 11 +528576.8645196604 + 21 +188776.8076779879 + 31 +0.0 + 0 +LINE + 5 +1006 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528635.0622695969 + 20 +188786.3145669094 + 30 +0.0 + 11 +528614.1015629134 + 21 +188774.4910645538 + 31 +0.0 + 0 +LINE + 5 +1007 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528645.013460359 + 20 +188849.6347350237 + 30 +0.0 + 11 +528631.8121348874 + 21 +188779.0118819444 + 31 +0.0 + 0 +LINE + 5 +1008 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528816.3556045137 + 20 +188658.3673484307 + 30 +0.0 + 11 +528769.4797142685 + 21 +188310.2403956821 + 31 +0.0 + 0 +LINE + 5 +1009 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528858.739831169 + 20 +188423.1701629402 + 30 +0.0 + 11 +528832.7451079655 + 21 +188618.4731858466 + 31 +0.0 + 0 +LINE + 5 +100A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529163.3023877976 + 20 +188861.749687461 + 30 +0.0 + 11 +528748.8838189233 + 21 +188297.0863431962 + 31 +0.0 + 0 +LINE + 5 +100B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528798.4103537806 + 20 +188475.1876621353 + 30 +0.0 + 11 +528705.0741880239 + 21 +188475.6352807375 + 31 +0.0 + 0 +LINE + 5 +100C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528739.9594058419 + 20 +188471.3274185242 + 30 +0.0 + 11 +528670.6559632971 + 21 +188517.691360261 + 31 +0.0 + 0 +LINE + 5 +100D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528743.2300711934 + 20 +188484.0385852572 + 30 +0.0 + 11 +528671.0809144397 + 21 +188449.1294632764 + 31 +0.0 + 0 +LINE + 5 +100E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528674.3689592359 + 20 +188281.9732387523 + 30 +0.0 + 11 +528676.6016874598 + 21 +188460.4823922414 + 31 +0.0 + 0 +LINE + 5 +100F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528867.3962947459 + 20 +188865.6767080673 + 30 +0.0 + 11 +528849.1500965991 + 21 +188822.3502012712 + 31 +0.0 + 0 +LINE + 5 +1010 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528911.5471733497 + 20 +188808.9735270618 + 30 +0.0 + 11 +528847.9920687762 + 21 +188823.8579595558 + 31 +0.0 + 0 +LINE + 5 +1011 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529084.0095456938 + 20 +188744.1930036312 + 30 +0.0 + 11 +528785.4168205069 + 21 +188745.2493220176 + 31 +0.0 + 0 +LINE + 5 +1012 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528721.7970170586 + 20 +188820.4974404503 + 30 +0.0 + 11 +528682.848956227 + 21 +188658.3917614921 + 31 +0.0 + 0 +LINE + 5 +1013 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528881.9155969028 + 20 +189060.359209691 + 30 +0.0 + 11 +528635.0928427313 + 21 +189155.7126458224 + 31 +0.0 + 0 +LINE + 5 +1014 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529005.5742357306 + 20 +187951.1941100283 + 30 +0.0 + 11 +529170.3123569273 + 21 +187974.2718737496 + 31 +0.0 + 0 +LINE + 5 +1015 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528914.0106005493 + 20 +187912.3245896476 + 30 +0.0 + 11 +529001.2995244179 + 21 +187749.7460745823 + 31 +0.0 + 0 +LINE + 5 +1016 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528902.4585341773 + 20 +188824.2821025381 + 30 +0.0 + 11 +528880.8568956467 + 21 +188709.114560081 + 31 +0.0 + 0 +LINE + 5 +1017 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529568.232106769 + 20 +188122.590896667 + 30 +0.0 + 11 +529750.5420645888 + 21 +188200.2264006352 + 31 +0.0 + 0 +LINE + 5 +1018 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532031.6637419214 + 20 +189206.8229816716 + 30 +0.0 + 11 +532139.3496554863 + 21 +189308.1217414095 + 31 +0.0 + 0 +LINE + 5 +1019 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532191.7713961092 + 20 +189168.5143173241 + 30 +0.0 + 11 +531798.5900445994 + 21 +189468.3359836828 + 31 +0.0 + 0 +LINE + 5 +101A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532122.8672957487 + 20 +189279.9419247654 + 30 +0.0 + 11 +532143.7102761921 + 21 +189359.2304385668 + 31 +0.0 + 0 +LINE + 5 +101B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532201.5098460327 + 20 +189266.8780471429 + 30 +0.0 + 11 +532116.8583799476 + 21 +189290.3633142239 + 31 +0.0 + 0 +LINE + 5 +101C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532182.879295075 + 20 +189263.0541117607 + 30 +0.0 + 11 +532339.2791202549 + 21 +189385.9090972841 + 31 +0.0 + 0 +LINE + 5 +101D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532275.8011499364 + 20 +189183.076782106 + 30 +0.0 + 11 +532064.1640193323 + 21 +189560.7922123821 + 31 +0.0 + 0 +LINE + 5 +101E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532310.3288497661 + 20 +189433.9305914979 + 30 +0.0 + 11 +532140.6377589193 + 21 +189356.1824568091 + 31 +0.0 + 0 +LINE + 5 +101F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532338.8483841458 + 20 +189380.4492864692 + 30 +0.0 + 11 +532309.5166327113 + 21 +189434.1732945015 + 31 +0.0 + 0 +LINE + 5 +1020 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532581.2590586423 + 20 +189552.7548816218 + 30 +0.0 + 11 +532317.8707829392 + 21 +189415.0138841873 + 31 +0.0 + 0 +LINE + 5 +1021 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532522.4104459652 + 20 +189517.8477431132 + 30 +0.0 + 11 +532463.2642730652 + 21 +189614.2818218812 + 31 +0.0 + 0 +LINE + 5 +1022 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532535.7028271408 + 20 +189651.5572959675 + 30 +0.0 + 11 +531820.0585549223 + 21 +189259.0289520904 + 31 +0.0 + 0 +LINE + 5 +1023 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532038.0875403904 + 20 +189457.9451817606 + 30 +0.0 + 11 +531750.9298642218 + 21 +189790.2466061002 + 31 +0.0 + 0 +LINE + 5 +1024 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531979.1741634221 + 20 +189421.0827206187 + 30 +0.0 + 11 +532139.6848387839 + 21 +189529.9213222574 + 31 +0.0 + 0 +LINE + 5 +1025 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531939.3346770747 + 20 +189481.7886802488 + 30 +0.0 + 11 +531992.8569659881 + 21 +189517.4399115257 + 31 +0.0 + 0 +LINE + 5 +1026 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531949.3822257373 + 20 +189428.3442063141 + 30 +0.0 + 11 +531944.0126425981 + 21 +189496.9621565889 + 31 +0.0 + 0 +LINE + 5 +1027 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531953.1733588967 + 20 +189478.6825219247 + 30 +0.0 + 11 +531671.1683416162 + 21 +189766.9016538019 + 31 +0.0 + 0 +LINE + 5 +1028 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531755.6417816337 + 20 +189416.7066298191 + 30 +0.0 + 11 +532027.1838522537 + 21 +189720.312621406 + 31 +0.0 + 0 +LINE + 5 +1029 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532034.6699812882 + 20 +189709.3010426241 + 30 +0.0 + 11 +531866.3692592388 + 21 +189878.7431821604 + 31 +0.0 + 0 +LINE + 5 +102A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532218.144887253 + 20 +189760.7088206811 + 30 +0.0 + 11 +532016.7821271637 + 21 +189712.1298051467 + 31 +0.0 + 0 +LINE + 5 +102B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532196.8065175713 + 20 +189676.1709095325 + 30 +0.0 + 11 +532157.5097438913 + 21 +189751.9804296455 + 31 +0.0 + 0 +LINE + 5 +102C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531405.6950599251 + 20 +189397.6918620768 + 30 +0.0 + 11 +531723.7921117423 + 21 +189537.8611520869 + 31 +0.0 + 0 +LINE + 5 +102D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531528.8411038234 + 20 +189551.8548372382 + 30 +0.0 + 11 +531869.470434986 + 21 +189878.8407822911 + 31 +0.0 + 0 +LINE + 5 +102E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532088.74975918 + 20 +189523.5864930972 + 30 +0.0 + 11 +531805.1927822128 + 21 +189838.9127799219 + 31 +0.0 + 0 +LINE + 5 +102F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532246.1302548441 + 20 +190023.238120023 + 30 +0.0 + 11 +531801.6612649959 + 21 +189832.8976604999 + 31 +0.0 + 0 +LINE + 5 +1030 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532470.7391336279 + 20 +190140.428907227 + 30 +0.0 + 11 +531984.7594943132 + 21 +189906.3534569081 + 31 +0.0 + 0 +LINE + 5 +1031 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532301.7252596375 + 20 +189949.1983383498 + 30 +0.0 + 11 +532209.3368012323 + 21 +190021.6821329716 + 31 +0.0 + 0 +LINE + 5 +1032 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532244.7805702968 + 20 +189924.453399633 + 30 +0.0 + 11 +532240.4817546558 + 21 +190034.2127776569 + 31 +0.0 + 0 +LINE + 5 +1033 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532075.9476160555 + 20 +189837.2828058441 + 30 +0.0 + 11 +532246.4030078652 + 21 +189945.6903275581 + 31 +0.0 + 0 +LINE + 5 +1034 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532268.6167204107 + 20 +189678.4203122155 + 30 +0.0 + 11 +532072.767541199 + 21 +189950.3266036608 + 31 +0.0 + 0 +LINE + 5 +1035 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532195.6990315971 + 20 +189619.7720839555 + 30 +0.0 + 11 +532285.5589545911 + 21 +189701.4584338929 + 31 +0.0 + 0 +LINE + 5 +1036 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532338.0010107443 + 20 +189613.8580269038 + 30 +0.0 + 11 +532222.6820952939 + 21 +189577.9514995641 + 31 +0.0 + 0 +LINE + 5 +1037 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532229.4091453788 + 20 +189577.6030549164 + 30 +0.0 + 11 +532195.459634246 + 21 +189621.9319573072 + 31 +0.0 + 0 +LINE + 5 +1038 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532467.022615763 + 20 +189337.1839935896 + 30 +0.0 + 11 +532174.3049913963 + 21 +189817.635823486 + 31 +0.0 + 0 +LINE + 5 +1039 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532161.6679775332 + 20 +189821.0026685536 + 30 +0.0 + 11 +532182.5046815933 + 21 +189833.4760937429 + 31 +0.0 + 0 +LINE + 5 +103A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531976.7650487176 + 20 +189865.3219824437 + 30 +0.0 + 11 +531957.2901799326 + 21 +189906.2471172519 + 31 +0.0 + 0 +LINE + 5 +103B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531974.7421079803 + 20 +189849.9195996247 + 30 +0.0 + 11 +531975.9740472566 + 21 +189873.953508134 + 31 +0.0 + 0 +LINE + 5 +103C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531922.5098082239 + 20 +189812.7677928074 + 30 +0.0 + 11 +531979.8281759879 + 21 +189856.0860001588 + 31 +0.0 + 0 +LINE + 5 +103D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532170.1247097689 + 20 +189744.736887547 + 30 +0.0 + 11 +532526.1201255466 + 21 +189993.58332384 + 31 +0.0 + 0 +LINE + 5 +103E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532516.4835480185 + 20 +189963.3210453037 + 30 +0.0 + 11 +532373.8361481662 + 21 +190105.3281985797 + 31 +0.0 + 0 +LINE + 5 +103F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532524.0494471331 + 20 +189635.5096147978 + 30 +0.0 + 11 +532505.5035082588 + 21 +189997.781077944 + 31 +0.0 + 0 +LINE + 5 +1040 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532585.1762395939 + 20 +189882.9770222952 + 30 +0.0 + 11 +532213.1407573749 + 21 +189747.8641355415 + 31 +0.0 + 0 +LINE + 5 +1041 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532280.2215546078 + 20 +189638.2372237165 + 30 +0.0 + 11 +532310.3957018821 + 21 +189656.9859454393 + 31 +0.0 + 0 +LINE + 5 +1042 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532326.0648090236 + 20 +189842.5096595214 + 30 +0.0 + 11 +532284.0292765015 + 21 +189925.8454513888 + 31 +0.0 + 0 +LINE + 5 +1043 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532303.4462126704 + 20 +189896.5449618215 + 30 +0.0 + 11 +532231.0361635415 + 21 +189937.8894539226 + 31 +0.0 + 0 +LINE + 5 +1044 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532293.5287351565 + 20 +189887.9475987774 + 30 +0.0 + 11 +532292.588323795 + 21 +189968.0928621695 + 31 +0.0 + 0 +LINE + 5 +1045 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532443.6591333519 + 20 +190039.7142635487 + 30 +0.0 + 11 +532284.8901796214 + 21 +189958.0875382314 + 31 +0.0 + 0 +LINE + 5 +1046 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532714.8532277894 + 20 +189518.7983350472 + 30 +0.0 + 11 +532551.4203747162 + 21 +189451.8200780417 + 31 +0.0 + 0 +LINE + 5 +1047 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532613.6075195969 + 20 +189465.1154719042 + 30 +0.0 + 11 +532509.5353245167 + 21 +189706.9993271604 + 31 +0.0 + 0 +LINE + 5 +1048 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532007.3517006937 + 20 +189606.5802005249 + 30 +0.0 + 11 +532037.989566198 + 21 +189642.2373335461 + 31 +0.0 + 0 +LINE + 5 +1049 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532077.795397995 + 20 +189592.3592185572 + 30 +0.0 + 11 +532036.1235619935 + 21 +189642.6011903765 + 31 +0.0 + 0 +LINE + 5 +104A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532060.190368608 + 20 +189546.0382893018 + 30 +0.0 + 11 +532147.4960968193 + 21 +189603.1404158431 + 31 +0.0 + 0 +LINE + 5 +104B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532212.7048115895 + 20 +189466.9031058558 + 30 +0.0 + 11 +532078.5647071548 + 21 +189733.6711019223 + 31 +0.0 + 0 +LINE + 5 +104C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531982.8387736801 + 20 +189757.0442570122 + 30 +0.0 + 11 +532034.56869682 + 21 +189802.4708880157 + 31 +0.0 + 0 +LINE + 5 +104D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532054.8353292636 + 20 +189777.9105230313 + 30 +0.0 + 11 +532015.3109772028 + 21 +189823.191838723 + 31 +0.0 + 0 +LINE + 5 +104E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532046.2392857908 + 20 +189777.4953171877 + 30 +0.0 + 11 +532100.4986561253 + 21 +189823.8029477473 + 31 +0.0 + 0 +LINE + 5 +104F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532100.4879973464 + 20 +189820.0855261795 + 30 +0.0 + 11 +532064.6460298329 + 21 +189863.2936638331 + 31 +0.0 + 0 +LINE + 5 +1050 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532013.0049510107 + 20 +189814.4555873601 + 30 +0.0 + 11 +532071.3914760512 + 21 +189865.4173523631 + 31 +0.0 + 0 +LINE + 5 +1051 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532459.1306889654 + 20 +189483.299482677 + 30 +0.0 + 11 +532400.9612071705 + 21 +189579.8441973495 + 31 +0.0 + 0 +LINE + 5 +1052 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531839.5884021576 + 20 +189506.7425210747 + 30 +0.0 + 11 +531644.1460684732 + 21 +189685.1130454415 + 31 +0.0 + 0 +LINE + 5 +1053 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531261.8280108232 + 20 +189635.3713330043 + 30 +0.0 + 11 +530793.9869514637 + 21 +189997.6585587048 + 31 +0.0 + 0 +LINE + 5 +1054 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531271.1054127446 + 20 +189503.5805225813 + 30 +0.0 + 11 +531418.5747294049 + 21 +189699.5365689853 + 31 +0.0 + 0 +LINE + 5 +1055 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532139.467897414 + 20 +189076.1120245828 + 30 +0.0 + 11 +531077.8151185179 + 21 +189859.7508112586 + 31 +0.0 + 0 +LINE + 5 +1056 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531402.0923696672 + 20 +189671.3567523413 + 30 +0.0 + 11 +531422.9353501108 + 21 +189750.6452661428 + 31 +0.0 + 0 +LINE + 5 +1057 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531480.7349199513 + 20 +189658.2928747189 + 30 +0.0 + 11 +531396.0834538663 + 21 +189681.7781418 + 31 +0.0 + 0 +LINE + 5 +1058 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531463.4189746374 + 20 +189655.7308904651 + 30 +0.0 + 11 +531619.8187998175 + 21 +189778.5858759885 + 31 +0.0 + 0 +LINE + 5 +1059 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531596.6289551386 + 20 +189500.2419092503 + 30 +0.0 + 11 +531343.389093251 + 21 +189952.207039958 + 31 +0.0 + 0 +LINE + 5 +105A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531589.5539236847 + 20 +189825.3454190738 + 30 +0.0 + 11 +531419.862832838 + 21 +189747.5972843849 + 31 +0.0 + 0 +LINE + 5 +105B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531618.0734580644 + 20 +189771.8641140451 + 30 +0.0 + 11 +531588.7417066297 + 21 +189825.5881220773 + 31 +0.0 + 0 +LINE + 5 +105C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531860.484132561 + 20 +189944.1697091979 + 30 +0.0 + 11 +531597.0958568579 + 21 +189806.4287117634 + 31 +0.0 + 0 +LINE + 5 +105D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531801.6355198837 + 20 +189909.2625706889 + 30 +0.0 + 11 +531742.489346984 + 21 +190005.6966494571 + 31 +0.0 + 0 +LINE + 5 +105E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531814.9279010593 + 20 +190042.9721235435 + 30 +0.0 + 11 +531151.7309556583 + 21 +189680.9756981938 + 31 +0.0 + 0 +LINE + 5 +105F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531317.3126143089 + 20 +189849.3600093366 + 30 +0.0 + 11 +531030.1549381406 + 21 +190181.6614336764 + 31 +0.0 + 0 +LINE + 5 +1060 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531258.3992373407 + 20 +189812.4975481947 + 30 +0.0 + 11 +531418.9099127025 + 21 +189921.3361498332 + 31 +0.0 + 0 +LINE + 5 +1061 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531218.5597509931 + 20 +189873.2035078246 + 30 +0.0 + 11 +531272.0820399069 + 21 +189908.8547391015 + 31 +0.0 + 0 +LINE + 5 +1062 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531228.6072996558 + 20 +189819.7590338899 + 30 +0.0 + 11 +531223.2377165169 + 21 +189888.3769841649 + 31 +0.0 + 0 +LINE + 5 +1063 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531232.3984328154 + 20 +189870.0973495005 + 30 +0.0 + 11 +530950.3934155348 + 21 +190158.3164813777 + 31 +0.0 + 0 +LINE + 5 +1064 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531034.8668555523 + 20 +189808.1214573949 + 30 +0.0 + 11 +531306.4089261723 + 21 +190111.7274489819 + 31 +0.0 + 0 +LINE + 5 +1065 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531313.8950552069 + 20 +190100.7158702 + 30 +0.0 + 11 +531145.5943331574 + 21 +190270.1580097362 + 31 +0.0 + 0 +LINE + 5 +1066 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531497.3699611719 + 20 +190152.1236482572 + 30 +0.0 + 11 +531296.0072010822 + 21 +190103.5446327226 + 31 +0.0 + 0 +LINE + 5 +1067 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531476.0315914901 + 20 +190067.5857371085 + 30 +0.0 + 11 +531436.7348178098 + 21 +190143.3952572212 + 31 +0.0 + 0 +LINE + 5 +1068 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530928.7867488221 + 20 +189884.8131776398 + 30 +0.0 + 11 +530992.320475658 + 21 +189948.7315361369 + 31 +0.0 + 0 +LINE + 5 +1069 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530808.066177742 + 20 +189943.2696648143 + 30 +0.0 + 11 +531148.6955089044 + 21 +190270.255609867 + 31 +0.0 + 0 +LINE + 5 +106A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531367.9748330986 + 20 +189915.001320673 + 30 +0.0 + 11 +531084.4178561316 + 21 +190230.3276074982 + 31 +0.0 + 0 +LINE + 5 +106B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531581.3258303478 + 20 +190436.6834793387 + 30 +0.0 + 11 +531080.8863389146 + 21 +190224.3124880759 + 31 +0.0 + 0 +LINE + 5 +106C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531580.9503335561 + 20 +190340.6131659256 + 30 +0.0 + 11 +531488.5618751509 + 21 +190413.0969605477 + 31 +0.0 + 0 +LINE + 5 +106D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531524.0056442154 + 20 +190315.868227209 + 30 +0.0 + 11 +531519.7068285743 + 21 +190425.6276052329 + 31 +0.0 + 0 +LINE + 5 +106E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531355.1726899743 + 20 +190228.6976334198 + 30 +0.0 + 11 +531525.6280817838 + 21 +190337.105155134 + 31 +0.0 + 0 +LINE + 5 +106F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531547.8417943295 + 20 +190069.8351397915 + 30 +0.0 + 11 +531351.9926151177 + 21 +190341.7414312368 + 31 +0.0 + 0 +LINE + 5 +1070 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531474.9241055158 + 20 +190011.1869115315 + 30 +0.0 + 11 +531564.7840285096 + 21 +190092.8732614688 + 31 +0.0 + 0 +LINE + 5 +1071 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531617.2260846627 + 20 +190005.2728544797 + 30 +0.0 + 11 +531501.9071692126 + 21 +189969.3663271401 + 31 +0.0 + 0 +LINE + 5 +1072 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531508.6342192977 + 20 +189969.0178824923 + 30 +0.0 + 11 +531474.6847081646 + 21 +190013.3467848832 + 31 +0.0 + 0 +LINE + 5 +1073 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531746.2476896815 + 20 +189728.5988211656 + 30 +0.0 + 11 +531453.5300653147 + 21 +190209.0506510619 + 31 +0.0 + 0 +LINE + 5 +1074 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531440.8930514517 + 20 +190212.4174961294 + 30 +0.0 + 11 +531461.7297555117 + 21 +190224.8909213187 + 31 +0.0 + 0 +LINE + 5 +1075 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531255.9901226361 + 20 +190256.7368100196 + 30 +0.0 + 11 +531236.5152538514 + 21 +190297.6619448278 + 31 +0.0 + 0 +LINE + 5 +1076 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531253.9671818987 + 20 +190241.3344272003 + 30 +0.0 + 11 +531255.1991211752 + 21 +190265.3683357099 + 31 +0.0 + 0 +LINE + 5 +1077 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531201.7348821424 + 20 +190204.1826203831 + 30 +0.0 + 11 +531259.0532499064 + 21 +190247.5008277345 + 31 +0.0 + 0 +LINE + 5 +1078 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531449.3497836877 + 20 +190136.151715123 + 30 +0.0 + 11 +531736.5174682032 + 21 +190344.9304718819 + 31 +0.0 + 0 +LINE + 5 +1079 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531803.2745210516 + 20 +190026.9244423737 + 30 +0.0 + 11 +531797.309994369 + 21 +190230.8633370709 + 31 +0.0 + 0 +LINE + 5 +107A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531827.2245172675 + 20 +190222.350860722 + 30 +0.0 + 11 +531492.3658312936 + 21 +190139.2789631173 + 31 +0.0 + 0 +LINE + 5 +107B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531559.4466285263 + 20 +190029.6520512927 + 30 +0.0 + 11 +531589.6207758007 + 21 +190048.4007730151 + 31 +0.0 + 0 +LINE + 5 +107C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531605.2898829422 + 20 +190233.9244870974 + 30 +0.0 + 11 +531563.2543504202 + 21 +190317.2602789646 + 31 +0.0 + 0 +LINE + 5 +107D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531582.6712865889 + 20 +190287.9597893974 + 30 +0.0 + 11 +531510.2612374601 + 21 +190329.3042814985 + 31 +0.0 + 0 +LINE + 5 +107E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531572.753809075 + 20 +190279.3624263534 + 30 +0.0 + 11 +531571.8133977135 + 21 +190359.5076897454 + 31 +0.0 + 0 +LINE + 5 +107F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531677.3906608113 + 20 +190404.6452770142 + 30 +0.0 + 11 +531564.11525354 + 21 +190349.5023658073 + 31 +0.0 + 0 +LINE + 5 +1080 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531879.5088061571 + 20 +189844.6153308284 + 30 +0.0 + 11 +531788.7603984353 + 21 +190098.4141547363 + 31 +0.0 + 0 +LINE + 5 +1081 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531286.5767746124 + 20 +189997.9950281009 + 30 +0.0 + 11 +531317.2146401164 + 21 +190033.652161122 + 31 +0.0 + 0 +LINE + 5 +1082 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531357.0204719137 + 20 +189983.7740461333 + 30 +0.0 + 11 +531315.3486359122 + 21 +190034.0160179524 + 31 +0.0 + 0 +LINE + 5 +1083 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531339.4154425268 + 20 +189937.4531168776 + 30 +0.0 + 11 +531426.721170738 + 21 +189994.5552434192 + 31 +0.0 + 0 +LINE + 5 +1084 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531491.9298855079 + 20 +189858.3179334316 + 30 +0.0 + 11 +531357.7897810734 + 21 +190125.0859294983 + 31 +0.0 + 0 +LINE + 5 +1085 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531262.0638475986 + 20 +190148.4590845882 + 30 +0.0 + 11 +531313.7937707388 + 21 +190193.8857155916 + 31 +0.0 + 0 +LINE + 5 +1086 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531334.0604031822 + 20 +190169.3253506072 + 30 +0.0 + 11 +531294.5360511213 + 21 +190214.6066662988 + 31 +0.0 + 0 +LINE + 5 +1087 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531325.4643597094 + 20 +190168.9101447634 + 30 +0.0 + 11 +531379.7237300438 + 21 +190215.2177753232 + 31 +0.0 + 0 +LINE + 5 +1088 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531379.7130712649 + 20 +190211.5003537553 + 30 +0.0 + 11 +531343.8711037515 + 21 +190254.7084914091 + 31 +0.0 + 0 +LINE + 5 +1089 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531292.2300249293 + 20 +190205.8704149363 + 30 +0.0 + 11 +531350.6165499698 + 21 +190256.8321799389 + 31 +0.0 + 0 +LINE + 5 +108A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531738.3557628839 + 20 +189874.7143102527 + 30 +0.0 + 11 +531680.1862810891 + 21 +189971.2590249253 + 31 +0.0 + 0 +LINE + 5 +108B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531118.8134760765 + 20 +189898.157348651 + 30 +0.0 + 11 +530923.3711423917 + 21 +190076.5278730174 + 31 +0.0 + 0 +LINE + 5 +108C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531549.0232186045 + 20 +190408.9283136724 + 30 +0.0 + 11 +531815.5912827789 + 21 +190918.3242959899 + 31 +0.0 + 0 +LINE + 5 +108D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531725.3179468167 + 20 +190263.1451353913 + 30 +0.0 + 11 +531858.3226310664 + 21 +190368.7038944124 + 31 +0.0 + 0 +LINE + 5 +108E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532023.1126640984 + 20 +189917.6702009027 + 30 +0.0 + 11 +531560.0017468874 + 21 +190514.6625615866 + 31 +0.0 + 0 +LINE + 5 +108F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531752.6335439978 + 20 +190378.0479479378 + 30 +0.0 + 11 +532027.0884013829 + 21 +190720.947159359 + 31 +0.0 + 0 +LINE + 5 +1090 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531706.8490401603 + 20 +190430.3299356158 + 30 +0.0 + 11 +531839.8883803324 + 21 +190289.2269516705 + 31 +0.0 + 0 +LINE + 5 +1091 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531760.4259942967 + 20 +190479.3392020101 + 30 +0.0 + 11 +531804.1551633149 + 21 +190432.1862012669 + 31 +0.0 + 0 +LINE + 5 +1092 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531709.2673430877 + 20 +190460.8985557431 + 30 +0.0 + 11 +531776.1512396244 + 21 +190477.1404739515 + 31 +0.0 + 0 +LINE + 5 +1093 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531759.5661330731 + 20 +190465.1822965296 + 30 +0.0 + 11 +531999.1325695614 + 21 +190789.5355303038 + 31 +0.0 + 0 +LINE + 5 +1094 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531666.8870233325 + 20 +190650.3047366494 + 30 +0.0 + 11 +532009.9057406248 + 21 +190430.6462430029 + 31 +0.0 + 0 +LINE + 5 +1095 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532000.2286936998 + 20 +190421.5001095026 + 30 +0.0 + 11 +532140.6677263311 + 21 +190614.6649349926 + 31 +0.0 + 0 +LINE + 5 +1096 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532080.2335795344 + 20 +190248.5694326226 + 30 +0.0 + 11 +532000.1690734311 + 21 +190439.6101527941 + 31 +0.0 + 0 +LINE + 5 +1097 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531993.374854094 + 20 +190256.1553575474 + 30 +0.0 + 11 +532061.948672143 + 21 +190307.0370953283 + 31 +0.0 + 0 +LINE + 5 +1098 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531754.1490246187 + 20 +190815.97404762 + 30 +0.0 + 11 +531827.379987234 + 21 +190763.4448451408 + 31 +0.0 + 0 +LINE + 5 +1099 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531825.5130731995 + 20 +190338.500300852 + 30 +0.0 + 11 +532091.5924045128 + 21 +190668.7078352868 + 31 +0.0 + 0 +LINE + 5 +109A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532343.8663683539 + 20 +190262.8020174649 + 30 +0.0 + 11 +532103.326302272 + 21 +190636.37358738 + 31 +0.0 + 0 +LINE + 5 +109B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532473.8057340179 + 20 +190090.674340814 + 30 +0.0 + 11 +532186.8019124103 + 21 +190502.1917741612 + 31 +0.0 + 0 +LINE + 5 +109C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532279.6383763485 + 20 +190196.11274643 + 30 +0.0 + 11 +532336.463625641 + 21 +190298.8766446244 + 31 +0.0 + 0 +LINE + 5 +109D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532246.1302706473 + 20 +190248.3833546964 + 30 +0.0 + 11 +532353.799973734 + 21 +190270.1281452764 + 31 +0.0 + 0 +LINE + 5 +109E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532133.1547478067 + 20 +190401.1570765797 + 30 +0.0 + 11 +532267.3541937391 + 21 +190250.1678714276 + 31 +0.0 + 0 +LINE + 5 +109F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532031.7148287482 + 20 +190209.3461047226 + 30 +0.0 + 11 +532244.2452321987 + 21 +190422.3211352275 + 31 +0.0 + 0 +LINE + 5 +10A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532047.5686717147 + 20 +190119.5293704757 + 30 +0.0 + 11 +531987.5720785385 + 21 +190225.1128650848 + 31 +0.0 + 0 +LINE + 5 +10A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531910.4851815169 + 20 +190158.168030588 + 30 +0.0 + 11 +532008.9166929821 + 21 +190088.1753987119 + 31 +0.0 + 0 +LINE + 5 +10A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532002.4149168784 + 20 +190089.9365131366 + 30 +0.0 + 11 +532048.4679687842 + 21 +190121.5076598298 + 31 +0.0 + 0 +LINE + 5 +10A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531701.8104183642 + 20 +189935.3453690496 + 30 +0.0 + 11 +531701.8198704416 + 21 +189935.3534495803 + 31 +0.0 + 0 +LINE + 5 +10A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531813.0607339144 + 20 +190030.4526695709 + 30 +0.0 + 11 +532129.4420644395 + 21 +190300.9253790891 + 31 +0.0 + 0 +LINE + 5 +10A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532130.7508814489 + 20 +190313.9375565826 + 30 +0.0 + 11 +532146.3871067527 + 21 +190295.356301773 + 31 +0.0 + 0 +LINE + 5 +10A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532145.0206820415 + 20 +190503.5415319083 + 30 +0.0 + 11 +532182.3169910715 + 21 +190529.2926970463 + 31 +0.0 + 0 +LINE + 5 +10A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532129.4927986443 + 20 +190503.0827041237 + 30 +0.0 + 11 +532153.4156540405 + 21 +190505.6986976858 + 31 +0.0 + 0 +LINE + 5 +10A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532084.48793898 + 20 +190548.722954936 + 30 +0.0 + 11 +532136.3912738704 + 21 +190499.0449296283 + 31 +0.0 + 0 +LINE + 5 +10A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532056.8092401119 + 20 +190293.4285500489 + 30 +0.0 + 11 +532297.8757637227 + 21 +190037.9355843721 + 31 +0.0 + 0 +LINE + 5 +10AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532207.5227721233 + 20 +189994.9465784494 + 30 +0.0 + 11 +532066.7553249823 + 21 +190251.4614745323 + 31 +0.0 + 0 +LINE + 5 +10AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531969.2268888711 + 20 +190167.7590414535 + 30 +0.0 + 11 +531992.5469677952 + 21 +190140.9603913208 + 31 +0.0 + 0 +LINE + 5 +10AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532178.1955524762 + 20 +190155.0732369392 + 30 +0.0 + 11 +532253.7626618632 + 21 +190209.85874761 + 31 +0.0 + 0 +LINE + 5 +10AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532227.9330378915 + 20 +190186.0183066627 + 30 +0.0 + 11 +532257.2029016576 + 21 +190264.0942781078 + 31 +0.0 + 0 +LINE + 5 +10AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532217.8643400956 + 20 +190194.4380653439 + 30 +0.0 + 11 +532296.8342970701 + 21 +190208.1454908176 + 31 +0.0 + 0 +LINE + 5 +10AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532391.6274120264 + 20 +190070.4273729366 + 30 +0.0 + 11 +532285.7295209613 + 21 +190214.1498124604 + 31 +0.0 + 0 +LINE + 5 +10B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531894.4661772635 + 20 +190432.0901979454 + 30 +0.0 + 11 +531934.5522845409 + 21 +190407.5297838349 + 31 +0.0 + 0 +LINE + 5 +10B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531891.6592800405 + 20 +190360.280225479 + 30 +0.0 + 11 +531934.6139546222 + 21 +190409.4299312725 + 31 +0.0 + 0 +LINE + 5 +10B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531843.1238733045 + 20 +190370.2742156616 + 30 +0.0 + 11 +531913.4162201869 + 21 +190293.1903068104 + 31 +0.0 + 0 +LINE + 5 +10B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531789.3193321156 + 20 +190207.0930159958 + 30 +0.0 + 11 +532031.2859184319 + 21 +190382.0527326439 + 31 +0.0 + 0 +LINE + 5 +10B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532039.096682347 + 20 +190480.2807871166 + 30 +0.0 + 11 +532092.1903968702 + 21 +190436.4558942987 + 31 +0.0 + 0 +LINE + 5 +10B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532071.1757363024 + 20 +190412.5324338467 + 30 +0.0 + 11 +532109.5756333829 + 21 +190458.7711606978 + 31 +0.0 + 0 +LINE + 5 +10B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532069.3952158915 + 20 +190420.9522976431 + 30 +0.0 + 11 +532123.761975346 + 21 +190374.7707928645 + 31 +0.0 + 0 +LINE + 5 +10B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532120.0904140471 + 20 +190374.1885778235 + 30 +0.0 + 11 +532157.0308076825 + 21 +190416.4614664497 + 31 +0.0 + 0 +LINE + 5 +10B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532100.5834589982 + 20 +190459.6547015916 + 30 +0.0 + 11 +532160.2028778269 + 21 +190410.1409388884 + 31 +0.0 + 0 +LINE + 5 +10B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531769.1561834484 + 20 +190581.7882006832 + 30 +0.0 + 11 +531914.0816828643 + 21 +190803.171012523 + 31 +0.0 + 0 +LINE + 5 +10BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531719.4153004631 + 20 +189040.0434887144 + 30 +0.0 + 11 +531322.9694125037 + 21 +189229.0260951112 + 31 +0.0 + 0 +LINE + 5 +10BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531968.8214497981 + 20 +188995.9724442154 + 30 +0.0 + 11 +531365.6109342521 + 21 +189366.7655952858 + 31 +0.0 + 0 +LINE + 5 +10BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531684.4393783764 + 20 +189323.3329337703 + 30 +0.0 + 11 +531352.3449747928 + 21 +188808.9261875 + 31 +0.0 + 0 +LINE + 5 +10BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531476.1160381618 + 20 +188976.8223097931 + 30 +0.0 + 11 +531268.1767972716 + 21 +189094.2831279027 + 31 +0.0 + 0 +LINE + 5 +10BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531647.4109409196 + 20 +188919.6673788751 + 30 +0.0 + 11 +531416.1677844149 + 21 +188743.6164943205 + 31 +0.0 + 0 +LINE + 5 +10BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531466.3846967644 + 20 +189459.5185089535 + 30 +0.0 + 11 +531268.9033481682 + 21 +189091.2666828764 + 31 +0.0 + 0 +LINE + 5 +10C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531669.5210069521 + 20 +188973.8165935606 + 30 +0.0 + 11 +531290.3979437241 + 21 +189163.819039014 + 31 +0.0 + 0 +LINE + 5 +10C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531194.0533733342 + 20 +188433.5445984078 + 30 +0.0 + 11 +531295.2640665268 + 21 +189168.8164507826 + 31 +0.0 + 0 +LINE + 5 +10C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531499.0396327037 + 20 +188680.1597014088 + 30 +0.0 + 11 +531241.3553360876 + 21 +188965.0451001069 + 31 +0.0 + 0 +LINE + 5 +10C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531310.3338233292 + 20 +188991.3747021521 + 30 +0.0 + 11 +531265.7140145608 + 21 +188999.3251636938 + 31 +0.0 + 0 +LINE + 5 +10C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531324.6517658388 + 20 +188997.4014930081 + 30 +0.0 + 11 +531301.800692387 + 21 +188989.8533227177 + 31 +0.0 + 0 +LINE + 5 +10C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531346.6567294156 + 20 +189057.6032493413 + 30 +0.0 + 11 +531320.0511396683 + 21 +188990.8649172865 + 31 +0.0 + 0 +LINE + 5 +10C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531567.9455156609 + 20 +189030.3499374114 + 30 +0.0 + 11 +531541.6673532669 + 21 +188991.3682991808 + 31 +0.0 + 0 +LINE + 5 +10C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531600.301193957 + 20 +188966.180934773 + 30 +0.0 + 11 +531540.8226630274 + 21 +188993.0714908561 + 31 +0.0 + 0 +LINE + 5 +10C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531886.7588520884 + 20 +189321.9919267621 + 30 +0.0 + 11 +531608.349415042 + 21 +188896.1120560258 + 31 +0.0 + 0 +LINE + 5 +10C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531756.9861162266 + 20 +188869.2808768581 + 30 +0.0 + 11 +531407.9373381911 + 21 +188939.3426849193 + 31 +0.0 + 0 +LINE + 5 +10CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531294.8779524876 + 20 +189527.3186458787 + 30 +0.0 + 11 +531058.9344860326 + 21 +189579.1778047209 + 31 +0.0 + 0 +LINE + 5 +10CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531203.525372206 + 20 +189082.6444684779 + 30 +0.0 + 11 +531314.0853586686 + 21 +189591.3148192839 + 31 +0.0 + 0 +LINE + 5 +10CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531096.1896724 + 20 +189100.4302733887 + 30 +0.0 + 11 +531269.7773097273 + 21 +189835.7798042393 + 31 +0.0 + 0 +LINE + 5 +10CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531151.2142742812 + 20 +189631.5412952697 + 30 +0.0 + 11 +530754.7683863218 + 21 +189820.5239016666 + 31 +0.0 + 0 +LINE + 5 +10CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531171.1721781701 + 20 +189698.109373953 + 30 +0.0 + 11 +531108.6900636548 + 21 +189514.5187873819 + 31 +0.0 + 0 +LINE + 5 +10CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531102.0876062626 + 20 +189720.4637947992 + 30 +0.0 + 11 +531081.8710946612 + 21 +189659.4151391157 + 31 +0.0 + 0 +LINE + 5 +10D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531156.2856576337 + 20 +189724.9175859754 + 30 +0.0 + 11 +531088.6930151012 + 21 +189711.9372085358 + 31 +0.0 + 0 +LINE + 5 +10D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531108.7451913958 + 20 +189707.9404608063 + 30 +0.0 + 11 +530756.1735946894 + 21 +189903.6197058668 + 31 +0.0 + 0 +LINE + 5 +10D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531056.6520987661 + 20 +189822.3268650833 + 30 +0.0 + 11 +530895.3149307944 + 21 +189572.6253398407 + 31 +0.0 + 0 +LINE + 5 +10D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530907.9150119798 + 20 +189568.3201163484 + 30 +0.0 + 11 +530699.9757710894 + 21 +189685.7809344579 + 31 +0.0 + 0 +LINE + 5 +10D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530906.8933548907 + 20 +189377.7820440888 + 30 +0.0 + 11 +530900.4533912059 + 21 +189584.8216750027 + 31 +0.0 + 0 +LINE + 5 +10D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530982.7706124859 + 20 +189420.7311560924 + 30 +0.0 + 11 +530899.2645509212 + 21 +189438.5653211523 + 31 +0.0 + 0 +LINE + 5 +10D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530863.1775169132 + 20 +189980.745130767 + 30 +0.0 + 11 +530700.7023219861 + 21 +189682.7644894318 + 31 +0.0 + 0 +LINE + 5 +10D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531101.31998077 + 20 +189565.3144001159 + 30 +0.0 + 11 +530722.196917542 + 21 +189755.3168455691 + 31 +0.0 + 0 +LINE + 5 +10D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530654.6957032442 + 20 +189221.5155091609 + 30 +0.0 + 11 +530727.0630403447 + 21 +189760.3142573377 + 31 +0.0 + 0 +LINE + 5 +10D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530747.2416806323 + 20 +189247.3009350145 + 30 +0.0 + 11 +530652.8930014143 + 21 +189317.2141273253 + 31 +0.0 + 0 +LINE + 5 +10DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530756.0350379258 + 20 +189308.7638222205 + 30 +0.0 + 11 +530649.051045308 + 21 +189283.8634968476 + 31 +0.0 + 0 +LINE + 5 +10DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530795.4192782982 + 20 +189494.645936663 + 30 +0.0 + 11 +530735.984569425 + 21 +189301.57924678 + 31 +0.0 + 0 +LINE + 5 +10DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530999.6047073716 + 20 +189350.8857676001 + 30 +0.0 + 11 +530685.5640125669 + 21 +189467.7975904928 + 31 +0.0 + 0 +LINE + 5 +10DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531036.8657076219 + 20 +189436.7241149764 + 30 +0.0 + 11 +530981.8713730649 + 21 +189328.4509017923 + 31 +0.0 + 0 +LINE + 5 +10DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531086.4521717799 + 20 +189415.375078614 + 30 +0.0 + 11 +531034.7194828299 + 21 +189436.3834052333 + 31 +0.0 + 0 +LINE + 5 +10DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531381.1803599318 + 20 +189249.8553472654 + 30 +0.0 + 11 +530840.3943797157 + 21 +189404.9942916577 + 31 +0.0 + 0 +LINE + 5 +10E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530833.8034017388 + 20 +189416.2898117606 + 30 +0.0 + 11 +530827.288728647 + 21 +189392.8950771704 + 31 +0.0 + 0 +LINE + 5 +10E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530742.1327971468 + 20 +189582.8725087071 + 30 +0.0 + 11 +530697.5129883786 + 21 +189590.8229702489 + 31 +0.0 + 0 +LINE + 5 +10E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530756.4507396567 + 20 +189588.8992995633 + 30 +0.0 + 11 +530733.5996662051 + 21 +189581.3511292729 + 31 +0.0 + 0 +LINE + 5 +10E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530778.4557032334 + 20 +189649.1010558965 + 30 +0.0 + 11 +530751.8501134863 + 21 +189582.3627238419 + 31 +0.0 + 0 +LINE + 5 +10E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530909.5881846175 + 20 +189428.3169625748 + 30 +0.0 + 11 +530784.2463905739 + 21 +189096.1373681236 + 31 +0.0 + 0 +LINE + 5 +10E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531108.5813818942 + 20 +189115.914939105 + 30 +0.0 + 11 +530910.3346308408 + 21 +189067.6979914053 + 31 +0.0 + 0 +LINE + 5 +10E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530926.4599834396 + 20 +189041.102617044 + 30 +0.0 + 11 +530917.9558640805 + 21 +189386.0068931815 + 31 +0.0 + 0 +LINE + 5 +10E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531041.426258261 + 20 +189350.3283994556 + 30 +0.0 + 11 +531031.3309967528 + 21 +189316.2684607437 + 31 +0.0 + 0 +LINE + 5 +10E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530856.5678735057 + 20 +189252.0623850323 + 30 +0.0 + 11 +530765.0790922604 + 21 +189270.5459752372 + 31 +0.0 + 0 +LINE + 5 +10E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530798.4733508944 + 20 +189259.5751234313 + 30 +0.0 + 11 +530739.440772385 + 21 +189318.4626171501 + 31 +0.0 + 0 +LINE + 5 +10EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530804.1397268244 + 20 +189271.4141772521 + 30 +0.0 + 11 +530726.6028294479 + 21 +189251.1120304952 + 31 +0.0 + 0 +LINE + 5 +10EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530711.0135881931 + 20 +189137.3537963988 + 30 +0.0 + 11 +530734.2142790415 + 21 +189261.1834636557 + 31 +0.0 + 0 +LINE + 5 +10EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531304.5651187085 + 20 +189090.643348688 + 30 +0.0 + 11 +531035.799416155 + 21 +189110.9931312904 + 31 +0.0 + 0 +LINE + 5 +10ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530999.7444894787 + 20 +189621.8477439666 + 30 +0.0 + 11 +530973.4663270845 + 21 +189582.8661057361 + 31 +0.0 + 0 +LINE + 5 +10EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531032.1001677749 + 20 +189557.6787413281 + 30 +0.0 + 11 +530972.6216368453 + 21 +189584.5692974113 + 31 +0.0 + 0 +LINE + 5 +10EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531072.1108657749 + 20 +189586.9141580743 + 30 +0.0 + 11 +531040.1483888599 + 21 +189487.6098625809 + 31 +0.0 + 0 +LINE + 5 +10F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531188.7850900446 + 20 +189460.7786834135 + 30 +0.0 + 11 +530896.0297265131 + 21 +189519.5411584004 + 31 +0.0 + 0 +LINE + 5 +10F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530848.1576575035 + 20 +189605.6691081451 + 30 +0.0 + 11 +530818.0399273344 + 21 +189543.7620319594 + 31 +0.0 + 0 +LINE + 5 +10F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530847.0879069723 + 20 +189530.7173856346 + 30 +0.0 + 11 +530792.9614754305 + 21 +189556.8497671789 + 31 +0.0 + 0 +LINE + 5 +10F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530845.2135190155 + 20 +189539.1168516337 + 30 +0.0 + 11 +530814.9155711146 + 21 +189474.5373636352 + 31 +0.0 + 0 +LINE + 5 +10F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530818.4976435953 + 20 +189475.531392542 + 30 +0.0 + 11 +530767.3449581734 + 21 +189498.6612989157 + 31 +0.0 + 0 +LINE + 5 +10F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530800.7760247072 + 20 +189561.3854770761 + 30 +0.0 + 11 +530767.0820439746 + 21 +189491.5943353683 + 31 +0.0 + 0 +LINE + 5 +10F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531238.1855210372 + 20 +189218.7990321386 + 30 +0.0 + 11 +531129.6891580291 + 21 +189249.3458774341 + 31 +0.0 + 0 +LINE + 5 +10F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530672.9130626553 + 20 +189260.0114279406 + 30 +0.0 + 11 +530252.2199106406 + 21 +188868.1440122411 + 31 +0.0 + 0 +LINE + 5 +10F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530684.471856032 + 20 +189192.2221138704 + 30 +0.0 + 11 +530519.5811621016 + 21 +189035.7594543587 + 31 +0.0 + 0 +LINE + 5 +10F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530860.1522721009 + 20 +189128.5806677993 + 30 +0.0 + 11 +530793.5540958264 + 21 +188972.3834189265 + 31 +0.0 + 0 +LINE + 5 +10FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531272.1169317574 + 20 +188932.8263748838 + 30 +0.0 + 11 +530573.8535816081 + 21 +189221.4435853778 + 31 +0.0 + 0 +LINE + 5 +10FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530756.5744089849 + 20 +189071.8318840867 + 30 +0.0 + 11 +530499.3980613915 + 21 +188619.3786656358 + 31 +0.0 + 0 +LINE + 5 +10FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530694.0402449708 + 20 +189102.1486345439 + 30 +0.0 + 11 +530865.3193356496 + 21 +189011.1926495405 + 31 +0.0 + 0 +LINE + 5 +10FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530660.9563868377 + 20 +189037.5122938518 + 30 +0.0 + 11 +530718.0005073976 + 21 +189007.8203082046 + 31 +0.0 + 0 +LINE + 5 +10FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530665.2013767399 + 20 +189091.7270989238 + 30 +0.0 + 11 +530667.2381379603 + 21 +189022.9295181036 + 31 +0.0 + 0 +LINE + 5 +10FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530674.3810425642 + 20 +189042.0878760805 + 30 +0.0 + 11 +530437.7811339434 + 21 +188827.1015365688 + 31 +0.0 + 0 +LINE + 5 +1100 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530906.5493413559 + 20 +188952.519278251 + 30 +0.0 + 11 +530631.0793766138 + 21 +188635.0148490799 + 31 +0.0 + 0 +LINE + 5 +1101 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531083.9260207276 + 20 +188855.8237667776 + 30 +0.0 + 11 +530966.2296031682 + 21 +188885.7406319248 + 31 +0.0 + 0 +LINE + 5 +1102 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531010.3881229036 + 20 +188977.7951032612 + 30 +0.0 + 11 +531103.9336384209 + 21 +188901.3950542242 + 31 +0.0 + 0 +LINE + 5 +1103 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531100.5147283493 + 20 +188907.198989996 + 30 +0.0 + 11 +531082.2562417648 + 21 +188854.4330107956 + 31 +0.0 + 0 +LINE + 5 +1104 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531170.0449162952 + 20 +189237.9965705819 + 30 +0.0 + 11 +531170.0396251662 + 21 +189237.9853171069 + 31 +0.0 + 0 +LINE + 5 +1105 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531107.7686870358 + 20 +189105.5439277551 + 30 +0.0 + 11 +530790.0936627911 + 21 +188558.1746075611 + 31 +0.0 + 0 +LINE + 5 +1106 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530770.2701002741 + 20 +188834.3343962393 + 30 +0.0 + 11 +531228.8502984493 + 21 +188636.032638733 + 31 +0.0 + 0 +LINE + 5 +1107 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531455.2532802372 + 20 +188641.247114639 + 30 +0.0 + 11 +530938.8815154797 + 21 +188837.4798149403 + 31 +0.0 + 0 +LINE + 5 +1108 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531016.6839955069 + 20 +188918.6094828753 + 30 +0.0 + 11 +531048.6985048241 + 21 +188903.2125700951 + 31 +0.0 + 0 +LINE + 5 +1109 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530596.0115345955 + 20 +188896.9408068378 + 30 +0.0 + 11 +530776.2852085942 + 21 +188888.5968132422 + 31 +0.0 + 0 +LINE + 5 +110A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530810.499412421 + 20 +188942.4644181304 + 30 +0.0 + 11 +530774.4691225146 + 21 +188888.034501198 + 31 +0.0 + 0 +LINE + 5 +110B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530931.1429369639 + 20 +189081.6941781546 + 30 +0.0 + 11 +530848.8341201208 + 21 +188861.8370460586 + 31 +0.0 + 0 +LINE + 5 +110C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531203.0140174917 + 20 +188919.6828447229 + 30 +0.0 + 11 +531154.1005040535 + 21 +189123.1156930919 + 31 +0.0 + 0 +LINE + 5 +110D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530792.987268706 + 20 +188939.2580701113 + 30 +0.0 + 11 +530893.48422323 + 21 +188879.0039768547 + 31 +0.0 + 0 +LINE + 5 +110E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531682.2218760266 + 20 +189319.8980726093 + 30 +0.0 + 11 +531672.7338951584 + 21 +189517.8227310418 + 31 +0.0 + 0 +LINE + 5 +110F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528393.7599560187 + 20 +187524.6938483252 + 30 +0.0 + 11 +530003.6132568962 + 21 +189942.2237126069 + 31 +0.0 + 0 +LINE + 5 +1110 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528674.734682812 + 20 +188311.2132533978 + 30 +0.0 + 11 +528559.3309317352 + 21 +188037.4355296202 + 31 +0.0 + 0 +LINE + 5 +1111 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529022.3447486716 + 20 +187884.9339930147 + 30 +0.0 + 11 +528621.9671427173 + 21 +188233.4860521839 + 31 +0.0 + 0 +LINE + 5 +1112 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528790.496679948 + 20 +187830.6395476078 + 30 +0.0 + 11 +528886.1965418544 + 21 +188042.1536712512 + 31 +0.0 + 0 +LINE + 5 +1113 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529017.9036586692 + 20 +188125.0850155283 + 30 +0.0 + 11 +528771.9057892071 + 21 +188328.2578044422 + 31 +0.0 + 0 +LINE + 5 +1114 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529180.9709087853 + 20 +188540.5938421276 + 30 +0.0 + 11 +529006.0636934473 + 21 +188684.6353220643 + 31 +0.0 + 0 +LINE + 5 +1115 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528854.9383508704 + 20 +187993.2720995656 + 30 +0.0 + 11 +529032.4021209982 + 21 +188160.2722698406 + 31 +0.0 + 0 +LINE + 5 +1116 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528690.2652093164 + 20 +188107.9072833756 + 30 +0.0 + 11 +528862.7144473831 + 21 +188341.1823277175 + 31 +0.0 + 0 +LINE + 5 +1117 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529891.4941110528 + 20 +189786.6610053253 + 30 +0.0 + 11 +532033.4775431653 + 21 +192553.6794256942 + 31 +0.0 + 0 +LINE + 5 +1118 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530424.1573235889 + 20 +189057.2601955194 + 30 +0.0 + 11 +530615.1814091358 + 21 +188886.4997984614 + 31 +0.0 + 0 +LINE + 5 +1119 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529791.779404945 + 20 +189319.6821134301 + 30 +0.0 + 11 +530003.6689285722 + 21 +189704.3723750401 + 31 +0.0 + 0 +LINE + 5 +111A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529597.6850152232 + 20 +189461.4597606462 + 30 +0.0 + 11 +529894.5596331585 + 21 +189249.4055132699 + 31 +0.0 + 0 +LINE + 5 +111B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529779.842494701 + 20 +189420.5689342099 + 30 +0.0 + 11 +529831.8626403138 + 21 +189382.7595418249 + 31 +0.0 + 0 +LINE + 5 +111C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529655.0159155208 + 20 +189570.2254684934 + 30 +0.0 + 11 +530034.0293144771 + 21 +189421.025811471 + 31 +0.0 + 0 +LINE + 5 +111D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530026.3030274082 + 20 +189410.1813897105 + 30 +0.0 + 11 +530126.7485781536 + 21 +189626.8527145978 + 31 +0.0 + 0 +LINE + 5 +111E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530138.2307661828 + 20 +189255.9802805821 + 30 +0.0 + 11 +530022.7433686064 + 21 +189427.9382489995 + 31 +0.0 + 0 +LINE + 5 +111F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530051.5441219289 + 20 +189246.6309410291 + 30 +0.0 + 11 +530108.9874280879 + 21 +189309.8099433867 + 31 +0.0 + 0 +LINE + 5 +1120 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529675.5633810097 + 20 +189679.5496308565 + 30 +0.0 + 11 +529757.5681154661 + 21 +189642.1689603781 + 31 +0.0 + 0 +LINE + 5 +1121 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529702.9854214259 + 20 +189829.8454059539 + 30 +0.0 + 11 +530127.917123712 + 21 +189623.9784637252 + 31 +0.0 + 0 +LINE + 5 +1122 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529870.9296487201 + 20 +189294.9701512054 + 30 +0.0 + 11 +530068.1511336619 + 21 +189670.3884675232 + 31 +0.0 + 0 +LINE + 5 +1123 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530394.1384051356 + 20 +189320.9117378102 + 30 +0.0 + 11 +530061.2839424964 + 21 +189671.6111535061 + 31 +0.0 + 0 +LINE + 5 +1124 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530582.040160884 + 20 +189150.9830491771 + 30 +0.0 + 11 +530193.7565299102 + 21 +189525.4204246993 + 31 +0.0 + 0 +LINE + 5 +1125 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530344.0149637483 + 20 +189243.063587853 + 30 +0.0 + 11 +530379.9011146352 + 21 +189354.8746423326 + 31 +0.0 + 0 +LINE + 5 +1126 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530301.0336818742 + 20 +189287.8700499391 + 30 +0.0 + 11 +530402.4682670551 + 21 +189330.0200891955 + 31 +0.0 + 0 +LINE + 5 +1127 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530160.6542056199 + 20 +189415.9203584347 + 30 +0.0 + 11 +530321.5122062477 + 21 +189293.7240614566 + 31 +0.0 + 0 +LINE + 5 +1128 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529972.8374165564 + 20 +189026.1966783911 + 30 +0.0 + 11 +530265.5573080922 + 21 +189458.1619515941 + 31 +0.0 + 0 +LINE + 5 +1129 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530175.1575922121 + 20 +189329.8815589349 + 30 +0.0 + 11 +530194.0910912162 + 21 +189314.6737587161 + 31 +0.0 + 0 +LINE + 5 +112A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530152.5025848808 + 20 +189518.6672716123 + 30 +0.0 + 11 +530184.1168749776 + 21 +189551.1430138658 + 31 +0.0 + 0 +LINE + 5 +112B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530137.3563490113 + 20 +189515.2151382539 + 30 +0.0 + 11 +530160.3221415125 + 21 +189522.4067171776 + 31 +0.0 + 0 +LINE + 5 +112C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530084.3770351425 + 20 +189551.2936940677 + 30 +0.0 + 11 +530144.9052914925 + 21 +189512.5872016605 + 31 +0.0 + 0 +LINE + 5 +112D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530106.5758562604 + 20 +189295.4645403759 + 30 +0.0 + 11 +530463.5683009287 + 21 +189048.0505566158 + 31 +0.0 + 0 +LINE + 5 +112E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530431.8429333872 + 20 +189046.5774025137 + 30 +0.0 + 11 +530515.4704058857 + 21 +189229.6641527433 + 31 +0.0 + 0 +LINE + 5 +112F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530380.3564014845 + 20 +188954.2573887482 + 30 +0.0 + 11 +530124.4476774383 + 21 +189256.2120495064 + 31 +0.0 + 0 +LINE + 5 +1130 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530252.4199769282 + 20 +189183.1866620482 + 30 +0.0 + 11 +530315.9699360793 + 21 +189251.5477832537 + 31 +0.0 + 0 +LINE + 5 +1131 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530295.2366096555 + 20 +189223.1635398347 + 30 +0.0 + 11 +530308.8600722086 + 21 +189305.4252168782 + 31 +0.0 + 0 +LINE + 5 +1132 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530283.7300963471 + 20 +189229.477901484 + 30 +0.0 + 11 +530358.560215857 + 21 +189258.1937652501 + 31 +0.0 + 0 +LINE + 5 +1133 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530478.1896499934 + 20 +189141.3998736121 + 30 +0.0 + 11 +530346.5041401216 + 21 +189261.9379565754 + 31 +0.0 + 0 +LINE + 5 +1134 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529920.4884380986 + 20 +189400.1249218689 + 30 +0.0 + 11 +529964.5664900084 + 21 +189383.7775894323 + 31 +0.0 + 0 +LINE + 5 +1135 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529931.6173131438 + 20 +189329.1270419157 + 30 +0.0 + 11 +529964.2596465282 + 21 +189385.6538118503 + 31 +0.0 + 0 +LINE + 5 +1136 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529882.0654487507 + 20 +189329.549276416 + 30 +0.0 + 11 +529965.9340981221 + 21 +189267.5090258793 + 31 +0.0 + 0 +LINE + 5 +1137 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529860.8233238849 + 20 +189159.0447172158 + 30 +0.0 + 11 +530064.4005868218 + 21 +189377.4824185364 + 31 +0.0 + 0 +LINE + 5 +1138 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530053.0738443868 + 20 +189475.3673694956 + 30 +0.0 + 11 +530113.6384535762 + 21 +189442.6337191324 + 31 +0.0 + 0 +LINE + 5 +1139 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530097.6453030549 + 20 +189415.0988856449 + 30 +0.0 + 11 +530126.3815590909 + 21 +189467.8890319381 + 31 +0.0 + 0 +LINE + 5 +113A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530094.2705849351 + 20 +189423.0156802548 + 30 +0.0 + 11 +530156.5398193389 + 21 +189388.2159911196 + 31 +0.0 + 0 +LINE + 5 +113B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530153.0500824229 + 20 +189386.934947412 + 30 +0.0 + 11 +530181.1210737556 + 21 +189435.5519119445 + 31 +0.0 + 0 +LINE + 5 +113C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530117.3882154891 + 20 +189467.0174726847 + 30 +0.0 + 11 +530185.4552303947 + 21 +189429.9638725852 + 31 +0.0 + 0 +LINE + 5 +113D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529633.0482007297 + 20 +189917.753207084 + 30 +0.0 + 11 +529865.8300288423 + 21 +190673.7845134428 + 31 +0.0 + 0 +LINE + 5 +113E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529670.7877707331 + 20 +190050.3400571805 + 30 +0.0 + 11 +529803.1800083046 + 21 +189984.5373966304 + 31 +0.0 + 0 +LINE + 5 +113F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529690.468046342 + 20 +189886.8937312946 + 30 +0.0 + 11 +529835.0780648242 + 21 +190359.728321133 + 31 +0.0 + 0 +LINE + 5 +1140 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529771.0299817181 + 20 +189990.2071443399 + 30 +0.0 + 11 +529852.6219251565 + 21 +189998.1979528455 + 31 +0.0 + 0 +LINE + 5 +1141 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529786.091352851 + 20 +189911.9225946936 + 30 +0.0 + 11 +529778.7158427058 + 21 +189999.461330864 + 31 +0.0 + 0 +LINE + 5 +1142 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529678.12740668 + 20 +189748.3520551558 + 30 +0.0 + 11 +530014.0117758446 + 21 +190142.7941897908 + 31 +0.0 + 0 +LINE + 5 +1143 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530132.8866705972 + 20 +189698.1563884737 + 30 +0.0 + 11 +530202.777203116 + 21 +189787.1120784594 + 31 +0.0 + 0 +LINE + 5 +1144 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530262.8900021763 + 20 +189732.12793098 + 30 +0.0 + 11 +529693.1011346465 + 21 +190228.3257209733 + 31 +0.0 + 0 +LINE + 5 +1145 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529908.5101230068 + 20 +190131.5293901852 + 30 +0.0 + 11 +530125.3000962972 + 21 +190582.6184565757 + 31 +0.0 + 0 +LINE + 5 +1146 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529853.4818453089 + 20 +190173.9736557676 + 30 +0.0 + 11 +530011.2903512204 + 21 +190061.2527900251 + 31 +0.0 + 0 +LINE + 5 +1147 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529896.5732127627 + 20 +190232.416210965 + 30 +0.0 + 11 +529948.5933583757 + 21 +190194.6068185801 + 31 +0.0 + 0 +LINE + 5 +1148 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529849.9447807383 + 20 +190204.4331025739 + 30 +0.0 + 11 +529912.426864935 + 21 +190233.2990804276 + 31 +0.0 + 0 +LINE + 5 +1149 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529898.4664877692 + 20 +190218.360150213 + 30 +0.0 + 11 +529958.5477179953 + 21 +190345.4488586622 + 31 +0.0 + 0 +LINE + 5 +114A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529771.7466335826 + 20 +190382.0727452485 + 30 +0.0 + 11 +530512.071249634 + 21 +190087.5854839669 + 31 +0.0 + 0 +LINE + 5 +114B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530143.0337454699 + 20 +190222.0286664657 + 30 +0.0 + 11 +530272.5447482439 + 21 +190505.4522987187 + 31 +0.0 + 0 +LINE + 5 +114C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529800.495504817 + 20 +190503.9870758497 + 30 +0.0 + 11 +529882.500239273 + 21 +190466.6064053712 + 31 +0.0 + 0 +LINE + 5 +114D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529987.6603667819 + 20 +190106.8174279606 + 30 +0.0 + 11 +530206.9770089463 + 21 +190524.2946848936 + 31 +0.0 + 0 +LINE + 5 +114E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530195.3235001076 + 20 +189991.9189582468 + 30 +0.0 + 11 +530441.7331030244 + 21 +190342.1924138142 + 31 +0.0 + 0 +LINE + 5 +114F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529944.2322428545 + 20 +189687.3531936067 + 30 +0.0 + 11 +530293.1197923231 + 21 +190128.7091115361 + 31 +0.0 + 0 +LINE + 5 +1150 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530223.3065743222 + 20 +190107.3118171309 + 30 +0.0 + 11 +530663.2321954126 + 21 +189814.3623448716 + 31 +0.0 + 0 +LINE + 5 +1151 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530243.7940378211 + 20 +189737.4826935213 + 30 +0.0 + 11 +530432.9675583755 + 21 +189813.9027659494 + 31 +0.0 + 0 +LINE + 5 +1152 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530435.3740718211 + 20 +189782.8939022669 + 30 +0.0 + 11 +530241.1783954999 + 21 +190068.0593262615 + 31 +0.0 + 0 +LINE + 5 +1153 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530369.1506949899 + 20 +189995.0339388033 + 30 +0.0 + 11 +530514.4874132149 + 21 +190153.0233038265 + 31 +0.0 + 0 +LINE + 5 +1154 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530554.2853607679 + 20 +189986.7113306505 + 30 +0.0 + 11 +530458.5247020654 + 21 +190122.4572681574 + 31 +0.0 + 0 +LINE + 5 +1155 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530099.3082621901 + 20 +189602.6786171054 + 30 +0.0 + 11 +530305.7932890129 + 21 +189775.9213665038 + 31 +0.0 + 0 +LINE + 5 +1156 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530037.2191561604 + 20 +190211.9721986242 + 30 +0.0 + 11 +530081.2972080702 + 21 +190195.6248661874 + 31 +0.0 + 0 +LINE + 5 +1157 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530048.3480312057 + 20 +190140.974318671 + 30 +0.0 + 11 +530080.9903645901 + 21 +190197.5010886054 + 31 +0.0 + 0 +LINE + 5 +1158 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529998.7961668124 + 20 +190141.3965531712 + 30 +0.0 + 11 +530082.6648161838 + 21 +190079.3563026345 + 31 +0.0 + 0 +LINE + 5 +1159 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530078.5121304261 + 20 +189745.4989626146 + 30 +0.0 + 11 +530148.8456116325 + 21 +189833.577177656 + 31 +0.0 + 0 +LINE + 5 +115A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529885.3325268359 + 20 +190334.6202251309 + 30 +0.0 + 11 +529999.4182105816 + 21 +190659.536911753 + 31 +0.0 + 0 +LINE + 5 +115B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530543.8561078087 + 20 +190046.7631956589 + 30 +0.0 + 11 +530885.6216848795 + 21 +189962.0778141541 + 31 +0.0 + 0 +LINE + 5 +115C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530217.6887113289 + 20 +189493.3847411613 + 30 +0.0 + 11 +530635.4718868977 + 21 +190165.2105370837 + 31 +0.0 + 0 +LINE + 5 +115D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530547.8292868897 + 20 +189554.7386399882 + 30 +0.0 + 11 +530729.0204895633 + 21 +189707.5601312849 + 31 +0.0 + 0 +LINE + 5 +115E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530524.7775013762 + 20 +189638.8254976219 + 30 +0.0 + 11 +530596.3074582908 + 21 +189592.1909071853 + 31 +0.0 + 0 +LINE + 5 +115F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530567.889837774 + 20 +189349.5276480384 + 30 +0.0 + 11 +530683.9924030411 + 21 +189331.9287256953 + 31 +0.0 + 0 +LINE + 5 +1160 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530605.2697539877 + 20 +189399.1033628598 + 30 +0.0 + 11 +530663.0541326525 + 21 +189305.6872696934 + 31 +0.0 + 0 +LINE + 5 +1161 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530504.9687196564 + 20 +189599.6951843686 + 30 +0.0 + 11 +530706.8746037114 + 21 +189455.3898307983 + 31 +0.0 + 0 +LINE + 5 +1162 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530415.4768326146 + 20 +189540.5554919245 + 30 +0.0 + 11 +530493.6519406615 + 21 +189633.4862080975 + 31 +0.0 + 0 +LINE + 5 +1163 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530404.1021717828 + 20 +189682.5253705288 + 30 +0.0 + 11 +530372.6508416777 + 21 +189565.9125719136 + 31 +0.0 + 0 +LINE + 5 +1164 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530372.0443083815 + 20 +189572.621277741 + 30 +0.0 + 11 +530417.6443064328 + 21 +189540.3992189759 + 31 +0.0 + 0 +LINE + 5 +1165 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530122.6772955924 + 20 +189800.8264032089 + 30 +0.0 + 11 +530122.6881558121 + 21 +189800.8203457863 + 31 +0.0 + 0 +LINE + 5 +1166 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530250.5013500226 + 20 +189729.5309445075 + 30 +0.0 + 11 +530614.0162237905 + 21 +189526.7759952493 + 31 +0.0 + 0 +LINE + 5 +1167 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530581.7610652955 + 20 +189592.2842723292 + 30 +0.0 + 11 +530425.8919601132 + 21 +189277.4914096943 + 31 +0.0 + 0 +LINE + 5 +1168 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530354.1996803542 + 20 +189347.2906557087 + 30 +0.0 + 11 +530545.8603971944 + 21 +189568.3823464327 + 31 +0.0 + 0 +LINE + 5 +1169 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530433.4968575933 + 20 +189630.7708719959 + 30 +0.0 + 11 +530416.4651855908 + 21 +189599.5953065837 + 31 +0.0 + 0 +LINE + 5 +116A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530494.1742757037 + 20 +189430.4035020564 + 30 +0.0 + 11 +530571.7937496105 + 21 +189378.5666669773 + 31 +0.0 + 0 +LINE + 5 +116B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530540.4667486668 + 20 +189394.5089099479 + 30 +0.0 + 11 +530623.8482308888 + 21 +189394.1762472761 + 31 +0.0 + 0 +LINE + 5 +116C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530544.8656291073 + 20 +189406.875027464 + 30 +0.0 + 11 +530585.145662588 + 21 +189337.5809691292 + 31 +0.0 + 0 +LINE + 5 +116D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530488.9207428889 + 20 +189200.8594292581 + 30 +0.0 + 11 +530586.919627916 + 21 +189350.0798081888 + 31 +0.0 + 0 +LINE + 5 +116E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530407.9016811688 + 20 +189813.1407639047 + 30 +0.0 + 11 +530656.0048411988 + 21 +189646.9975927352 + 31 +0.0 + 0 +LINE + 5 +116F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529599.7443129627 + 20 +189141.9164963533 + 30 +0.0 + 11 +529073.0465794991 + 21 +189156.8615358623 + 31 +0.0 + 0 +LINE + 5 +1170 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529397.9785832684 + 20 +189142.0982707312 + 30 +0.0 + 11 +529627.9073701178 + 21 +189899.0021408969 + 31 +0.0 + 0 +LINE + 5 +1171 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529440.8580157359 + 20 +189273.1131639067 + 30 +0.0 + 11 +529294.3072642183 + 21 +189292.6214168864 + 31 +0.0 + 0 +LINE + 5 +1172 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529333.1202366099 + 20 +189148.6359144085 + 30 +0.0 + 11 +529477.7302550919 + 21 +189621.470504247 + 31 +0.0 + 0 +LINE + 5 +1173 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529324.1287595416 + 20 +189279.3380187785 + 30 +0.0 + 11 +529260.9644783164 + 21 +189331.6005467687 + 31 +0.0 + 0 +LINE + 5 +1174 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529267.8552350962 + 20 +189222.8702752408 + 30 +0.0 + 11 +529322.9340814623 + 21 +189291.308197208 + 31 +0.0 + 0 +LINE + 5 +1175 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529285.220690443 + 20 +189230.6266191861 + 30 +0.0 + 11 +529086.5249493996 + 21 +189239.2437692679 + 31 +0.0 + 0 +LINE + 5 +1176 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529256.3618522856 + 20 +189111.4712087769 + 30 +0.0 + 11 +529208.0640394783 + 21 +189541.7345497636 + 31 +0.0 + 0 +LINE + 5 +1177 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529082.044641571 + 20 +189295.137497983 + 30 +0.0 + 11 +529265.2378484767 + 21 +189330.9158113016 + 31 +0.0 + 0 +LINE + 5 +1178 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529090.0583594282 + 20 +189235.0592643627 + 30 +0.0 + 11 +529082.5629886751 + 21 +189295.808256935 + 31 +0.0 + 0 +LINE + 5 +1179 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528792.6523966713 + 20 +189233.7003870718 + 30 +0.0 + 11 +529086.9472625145 + 21 +189275.3716972314 + 31 +0.0 + 0 +LINE + 5 +117A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528860.8155782081 + 20 +189239.6542274844 + 30 +0.0 + 11 +528852.6389035224 + 21 +189352.4857093842 + 31 +0.0 + 0 +LINE + 5 +117B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528772.0540770689 + 20 +189340.5320141246 + 30 +0.0 + 11 +529635.8297696164 + 21 +189445.595253 + 31 +0.0 + 0 +LINE + 5 +117C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529289.216465819 + 20 +189473.3841425907 + 30 +0.0 + 11 +529328.7527121662 + 21 +189910.7863063088 + 31 +0.0 + 0 +LINE + 5 +117D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529358.572360176 + 20 +189477.7872034763 + 30 +0.0 + 11 +529164.7094688229 + 21 +189472.6202442182 + 31 +0.0 + 0 +LINE + 5 +117E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529355.5426843992 + 20 +189550.3352514977 + 30 +0.0 + 11 +529291.2728503051 + 21 +189548.0915653369 + 31 +0.0 + 0 +LINE + 5 +117F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529378.5419250274 + 20 +189501.0574678744 + 30 +0.0 + 11 +529342.8949609663 + 21 +189559.9348784515 + 31 +0.0 + 0 +LINE + 5 +1180 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529346.1109909713 + 20 +189539.7427780762 + 30 +0.0 + 11 +529407.1643398471 + 21 +189938.3272563772 + 31 +0.0 + 0 +LINE + 5 +1181 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529542.725968138 + 20 +189604.5678193184 + 30 +0.0 + 11 +529145.0952981153 + 21 +189692.8941715661 + 31 +0.0 + 0 +LINE + 5 +1182 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529145.4339834579 + 20 +189679.5831878522 + 30 +0.0 + 11 +529183.3674982138 + 21 +189915.3729674253 + 31 +0.0 + 0 +LINE + 5 +1183 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528966.4009061653 + 20 +189614.3684809313 + 30 +0.0 + 11 +529158.3170448564 + 21 +189692.311265146 + 31 +0.0 + 0 +LINE + 5 +1184 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529033.0284363266 + 20 +189558.1300895361 + 30 +0.0 + 11 +529020.7513625082 + 21 +189642.6321203984 + 31 +0.0 + 0 +LINE + 5 +1185 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529598.6615891 + 20 +189783.2636048686 + 30 +0.0 + 11 +529509.7764530662 + 21 +189798.1472734654 + 31 +0.0 + 0 +LINE + 5 +1186 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529648.1818643421 + 20 +189846.6063273694 + 30 +0.0 + 11 +529180.7911350706 + 21 +189913.644045867 + 31 +0.0 + 0 +LINE + 5 +1187 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529209.7837831938 + 20 +189497.1726082335 + 30 +0.0 + 11 +529256.2925069518 + 21 +189918.6843695926 + 31 +0.0 + 0 +LINE + 5 +1188 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528915.0275073097 + 20 +189863.6918634366 + 30 +0.0 + 11 +529197.3740694625 + 21 +189907.0042125853 + 31 +0.0 + 0 +LINE + 5 +1189 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528630.6392415507 + 20 +189668.1399893563 + 30 +0.0 + 11 +528867.6389683824 + 21 +189709.7115438169 + 31 +0.0 + 0 +LINE + 5 +118A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529011.1539890148 + 20 +189125.1746906123 + 30 +0.0 + 11 +528968.8246504097 + 21 +189686.1789647126 + 31 +0.0 + 0 +LINE + 5 +118B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529101.5053739744 + 20 +189840.1004521793 + 30 +0.0 + 11 +529091.814488364 + 21 +189901.7571293312 + 31 +0.0 + 0 +LINE + 5 +118C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529112.1295733161 + 20 +189828.7667822493 + 30 +0.0 + 11 +529097.1151838522 + 21 +189847.5740824715 + 31 +0.0 + 0 +LINE + 5 +118D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529176.2263413235 + 20 +189829.0392131988 + 30 +0.0 + 11 +529104.4020878985 + 21 +189830.8109330373 + 31 +0.0 + 0 +LINE + 5 +118E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528613.6534800922 + 20 +189380.0428021393 + 30 +0.0 + 11 +528496.9060559934 + 21 +189575.3968549445 + 31 +0.0 + 0 +LINE + 5 +118F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528790.8784877498 + 20 +189334.2893465018 + 30 +0.0 + 11 +528582.4828990723 + 21 +189388.0899835995 + 31 +0.0 + 0 +LINE + 5 +1190 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529227.5216962489 + 20 +189612.0593604654 + 30 +0.0 + 11 +529181.840168628 + 21 +189623.1637727485 + 31 +0.0 + 0 +LINE + 5 +1191 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529178.583755367 + 20 +189559.4320979504 + 30 +0.0 + 11 +529183.1439911666 + 21 +189624.5473949048 + 31 +0.0 + 0 +LINE + 5 +1192 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529219.8949335223 + 20 +189532.065108598 + 30 +0.0 + 11 +529115.6713294665 + 21 +189527.5503116321 + 31 +0.0 + 0 +LINE + 5 +1193 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529142.1308924119 + 20 +189378.8470075555 + 30 +0.0 + 11 +529095.5635214133 + 21 +189673.7880377656 + 31 +0.0 + 0 +LINE + 5 +1194 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529159.7048485519 + 20 +189748.5921076506 + 30 +0.0 + 11 +529091.1913892631 + 21 +189755.335226266 + 31 +0.0 + 0 +LINE + 5 +1195 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529089.0468866706 + 20 +189723.5649724518 + 30 +0.0 + 11 +529094.7548927941 + 21 +189783.3979952963 + 31 +0.0 + 0 +LINE + 5 +1196 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529096.2725740104 + 20 +189728.2397774477 + 30 +0.0 + 11 +529025.1904553542 + 21 +189734.2237831711 + 31 +0.0 + 0 +LINE + 5 +1197 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529027.3666452278 + 20 +189731.2098929347 + 30 +0.0 + 11 +529031.2918264516 + 21 +189787.2115245815 + 31 +0.0 + 0 +LINE + 5 +1198 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529101.7222307826 + 20 +189777.6450789907 + 30 +0.0 + 11 +529024.5734288724 + 21 +189785.003758375 + 31 +0.0 + 0 +LINE + 5 +1199 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529681.4765692738 + 20 +190017.5958356645 + 30 +0.0 + 11 +529618.3122880486 + 21 +190069.8583636548 + 31 +0.0 + 0 +LINE + 5 +119A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529625.2030448283 + 20 +189961.1280921271 + 30 +0.0 + 11 +529680.2818911949 + 21 +190029.5660140943 + 31 +0.0 + 0 +LINE + 5 +119B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529640.7646787354 + 20 +189969.1431576651 + 30 +0.0 + 11 +529442.068937692 + 21 +189977.7603077468 + 31 +0.0 + 0 +LINE + 5 +119C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529623.2038416172 + 20 +189765.1496793769 + 30 +0.0 + 11 +529565.4118492106 + 21 +190279.9923666497 + 31 +0.0 + 0 +LINE + 5 +119D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529439.3924513033 + 20 +190033.3953148692 + 30 +0.0 + 11 +529622.5856582088 + 21 +190069.1736281878 + 31 +0.0 + 0 +LINE + 5 +119E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529447.4061691604 + 20 +189973.3170812488 + 30 +0.0 + 11 +529439.9107984073 + 21 +190034.0660738211 + 31 +0.0 + 0 +LINE + 5 +119F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529150.0002064036 + 20 +189971.958203958 + 30 +0.0 + 11 +529444.2950722467 + 21 +190013.6295141177 + 31 +0.0 + 0 +LINE + 5 +11A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529234.2783157637 + 20 +190088.9390749303 + 30 +0.0 + 11 +529879.2664644778 + 21 +190171.3895907363 + 31 +0.0 + 0 +LINE + 5 +11A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529646.5642755513 + 20 +190211.6419594768 + 30 +0.0 + 11 +529670.4577492668 + 21 +190475.9831164549 + 31 +0.0 + 0 +LINE + 5 +11A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529715.9201699082 + 20 +190216.0450203624 + 30 +0.0 + 11 +529522.0572785551 + 21 +190210.8780611042 + 31 +0.0 + 0 +LINE + 5 +11A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529712.8904941317 + 20 +190288.5930683839 + 30 +0.0 + 11 +529648.6206600372 + 21 +190286.3493822232 + 31 +0.0 + 0 +LINE + 5 +11A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529735.8897347596 + 20 +190239.3152847607 + 30 +0.0 + 11 +529700.2427706988 + 21 +190298.1926953377 + 31 +0.0 + 0 +LINE + 5 +11A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529703.4588007035 + 20 +190278.0005949622 + 30 +0.0 + 11 +529764.5121495793 + 21 +190676.5850732634 + 31 +0.0 + 0 +LINE + 5 +11A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529792.6337321126 + 20 +190366.5769540622 + 30 +0.0 + 11 +529502.4431078476 + 21 +190431.151988452 + 31 +0.0 + 0 +LINE + 5 +11A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529502.7817931904 + 20 +190417.8410047382 + 30 +0.0 + 11 +529540.715307946 + 21 +190653.6307843117 + 31 +0.0 + 0 +LINE + 5 +11A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529323.7487158978 + 20 +190352.6262978175 + 30 +0.0 + 11 +529515.6648545887 + 21 +190430.5690820322 + 31 +0.0 + 0 +LINE + 5 +11A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529433.1144004612 + 20 +190090.1837804841 + 30 +0.0 + 11 +529378.0991722405 + 21 +190380.8899372845 + 31 +0.0 + 0 +LINE + 5 +11AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529567.131592926 + 20 +190235.4304251197 + 30 +0.0 + 11 +529614.7390158634 + 21 +190694.1570997866 + 31 +0.0 + 0 +LINE + 5 +11AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529179.290859914 + 20 +190439.6790580357 + 30 +0.0 + 11 +529539.3947473728 + 21 +190386.1536617259 + 31 +0.0 + 0 +LINE + 5 +11AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529236.7986886044 + 20 +190349.5859306546 + 30 +0.0 + 11 +529269.5934678258 + 21 +190462.342439048 + 31 +0.0 + 0 +LINE + 5 +11AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529297.4897753574 + 20 +190362.6856109918 + 30 +0.0 + 11 +529236.9844176113 + 21 +190454.3627758919 + 31 +0.0 + 0 +LINE + 5 +11AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529368.5017987471 + 20 +189863.4325074985 + 30 +0.0 + 11 +529349.6696075257 + 21 +190181.6308220653 + 31 +0.0 + 0 +LINE + 5 +11AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529385.9158724497 + 20 +190087.9554098637 + 30 +0.0 + 11 +529107.8956361627 + 21 +190262.3863000119 + 31 +0.0 + 0 +LINE + 5 +11B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529190.5207611801 + 20 +190184.8997290861 + 30 +0.0 + 11 +529277.6501320874 + 21 +190327.1649891366 + 31 +0.0 + 0 +LINE + 5 +11B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529266.1013483288 + 20 +190305.8058681578 + 30 +0.0 + 11 +529300.8217879958 + 21 +190381.6153221281 + 31 +0.0 + 0 +LINE + 5 +11B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529279.1713942825 + 20 +190304.6038239317 + 30 +0.0 + 11 +529233.2048132479 + 21 +190370.2637131008 + 31 +0.0 + 0 +LINE + 5 +11B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529121.1132686136 + 20 +190345.3750432046 + 30 +0.0 + 11 +529245.2927747905 + 21 +190366.6237795077 + 31 +0.0 + 0 +LINE + 5 +11B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529192.5917265354 + 20 +189879.9855184976 + 30 +0.0 + 11 +529151.473581988 + 21 +190023.4573339458 + 31 +0.0 + 0 +LINE + 5 +11B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529584.8695059813 + 20 +190350.3171773516 + 30 +0.0 + 11 +529539.1879783602 + 21 +190361.4215896345 + 31 +0.0 + 0 +LINE + 5 +11B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529535.9315650991 + 20 +190297.6899148364 + 30 +0.0 + 11 +529540.4918008986 + 21 +190362.805211791 + 31 +0.0 + 0 +LINE + 5 +11B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529577.2427432546 + 20 +190270.3229254841 + 30 +0.0 + 11 +529473.0191391987 + 21 +190265.8081285183 + 31 +0.0 + 0 +LINE + 5 +11B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529499.4787021441 + 20 +190117.1048244416 + 30 +0.0 + 11 +529452.9113311455 + 21 +190412.0458546517 + 31 +0.0 + 0 +LINE + 5 +11B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529517.0526582841 + 20 +190486.8499245364 + 30 +0.0 + 11 +529448.5391989954 + 21 +190493.5930431521 + 31 +0.0 + 0 +LINE + 5 +11BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529446.3946964027 + 20 +190461.822789338 + 30 +0.0 + 11 +529452.1027025263 + 21 +190521.6558121825 + 31 +0.0 + 0 +LINE + 5 +11BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529289.7172643801 + 20 +189986.7411276527 + 30 +0.0 + 11 +529280.6825980962 + 21 +190099.0930094734 + 31 +0.0 + 0 +LINE + 5 +11BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529222.9041325545 + 20 +190423.7023349991 + 30 +0.0 + 11 +528709.3237252108 + 21 +190682.1166628364 + 31 +0.0 + 0 +LINE + 5 +11BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529163.3485840849 + 20 +190389.3201673407 + 30 +0.0 + 11 +528959.3591667059 + 21 +190489.6088624351 + 31 +0.0 + 0 +LINE + 5 +11BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529164.681216433 + 20 +190202.4724583925 + 30 +0.0 + 11 +528995.0771133086 + 21 +190210.678909631 + 31 +0.0 + 0 +LINE + 5 +11BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529136.4969689673 + 20 +190064.9659453543 + 30 +0.0 + 11 +529183.7428766971 + 21 +191350.1385539917 + 31 +0.0 + 0 +LINE + 5 +11C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529075.492698009 + 20 +190279.8947185111 + 30 +0.0 + 11 +528649.9905491098 + 21 +190388.6682855325 + 31 +0.0 + 0 +LINE + 5 +11C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529082.2046651557 + 20 +190349.065351906 + 30 +0.0 + 11 +529056.3943639352 + 21 +190156.8588315621 + 31 +0.0 + 0 +LINE + 5 +11C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529010.1017019967 + 20 +190357.6421176554 + 30 +0.0 + 11 +529002.0689515459 + 21 +190293.8367838478 + 31 +0.0 + 0 +LINE + 5 +11C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529062.4162329431 + 20 +190372.4898407178 + 30 +0.0 + 11 +528998.6082292791 + 21 +190346.6868526846 + 31 +0.0 + 0 +LINE + 5 +11C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529019.0547880857 + 20 +190346.6421365833 + 30 +0.0 + 11 +528635.3045711425 + 21 +190470.4680981078 + 31 +0.0 + 0 +LINE + 5 +11C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528986.4090745275 + 20 +190551.0779274919 + 30 +0.0 + 11 +528835.8111172078 + 21 +190172.6179566959 + 31 +0.0 + 0 +LINE + 5 +11C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528849.0058062867 + 20 +190170.8298920155 + 30 +0.0 + 11 +528622.2811080334 + 21 +190245.8744314231 + 31 +0.0 + 0 +LINE + 5 +11C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528884.8396085598 + 20 +189983.6889307637 + 30 +0.0 + 11 +528838.4947543224 + 21 +190185.5776040143 + 31 +0.0 + 0 +LINE + 5 +11C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528950.9821621563 + 20 +190040.4969147609 + 30 +0.0 + 11 +528865.6036683856 + 21 +190041.8506366036 + 31 +0.0 + 0 +LINE + 5 +11C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528818.9183331026 + 20 +190634.7907043113 + 30 +0.0 + 11 +528790.0524771059 + 21 +190549.4159225766 + 31 +0.0 + 0 +LINE + 5 +11CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528764.2819378928 + 20 +190693.7773339177 + 30 +0.0 + 11 +528623.5771128351 + 21 +190243.0553556253 + 31 +0.0 + 0 +LINE + 5 +11CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529039.3431507226 + 20 +190205.2713146913 + 30 +0.0 + 11 +528630.6398575692 + 21 +190318.3944534166 + 31 +0.0 + 0 +LINE + 5 +11CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528662.360593598 + 20 +189841.5344313142 + 30 +0.0 + 11 +528634.4480423454 + 21 +190324.238339472 + 31 +0.0 + 0 +LINE + 5 +11CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528642.1873241249 + 20 +189641.292104649 + 30 +0.0 + 11 +528650.3809379063 + 21 +190127.5994357825 + 31 +0.0 + 0 +LINE + 5 +11CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528753.425410089 + 20 +189824.8044275578 + 30 +0.0 + 11 +528647.3405610826 + 21 +189875.1584992957 + 31 +0.0 + 0 +LINE + 5 +11CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528750.170429287 + 20 +189886.8077721141 + 30 +0.0 + 11 +528650.0186687917 + 21 +189841.694295748 + 31 +0.0 + 0 +LINE + 5 +11D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528752.8755982489 + 20 +190076.7971426593 + 30 +0.0 + 11 +528731.887199553 + 21 +189875.8824381668 + 31 +0.0 + 0 +LINE + 5 +11D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528947.1272669612 + 20 +189980.1131455051 + 30 +0.0 + 11 +528650.2833384174 + 21 +190029.2173010918 + 31 +0.0 + 0 +LINE + 5 +11D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528942.591557104 + 20 +189876.9953841607 + 30 +0.0 + 11 +529048.8655200789 + 21 +189768.3325097931 + 31 +0.0 + 0 +LINE + 5 +11D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529284.0550368516 + 20 +190057.307597568 + 30 +0.0 + 11 +529284.0426462572 + 21 +190057.3086510901 + 31 +0.0 + 0 +LINE + 5 +11D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529069.2172349707 + 20 +189964.3602476667 + 30 +0.0 + 11 +528814.3343133004 + 21 +189997.5317432476 + 31 +0.0 + 0 +LINE + 5 +11D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528805.6839475577 + 20 +190007.3399509129 + 30 +0.0 + 11 +528803.8150157145 + 21 +189983.1271099848 + 31 +0.0 + 0 +LINE + 5 +11D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528683.5378083801 + 20 +190153.0575385689 + 30 +0.0 + 11 +528638.2227412406 + 21 +190152.2317883801 + 31 +0.0 + 0 +LINE + 5 +11D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528696.420491177 + 20 +190161.7386773015 + 30 +0.0 + 11 +528675.4597844933 + 21 +190149.9151749459 + 31 +0.0 + 0 +LINE + 5 +11D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528706.3716819392 + 20 +190225.0588454159 + 30 +0.0 + 11 +528693.1703564675 + 21 +190154.4359923367 + 31 +0.0 + 0 +LINE + 5 +11D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528877.7138260937 + 20 +190033.7914588225 + 30 +0.0 + 11 +528830.8379358486 + 21 +189685.6645060741 + 31 +0.0 + 0 +LINE + 5 +11DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528920.0980527489 + 20 +189798.5942733324 + 30 +0.0 + 11 +528894.1033295456 + 21 +189993.8972962386 + 31 +0.0 + 0 +LINE + 5 +11DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529224.660609378 + 20 +190237.173797853 + 30 +0.0 + 11 +528810.2420405034 + 21 +189672.5104535883 + 31 +0.0 + 0 +LINE + 5 +11DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528859.7685753607 + 20 +189850.6117725274 + 30 +0.0 + 11 +528766.4324096041 + 21 +189851.0593911296 + 31 +0.0 + 0 +LINE + 5 +11DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528801.3176274221 + 20 +189846.7515289162 + 30 +0.0 + 11 +528732.0141848773 + 21 +189893.1154706532 + 31 +0.0 + 0 +LINE + 5 +11DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528804.5882927735 + 20 +189859.4626956493 + 30 +0.0 + 11 +528732.4391360198 + 21 +189824.5535736687 + 31 +0.0 + 0 +LINE + 5 +11DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528735.7271808159 + 20 +189657.3973491444 + 30 +0.0 + 11 +528737.95990904 + 21 +189835.9065026335 + 31 +0.0 + 0 +LINE + 5 +11E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528928.7545163261 + 20 +190241.1008184592 + 30 +0.0 + 11 +528910.5083181793 + 21 +190197.7743116633 + 31 +0.0 + 0 +LINE + 5 +11E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528972.9053949298 + 20 +190184.3976374539 + 30 +0.0 + 11 +528909.3502903563 + 21 +190199.2820699479 + 31 +0.0 + 0 +LINE + 5 +11E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529145.3677672739 + 20 +190119.6171140234 + 30 +0.0 + 11 +528846.7750420871 + 21 +190120.6734324097 + 31 +0.0 + 0 +LINE + 5 +11E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528783.1552386387 + 20 +190195.9215508423 + 30 +0.0 + 11 +528744.2071778071 + 21 +190033.8158718843 + 31 +0.0 + 0 +LINE + 5 +11E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528943.273818483 + 20 +190435.7833200833 + 30 +0.0 + 11 +528696.4510643113 + 21 +190531.1367562146 + 31 +0.0 + 0 +LINE + 5 +11E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528976.0769089332 + 20 +189434.0576018465 + 30 +0.0 + 11 +529140.8150301299 + 21 +189457.1353655681 + 31 +0.0 + 0 +LINE + 5 +11E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528884.5132737517 + 20 +189395.1880814658 + 30 +0.0 + 11 +528971.8021976204 + 21 +189232.6095664005 + 31 +0.0 + 0 +LINE + 5 +11E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528963.8167557576 + 20 +190199.7062129303 + 30 +0.0 + 11 +528942.2151172271 + 21 +190084.5386704732 + 31 +0.0 + 0 +LINE + 5 +11E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529538.7347799715 + 20 +189605.4543884852 + 30 +0.0 + 11 +529721.0447377914 + 21 +189683.0898924534 + 31 +0.0 + 0 +LINE + 5 +11E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532093.4400750394 + 20 +190602.6288740622 + 30 +0.0 + 11 +532537.709917907 + 21 +190944.7038226986 + 31 +0.0 + 0 +LINE + 5 +11EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532113.3938232591 + 20 +190608.2493097254 + 30 +0.0 + 11 +531485.2645507479 + 21 +191089.1072229474 + 31 +0.0 + 0 +LINE + 5 +11EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532002.1664151241 + 20 +190689.6864734899 + 30 +0.0 + 11 +532109.8523286888 + 21 +190790.9852332279 + 31 +0.0 + 0 +LINE + 5 +11EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532093.3699689512 + 20 +190762.8054165837 + 30 +0.0 + 11 +532114.2129493946 + 21 +190842.0939303852 + 31 +0.0 + 0 +LINE + 5 +11ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532172.0125192354 + 20 +190749.7415389612 + 30 +0.0 + 11 +532087.3610531503 + 21 +190773.2268060422 + 31 +0.0 + 0 +LINE + 5 +11EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532153.3819682775 + 20 +190745.9176035789 + 30 +0.0 + 11 +532309.7817934577 + 21 +190868.7725891024 + 31 +0.0 + 0 +LINE + 5 +11EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532246.303823139 + 20 +190665.9402739241 + 30 +0.0 + 11 +532034.6666925351 + 21 +191043.6557042007 + 31 +0.0 + 0 +LINE + 5 +11F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532280.8315229687 + 20 +190916.7940833162 + 30 +0.0 + 11 +532111.1404321221 + 21 +190839.0459486273 + 31 +0.0 + 0 +LINE + 5 +11F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532309.3510573484 + 20 +190863.3127782874 + 30 +0.0 + 11 +532280.0193059137 + 21 +190917.0367863198 + 31 +0.0 + 0 +LINE + 5 +11F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532551.761731845 + 20 +191035.6183734401 + 30 +0.0 + 11 +532288.373456142 + 21 +190897.8773760057 + 31 +0.0 + 0 +LINE + 5 +11F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532492.9131191679 + 20 +191000.7112349314 + 30 +0.0 + 11 +532433.7669462679 + 21 +191097.1453136996 + 31 +0.0 + 0 +LINE + 5 +11F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532506.2055003433 + 20 +191134.4207877858 + 30 +0.0 + 11 +531880.4091661065 + 21 +190762.0070556545 + 31 +0.0 + 0 +LINE + 5 +11F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532008.590213593 + 20 +190940.8086735789 + 30 +0.0 + 11 +531721.4325374245 + 21 +191273.1100979186 + 31 +0.0 + 0 +LINE + 5 +11F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531949.6768366249 + 20 +190903.9462124372 + 30 +0.0 + 11 +532110.1875119865 + 21 +191012.7848140758 + 31 +0.0 + 0 +LINE + 5 +11F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531909.8373502772 + 20 +190964.652172067 + 30 +0.0 + 11 +531963.3596391908 + 21 +191000.303403344 + 31 +0.0 + 0 +LINE + 5 +11F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531919.8848989398 + 20 +190911.2076981324 + 30 +0.0 + 11 +531914.5153158007 + 21 +190979.8256484073 + 31 +0.0 + 0 +LINE + 5 +11F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531923.6760320993 + 20 +190961.5460137429 + 30 +0.0 + 11 +531641.6710148187 + 21 +191249.7651456203 + 31 +0.0 + 0 +LINE + 5 +11FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531726.1444548365 + 20 +190899.5701216376 + 30 +0.0 + 11 +531997.6865254563 + 21 +191203.1761132243 + 31 +0.0 + 0 +LINE + 5 +11FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532005.1726544908 + 20 +191192.1645344424 + 30 +0.0 + 11 +531836.8719324415 + 21 +191361.6066739787 + 31 +0.0 + 0 +LINE + 5 +11FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532188.6475604557 + 20 +191243.5723124995 + 30 +0.0 + 11 +531987.2848003661 + 21 +191194.9932969649 + 31 +0.0 + 0 +LINE + 5 +11FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532167.309190774 + 20 +191159.034401351 + 30 +0.0 + 11 +532128.0124170939 + 21 +191234.8439214637 + 31 +0.0 + 0 +LINE + 5 +11FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531630.7610581088 + 20 +190956.806285408 + 30 +0.0 + 11 +531694.2947849448 + 21 +191020.7246439053 + 31 +0.0 + 0 +LINE + 5 +11FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531499.3437770261 + 20 +191034.7183290566 + 30 +0.0 + 11 +531839.9731081884 + 21 +191361.7042741094 + 31 +0.0 + 0 +LINE + 5 +1200 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532059.2524323825 + 20 +191006.4499849154 + 30 +0.0 + 11 +531775.6954554155 + 21 +191321.7762717404 + 31 +0.0 + 0 +LINE + 5 +1201 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532216.6329280467 + 20 +191506.1016118414 + 30 +0.0 + 11 +531772.1639381984 + 21 +191315.7611523182 + 31 +0.0 + 0 +LINE + 5 +1202 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532441.2418068305 + 20 +191623.2923990452 + 30 +0.0 + 11 +531955.262167516 + 21 +191389.2169487265 + 31 +0.0 + 0 +LINE + 5 +1203 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532272.2279328401 + 20 +191432.061830168 + 30 +0.0 + 11 +532179.8394744348 + 21 +191504.5456247899 + 31 +0.0 + 0 +LINE + 5 +1204 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532215.2832434994 + 20 +191407.3168914513 + 30 +0.0 + 11 +532210.9844278584 + 21 +191517.0762694753 + 31 +0.0 + 0 +LINE + 5 +1205 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532046.4502892583 + 20 +191320.1462976625 + 30 +0.0 + 11 +532216.905681068 + 21 +191428.5538193766 + 31 +0.0 + 0 +LINE + 5 +1206 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532239.1193936134 + 20 +191161.2838040338 + 30 +0.0 + 11 +532043.2702144016 + 21 +191433.1900954792 + 31 +0.0 + 0 +LINE + 5 +1207 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532166.2017047998 + 20 +191102.635575774 + 30 +0.0 + 11 +532256.0616277937 + 21 +191184.3219257113 + 31 +0.0 + 0 +LINE + 5 +1208 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532308.5036839469 + 20 +191096.7215187221 + 30 +0.0 + 11 +532193.1847684965 + 21 +191060.8149913824 + 31 +0.0 + 0 +LINE + 5 +1209 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532199.9118185815 + 20 +191060.4665467347 + 30 +0.0 + 11 +532165.9623074486 + 21 +191104.7954491255 + 31 +0.0 + 0 +LINE + 5 +120A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532437.5252889657 + 20 +190820.0474854079 + 30 +0.0 + 11 +532144.8076645989 + 21 +191300.4993153043 + 31 +0.0 + 0 +LINE + 5 +120B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532132.1706507358 + 20 +191303.8661603718 + 30 +0.0 + 11 +532153.0073547956 + 21 +191316.3395855612 + 31 +0.0 + 0 +LINE + 5 +120C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531947.2677219202 + 20 +191348.1854742621 + 30 +0.0 + 11 +531927.7928531354 + 21 +191389.1106090703 + 31 +0.0 + 0 +LINE + 5 +120D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531945.2447811827 + 20 +191332.7830914429 + 30 +0.0 + 11 +531946.4767204593 + 21 +191356.8169999523 + 31 +0.0 + 0 +LINE + 5 +120E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531893.0124814265 + 20 +191295.6312846257 + 30 +0.0 + 11 +531950.3308491905 + 21 +191338.9494919771 + 31 +0.0 + 0 +LINE + 5 +120F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532140.6273829715 + 20 +191227.6003793653 + 30 +0.0 + 11 +532496.6227987491 + 21 +191476.4468156583 + 31 +0.0 + 0 +LINE + 5 +1210 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532486.9862212213 + 20 +191446.1845371221 + 30 +0.0 + 11 +532344.3388213688 + 21 +191588.191690398 + 31 +0.0 + 0 +LINE + 5 +1211 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532494.5521203357 + 20 +191118.373106616 + 30 +0.0 + 11 +532476.0061814613 + 21 +191480.6445697622 + 31 +0.0 + 0 +LINE + 5 +1212 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532555.6789127965 + 20 +191365.8405141135 + 30 +0.0 + 11 +532183.6434305776 + 21 +191230.7276273598 + 31 +0.0 + 0 +LINE + 5 +1213 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532250.7242278104 + 20 +191121.100715535 + 30 +0.0 + 11 +532280.8983750848 + 21 +191139.8494372576 + 31 +0.0 + 0 +LINE + 5 +1214 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532296.5674822263 + 20 +191325.3731513396 + 30 +0.0 + 11 +532254.5319497042 + 21 +191408.7089432071 + 31 +0.0 + 0 +LINE + 5 +1215 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532273.9488858729 + 20 +191379.4084536399 + 30 +0.0 + 11 +532201.5388367442 + 21 +191420.752945741 + 31 +0.0 + 0 +LINE + 5 +1216 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532264.031408359 + 20 +191370.8110905958 + 30 +0.0 + 11 +532263.0909969975 + 21 +191450.9563539879 + 31 +0.0 + 0 +LINE + 5 +1217 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532414.1618065546 + 20 +191522.577755367 + 30 +0.0 + 11 +532255.3928528242 + 21 +191440.9510300498 + 31 +0.0 + 0 +LINE + 5 +1218 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532685.3559009919 + 20 +191001.6618268656 + 30 +0.0 + 11 +532521.9230479188 + 21 +190934.6835698601 + 31 +0.0 + 0 +LINE + 5 +1219 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532584.1101927998 + 20 +190947.9789637227 + 30 +0.0 + 11 +532480.0379977193 + 21 +191189.8628189787 + 31 +0.0 + 0 +LINE + 5 +121A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531977.8543738964 + 20 +191089.4436923433 + 30 +0.0 + 11 +532008.4922394006 + 21 +191125.1008253645 + 31 +0.0 + 0 +LINE + 5 +121B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532048.2980711977 + 20 +191075.2227103755 + 30 +0.0 + 11 +532006.6262351963 + 21 +191125.4646821949 + 31 +0.0 + 0 +LINE + 5 +121C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532030.6930418108 + 20 +191028.9017811203 + 30 +0.0 + 11 +532117.998770022 + 21 +191086.0039076615 + 31 +0.0 + 0 +LINE + 5 +121D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532183.2074847922 + 20 +190949.7665976741 + 30 +0.0 + 11 +532049.0673803575 + 21 +191216.5345937405 + 31 +0.0 + 0 +LINE + 5 +121E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531953.3414468827 + 20 +191239.9077488307 + 30 +0.0 + 11 +532005.0713700226 + 21 +191285.334379834 + 31 +0.0 + 0 +LINE + 5 +121F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532025.3380024663 + 20 +191260.7740148495 + 30 +0.0 + 11 +531985.8136504054 + 21 +191306.0553305413 + 31 +0.0 + 0 +LINE + 5 +1220 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532016.7419589933 + 20 +191260.358809006 + 30 +0.0 + 11 +532071.0013293279 + 21 +191306.6664395658 + 31 +0.0 + 0 +LINE + 5 +1221 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532070.9906705489 + 20 +191302.9490179977 + 30 +0.0 + 11 +532035.1487030354 + 21 +191346.1571556514 + 31 +0.0 + 0 +LINE + 5 +1222 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531983.5076242133 + 20 +191297.3190791788 + 30 +0.0 + 11 +532041.8941492539 + 21 +191348.2808441813 + 31 +0.0 + 0 +LINE + 5 +1223 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532429.633362168 + 20 +190966.1629744953 + 30 +0.0 + 11 +532371.4638803732 + 21 +191062.7076891677 + 31 +0.0 + 0 +LINE + 5 +1224 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531810.0910753604 + 20 +190989.6060128932 + 30 +0.0 + 11 +531614.6487416758 + 21 +191167.9765372598 + 31 +0.0 + 0 +LINE + 5 +1225 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531796.2678138876 + 20 +190690.6548548851 + 30 +0.0 + 11 +530764.4896246664 + 21 +191480.5220505232 + 31 +0.0 + 0 +LINE + 5 +1226 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531281.3914890426 + 20 +191081.1013010658 + 30 +0.0 + 11 +531389.0774026074 + 21 +191182.4000608037 + 31 +0.0 + 0 +LINE + 5 +1227 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531441.4991432304 + 20 +191042.7926367183 + 30 +0.0 + 11 +531048.3177917206 + 21 +191342.6143030769 + 31 +0.0 + 0 +LINE + 5 +1228 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531372.5950428699 + 20 +191154.2202441596 + 30 +0.0 + 11 +531393.4380233133 + 21 +191233.5087579612 + 31 +0.0 + 0 +LINE + 5 +1229 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531451.2375931538 + 20 +191141.1563665371 + 30 +0.0 + 11 +531366.5861270688 + 21 +191164.6416336182 + 31 +0.0 + 0 +LINE + 5 +122A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531433.92164784 + 20 +191138.5943822833 + 30 +0.0 + 11 +531590.3214730201 + 21 +191261.4493678067 + 31 +0.0 + 0 +LINE + 5 +122B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531567.1316283411 + 20 +190983.1054010685 + 30 +0.0 + 11 +531313.8917664535 + 21 +191435.0705317762 + 31 +0.0 + 0 +LINE + 5 +122C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531560.0565968872 + 20 +191308.2089108923 + 30 +0.0 + 11 +531390.3655060405 + 21 +191230.4607762033 + 31 +0.0 + 0 +LINE + 5 +122D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531588.5761312669 + 20 +191254.7276058633 + 30 +0.0 + 11 +531559.2443798324 + 21 +191308.4516138957 + 31 +0.0 + 0 +LINE + 5 +122E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531830.9868057637 + 20 +191427.0332010161 + 30 +0.0 + 11 +531567.5985300605 + 21 +191289.2922035817 + 31 +0.0 + 0 +LINE + 5 +122F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531772.1381930866 + 20 +191392.1260625073 + 30 +0.0 + 11 +531712.9920201865 + 21 +191488.5601412755 + 31 +0.0 + 0 +LINE + 5 +1230 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531785.4305742621 + 20 +191525.8356153619 + 30 +0.0 + 11 +531122.2336288609 + 21 +191163.8391900123 + 31 +0.0 + 0 +LINE + 5 +1231 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531287.8152875113 + 20 +191332.2235011548 + 30 +0.0 + 11 +531000.6576113431 + 21 +191664.5249254946 + 31 +0.0 + 0 +LINE + 5 +1232 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531228.9019105434 + 20 +191295.3610400128 + 30 +0.0 + 11 +531389.412585905 + 21 +191404.1996416514 + 31 +0.0 + 0 +LINE + 5 +1233 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531189.0624241958 + 20 +191356.0669996431 + 30 +0.0 + 11 +531242.5847131093 + 21 +191391.7182309199 + 31 +0.0 + 0 +LINE + 5 +1234 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531199.1099728586 + 20 +191302.6225257084 + 30 +0.0 + 11 +531193.7403897194 + 21 +191371.2404759832 + 31 +0.0 + 0 +LINE + 5 +1235 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531202.901106018 + 20 +191352.9608413188 + 30 +0.0 + 11 +530920.8960887374 + 21 +191641.1799731962 + 31 +0.0 + 0 +LINE + 5 +1236 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530791.3001046506 + 20 +191134.8743590273 + 30 +0.0 + 11 +531243.4633766599 + 21 +191657.8057239712 + 31 +0.0 + 0 +LINE + 5 +1237 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531284.3977284094 + 20 +191583.5793620181 + 30 +0.0 + 11 +531116.0970063601 + 21 +191753.0215015545 + 31 +0.0 + 0 +LINE + 5 +1238 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531467.8726343744 + 20 +191634.9871400754 + 30 +0.0 + 11 +531266.5098742847 + 21 +191586.4081245408 + 31 +0.0 + 0 +LINE + 5 +1239 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531446.5342646923 + 20 +191550.4492289268 + 30 +0.0 + 11 +531407.2374910125 + 21 +191626.2587490396 + 31 +0.0 + 0 +LINE + 5 +123A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530855.7335500447 + 20 +191403.5462717947 + 30 +0.0 + 11 +530919.2672768807 + 21 +191467.4646302917 + 31 +0.0 + 0 +LINE + 5 +123B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530778.5688509447 + 20 +191426.1331566325 + 30 +0.0 + 11 +531119.1981821072 + 21 +191753.1191016854 + 31 +0.0 + 0 +LINE + 5 +123C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531338.4775063013 + 20 +191397.8648124914 + 30 +0.0 + 11 +531054.9205293343 + 21 +191713.1910993164 + 31 +0.0 + 0 +LINE + 5 +123D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531377.5029102171 + 20 +191845.5685987614 + 30 +0.0 + 11 +531051.3890121169 + 21 +191707.1759798942 + 31 +0.0 + 0 +LINE + 5 +123E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531518.344467532 + 20 +191552.6986316098 + 30 +0.0 + 11 +531322.4952883203 + 21 +191824.604923055 + 31 +0.0 + 0 +LINE + 5 +123F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531445.4267787183 + 20 +191494.0504033497 + 30 +0.0 + 11 +531535.2867017123 + 21 +191575.7367532872 + 31 +0.0 + 0 +LINE + 5 +1240 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531587.7287578654 + 20 +191488.136346298 + 30 +0.0 + 11 +531472.4098424151 + 21 +191452.2298189583 + 31 +0.0 + 0 +LINE + 5 +1241 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531479.1368925001 + 20 +191451.8813743105 + 30 +0.0 + 11 +531445.1873813673 + 21 +191496.2102767015 + 31 +0.0 + 0 +LINE + 5 +1242 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531716.7503628843 + 20 +191211.4623129839 + 30 +0.0 + 11 +531424.0327385175 + 21 +191691.9141428803 + 31 +0.0 + 0 +LINE + 5 +1243 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531411.3957246545 + 20 +191695.2809879477 + 30 +0.0 + 11 +531432.2324287142 + 21 +191707.7544131372 + 31 +0.0 + 0 +LINE + 5 +1244 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531226.4927958389 + 20 +191739.600301838 + 30 +0.0 + 11 +531207.017927054 + 21 +191780.5254366461 + 31 +0.0 + 0 +LINE + 5 +1245 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531224.4698551012 + 20 +191724.1979190188 + 30 +0.0 + 11 +531225.7017943778 + 21 +191748.2318275282 + 31 +0.0 + 0 +LINE + 5 +1246 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531172.2375553451 + 20 +191687.0461122015 + 30 +0.0 + 11 +531229.5559231091 + 21 +191730.3643195529 + 31 +0.0 + 0 +LINE + 5 +1247 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531419.8524568902 + 20 +191619.0152069412 + 30 +0.0 + 11 +531707.0201414058 + 21 +191827.7939637002 + 31 +0.0 + 0 +LINE + 5 +1248 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531773.7771942542 + 20 +191509.787934192 + 30 +0.0 + 11 +531767.8126675716 + 21 +191713.7268288893 + 31 +0.0 + 0 +LINE + 5 +1249 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531797.7271904702 + 20 +191705.2143525404 + 30 +0.0 + 11 +531462.8685044961 + 21 +191622.1424549358 + 31 +0.0 + 0 +LINE + 5 +124A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531529.949301729 + 20 +191512.5155431109 + 30 +0.0 + 11 +531560.1234490032 + 21 +191531.2642648336 + 31 +0.0 + 0 +LINE + 5 +124B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531850.0114793597 + 20 +191327.4788226467 + 30 +0.0 + 11 +531759.2630716378 + 21 +191581.2776465546 + 31 +0.0 + 0 +LINE + 5 +124C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531257.0794478149 + 20 +191480.858519919 + 30 +0.0 + 11 +531287.7173133191 + 21 +191516.5156529402 + 31 +0.0 + 0 +LINE + 5 +124D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531327.5231451162 + 20 +191466.6375379514 + 30 +0.0 + 11 +531285.8513091147 + 21 +191516.8795097707 + 31 +0.0 + 0 +LINE + 5 +124E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531309.9181157294 + 20 +191420.3166086959 + 30 +0.0 + 11 +531397.2238439407 + 21 +191477.4187352375 + 31 +0.0 + 0 +LINE + 5 +124F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531462.4325587107 + 20 +191341.18142525 + 30 +0.0 + 11 +531328.292454276 + 21 +191607.9494213166 + 31 +0.0 + 0 +LINE + 5 +1250 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531708.8584360867 + 20 +191357.5778020711 + 30 +0.0 + 11 +531650.6889542918 + 21 +191454.1225167437 + 31 +0.0 + 0 +LINE + 5 +1251 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531059.8805382769 + 20 +191405.2619729084 + 30 +0.0 + 11 +530893.8738155942 + 21 +191559.3913648357 + 31 +0.0 + 0 +LINE + 5 +1252 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531695.8206200191 + 20 +191746.0086272095 + 30 +0.0 + 11 +531828.8253042691 + 21 +191851.5673862307 + 31 +0.0 + 0 +LINE + 5 +1253 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531993.615337301 + 20 +191400.533692721 + 30 +0.0 + 11 +531530.5044200901 + 21 +191997.5260534049 + 31 +0.0 + 0 +LINE + 5 +1254 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531723.1362172004 + 20 +191860.9114397561 + 30 +0.0 + 11 +532005.3993839649 + 21 +192197.3802678644 + 31 +0.0 + 0 +LINE + 5 +1255 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531677.3517133629 + 20 +191913.1934274341 + 30 +0.0 + 11 +531810.391053535 + 21 +191772.0904434886 + 31 +0.0 + 0 +LINE + 5 +1256 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531730.9286674994 + 20 +191962.2026938285 + 30 +0.0 + 11 +531774.6578365174 + 21 +191915.0496930851 + 31 +0.0 + 0 +LINE + 5 +1257 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531679.7700162902 + 20 +191943.7620475613 + 30 +0.0 + 11 +531746.6539128269 + 21 +191960.0039657696 + 31 +0.0 + 0 +LINE + 5 +1258 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531730.0688062759 + 20 +191948.045788348 + 30 +0.0 + 11 +531969.6352427643 + 21 +192272.3990221221 + 31 +0.0 + 0 +LINE + 5 +1259 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531637.389696535 + 20 +192133.1682284677 + 30 +0.0 + 11 +531980.4084138274 + 21 +191913.5097348211 + 31 +0.0 + 0 +LINE + 5 +125A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531970.7313669026 + 20 +191904.3636013212 + 30 +0.0 + 11 +532111.1703995337 + 21 +192097.5284268109 + 31 +0.0 + 0 +LINE + 5 +125B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532050.7362527369 + 20 +191731.4329244408 + 30 +0.0 + 11 +531970.6717466338 + 21 +191922.4736446127 + 31 +0.0 + 0 +LINE + 5 +125C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531963.8775272967 + 20 +191739.018849366 + 30 +0.0 + 11 +532032.4513453455 + 21 +191789.9005871466 + 31 +0.0 + 0 +LINE + 5 +125D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531734.6458126212 + 20 +192378.6164578516 + 30 +0.0 + 11 +532111.7612289476 + 21 +192094.4824889581 + 31 +0.0 + 0 +LINE + 5 +125E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531796.0157464022 + 20 +191821.3637926705 + 30 +0.0 + 11 +532062.0950777154 + 21 +192151.5713271051 + 31 +0.0 + 0 +LINE + 5 +125F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532314.3690415566 + 20 +191745.6655092834 + 30 +0.0 + 11 +532055.593819006 + 21 +192154.0985609112 + 31 +0.0 + 0 +LINE + 5 +1260 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532444.3084072207 + 20 +191573.5378326324 + 30 +0.0 + 11 +532157.3045856129 + 21 +191985.0552659795 + 31 +0.0 + 0 +LINE + 5 +1261 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532250.1410495512 + 20 +191678.9762382483 + 30 +0.0 + 11 +532306.9662988436 + 21 +191781.7401364429 + 31 +0.0 + 0 +LINE + 5 +1262 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532216.6329438502 + 20 +191731.2468465146 + 30 +0.0 + 11 +532324.3026469366 + 21 +191752.9916370946 + 31 +0.0 + 0 +LINE + 5 +1263 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532103.6574210093 + 20 +191884.0205683982 + 30 +0.0 + 11 +532237.8568669417 + 21 +191733.0313632459 + 31 +0.0 + 0 +LINE + 5 +1264 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532002.2175019509 + 20 +191692.209596541 + 30 +0.0 + 11 +532214.7479054014 + 21 +191905.1846270458 + 31 +0.0 + 0 +LINE + 5 +1265 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532018.0713449173 + 20 +191602.3928622941 + 30 +0.0 + 11 +531958.0747517411 + 21 +191707.9763569033 + 31 +0.0 + 0 +LINE + 5 +1266 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531880.9878547196 + 20 +191641.0315224062 + 30 +0.0 + 11 +531979.4193661846 + 21 +191571.0388905303 + 31 +0.0 + 0 +LINE + 5 +1267 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531972.917590081 + 20 +191572.800004955 + 30 +0.0 + 11 +532018.9706419868 + 21 +191604.3711516482 + 31 +0.0 + 0 +LINE + 5 +1268 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531672.3130915669 + 20 +191418.2088608678 + 30 +0.0 + 11 +531672.3225436441 + 21 +191418.2169413986 + 31 +0.0 + 0 +LINE + 5 +1269 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531783.5634071171 + 20 +191513.3161613891 + 30 +0.0 + 11 +532099.9447376423 + 21 +191783.7888709074 + 31 +0.0 + 0 +LINE + 5 +126A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532101.2535546515 + 20 +191796.8010484009 + 30 +0.0 + 11 +532116.8897799552 + 21 +191778.2197935914 + 31 +0.0 + 0 +LINE + 5 +126B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532115.5233552441 + 20 +191986.4050237265 + 30 +0.0 + 11 +532152.8196642743 + 21 +192012.1561888647 + 31 +0.0 + 0 +LINE + 5 +126C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532099.995471847 + 20 +191985.9461959419 + 30 +0.0 + 11 +532123.9183272432 + 21 +191988.5621895042 + 31 +0.0 + 0 +LINE + 5 +126D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532054.9906121824 + 20 +192031.5864467543 + 30 +0.0 + 11 +532106.893947073 + 21 +191981.9084214466 + 31 +0.0 + 0 +LINE + 5 +126E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532027.3119133144 + 20 +191776.2920418672 + 30 +0.0 + 11 +532268.3784369255 + 21 +191520.7990761905 + 31 +0.0 + 0 +LINE + 5 +126F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532178.0254453258 + 20 +191477.8100702677 + 30 +0.0 + 11 +532037.2579981849 + 21 +191734.3249663507 + 31 +0.0 + 0 +LINE + 5 +1270 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531939.7295620738 + 20 +191650.6225332717 + 30 +0.0 + 11 +531963.0496409979 + 21 +191623.823883139 + 31 +0.0 + 0 +LINE + 5 +1271 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532148.6982256789 + 20 +191637.9367287575 + 30 +0.0 + 11 +532224.2653350659 + 21 +191692.7222394283 + 31 +0.0 + 0 +LINE + 5 +1272 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532198.4357110942 + 20 +191668.8817984812 + 30 +0.0 + 11 +532227.7055748605 + 21 +191746.9577699262 + 31 +0.0 + 0 +LINE + 5 +1273 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532188.3670132983 + 20 +191677.3015571623 + 30 +0.0 + 11 +532267.336970273 + 21 +191691.0089826361 + 31 +0.0 + 0 +LINE + 5 +1274 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532362.1300852291 + 20 +191553.2908647549 + 30 +0.0 + 11 +532256.2321941641 + 21 +191697.0133042788 + 31 +0.0 + 0 +LINE + 5 +1275 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531864.9688504661 + 20 +191914.9536897637 + 30 +0.0 + 11 +531905.0549577436 + 21 +191890.3932756532 + 31 +0.0 + 0 +LINE + 5 +1276 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531862.1619532432 + 20 +191843.1437172973 + 30 +0.0 + 11 +531905.1166278249 + 21 +191892.2934230909 + 31 +0.0 + 0 +LINE + 5 +1277 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531813.6265465071 + 20 +191853.1377074801 + 30 +0.0 + 11 +531883.9188933896 + 21 +191776.0537986287 + 31 +0.0 + 0 +LINE + 5 +1278 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531759.8220053184 + 20 +191689.9565078141 + 30 +0.0 + 11 +532001.7885916345 + 21 +191864.9162244624 + 31 +0.0 + 0 +LINE + 5 +1279 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532009.5993555495 + 20 +191963.144278935 + 30 +0.0 + 11 +532062.6930700728 + 21 +191919.319386117 + 31 +0.0 + 0 +LINE + 5 +127A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532041.6784095048 + 20 +191895.395925665 + 30 +0.0 + 11 +532080.0783065855 + 21 +191941.6346525161 + 31 +0.0 + 0 +LINE + 5 +127B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532039.8978890943 + 20 +191903.8157894616 + 30 +0.0 + 11 +532094.2646485485 + 21 +191857.6342846829 + 31 +0.0 + 0 +LINE + 5 +127C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532090.5930872497 + 20 +191857.0520696418 + 30 +0.0 + 11 +532127.5334808851 + 21 +191899.3249582679 + 31 +0.0 + 0 +LINE + 5 +127D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532071.0861322011 + 20 +191942.51819341 + 30 +0.0 + 11 +532130.7055510295 + 21 +191893.0044307067 + 31 +0.0 + 0 +LINE + 5 +127E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531739.658856651 + 20 +192064.6516925016 + 30 +0.0 + 11 +531884.5843560669 + 21 +192286.0345043412 + 31 +0.0 + 0 +LINE + 5 +127F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531726.566720581 + 20 +190667.1991249742 + 30 +0.0 + 11 +531616.5188179025 + 21 +190751.1164965218 + 31 +0.0 + 0 +LINE + 5 +1280 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531689.9179736658 + 20 +190522.9069805326 + 30 +0.0 + 11 +531293.4720857064 + 21 +190711.8895869297 + 31 +0.0 + 0 +LINE + 5 +1281 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531647.4488907804 + 20 +190599.3061460694 + 30 +0.0 + 11 +531294.8772940742 + 21 +190794.98539113 + 31 +0.0 + 0 +LINE + 5 +1282 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531654.9420515791 + 20 +190806.1964255886 + 30 +0.0 + 11 +531464.5204324898 + 21 +190511.2376294206 + 31 +0.0 + 0 +LINE + 5 +1283 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531506.7950860217 + 20 +190920.7104162707 + 30 +0.0 + 11 +531461.9685388102 + 21 +190842.5268395827 + 31 +0.0 + 0 +LINE + 5 +1284 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531464.5931598749 + 20 +190989.1469239503 + 30 +0.0 + 11 +531239.4060213708 + 21 +190574.130174695 + 31 +0.0 + 0 +LINE + 5 +1285 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531640.0236801546 + 20 +190456.680085379 + 30 +0.0 + 11 +531260.9006169267 + 21 +190646.6825308323 + 31 +0.0 + 0 +LINE + 5 +1286 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531212.7647778893 + 20 +190266.6331710364 + 30 +0.0 + 11 +531265.7667397293 + 21 +190651.6799426009 + 31 +0.0 + 0 +LINE + 5 +1287 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531538.4481888635 + 20 +190513.2134292297 + 30 +0.0 + 11 +531512.1700264695 + 21 +190474.2317909991 + 31 +0.0 + 0 +LINE + 5 +1288 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531570.8038671595 + 20 +190449.0444265913 + 30 +0.0 + 11 +531511.32533623 + 21 +190475.9349826742 + 31 +0.0 + 0 +LINE + 5 +1289 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531532.3049148279 + 20 +190937.4342044066 + 30 +0.0 + 11 +531029.4371592352 + 21 +191062.0412965392 + 31 +0.0 + 0 +LINE + 5 +128A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531174.0280454086 + 20 +190565.5079602962 + 30 +0.0 + 11 +531255.8981468314 + 21 +190942.1803400939 + 31 +0.0 + 0 +LINE + 5 +128B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531066.6923456027 + 20 +190583.2937652071 + 30 +0.0 + 11 +531240.2799829301 + 21 +191318.6432960578 + 31 +0.0 + 0 +LINE + 5 +128C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531121.7169474838 + 20 +191114.404787088 + 30 +0.0 + 11 +530725.2710595243 + 21 +191303.3873934849 + 31 +0.0 + 0 +LINE + 5 +128D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531141.6748513727 + 20 +191180.9728657711 + 30 +0.0 + 11 +531079.1927368576 + 21 +190997.3822792003 + 31 +0.0 + 0 +LINE + 5 +128E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531072.5902794654 + 20 +191203.3272866175 + 30 +0.0 + 11 +531052.3737678636 + 21 +191142.278630934 + 31 +0.0 + 0 +LINE + 5 +128F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531126.7883308363 + 20 +191207.7810777936 + 30 +0.0 + 11 +531059.1956883039 + 21 +191194.8007003539 + 31 +0.0 + 0 +LINE + 5 +1290 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530935.1011591012 + 20 +191270.8061954971 + 30 +0.0 + 11 +530726.6762678921 + 21 +191386.4831976849 + 31 +0.0 + 0 +LINE + 5 +1291 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530953.2732856884 + 20 +190903.5946479108 + 30 +0.0 + 11 +530869.7672241239 + 21 +190921.4288129707 + 31 +0.0 + 0 +LINE + 5 +1292 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530833.6801901157 + 20 +191463.6086225853 + 30 +0.0 + 11 +530751.3796565852 + 21 +191262.9827624679 + 31 +0.0 + 0 +LINE + 5 +1293 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531071.8226539727 + 20 +191048.1778919344 + 30 +0.0 + 11 +530692.6995907446 + 21 +191238.1803373874 + 31 +0.0 + 0 +LINE + 5 +1294 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530970.1073805743 + 20 +190833.7492594184 + 30 +0.0 + 11 +530656.0666857695 + 21 +190950.6610823109 + 31 +0.0 + 0 +LINE + 5 +1295 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531007.3683808244 + 20 +190919.5876067948 + 30 +0.0 + 11 +530952.3740462676 + 21 +190811.3143936106 + 31 +0.0 + 0 +LINE + 5 +1296 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531056.9548449825 + 20 +190898.2385704325 + 30 +0.0 + 11 +531005.2221560326 + 21 +190919.2468970518 + 31 +0.0 + 0 +LINE + 5 +1297 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531351.6830331344 + 20 +190732.7188390835 + 30 +0.0 + 11 +530810.8970529181 + 21 +190887.8577834759 + 31 +0.0 + 0 +LINE + 5 +1298 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530804.3060749416 + 20 +190899.153303579 + 30 +0.0 + 11 +530797.7914018496 + 21 +190875.7585689889 + 31 +0.0 + 0 +LINE + 5 +1299 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530880.0908578202 + 20 +190911.1804543932 + 30 +0.0 + 11 +530754.7490637765 + 21 +190579.0008599418 + 31 +0.0 + 0 +LINE + 5 +129A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531079.0840550969 + 20 +190598.7784309232 + 30 +0.0 + 11 +530880.8373040431 + 21 +190550.5614832236 + 31 +0.0 + 0 +LINE + 5 +129B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530896.9626566423 + 20 +190523.9661088623 + 30 +0.0 + 11 +530888.458537283 + 21 +190868.8703849999 + 31 +0.0 + 0 +LINE + 5 +129C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531275.0677919114 + 20 +190573.5068405064 + 30 +0.0 + 11 +531006.3020893577 + 21 +190593.8566231087 + 31 +0.0 + 0 +LINE + 5 +129D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530970.2471626816 + 20 +191104.7112357848 + 30 +0.0 + 11 +530943.9690002872 + 21 +191065.7295975544 + 31 +0.0 + 0 +LINE + 5 +129E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531002.6028409777 + 20 +191040.5422331465 + 30 +0.0 + 11 +530943.124310048 + 21 +191067.4327892296 + 31 +0.0 + 0 +LINE + 5 +129F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531042.6135389779 + 20 +191069.7776498928 + 30 +0.0 + 11 +531010.6510620626 + 21 +190970.4733543993 + 31 +0.0 + 0 +LINE + 5 +12A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531208.6881942397 + 20 +190701.6625239569 + 30 +0.0 + 11 +531100.1918312319 + 21 +190732.2093692526 + 31 +0.0 + 0 +LINE + 5 +12A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530830.6549453034 + 20 +190611.4441596177 + 30 +0.0 + 11 +530764.056769029 + 21 +190455.2469107448 + 31 +0.0 + 0 +LINE + 5 +12A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531242.6196049599 + 20 +190415.6898667019 + 30 +0.0 + 11 +530544.3562548107 + 21 +190704.3070771961 + 31 +0.0 + 0 +LINE + 5 +12A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530727.0770821876 + 20 +190554.695375905 + 30 +0.0 + 11 +530469.9007345941 + 21 +190102.2421574541 + 31 +0.0 + 0 +LINE + 5 +12A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530664.5429181734 + 20 +190585.0121263624 + 30 +0.0 + 11 +530835.8220088523 + 21 +190494.0561413587 + 31 +0.0 + 0 +LINE + 5 +12A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530691.5892971918 + 20 +190658.1596607209 + 30 +0.0 + 11 +530637.7408111629 + 21 +190505.793009922 + 31 +0.0 + 0 +LINE + 5 +12A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530644.8837157669 + 20 +190524.9513678989 + 30 +0.0 + 11 +530408.283807146 + 21 +190309.9650283871 + 31 +0.0 + 0 +LINE + 5 +12A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530877.0520145585 + 20 +190435.3827700694 + 30 +0.0 + 11 +530601.5820498165 + 21 +190117.8783408983 + 31 +0.0 + 0 +LINE + 5 +12A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531054.4286939304 + 20 +190338.687258596 + 30 +0.0 + 11 +530936.7322763709 + 21 +190368.6041237431 + 31 +0.0 + 0 +LINE + 5 +12A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530980.8907961061 + 20 +190460.6585950796 + 30 +0.0 + 11 +531074.4363116233 + 21 +190384.2585460425 + 31 +0.0 + 0 +LINE + 5 +12AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531071.0174015519 + 20 +190390.0624818143 + 30 +0.0 + 11 +531052.7589149675 + 21 +190337.296502614 + 31 +0.0 + 0 +LINE + 5 +12AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531140.5475894979 + 20 +190720.8600624002 + 30 +0.0 + 11 +531140.5422983688 + 21 +190720.8488089252 + 31 +0.0 + 0 +LINE + 5 +12AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531078.2713602384 + 20 +190588.4074195735 + 30 +0.0 + 11 +530552.7345483289 + 21 +189682.8822585834 + 31 +0.0 + 0 +LINE + 5 +12AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530740.7727734767 + 20 +190317.1978880576 + 30 +0.0 + 11 +531066.8566840048 + 21 +190154.7626582723 + 31 +0.0 + 0 +LINE + 5 +12AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531172.6815375744 + 20 +190253.818759882 + 30 +0.0 + 11 +530909.3841886824 + 21 +190320.3433067586 + 31 +0.0 + 0 +LINE + 5 +12AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530987.1866687095 + 20 +190401.4729746934 + 30 +0.0 + 11 +531019.2011780268 + 21 +190386.0760619135 + 31 +0.0 + 0 +LINE + 5 +12B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530566.5142077983 + 20 +190379.8042986561 + 30 +0.0 + 11 +530746.7878817967 + 21 +190371.4603050605 + 31 +0.0 + 0 +LINE + 5 +12B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530781.0020856237 + 20 +190425.3279099487 + 30 +0.0 + 11 +530744.9717957172 + 21 +190370.8979930163 + 31 +0.0 + 0 +LINE + 5 +12B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530901.6456101665 + 20 +190564.5576699728 + 30 +0.0 + 11 +530819.3367933233 + 21 +190344.7005378771 + 31 +0.0 + 0 +LINE + 5 +12B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531173.5166906944 + 20 +190402.5463365411 + 30 +0.0 + 11 +531124.6031772562 + 21 +190605.9791849102 + 31 +0.0 + 0 +LINE + 5 +12B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530763.4899419086 + 20 +190422.1215619297 + 30 +0.0 + 11 +530863.9868964326 + 21 +190361.8674686729 + 31 +0.0 + 0 +LINE + 5 +12B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531652.7245492292 + 20 +190802.7615644275 + 30 +0.0 + 11 +531643.2365683611 + 21 +191000.68622286 + 31 +0.0 + 0 +LINE + 5 +12B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528736.092904392 + 20 +189686.6373637899 + 30 +0.0 + 11 +528620.6891533154 + 21 +189412.8596400124 + 31 +0.0 + 0 +LINE + 5 +12B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528883.5141672747 + 20 +189434.6341329915 + 30 +0.0 + 11 +528683.3253642974 + 21 +189608.9101625759 + 31 +0.0 + 0 +LINE + 5 +12B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528709.7858504974 + 20 +189222.7317666962 + 30 +0.0 + 11 +528856.699215057 + 21 +189525.0171630695 + 31 +0.0 + 0 +LINE + 5 +12B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528945.836060306 + 20 +189561.5091656175 + 30 +0.0 + 11 +528833.2640107872 + 21 +189703.6819148343 + 31 +0.0 + 0 +LINE + 5 +12BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529194.1836177331 + 20 +189955.6672653194 + 30 +0.0 + 11 +529067.4219150274 + 21 +190060.0594324565 + 31 +0.0 + 0 +LINE + 5 +12BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528825.4410240728 + 20 +189476.1355913837 + 30 +0.0 + 11 +529002.9047942007 + 21 +189643.1357616589 + 31 +0.0 + 0 +LINE + 5 +12BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528660.7678825191 + 20 +189590.7707751939 + 30 +0.0 + 11 +528833.2171205858 + 21 +189824.0458195359 + 31 +0.0 + 0 +LINE + 5 +12BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530606.7976766392 + 20 +190323.4935651079 + 30 +0.0 + 11 +530953.6176210528 + 21 +190051.2345594849 + 31 +0.0 + 0 +LINE + 5 +12BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530952.1102433072 + 20 +189920.7174612524 + 30 +0.0 + 11 +530840.126610297 + 21 +189582.7534186109 + 31 +0.0 + 0 +LINE + 5 +12BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531395.6742002643 + 20 +190631.2880820697 + 30 +0.0 + 11 +531358.5835637108 + 21 +190314.4144565366 + 31 +0.0 + 0 +LINE + 5 +12C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529420.8840551164 + 20 +188885.5709871339 + 30 +0.0 + 11 +529215.7566812801 + 21 +189003.180972715 + 31 +0.0 + 0 +LINE + 5 +12C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529578.2053426957 + 20 +190618.865623553 + 30 +0.0 + 11 +529786.5781078201 + 21 +190957.2416225101 + 31 +0.0 + 0 +LINE + 5 +12C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528306.4601697287 + 20 +191394.6659840302 + 30 +0.0 + 11 +530681.24822964 + 21 +190279.6287509912 + 31 +0.0 + 0 +LINE + 5 +12C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530786.8875049436 + 20 +191256.1992820703 + 30 +0.0 + 11 +530934.3568216041 + 21 +191452.1553284745 + 31 +0.0 + 0 +LINE + 5 +12C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530810.6600446865 + 20 +191279.9374053675 + 30 +0.0 + 11 +530574.7165782317 + 21 +191331.7965642098 + 31 +0.0 + 0 +LINE + 5 +12C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530611.9717645991 + 20 +190853.0490328778 + 30 +0.0 + 11 +530785.5594019265 + 21 +191588.3985637284 + 31 +0.0 + 0 +LINE + 5 +12C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530666.9963664804 + 20 +191384.1600547587 + 30 +0.0 + 11 +530270.5504785207 + 21 +191573.1426611555 + 31 +0.0 + 0 +LINE + 5 +12C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530686.9542703694 + 20 +191450.7281334419 + 30 +0.0 + 11 +530624.4721558542 + 21 +191267.1375468709 + 31 +0.0 + 0 +LINE + 5 +12C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530617.8696984619 + 20 +191473.0825542882 + 30 +0.0 + 11 +530597.6531868602 + 21 +191412.0338986045 + 31 +0.0 + 0 +LINE + 5 +12C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530624.5272835949 + 20 +191460.5592202951 + 30 +0.0 + 11 +530271.9556868885 + 21 +191656.2384653555 + 31 +0.0 + 0 +LINE + 5 +12CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530572.4341909653 + 20 +191574.9456245721 + 30 +0.0 + 11 +530411.0970229937 + 21 +191325.2440993296 + 31 +0.0 + 0 +LINE + 5 +12CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530423.6971041789 + 20 +191320.9388758374 + 30 +0.0 + 11 +530215.7578632887 + 21 +191438.3996939469 + 31 +0.0 + 0 +LINE + 5 +12CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530422.6754470898 + 20 +191130.4008035777 + 30 +0.0 + 11 +530416.2354834049 + 21 +191337.4404344914 + 31 +0.0 + 0 +LINE + 5 +12CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530498.5527046849 + 20 +191173.3499155815 + 30 +0.0 + 11 +530415.0466431205 + 21 +191191.1840806411 + 31 +0.0 + 0 +LINE + 5 +12CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530378.9596091123 + 20 +191733.363890256 + 30 +0.0 + 11 +530216.4844141852 + 21 +191435.3832489207 + 31 +0.0 + 0 +LINE + 5 +12CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530617.1020729691 + 20 +191317.9331596048 + 30 +0.0 + 11 +530237.9790097414 + 21 +191507.9356050581 + 31 +0.0 + 0 +LINE + 5 +12D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530170.4777954436 + 20 +190974.1342686499 + 30 +0.0 + 11 +530242.845132544 + 21 +191512.9330168268 + 31 +0.0 + 0 +LINE + 5 +12D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530263.0237728314 + 20 +190999.9196945033 + 30 +0.0 + 11 +530168.6750936133 + 21 +191069.8328868142 + 31 +0.0 + 0 +LINE + 5 +12D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530271.8171301251 + 20 +191061.3825817094 + 30 +0.0 + 11 +530164.8331375071 + 21 +191036.4822563365 + 31 +0.0 + 0 +LINE + 5 +12D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530311.2013704974 + 20 +191247.264696152 + 30 +0.0 + 11 +530251.7666616241 + 21 +191054.1980062689 + 31 +0.0 + 0 +LINE + 5 +12D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530515.3867995707 + 20 +191103.5045270889 + 30 +0.0 + 11 +530201.3461047661 + 21 +191220.4163499817 + 31 +0.0 + 0 +LINE + 5 +12D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530552.647799821 + 20 +191189.3428744654 + 30 +0.0 + 11 +530497.6534652642 + 21 +191081.0696612813 + 31 +0.0 + 0 +LINE + 5 +12D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530602.234263979 + 20 +191167.9938381031 + 30 +0.0 + 11 +530550.5015750291 + 21 +191189.0021647223 + 31 +0.0 + 0 +LINE + 5 +12D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531277.3814127393 + 20 +190896.6993731198 + 30 +0.0 + 11 +530356.1764719148 + 21 +191157.6130511465 + 31 +0.0 + 0 +LINE + 5 +12D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530349.5854939382 + 20 +191168.9085712497 + 30 +0.0 + 11 +530343.0708208462 + 21 +191145.5138366594 + 31 +0.0 + 0 +LINE + 5 +12D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530257.914889346 + 20 +191335.4912681963 + 30 +0.0 + 11 +530213.295080578 + 21 +191343.4417297378 + 31 +0.0 + 0 +LINE + 5 +12DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530272.2328318559 + 20 +191341.5180590523 + 30 +0.0 + 11 +530249.3817584041 + 21 +191333.969888762 + 31 +0.0 + 0 +LINE + 5 +12DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530294.2377954327 + 20 +191401.7198153854 + 30 +0.0 + 11 +530267.6322056853 + 21 +191334.9814833307 + 31 +0.0 + 0 +LINE + 5 +12DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530425.3702768167 + 20 +191180.9357220638 + 30 +0.0 + 11 +530300.0284827732 + 21 +190848.7561276125 + 31 +0.0 + 0 +LINE + 5 +12DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530624.3634740933 + 20 +190868.5336985939 + 30 +0.0 + 11 +530426.1167230396 + 21 +190820.3167508943 + 31 +0.0 + 0 +LINE + 5 +12DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530442.2420756388 + 20 +190793.721376533 + 30 +0.0 + 11 +530433.7379562795 + 21 +191138.6256526705 + 31 +0.0 + 0 +LINE + 5 +12DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530557.2083504603 + 20 +191102.9471589445 + 30 +0.0 + 11 +530547.1130889521 + 21 +191068.8872202327 + 31 +0.0 + 0 +LINE + 5 +12E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530372.3499657048 + 20 +191004.6811445212 + 30 +0.0 + 11 +530280.8611844596 + 21 +191023.1647347263 + 31 +0.0 + 0 +LINE + 5 +12E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530314.2554430935 + 20 +191012.1938829203 + 30 +0.0 + 11 +530255.222864584 + 21 +191071.0813766387 + 31 +0.0 + 0 +LINE + 5 +12E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530319.9218190236 + 20 +191024.032936741 + 30 +0.0 + 11 +530242.384921647 + 21 +191003.7307899842 + 31 +0.0 + 0 +LINE + 5 +12E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530226.7956803922 + 20 +190889.9725558877 + 30 +0.0 + 11 +530249.9963712407 + 21 +191013.8022231446 + 31 +0.0 + 0 +LINE + 5 +12E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530843.0219665133 + 20 +190748.4988920565 + 30 +0.0 + 11 +530551.5815083543 + 21 +190863.6118907793 + 31 +0.0 + 0 +LINE + 5 +12E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530515.5265816781 + 20 +191374.4665034555 + 30 +0.0 + 11 +530489.2484192839 + 21 +191335.4848652249 + 31 +0.0 + 0 +LINE + 5 +12E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530547.8822599742 + 20 +191310.297500817 + 30 +0.0 + 11 +530488.4037290445 + 21 +191337.1880569003 + 31 +0.0 + 0 +LINE + 5 +12E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530587.8929579744 + 20 +191339.5329175635 + 30 +0.0 + 11 +530555.9304810591 + 21 +191240.2286220699 + 31 +0.0 + 0 +LINE + 5 +12E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530704.5671822437 + 20 +191213.3974429023 + 30 +0.0 + 11 +530411.8118187123 + 21 +191272.1599178894 + 31 +0.0 + 0 +LINE + 5 +12E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530363.9397497025 + 20 +191358.287867634 + 30 +0.0 + 11 +530333.8220195336 + 21 +191296.3807914483 + 31 +0.0 + 0 +LINE + 5 +12EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530362.8699991715 + 20 +191283.3361451236 + 30 +0.0 + 11 +530308.7435676297 + 21 +191309.4685266677 + 31 +0.0 + 0 +LINE + 5 +12EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530360.9956112147 + 20 +191291.7356111226 + 30 +0.0 + 11 +530330.6976633138 + 21 +191227.1561231241 + 31 +0.0 + 0 +LINE + 5 +12EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530334.2797357945 + 20 +191228.1501520307 + 30 +0.0 + 11 +530283.1270503726 + 21 +191251.2800584046 + 31 +0.0 + 0 +LINE + 5 +12ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530316.5581169064 + 20 +191314.0042365652 + 30 +0.0 + 11 +530282.8641361738 + 21 +191244.2130948573 + 31 +0.0 + 0 +LINE + 5 +12EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530753.9676132364 + 20 +190971.4177916275 + 30 +0.0 + 11 +530645.4712502283 + 21 +191001.964636923 + 31 +0.0 + 0 +LINE + 5 +12EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530188.6951548543 + 20 +191012.6301874295 + 30 +0.0 + 11 +529846.2858622457 + 21 +190650.5201306966 + 31 +0.0 + 0 +LINE + 5 +12F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530200.2539482312 + 20 +190944.8408733593 + 30 +0.0 + 11 +530035.3632543009 + 21 +190788.3782138476 + 31 +0.0 + 0 +LINE + 5 +12F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530375.9343643 + 20 +190881.1994272883 + 30 +0.0 + 11 +530309.3361880256 + 21 +190725.0021784153 + 31 +0.0 + 0 +LINE + 5 +12F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530671.8834682779 + 20 +190733.3985119153 + 30 +0.0 + 11 +530089.6356738072 + 21 +190974.0623448668 + 31 +0.0 + 0 +LINE + 5 +12F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530209.82233717 + 20 +190854.7673940329 + 30 +0.0 + 11 +530381.1014278488 + 21 +190763.8114090294 + 31 +0.0 + 0 +LINE + 5 +12F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530176.738479037 + 20 +190790.1310533407 + 30 +0.0 + 11 +530233.7825995969 + 21 +190760.4390676936 + 31 +0.0 + 0 +LINE + 5 +12F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530180.983468939 + 20 +190844.3458584129 + 30 +0.0 + 11 +530183.0202301594 + 21 +190775.5482775925 + 31 +0.0 + 0 +LINE + 5 +12F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530190.1631347634 + 20 +190794.7066355697 + 30 +0.0 + 11 +529953.5632261425 + 21 +190579.7202960579 + 31 +0.0 + 0 +LINE + 5 +12F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530422.331433555 + 20 +190705.13803774 + 30 +0.0 + 11 +530242.3648234194 + 21 +190452.4459640357 + 31 +0.0 + 0 +LINE + 5 +12F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530685.8270084943 + 20 +190990.6153300706 + 30 +0.0 + 11 +530685.8217173655 + 21 +190990.6040765957 + 31 +0.0 + 0 +LINE + 5 +12F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530658.1253966024 + 20 +190512.595404907 + 30 +0.0 + 11 +530294.1637362402 + 21 +190689.0570376765 + 31 +0.0 + 0 +LINE + 5 +12FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530111.7936267947 + 20 +190649.5595663267 + 30 +0.0 + 11 +530292.0673007933 + 21 +190641.2155727311 + 31 +0.0 + 0 +LINE + 5 +12FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530326.2815046201 + 20 +190695.0831776194 + 30 +0.0 + 11 +530290.2512147138 + 21 +190640.653260687 + 31 +0.0 + 0 +LINE + 5 +12FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530446.9250291631 + 20 +190834.3129376435 + 30 +0.0 + 11 +530364.6162123198 + 21 +190614.4558055476 + 31 +0.0 + 0 +LINE + 5 +12FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529939.939415788 + 20 +190809.8789550084 + 30 +0.0 + 11 +530130.9635013352 + 21 +190639.1185579506 + 31 +0.0 + 0 +LINE + 5 +12FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529654.0128583817 + 20 +191008.5990400711 + 30 +0.0 + 11 +529538.5254608057 + 21 +191180.5570084886 + 31 +0.0 + 0 +LINE + 5 +12FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529909.9204973347 + 20 +191073.5304972992 + 30 +0.0 + 11 +529577.0660346956 + 21 +191424.229912995 + 31 +0.0 + 0 +LINE + 5 +1300 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530097.8222530831 + 20 +190903.6018086659 + 30 +0.0 + 11 +529709.5386221093 + 21 +191278.0391841883 + 31 +0.0 + 0 +LINE + 5 +1301 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529859.7970559477 + 20 +190995.6823473421 + 30 +0.0 + 11 +529895.6832068345 + 21 +191107.4934018215 + 31 +0.0 + 0 +LINE + 5 +1302 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529816.8157740735 + 20 +191040.488809428 + 30 +0.0 + 11 +529918.2503592541 + 21 +191082.6388486844 + 31 +0.0 + 0 +LINE + 5 +1303 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529676.4362978191 + 20 +191168.5391179237 + 30 +0.0 + 11 +529837.294298447 + 21 +191046.3428209456 + 31 +0.0 + 0 +LINE + 5 +1304 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529488.6195087556 + 20 +190778.8154378799 + 30 +0.0 + 11 +529781.3394002914 + 21 +191210.780711083 + 31 +0.0 + 0 +LINE + 5 +1305 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529690.9396844112 + 20 +191082.5003184239 + 30 +0.0 + 11 +529709.8731834154 + 21 +191067.2925182051 + 31 +0.0 + 0 +LINE + 5 +1306 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529622.3579484594 + 20 +191048.0832998647 + 30 +0.0 + 11 +529979.350393128 + 21 +190800.6693161047 + 31 +0.0 + 0 +LINE + 5 +1307 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529947.6250255865 + 20 +190799.1961620026 + 30 +0.0 + 11 +530031.2524980849 + 21 +190982.2829122324 + 31 +0.0 + 0 +LINE + 5 +1308 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529909.4806381238 + 20 +190695.8884812792 + 30 +0.0 + 11 +529640.2297696372 + 21 +191008.8308089954 + 31 +0.0 + 0 +LINE + 5 +1309 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529768.2020691272 + 20 +190935.8054215372 + 30 +0.0 + 11 +529831.7520282783 + 21 +191004.1665427424 + 31 +0.0 + 0 +LINE + 5 +130A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529811.0187018545 + 20 +190975.7822993236 + 30 +0.0 + 11 +529824.6421644078 + 21 +191058.0439763673 + 31 +0.0 + 0 +LINE + 5 +130B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529799.5121885463 + 20 +190982.096660973 + 30 +0.0 + 11 +529874.3423080562 + 21 +191010.812524739 + 31 +0.0 + 0 +LINE + 5 +130C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529993.9717421925 + 20 +190894.018633101 + 30 +0.0 + 11 +529862.2862323207 + 21 +191014.5567160643 + 31 +0.0 + 0 +LINE + 5 +130D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530063.611379089 + 20 +191307.3573994773 + 30 +0.0 + 11 +530244.8025817625 + 21 +191460.1788907737 + 31 +0.0 + 0 +LINE + 5 +130E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530040.5595935753 + 20 +191391.4442571109 + 30 +0.0 + 11 +530112.0895504901 + 21 +191344.8096666741 + 31 +0.0 + 0 +LINE + 5 +130F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530083.6719299731 + 20 +191102.1464075275 + 30 +0.0 + 11 +530199.7744952403 + 21 +191084.5474851844 + 31 +0.0 + 0 +LINE + 5 +1310 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530121.0518461871 + 20 +191151.7221223488 + 30 +0.0 + 11 +530178.8362248517 + 21 +191058.3060291823 + 31 +0.0 + 0 +LINE + 5 +1311 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530020.7508118557 + 20 +191352.3139438574 + 30 +0.0 + 11 +530222.6566959106 + 21 +191208.0085902876 + 31 +0.0 + 0 +LINE + 5 +1312 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529931.2589248137 + 20 +191293.1742514133 + 30 +0.0 + 11 +530009.4340328605 + 21 +191386.1049675863 + 31 +0.0 + 0 +LINE + 5 +1313 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529919.8842639817 + 20 +191435.1441300177 + 30 +0.0 + 11 +529888.4329338768 + 21 +191318.5313314026 + 31 +0.0 + 0 +LINE + 5 +1314 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529887.8264005807 + 20 +191325.2400372301 + 30 +0.0 + 11 +529933.4263986319 + 21 +191293.0179784648 + 31 +0.0 + 0 +LINE + 5 +1315 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529766.283442222 + 20 +191482.1497039964 + 30 +0.0 + 11 +530129.7983159895 + 21 +191279.3947547383 + 31 +0.0 + 0 +LINE + 5 +1316 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530097.5431574947 + 20 +191344.9030318181 + 30 +0.0 + 11 +529941.6740523123 + 21 +191030.1101691833 + 31 +0.0 + 0 +LINE + 5 +1317 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529869.9817725534 + 20 +191099.9094151975 + 30 +0.0 + 11 +530061.6424893936 + 21 +191321.0011059216 + 31 +0.0 + 0 +LINE + 5 +1318 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529949.2789497925 + 20 +191383.3896314849 + 30 +0.0 + 11 +529932.2472777902 + 21 +191352.2140660729 + 31 +0.0 + 0 +LINE + 5 +1319 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530009.9563679029 + 20 +191183.0222615452 + 30 +0.0 + 11 +530087.5758418096 + 21 +191131.1854264664 + 31 +0.0 + 0 +LINE + 5 +131A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530056.2488408661 + 20 +191147.127669437 + 30 +0.0 + 11 +530139.6303230878 + 21 +191146.7950067648 + 31 +0.0 + 0 +LINE + 5 +131B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530060.6477213065 + 20 +191159.4937869528 + 30 +0.0 + 11 +530100.927754787 + 21 +191090.1997286182 + 31 +0.0 + 0 +LINE + 5 +131C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530004.702835088 + 20 +190953.4781887471 + 30 +0.0 + 11 +530102.7017201151 + 21 +191102.6985676777 + 31 +0.0 + 0 +LINE + 5 +131D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529923.683773368 + 20 +191565.7595233935 + 30 +0.0 + 11 +530171.786933398 + 21 +191399.6163522243 + 31 +0.0 + 0 +LINE + 5 +131E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530467.8923355064 + 20 +191673.3362207413 + 30 +0.0 + 11 +530355.9087024962 + 21 +191335.3721780998 + 31 +0.0 + 0 +LINE + 5 +131F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +531840.7935770436 + 20 +189057.792002755 + 30 +0.0 + 11 +531982.1822814013 + 21 +189216.3451605004 + 31 +0.0 + 0 +LINE + 5 +1320 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +532397.1314996439 + 20 +186862.2401610883 + 30 +0.0 + 11 +532751.6338472817 + 21 +186400.5866240799 + 31 +0.0 + 0 +LINE + 5 +1321 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529390.5920680657 + 20 +178053.3126901525 + 30 +0.0 + 11 +530115.1553102974 + 21 +178218.3674452636 + 31 +0.0 + 0 +LINE + 5 +1322 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529588.7373599372 + 20 +178091.3637877734 + 30 +0.0 + 11 +529220.8203963338 + 21 +178791.6550297485 + 31 +0.0 + 0 +LINE + 5 +1323 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529522.027867812 + 20 +178212.0012265017 + 30 +0.0 + 11 +529662.3119211489 + 21 +178258.6711213384 + 31 +0.0 + 0 +LINE + 5 +1324 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529651.2157191435 + 20 +178109.9595009088 + 30 +0.0 + 11 +529420.4224018896 + 21 +178547.2455074355 + 31 +0.0 + 0 +LINE + 5 +1325 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529635.5138608472 + 20 +178240.0261699392 + 30 +0.0 + 11 +529687.7454499261 + 21 +178303.2160374569 + 31 +0.0 + 0 +LINE + 5 +1326 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529701.3864531909 + 20 +178195.1249762844 + 30 +0.0 + 11 +529634.440434588 + 21 +178252.0078302338 + 31 +0.0 + 0 +LINE + 5 +1327 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529682.8737538791 + 20 +178199.4838608876 + 30 +0.0 + 11 +529876.420257985 + 21 +178245.2441442418 + 31 +0.0 + 0 +LINE + 5 +1328 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529733.5857718822 + 20 +178087.8633627716 + 30 +0.0 + 11 +529700.2622754637 + 21 +178519.5446872525 + 31 +0.0 + 0 +LINE + 5 +1329 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529870.3293648365 + 20 +178300.9853595905 + 30 +0.0 + 11 +529683.6765661495 + 21 +178301.741337488 + 31 +0.0 + 0 +LINE + 5 +132A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529873.7351080664 + 20 +178240.4707767044 + 30 +0.0 + 11 +529869.6943259762 + 21 +178301.5468993824 + 31 +0.0 + 0 +LINE + 5 +132B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530166.1098490548 + 20 +178294.9608130672 + 30 +0.0 + 11 +529869.2240375089 + 21 +178280.6506399475 + 31 +0.0 + 0 +LINE + 5 +132C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530098.0406759726 + 20 +178288.0142161451 + 30 +0.0 + 11 +530084.8929137669 + 21 +178400.3749640314 + 31 +0.0 + 0 +LINE + 5 +132D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530166.28914748 + 20 +178403.7599636211 + 30 +0.0 + 11 +529351.949710317 + 21 +178348.293701919 + 31 +0.0 + 0 +LINE + 5 +132E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529633.3820592434 + 20 +178437.1764218828 + 30 +0.0 + 11 +529512.4457275377 + 21 +178859.3827355189 + 31 +0.0 + 0 +LINE + 5 +132F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529564.4324633867 + 20 +178428.4827311594 + 30 +0.0 + 11 +529755.8193743748 + 21 +178459.7967601896 + 31 +0.0 + 0 +LINE + 5 +1330 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529553.7906139416 + 20 +178500.3099491722 + 30 +0.0 + 11 +529617.3392258458 + 21 +178510.169950549 + 31 +0.0 + 0 +LINE + 5 +1331 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529540.4498922314 + 20 +178447.5909756185 + 30 +0.0 + 11 +529564.4116247705 + 21 +178512.1129943156 + 31 +0.0 + 0 +LINE + 5 +1332 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529565.0429286165 + 20 +178491.6761349184 + 30 +0.0 + 11 +529430.2582499482 + 21 +178871.7158540896 + 31 +0.0 + 0 +LINE + 5 +1333 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529359.7546940634 + 20 +178518.4432037213 + 30 +0.0 + 11 +529733.7382635378 + 21 +178679.8370821898 + 31 +0.0 + 0 +LINE + 5 +1334 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529735.9041441907 + 20 +178666.6991235893 + 30 +0.0 + 11 +529654.3858264684 + 21 +178891.1774868423 + 31 +0.0 + 0 +LINE + 5 +1335 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529923.9961336309 + 20 +178636.2490944916 + 30 +0.0 + 11 +529720.8609436733 + 21 +178676.7827410348 + 31 +0.0 + 0 +LINE + 5 +1336 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529869.1091454615 + 20 +178568.5039620335 + 30 +0.0 + 11 +529865.3064953427 + 21 +178653.8084731304 + 31 +0.0 + 0 +LINE + 5 +1337 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529297.2528540473 + 20 +178610.462173554 + 30 +0.0 + 11 +529381.7643390703 + 21 +178641.7655263754 + 31 +0.0 + 0 +LINE + 5 +1338 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529210.7412612053 + 20 +178736.3848983364 + 30 +0.0 + 11 +529657.2409238578 + 21 +178889.9628940308 + 31 +0.0 + 0 +LINE + 5 +1339 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529706.9376248931 + 20 +178475.4520136958 + 30 +0.0 + 11 +529582.1354664721 + 21 +178880.7415985645 + 31 +0.0 + 0 +LINE + 5 +133A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530059.7092555507 + 20 +178862.7149028401 + 30 +0.0 + 11 +529576.4032417384 + 21 +178876.7673218856 + 31 +0.0 + 0 +LINE + 5 +133B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530312.7701853247 + 20 +178874.6729484941 + 30 +0.0 + 11 +529773.4183123891 + 21 +178866.4825009502 + 31 +0.0 + 0 +LINE + 5 +133C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530079.0449972051 + 20 +178772.167551013 + 30 +0.0 + 11 +530025.6681078049 + 21 +178876.7640873191 + 31 +0.0 + 0 +LINE + 5 +133D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530016.9737908839 + 20 +178773.6423330408 + 30 +0.0 + 11 +530059.1953704929 + 21 +178875.0471608128 + 31 +0.0 + 0 +LINE + 5 +133E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529827.1402371451 + 20 +178765.487534809 + 30 +0.0 + 11 +530027.3700867477 + 21 +178792.2314815871 + 31 +0.0 + 0 +LINE + 5 +133F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529935.2167503272 + 20 +178540.3694703332 + 30 +0.0 + 11 +529871.7571494588 + 21 +178869.4026166622 + 31 +0.0 + 0 +LINE + 5 +1340 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529844.4046062384 + 20 +178517.7916381525 + 30 +0.0 + 11 +529960.2714997501 + 21 +178554.1554734086 + 31 +0.0 + 0 +LINE + 5 +1341 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529971.0478116974 + 20 +178452.6277842837 + 30 +0.0 + 11 +529851.3161161499 + 21 +178468.5039314089 + 31 +0.0 + 0 +LINE + 5 +1342 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529857.2739883265 + 20 +178465.3609430782 + 30 +0.0 + 11 +529845.0949802163 + 21 +178519.8521593871 + 31 +0.0 + 0 +LINE + 5 +1343 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529971.8629280645 + 20 +178147.3501551373 + 30 +0.0 + 11 +529908.1362417926 + 21 +178706.3282208272 + 31 +0.0 + 0 +LINE + 5 +1344 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529898.0838949129 + 20 +178714.6936309961 + 30 +0.0 + 11 +529922.23314985 + 21 +178717.2564532717 + 31 +0.0 + 0 +LINE + 5 +1345 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529748.9219505447 + 20 +178832.6088930304 + 30 +0.0 + 11 +529748.4472840071 + 21 +178877.9289974535 + 31 +0.0 + 0 +LINE + 5 +1346 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529740.6139858995 + 20 +178819.4824537115 + 30 +0.0 + 11 +529751.8312643767 + 21 +178840.7737452691 + 31 +0.0 + 0 +LINE + 5 +1347 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529677.6053795027 + 20 +178807.7187209904 + 30 +0.0 + 11 +529747.8204193533 + 21 +178822.9407625761 + 31 +0.0 + 0 +LINE + 5 +1348 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529873.7097927802 + 20 +178641.9345159805 + 30 +0.0 + 11 +530301.3177057517 + 21 +178718.1497223015 + 31 +0.0 + 0 +LINE + 5 +1349 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530279.8565997225 + 20 +178694.7383990443 + 30 +0.0 + 11 +530210.0881816244 + 21 +178883.5416831849 + 31 +0.0 + 0 +LINE + 5 +134A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530148.9711179213 + 20 +178394.0948102993 + 30 +0.0 + 11 +530284.3736267778 + 21 +178730.6222615631 + 31 +0.0 + 0 +LINE + 5 +134B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530308.4283792124 + 20 +178592.96658897 + 30 +0.0 + 11 +529914.0577438836 + 21 +178626.6963115775 + 31 +0.0 + 0 +LINE + 5 +134C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529928.8617689076 + 20 +178499.0298163773 + 30 +0.0 + 11 +529964.1210211301 + 21 +178503.3632748896 + 31 +0.0 + 0 +LINE + 5 +134D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530056.2992316162 + 20 +178665.127754665 + 30 +0.0 + 11 +530053.1740083323 + 21 +178758.4126579452 + 31 +0.0 + 0 +LINE + 5 +134E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530058.4809445885 + 20 +178723.6653914825 + 30 +0.0 + 11 +530010.1477911528 + 21 +178791.6101375701 + 31 +0.0 + 0 +LINE + 5 +134F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530045.868844705 + 20 +178720.0313925719 + 30 +0.0 + 11 +530078.6936574002 + 21 +178793.1523833286 + 31 +0.0 + 0 +LINE + 5 +1350 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530245.8754076924 + 20 +178794.6613581359 + 30 +0.0 + 11 +530067.5037911571 + 21 +178787.3081704402 + 31 +0.0 + 0 +LINE + 5 +1351 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530273.0675218956 + 20 +178208.0096468544 + 30 +0.0 + 11 +530096.6192585914 + 21 +178215.9086817285 + 31 +0.0 + 0 +LINE + 5 +1352 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530158.6363406193 + 20 +178201.8413428505 + 30 +0.0 + 11 +530165.8416213736 + 21 +178465.0654016896 + 31 +0.0 + 0 +LINE + 5 +1353 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529667.9501122793 + 20 +178584.9671873393 + 30 +0.0 + 11 +529710.7353059648 + 21 +178604.4489002836 + 31 +0.0 + 0 +LINE + 5 +1354 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529725.8966288471 + 20 +178542.4612814524 + 30 +0.0 + 11 +529709.1949448264 + 21 +178605.5631942513 + 31 +0.0 + 0 +LINE + 5 +1355 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529690.4566796745 + 20 +178507.8263922591 + 30 +0.0 + 11 +529793.675196943 + 21 +178522.9551968021 + 31 +0.0 + 0 +LINE + 5 +1356 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529795.5983844062 + 20 +178371.9284360456 + 30 +0.0 + 11 +529785.9759576364 + 21 +178670.3679445664 + 31 +0.0 + 0 +LINE + 5 +1357 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529708.9335792827 + 20 +178731.8027120526 + 30 +0.0 + 11 +529774.9635139324 + 21 +178751.2863329311 + 31 +0.0 + 0 +LINE + 5 +1358 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529783.0333527766 + 20 +178720.4833197699 + 30 +0.0 + 11 +529766.195812011 + 21 +178778.1814061991 + 31 +0.0 + 0 +LINE + 5 +1359 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529775.0586125864 + 20 +178723.7187298189 + 30 +0.0 + 11 +529843.7540392793 + 21 +178742.9388824889 + 31 +0.0 + 0 +LINE + 5 +135A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529842.1822544748 + 20 +178739.5700801422 + 30 +0.0 + 11 +529827.8150230222 + 21 +178793.839523249 + 31 +0.0 + 0 +LINE + 5 +135B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529760.4321706216 + 20 +178771.2229377899 + 30 +0.0 + 11 +529834.828413398 + 21 +178792.9320800863 + 31 +0.0 + 0 +LINE + 5 +135C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530026.101377302 + 20 +178283.255303252 + 30 +0.0 + 11 +530013.8863797965 + 21 +178395.3060256032 + 31 +0.0 + 0 +LINE + 5 +135D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529473.7643035521 + 20 +178564.8684743813 + 30 +0.0 + 11 +529371.3688412569 + 21 +178808.8539638275 + 31 +0.0 + 0 +LINE + 5 +135E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529032.4566797877 + 20 +178870.0605803373 + 30 +0.0 + 11 +529172.7407331247 + 21 +178916.7304751739 + 31 +0.0 + 0 +LINE + 5 +135F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529161.6445311194 + 20 +178768.0188547444 + 30 +0.0 + 11 +528930.8512138653 + 21 +179205.304861271 + 31 +0.0 + 0 +LINE + 5 +1360 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529145.9426728229 + 20 +178898.0855237747 + 30 +0.0 + 11 +529198.1742619019 + 21 +178961.2753912924 + 31 +0.0 + 0 +LINE + 5 +1361 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529211.8152651667 + 20 +178853.1843301198 + 30 +0.0 + 11 +529144.8692465639 + 21 +178910.0671840692 + 31 +0.0 + 0 +LINE + 5 +1362 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529195.0257614894 + 20 +178858.1359249845 + 30 +0.0 + 11 +529388.5722655955 + 21 +178903.8962083386 + 31 +0.0 + 0 +LINE + 5 +1363 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529250.5651757271 + 20 +178661.0646291282 + 30 +0.0 + 11 +529210.6910874394 + 21 +179177.6040410879 + 31 +0.0 + 0 +LINE + 5 +1364 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529380.7581768124 + 20 +178959.044713426 + 30 +0.0 + 11 +529194.1053781251 + 21 +178959.8006913236 + 31 +0.0 + 0 +LINE + 5 +1365 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529384.1639200421 + 20 +178898.53013054 + 30 +0.0 + 11 +529380.123137952 + 21 +178959.6062532179 + 31 +0.0 + 0 +LINE + 5 +1366 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529676.5386610307 + 20 +178953.0201669028 + 30 +0.0 + 11 +529379.6528494846 + 21 +178938.7099937831 + 31 +0.0 + 0 +LINE + 5 +1367 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529608.4694879482 + 20 +178946.0735699806 + 30 +0.0 + 11 +529595.3217257426 + 21 +179058.4343178669 + 31 +0.0 + 0 +LINE + 5 +1368 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529676.7179594558 + 20 +179061.8193174565 + 30 +0.0 + 11 +528922.8004795738 + 21 +179012.0193788653 + 31 +0.0 + 0 +LINE + 5 +1369 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529143.8108712193 + 20 +179095.2357757184 + 30 +0.0 + 11 +528987.872384487 + 21 +179724.1392376596 + 31 +0.0 + 0 +LINE + 5 +136A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529074.8612753623 + 20 +179086.5420849948 + 30 +0.0 + 11 +529266.2481863507 + 21 +179117.8561140251 + 31 +0.0 + 0 +LINE + 5 +136B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529064.2194259175 + 20 +179158.3693030075 + 30 +0.0 + 11 +529127.7680378215 + 21 +179168.2293043844 + 31 +0.0 + 0 +LINE + 5 +136C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529050.8787042071 + 20 +179105.6503294541 + 30 +0.0 + 11 +529074.8404367462 + 21 +179170.1723481511 + 31 +0.0 + 0 +LINE + 5 +136D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529075.4717405924 + 20 +179149.735488754 + 30 +0.0 + 11 +529028.4832144465 + 21 +179282.2246296349 + 31 +0.0 + 0 +LINE + 5 +136E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528870.1835060391 + 20 +179176.5025575568 + 30 +0.0 + 11 +529244.1670755135 + 21 +179337.8964360254 + 31 +0.0 + 0 +LINE + 5 +136F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529246.3329561665 + 20 +179324.7584774249 + 30 +0.0 + 11 +529164.8146384443 + 21 +179549.2368406779 + 31 +0.0 + 0 +LINE + 5 +1370 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529434.4249456065 + 20 +179294.3084483272 + 30 +0.0 + 11 +529231.2897556491 + 21 +179334.8420948704 + 31 +0.0 + 0 +LINE + 5 +1371 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529379.5379574373 + 20 +179226.5633158691 + 30 +0.0 + 11 +529375.7353073186 + 21 +179311.8678269659 + 31 +0.0 + 0 +LINE + 5 +1372 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528804.6219794623 + 20 +179283.2325338339 + 30 +0.0 + 11 +528889.1334644851 + 21 +179314.5358866552 + 31 +0.0 + 0 +LINE + 5 +1373 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529217.3664368688 + 20 +179133.5113675314 + 30 +0.0 + 11 +529092.5642784479 + 21 +179538.8009524001 + 31 +0.0 + 0 +LINE + 5 +1374 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529589.4738091809 + 20 +179430.2269048485 + 30 +0.0 + 11 +529536.0969197806 + 21 +179534.8234411546 + 31 +0.0 + 0 +LINE + 5 +1375 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529527.4026028597 + 20 +179431.7016868763 + 30 +0.0 + 11 +529569.6241824687 + 21 +179533.1065146484 + 31 +0.0 + 0 +LINE + 5 +1376 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529337.5690491209 + 20 +179423.5468886444 + 30 +0.0 + 11 +529537.7988987233 + 21 +179450.2908354228 + 31 +0.0 + 0 +LINE + 5 +1377 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529445.6455623029 + 20 +179198.4288241688 + 30 +0.0 + 11 +529373.454971783 + 21 +179620.5635239094 + 31 +0.0 + 0 +LINE + 5 +1378 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529354.8334182141 + 20 +179175.850991988 + 30 +0.0 + 11 +529470.7003117257 + 21 +179212.2148272441 + 31 +0.0 + 0 +LINE + 5 +1379 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529481.4766236733 + 20 +179110.6871381193 + 30 +0.0 + 11 +529361.7449281256 + 21 +179126.5632852444 + 31 +0.0 + 0 +LINE + 5 +137A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529367.7028003022 + 20 +179123.4202969139 + 30 +0.0 + 11 +529355.523792192 + 21 +179177.9115132226 + 31 +0.0 + 0 +LINE + 5 +137B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529482.2917400402 + 20 +178805.4095089728 + 30 +0.0 + 11 +529418.5650537684 + 21 +179364.3875746627 + 31 +0.0 + 0 +LINE + 5 +137C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529408.5127068887 + 20 +179372.7529848317 + 30 +0.0 + 11 +529432.6619618259 + 21 +179375.3158071073 + 31 +0.0 + 0 +LINE + 5 +137D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529259.3507625205 + 20 +179490.6682468659 + 30 +0.0 + 11 +529255.8735480284 + 21 +179568.0055555123 + 31 +0.0 + 0 +LINE + 5 +137E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529251.0427978754 + 20 +179477.541807547 + 30 +0.0 + 11 +529262.2600763525 + 21 +179498.8330991046 + 31 +0.0 + 0 +LINE + 5 +137F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529188.0341914784 + 20 +179465.778074826 + 30 +0.0 + 11 +529258.249231329 + 21 +179481.0001164117 + 31 +0.0 + 0 +LINE + 5 +1380 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529384.1386047561 + 20 +179299.9938698159 + 30 +0.0 + 11 +529732.453511002 + 21 +179368.7730410141 + 31 +0.0 + 0 +LINE + 5 +1381 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529659.3999298971 + 20 +179052.1541641347 + 30 +0.0 + 11 +529739.685557499 + 21 +179239.7197962464 + 31 +0.0 + 0 +LINE + 5 +1382 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529763.253681698 + 20 +179219.4248595483 + 30 +0.0 + 11 +529424.4865558593 + 21 +179284.7556654132 + 31 +0.0 + 0 +LINE + 5 +1383 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529439.2905808833 + 20 +179157.0891702127 + 30 +0.0 + 11 +529474.549833106 + 21 +179161.4226287252 + 31 +0.0 + 0 +LINE + 5 +1384 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529566.728043592 + 20 +179323.1871085005 + 30 +0.0 + 11 +529563.6028203082 + 21 +179416.4720117807 + 31 +0.0 + 0 +LINE + 5 +1385 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529568.9097565642 + 20 +179381.7247453179 + 30 +0.0 + 11 +529520.5766031286 + 21 +179449.6694914057 + 31 +0.0 + 0 +LINE + 5 +1386 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529556.2976566809 + 20 +179378.0907464075 + 30 +0.0 + 11 +529589.1224693758 + 21 +179451.2117371642 + 31 +0.0 + 0 +LINE + 5 +1387 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529703.8933669607 + 20 +179447.8056638777 + 30 +0.0 + 11 +529577.9326031328 + 21 +179445.3675242758 + 31 +0.0 + 0 +LINE + 5 +1388 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529651.9679774769 + 20 +178854.6875987086 + 30 +0.0 + 11 +529676.2704333494 + 21 +179123.124755525 + 31 +0.0 + 0 +LINE + 5 +1389 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529178.378924255 + 20 +179243.0265411749 + 30 +0.0 + 11 +529221.1641179405 + 21 +179262.5082541191 + 31 +0.0 + 0 +LINE + 5 +138A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529236.3254408228 + 20 +179200.5206352878 + 30 +0.0 + 11 +529219.623756802 + 21 +179263.6225480869 + 31 +0.0 + 0 +LINE + 5 +138B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529200.8854916501 + 20 +179165.8857460946 + 30 +0.0 + 11 +529304.1040089189 + 21 +179181.0145506376 + 31 +0.0 + 0 +LINE + 5 +138C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529306.027196382 + 20 +179029.9877898812 + 30 +0.0 + 11 +529296.4047696122 + 21 +179328.427298402 + 31 +0.0 + 0 +LINE + 5 +138D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529219.3623912584 + 20 +179389.8620658881 + 30 +0.0 + 11 +529285.392325908 + 21 +179409.3456867667 + 31 +0.0 + 0 +LINE + 5 +138E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529293.4621647522 + 20 +179378.5426736056 + 30 +0.0 + 11 +529276.6246239869 + 21 +179436.2407600347 + 31 +0.0 + 0 +LINE + 5 +138F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529285.4874245623 + 20 +179381.7780836545 + 30 +0.0 + 11 +529354.1828512551 + 21 +179400.9982363247 + 31 +0.0 + 0 +LINE + 5 +1390 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529352.6110664505 + 20 +179397.6294339777 + 30 +0.0 + 11 +529338.243834998 + 21 +179451.8988770846 + 31 +0.0 + 0 +LINE + 5 +1391 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529270.8609825975 + 20 +179429.2822916254 + 30 +0.0 + 11 +529345.2572253737 + 21 +179450.9914339217 + 31 +0.0 + 0 +LINE + 5 +1392 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529536.5301892779 + 20 +178941.3146570876 + 30 +0.0 + 11 +529524.3151917721 + 21 +179053.3653794388 + 31 +0.0 + 0 +LINE + 5 +1393 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528984.1931155279 + 20 +179222.9278282168 + 30 +0.0 + 11 +528881.7976532325 + 21 +179466.913317663 + 31 +0.0 + 0 +LINE + 5 +1394 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528256.2762777142 + 20 +179214.9213572008 + 30 +0.0 + 11 +530103.7181598913 + 21 +179877.1135497176 + 31 +0.0 + 0 +LINE + 5 +1395 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529654.1600247581 + 20 +179483.0418736856 + 30 +0.0 + 11 +529835.6988509518 + 21 +179619.8379238862 + 31 +0.0 + 0 +LINE + 5 +1396 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529687.9234379178 + 20 +179299.2651771761 + 30 +0.0 + 11 +529852.9724886179 + 21 +179339.161398821 + 31 +0.0 + 0 +LINE + 5 +1397 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529812.9763927825 + 20 +178860.6350568236 + 30 +0.0 + 11 +529635.628069068 + 21 +179631.6345729913 + 31 +0.0 + 0 +LINE + 5 +1398 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529760.9940699366 + 20 +179392.0524657283 + 30 +0.0 + 11 +530158.5156557565 + 21 +179578.7617488612 + 31 +0.0 + 0 +LINE + 5 +1399 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529741.4176915706 + 20 +179458.7337407407 + 30 +0.0 + 11 +529802.8474606397 + 21 +179274.78836411 + 31 +0.0 + 0 +LINE + 5 +139A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529810.6291420638 + 20 +179480.6921862162 + 30 +0.0 + 11 +529830.4957305616 + 21 +179419.5287628033 + 31 +0.0 + 0 +LINE + 5 +139B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529756.457483715 + 20 +179485.4562664032 + 30 +0.0 + 11 +529823.9746865969 + 21 +179472.0890363976 + 31 +0.0 + 0 +LINE + 5 +139C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529803.899951935 + 20 +179468.2071818381 + 30 +0.0 + 11 +530157.5863137912 + 21 +179661.8642374505 + 31 +0.0 + 0 +LINE + 5 +139D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529794.8493942628 + 20 +179677.7989024762 + 30 +0.0 + 11 +530016.551838801 + 21 +179331.6720833669 + 31 +0.0 + 0 +LINE + 5 +139E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530003.9273105937 + 20 +179327.439084107 + 30 +0.0 + 11 +530212.5357747149 + 21 +179443.7072241541 + 31 +0.0 + 0 +LINE + 5 +139F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530003.8578455762 + 20 +179136.8982854884 + 30 +0.0 + 11 +530011.4833042558 + 21 +179343.8976436545 + 31 +0.0 + 0 +LINE + 5 +13A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529928.2277777098 + 20 +179180.2812000585 + 30 +0.0 + 11 +530011.8345964161 + 21 +179197.6368800278 + 31 +0.0 + 0 +LINE + 5 +13A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529868.044136958 + 20 +180083.1249647489 + 30 +0.0 + 11 +530211.7919622313 + 21 +179440.6949891383 + 31 +0.0 + 0 +LINE + 5 +13A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529810.5083008496 + 20 +179325.540939631 + 30 +0.0 + 11 +530190.7131860163 + 21 +179513.3692432622 + 31 +0.0 + 0 +LINE + 5 +13A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530249.0655645315 + 20 +179039.0310878337 + 30 +0.0 + 11 +530185.8757603917 + 21 +179518.3944386658 + 31 +0.0 + 0 +LINE + 5 +13A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530294.6453275093 + 20 +178828.2357818487 + 30 +0.0 + 11 +530207.136287022 + 21 +179322.2600316574 + 31 +0.0 + 0 +LINE + 5 +13A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530162.7597095563 + 20 +179005.505079643 + 30 +0.0 + 11 +530257.5071957045 + 21 +179074.8768433358 + 31 +0.0 + 0 +LINE + 5 +13A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530154.3184601428 + 20 +179067.0173137474 + 30 +0.0 + 11 +530261.1581083423 + 21 +179041.5047589406 + 31 +0.0 + 0 +LINE + 5 +13A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530115.9993088026 + 20 +179253.1219120244 + 30 +0.0 + 11 +530174.3274578325 + 21 +179059.7180382476 + 31 +0.0 + 0 +LINE + 5 +13A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529943.3485241449 + 20 +179121.6943172797 + 30 +0.0 + 11 +530225.6990278078 + 21 +179225.6449261795 + 31 +0.0 + 0 +LINE + 5 +13A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529919.992444411 + 20 +179033.5303585037 + 30 +0.0 + 11 +529909.9177026341 + 21 +179154.5508737263 + 31 +0.0 + 0 +LINE + 5 +13AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529811.8359642482 + 20 +179126.1964533755 + 30 +0.0 + 11 +529871.7432927308 + 21 +179021.321084674 + 31 +0.0 + 0 +LINE + 5 +13AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529866.583463484 + 20 +179025.6513016039 + 30 +0.0 + 11 +529921.639794042 + 21 +179034.9476104859 + 31 +0.0 + 0 +LINE + 5 +13AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529528.8460521422 + 20 +179011.6896635413 + 30 +0.0 + 11 +529528.8580247461 + 21 +179011.6930241212 + 31 +0.0 + 0 +LINE + 5 +13AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529669.7627948629 + 20 +179051.2434616328 + 30 +0.0 + 11 +530070.5115597969 + 21 +179163.7292843079 + 31 +0.0 + 0 +LINE + 5 +13AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530077.1671128554 + 20 +179174.9868763492 + 30 +0.0 + 11 +530083.5477105241 + 21 +179151.5552194418 + 31 +0.0 + 0 +LINE + 5 +13AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530169.790140668 + 20 +179341.0418955059 + 30 +0.0 + 11 +530214.4547457032 + 21 +179348.7367139115 + 31 +0.0 + 0 +LINE + 5 +13B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530155.5069449908 + 20 +179347.150578423 + 30 +0.0 + 11 +530178.3144196068 + 21 +179339.4716765309 + 31 +0.0 + 0 +LINE + 5 +13B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530133.8470841208 + 20 +179407.477357839 + 30 +0.0 + 11 +530160.0700644021 + 21 +179340.5877646542 + 31 +0.0 + 0 +LINE + 5 +13B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530001.4524453501 + 20 +179187.4478071817 + 30 +0.0 + 11 +530112.8405056052 + 21 +178854.307559915 + 31 +0.0 + 0 +LINE + 5 +13B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530012.787356849 + 20 +178853.2658569171 + 30 +0.0 + 11 +529992.8426168967 + 21 +179145.18634855 + 31 +0.0 + 0 +LINE + 5 +13B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529869.1699363119 + 20 +179110.215485955 + 30 +0.0 + 11 +529879.0699900083 + 21 +179076.0982957604 + 31 +0.0 + 0 +LINE + 5 +13B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530053.4625753887 + 20 +179010.8925017714 + 30 +0.0 + 11 +530145.0557017851 + 21 +179028.851883651 + 31 +0.0 + 0 +LINE + 5 +13B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530111.5991667361 + 20 +179018.0724420342 + 30 +0.0 + 11 +530170.9679931944 + 21 +179076.6209235426 + 31 +0.0 + 0 +LINE + 5 +13B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530106.0006793766 + 20 +179029.9437499166 + 30 +0.0 + 11 +530183.4200463617 + 21 +179009.1979254373 + 31 +0.0 + 0 +LINE + 5 +13B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530211.5666022765 + 20 +178844.3956620246 + 30 +0.0 + 11 +530175.8663950519 + 21 +179019.3127799945 + 31 +0.0 + 0 +LINE + 5 +13B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529912.4058616428 + 20 +179381.4916903172 + 30 +0.0 + 11 +529938.4603670565 + 21 +179342.3602108463 + 31 +0.0 + 0 +LINE + 5 +13BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529879.6832537396 + 20 +179317.5090227454 + 30 +0.0 + 11 +529939.3147966758 + 21 +179344.0585375256 + 31 +0.0 + 0 +LINE + 5 +13BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529839.8406267025 + 20 +179346.9730791118 + 30 +0.0 + 11 +529871.2339191949 + 21 +179247.487380539 + 31 +0.0 + 0 +LINE + 5 +13BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529722.446007878 + 20 +179221.5078008555 + 30 +0.0 + 11 +530015.5330712783 + 21 +179278.5928655428 + 31 +0.0 + 0 +LINE + 5 +13BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530063.8975621379 + 20 +179364.4452664547 + 30 +0.0 + 11 +530093.660291165 + 21 +179302.3667378539 + 31 +0.0 + 0 +LINE + 5 +13BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530064.538088384 + 20 +179289.4886470033 + 30 +0.0 + 11 +530118.8132780433 + 21 +179315.310648166 + 31 +0.0 + 0 +LINE + 5 +13BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530066.4605446687 + 20 +179297.8772417078 + 30 +0.0 + 11 +530096.3881850598 + 21 +179233.1253131048 + 31 +0.0 + 0 +LINE + 5 +13C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530092.811863561 + 20 +179234.139838246 + 30 +0.0 + 11 +530144.0961623568 + 21 +179256.9764424545 + 31 +0.0 + 0 +LINE + 5 +13C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530111.0248303785 + 20 +179319.8910332636 + 30 +0.0 + 11 +530144.3186036829 + 21 +179249.9080892157 + 31 +0.0 + 0 +LINE + 5 +13C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529861.6016424258 + 20 +179569.9884220753 + 30 +0.0 + 11 +530086.1388329739 + 21 +179709.9769923934 + 31 +0.0 + 0 +LINE + 5 +13C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529622.5161699437 + 20 +178175.7189232008 + 30 +0.0 + 11 +529077.4038483118 + 21 +177670.6570250304 + 31 +0.0 + 0 +LINE + 5 +13C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529774.3187212543 + 20 +177482.138466658 + 30 +0.0 + 11 +528687.2778214917 + 21 +179514.0567645756 + 31 +0.0 + 0 +LINE + 5 +13C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529417.3393448741 + 20 +178156.7481172629 + 30 +0.0 + 11 +529299.651861507 + 21 +178067.2643144636 + 31 +0.0 + 0 +LINE + 5 +13C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529428.6886676548 + 20 +177992.5128970265 + 30 +0.0 + 11 +529197.8953504009 + 21 +178429.7989035533 + 31 +0.0 + 0 +LINE + 5 +13C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529330.1661889128 + 20 +178078.8680238525 + 30 +0.0 + 11 +529248.5245953539 + 21 +178071.4015350011 + 31 +0.0 + 0 +LINE + 5 +13C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529330.0669757164 + 20 +177999.1478521863 + 30 +0.0 + 11 +529320.8798790198 + 21 +178086.5150413052 + 31 +0.0 + 0 +LINE + 5 +13C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529336.9143225266 + 20 +178016.8914074236 + 30 +0.0 + 11 +529189.9238064542 + 21 +177882.9211085918 + 31 +0.0 + 0 +LINE + 5 +13CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529400.4528063577 + 20 +177912.0405350285 + 30 +0.0 + 11 +529062.8618736286 + 21 +178183.1338463775 + 31 +0.0 + 0 +LINE + 5 +13CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529147.3409759589 + 20 +177919.4023998922 + 30 +0.0 + 11 +529252.0380194656 + 21 +178073.9286689897 + 31 +0.0 + 0 +LINE + 5 +13CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529195.3798063321 + 20 +177882.4445238005 + 30 +0.0 + 11 +529147.2356998853 + 21 +177920.2435409268 + 31 +0.0 + 0 +LINE + 5 +13CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528985.4169776725 + 20 +177671.8079557215 + 30 +0.0 + 11 +529164.7529224974 + 21 +177908.8408332845 + 31 +0.0 + 0 +LINE + 5 +13CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529029.5609383942 + 20 +177724.08585033 + 30 +0.0 + 11 +528944.2152067236 + 21 +177798.3415396893 + 31 +0.0 + 0 +LINE + 5 +13CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528895.4917239208 + 20 +177733.0512087936 + 30 +0.0 + 11 +529395.5462928345 + 21 +178370.1010164841 + 31 +0.0 + 0 +LINE + 5 +13D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529168.6027359841 + 20 +178191.8725241933 + 30 +0.0 + 11 +528888.2709667337 + 21 +178529.9521993433 + 31 +0.0 + 0 +LINE + 5 +13D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529214.6858789368 + 20 +178243.8914723069 + 30 +0.0 + 11 +529080.8407019511 + 21 +178103.5526440751 + 31 +0.0 + 0 +LINE + 5 +13D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529161.3904520156 + 20 +178293.2067404935 + 30 +0.0 + 11 +529117.3919810326 + 21 +178246.304925462 + 31 +0.0 + 0 +LINE + 5 +13D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529212.4426651124 + 20 +178274.4734394976 + 30 +0.0 + 11 +529145.6528736322 + 21 +178291.0980982021 + 31 +0.0 + 0 +LINE + 5 +13D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529162.1692304324 + 20 +178279.0451431864 + 30 +0.0 + 11 +528924.464112137 + 21 +178604.7649222723 + 31 +0.0 + 0 +LINE + 5 +13D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529255.9069136356 + 20 +178463.6338263879 + 30 +0.0 + 11 +528911.6359587691 + 21 +178245.9432113415 + 31 +0.0 + 0 +LINE + 5 +13D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528921.2604722176 + 20 +178236.7418127482 + 30 +0.0 + 11 +528781.9298895611 + 21 +178430.7076871426 + 31 +0.0 + 0 +LINE + 5 +13D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528840.2666205454 + 20 +178064.2721146709 + 30 +0.0 + 11 +528921.423797634 + 21 +178254.8512176915 + 31 +0.0 + 0 +LINE + 5 +13D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528927.1673621965 + 20 +178071.3605236999 + 30 +0.0 + 11 +528858.8860398547 + 21 +178122.6341112539 + 31 +0.0 + 0 +LINE + 5 +13D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529169.5950389337 + 20 +178629.8001218609 + 30 +0.0 + 11 +529096.0644715597 + 21 +178577.691133574 + 31 +0.0 + 0 +LINE + 5 +13DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529160.0579374052 + 20 +178709.6349629289 + 30 +0.0 + 11 +528781.3216274457 + 21 +178427.6651825823 + 31 +0.0 + 0 +LINE + 5 +13DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529095.4979343949 + 20 +178152.7428659879 + 30 +0.0 + 11 +528831.3138803026 + 21 +178484.4686743191 + 31 +0.0 + 0 +LINE + 5 +13DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528628.0581488629 + 20 +178204.8741762493 + 30 +0.0 + 11 +528837.8295044756 + 21 +178486.9586376026 + 31 +0.0 + 0 +LINE + 5 +13DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528424.0543547561 + 20 +177877.8356717893 + 30 +0.0 + 11 +528562.8268120758 + 21 +178074.4044123051 + 31 +0.0 + 0 +LINE + 5 +13DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529216.8899173546 + 20 +177748.886168231 + 30 +0.0 + 11 +528791.3587558008 + 21 +178116.9089922682 + 31 +0.0 + 0 +LINE + 5 +13DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528790.12447374 + 20 +178129.9284512769 + 30 +0.0 + 11 +528774.3821003199 + 21 +178111.4370410781 + 31 +0.0 + 0 +LINE + 5 +13E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528776.9406634209 + 20 +178319.6110330121 + 30 +0.0 + 11 +528726.5995712288 + 21 +178356.5059315515 + 31 +0.0 + 0 +LINE + 5 +13E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528792.4656647689 + 20 +178319.063293216 + 30 +0.0 + 11 +528768.558181954 + 21 +178321.8162367464 + 31 +0.0 + 0 +LINE + 5 +13E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528837.7311428057 + 20 +178364.4450779506 + 30 +0.0 + 11 +528785.5441805669 + 21 +178315.0650886479 + 31 +0.0 + 0 +LINE + 5 +13E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528755.2984108906 + 20 +177649.3990332462 + 30 +0.0 + 11 +528534.7752388648 + 21 +177705.6368993211 + 31 +0.0 + 0 +LINE + 5 +13E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528913.2431451212 + 20 +177741.8952113882 + 30 +0.0 + 11 +528727.5188711966 + 21 +177633.1306766926 + 31 +0.0 + 0 +LINE + 5 +13E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528996.851259631 + 20 +177534.4409062467 + 30 +0.0 + 11 +529089.8929912046 + 21 +177684.5729166937 + 31 +0.0 + 0 +LINE + 5 +13E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529066.5130080652 + 20 +177625.4342248347 + 30 +0.0 + 11 +528845.1307561178 + 21 +177768.0130442476 + 31 +0.0 + 0 +LINE + 5 +13E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529027.0818980847 + 20 +178246.7260845622 + 30 +0.0 + 11 +528986.8558042628 + 21 +178222.3956239463 + 31 +0.0 + 0 +LINE + 5 +13E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529029.4775335915 + 20 +178174.901215971 + 30 +0.0 + 11 +528986.8050162779 + 21 +178224.2960933789 + 31 +0.0 + 0 +LINE + 5 +13E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529078.0693745433 + 20 +178184.6171070637 + 30 +0.0 + 11 +529007.3367636004 + 21 +178107.936987194 + 31 +0.0 + 0 +LINE + 5 +13EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529130.9385857497 + 20 +178021.1304743279 + 30 +0.0 + 11 +528889.9778635624 + 21 +178197.4729300951 + 31 +0.0 + 0 +LINE + 5 +13EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528882.7297250409 + 20 +178295.7441018924 + 30 +0.0 + 11 +528829.3859203152 + 21 +178252.2239657511 + 31 +0.0 + 0 +LINE + 5 +13EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528850.2632399967 + 20 +178228.1805583032 + 30 +0.0 + 11 +528812.1287559493 + 21 +178274.6384218255 + 31 +0.0 + 0 +LINE + 5 +13ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528852.0919470814 + 20 +178236.5900879977 + 30 +0.0 + 11 +528797.4616232942 + 21 +178190.7206685541 + 31 +0.0 + 0 +LINE + 5 +13EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528801.1297903722 + 20 +178190.1174380736 + 30 +0.0 + 11 +528764.4320756943 + 21 +178232.6011706328 + 31 +0.0 + 0 +LINE + 5 +13EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528821.1258424423 + 20 +178275.4704550611 + 30 +0.0 + 11 +528761.2238634208 + 21 +178226.2989113819 + 31 +0.0 + 0 +LINE + 5 +13F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529090.8056720976 + 20 +178811.7223970167 + 30 +0.0 + 11 +528921.4179963483 + 21 +178657.3388480305 + 31 +0.0 + 0 +LINE + 5 +13F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529053.9482432962 + 20 +178755.0734565325 + 30 +0.0 + 11 +528795.8177370931 + 21 +178958.6398040954 + 31 +0.0 + 0 +LINE + 5 +13F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528880.2968394233 + 20 +178694.9083576101 + 30 +0.0 + 11 +528984.9938829302 + 21 +178849.4346267077 + 31 +0.0 + 0 +LINE + 5 +13F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528928.3356697966 + 20 +178657.9504815182 + 30 +0.0 + 11 +528880.1915633499 + 21 +178695.7494986447 + 31 +0.0 + 0 +LINE + 5 +13F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528718.372841137 + 20 +178447.3139134394 + 30 +0.0 + 11 +528897.7087859617 + 21 +178684.3467910024 + 31 +0.0 + 0 +LINE + 5 +13F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528695.6708666394 + 20 +178589.6934914857 + 30 +0.0 + 11 +529094.9695538866 + 21 +179102.887760648 + 31 +0.0 + 0 +LINE + 5 +13F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528901.5585994485 + 20 +178967.3784819112 + 30 +0.0 + 11 +528732.141915289 + 21 +179171.6947379631 + 31 +0.0 + 0 +LINE + 5 +13F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528947.6417424012 + 20 +179019.3974300246 + 30 +0.0 + 11 +528813.7965654157 + 21 +178879.0586017929 + 31 +0.0 + 0 +LINE + 5 +13F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528894.34631548 + 20 +179068.7126982114 + 30 +0.0 + 11 +528850.347844497 + 21 +179021.8108831797 + 31 +0.0 + 0 +LINE + 5 +13F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528945.3985285767 + 20 +179049.9793972156 + 30 +0.0 + 11 +528878.6087370967 + 21 +179066.6040559201 + 31 +0.0 + 0 +LINE + 5 +13FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528895.1250938969 + 20 +179054.5511009042 + 30 +0.0 + 11 +528657.4199756015 + 21 +179380.27087999 + 31 +0.0 + 0 +LINE + 5 +13FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528895.9212925059 + 20 +179180.2384345977 + 30 +0.0 + 11 +528644.5918222334 + 21 +179021.4491690592 + 31 +0.0 + 0 +LINE + 5 +13FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528654.216335682 + 20 +179012.2477704661 + 30 +0.0 + 11 +528514.8857530255 + 21 +179206.2136448606 + 31 +0.0 + 0 +LINE + 5 +13FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528586.5761248556 + 20 +178871.1360494124 + 30 +0.0 + 11 +528654.3796610985 + 21 +179030.3571754095 + 31 +0.0 + 0 +LINE + 5 +13FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528835.808251877 + 20 +178730.7567791569 + 30 +0.0 + 11 +528591.8419033192 + 21 +178898.1400689717 + 31 +0.0 + 0 +LINE + 5 +13FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528828.4537978593 + 20 +178928.2488237058 + 30 +0.0 + 11 +528564.269743767 + 21 +179259.9746320368 + 31 +0.0 + 0 +LINE + 5 +1400 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528269.2197572814 + 20 +178811.8149971797 + 30 +0.0 + 11 +528562.3417837797 + 21 +179027.729923469 + 31 +0.0 + 0 +LINE + 5 +1401 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528373.5205664697 + 20 +178788.4641264325 + 30 +0.0 + 11 +528317.2847204717 + 21 +178891.5517462234 + 31 +0.0 + 0 +LINE + 5 +1402 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528407.3274474087 + 20 +178840.5419954112 + 30 +0.0 + 11 +528299.7840299943 + 21 +178862.902993846 + 31 +0.0 + 0 +LINE + 5 +1403 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528949.8457808189 + 20 +178524.3921259489 + 30 +0.0 + 11 +528712.1583839063 + 21 +178736.7821449431 + 31 +0.0 + 0 +LINE + 5 +1404 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528735.5919425773 + 20 +178724.2733405178 + 30 +0.0 + 11 +528343.5785116573 + 21 +178635.7446258223 + 31 +0.0 + 0 +LINE + 5 +1405 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528456.8048605814 + 20 +178639.042180561 + 30 +0.0 + 11 +528418.2993716642 + 21 +178801.3636480728 + 31 +0.0 + 0 +LINE + 5 +1406 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528425.1672519241 + 20 +178778.0737645175 + 30 +0.0 + 11 +528396.3449656503 + 21 +178856.3160680103 + 31 +0.0 + 0 +LINE + 5 +1407 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528435.2839998973 + 20 +178786.435727325 + 30 +0.0 + 11 +528356.3938325171 + 21 +178800.5951449837 + 31 +0.0 + 0 +LINE + 5 +1408 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528294.4449571226 + 20 +178703.9188960649 + 30 +0.0 + 11 +528367.5328099538 + 21 +178806.5357773142 + 31 +0.0 + 0 +LINE + 5 +1409 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528813.4200762677 + 20 +178412.1139766217 + 30 +0.0 + 11 +528683.1105900724 + 21 +178484.8759271629 + 31 +0.0 + 0 +LINE + 5 +140A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528760.037761549 + 20 +179022.23204228 + 30 +0.0 + 11 +528719.8116677272 + 21 +178997.9015816641 + 31 +0.0 + 0 +LINE + 5 +140B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528762.4333970562 + 20 +178950.4071736888 + 30 +0.0 + 11 +528719.7608797423 + 21 +178999.8020510967 + 31 +0.0 + 0 +LINE + 5 +140C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528811.0252380077 + 20 +178960.1230647815 + 30 +0.0 + 11 +528740.292627065 + 21 +178883.4429449118 + 31 +0.0 + 0 +LINE + 5 +140D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528863.8944492142 + 20 +178796.6364320458 + 30 +0.0 + 11 +528622.9337270268 + 21 +178972.978887813 + 31 +0.0 + 0 +LINE + 5 +140E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528615.6855885053 + 20 +179071.2500596103 + 30 +0.0 + 11 +528562.3417837797 + 21 +179027.729923469 + 31 +0.0 + 0 +LINE + 5 +140F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528604.542523008 + 20 +178870.2673164959 + 30 +0.0 + 11 +528545.0846194137 + 21 +179050.1443795434 + 31 +0.0 + 0 +LINE + 5 +1410 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528807.0383873775 + 20 +178556.2992887536 + 30 +0.0 + 11 +528721.42228723 + 21 +178629.6099560472 + 31 +0.0 + 0 +LINE + 5 +1411 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528311.4140469933 + 20 +178831.2318750209 + 30 +0.0 + 11 +527764.9983652827 + 21 +178652.4227521558 + 31 +0.0 + 0 +LINE + 5 +1412 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528293.4167632091 + 20 +178764.8609884605 + 30 +0.0 + 11 +528078.0430157141 + 21 +178692.1722434146 + 31 +0.0 + 0 +LINE + 5 +1413 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528426.0905374633 + 20 +178633.2877697826 + 30 +0.0 + 11 +528300.0214083799 + 21 +178519.5359683435 + 31 +0.0 + 0 +LINE + 5 +1414 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528503.0450711533 + 20 +178515.8978525081 + 30 +0.0 + 11 +527848.7885761961 + 21 +179224.2979558424 + 31 +0.0 + 0 +LINE + 5 +1415 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528308.2547575839 + 20 +178625.3173770244 + 30 +0.0 + 11 +527929.8019000886 + 21 +178402.4784166646 + 31 +0.0 + 0 +LINE + 5 +1416 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528264.2492173824 + 20 +178679.1052888522 + 30 +0.0 + 11 +528381.4511659365 + 21 +178524.5956730775 + 31 +0.0 + 0 +LINE + 5 +1417 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528207.0669986657 + 20 +178634.3549584659 + 30 +0.0 + 11 +528246.3532710626 + 21 +178583.4409672331 + 31 +0.0 + 0 +LINE + 5 +1418 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528233.7008313366 + 20 +178681.767024288 + 30 +0.0 + 11 +528206.6393295455 + 21 +178618.4825029276 + 31 +0.0 + 0 +LINE + 5 +1419 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528221.171590992 + 20 +178632.8657273165 + 30 +0.0 + 11 +527861.7172574328 + 21 +178450.1372953824 + 31 +0.0 + 0 +LINE + 5 +141A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528053.8908279912 + 20 +178754.8365498442 + 30 +0.0 + 11 +528213.902859453 + 21 +178380.2596631688 + 31 +0.0 + 0 +LINE + 5 +141B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528224.5211522193 + 20 +178388.2938933077 + 30 +0.0 + 11 +528010.8207720457 + 21 +178281.6734487079 + 31 +0.0 + 0 +LINE + 5 +141C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528381.8699628479 + 20 +178280.8362153252 + 30 +0.0 + 11 +528206.6694766406 + 21 +178391.3426474184 + 31 +0.0 + 0 +LINE + 5 +141D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528388.7284378934 + 20 +178367.7554063139 + 30 +0.0 + 11 +528327.2234748795 + 21 +178308.5231576142 + 31 +0.0 + 0 +LINE + 5 +141E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527795.7539910907 + 20 +178699.4383652264 + 30 +0.0 + 11 +528013.7273650271 + 21 +178280.5878456312 + 31 +0.0 + 0 +LINE + 5 +141F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528335.2273462379 + 20 +178546.9086936534 + 30 +0.0 + 11 +527965.6217953812 + 21 +178338.9977436644 + 31 +0.0 + 0 +LINE + 5 +1420 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528324.307153484 + 20 +178023.1710512262 + 30 +0.0 + 11 +527964.202594872 + 21 +178345.8270295297 + 31 +0.0 + 0 +LINE + 5 +1421 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528451.1721830445 + 20 +177866.9365657112 + 30 +0.0 + 11 +528114.1337485903 + 21 +178217.6031442749 + 31 +0.0 + 0 +LINE + 5 +1422 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528400.6852306725 + 20 +178075.5073020777 + 30 +0.0 + 11 +528289.9497653272 + 21 +178036.4280947665 + 31 +0.0 + 0 +LINE + 5 +1423 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528354.6640913282 + 20 +178117.1854062772 + 30 +0.0 + 11 +528315.4415328623 + 21 +178014.5833020709 + 31 +0.0 + 0 +LINE + 5 +1424 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528222.6390442239 + 20 +178253.8333692926 + 30 +0.0 + 11 +528349.4000127607 + 21 +178096.5473615973 + 31 +0.0 + 0 +LINE + 5 +1425 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528428.5654308189 + 20 +178322.2134059058 + 30 +0.0 + 11 +528183.4244803492 + 21 +178147.7615489016 + 31 +0.0 + 0 +LINE + 5 +1426 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528498.0472897094 + 20 +178245.8844032025 + 30 +0.0 + 11 +528785.7765094022 + 21 +178228.4478699931 + 31 +0.0 + 0 +LINE + 5 +1427 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528753.2729735434 + 20 +178602.3532546211 + 30 +0.0 + 11 +528753.2634433724 + 21 +178602.3452663433 + 31 +0.0 + 0 +LINE + 5 +1428 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528526.2577362868 + 20 +178397.1155255769 + 30 +0.0 + 11 +528322.1082209895 + 21 +178240.946939484 + 31 +0.0 + 0 +LINE + 5 +1429 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528309.0585253266 + 20 +178241.8043823055 + 30 +0.0 + 11 +528324.8032623659 + 21 +178223.3149845974 + 31 +0.0 + 0 +LINE + 5 +142A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528119.700557502 + 20 +178259.033853847 + 30 +0.0 + 11 +528088.1451886887 + 21 +178226.5008571775 + 31 +0.0 + 0 +LINE + 5 +142B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528122.7167284986 + 20 +178274.2728957545 + 30 +0.0 + 11 +528116.1869921529 + 21 +178251.1102323525 + 31 +0.0 + 0 +LINE + 5 +142C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528085.1330619262 + 20 +178326.1953176414 + 30 +0.0 + 11 +528125.5601604262 + 21 +178266.8024554597 + 31 +0.0 + 0 +LINE + 5 +142D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528341.4937854892 + 20 +178311.3453024235 + 30 +0.0 + 11 +528553.6807481992 + 21 +178031.4052781823 + 31 +0.0 + 0 +LINE + 5 +142E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528537.3680729672 + 20 +178174.4241490659 + 30 +0.0 + 11 +528381.2428563006 + 21 +178294.6069810829 + 31 +0.0 + 0 +LINE + 5 +142F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528444.1633946261 + 20 +178700.1838262611 + 30 +0.0 + 11 +528548.3477819184 + 21 +178007.5561802428 + 31 +0.0 + 0 +LINE + 5 +1430 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528457.909674054 + 20 +178168.7824377468 + 30 +0.0 + 11 +528391.3999235287 + 21 +178103.2973762012 + 31 +0.0 + 0 +LINE + 5 +1431 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528419.1776495675 + 20 +178124.8365042053 + 30 +0.0 + 11 +528337.3406876953 + 21 +178108.8585846446 + 31 +0.0 + 0 +LINE + 5 +1432 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528412.535768426 + 20 +178136.1571237316 + 30 +0.0 + 11 +528385.9785806686 + 21 +178060.5339566718 + 31 +0.0 + 0 +LINE + 5 +1433 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528506.1565314453 + 20 +177944.3045508276 + 30 +0.0 + 11 +528381.8900450846 + 21 +178072.4776498863 + 31 +0.0 + 0 +LINE + 5 +1434 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528231.5376889895 + 20 +178494.3534429387 + 30 +0.0 + 11 +528249.142879486 + 21 +178450.7625355663 + 31 +0.0 + 0 +LINE + 5 +1435 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528302.8256281043 + 20 +178485.2660585849 + 30 +0.0 + 11 +528247.2586261313 + 21 +178451.0154244339 + 31 +0.0 + 0 +LINE + 5 +1436 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528470.8068808959 + 20 +178560.9105217073 + 30 +0.0 + 11 +528258.2996718624 + 21 +178351.1501406726 + 31 +0.0 + 0 +LINE + 5 +1437 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528160.1300526372 + 20 +178359.6639282912 + 30 +0.0 + 11 +528246.7934186207 + 21 +178217.2396902225 + 31 +0.0 + 0 +LINE + 5 +1438 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528104.5825630481 + 20 +178642.6588122643 + 30 +0.0 + 11 +527862.3107208053 + 21 +178536.2722331519 + 31 +0.0 + 0 +LINE + 5 +1439 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528974.2490269006 + 20 +177943.2169498362 + 30 +0.0 + 11 +529074.8116481313 + 21 +178075.7250287029 + 31 +0.0 + 0 +LINE + 5 +143A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528936.7151588525 + 20 +177851.0977463463 + 30 +0.0 + 11 +529113.2393739193 + 21 +177797.3359449813 + 31 +0.0 + 0 +LINE + 5 +143B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528285.5873183847 + 20 +178489.7153869756 + 30 +0.0 + 11 +528351.4611522887 + 21 +178392.8090836222 + 31 +0.0 + 0 +LINE + 5 +143C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529252.4513196267 + 20 +178461.4487730904 + 30 +0.0 + 11 +529327.0124102068 + 21 +178645.0375417232 + 31 +0.0 + 0 +LINE + 5 +143D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530338.2961201331 + 20 +180788.7547084909 + 30 +0.0 + 11 +530435.1516274485 + 21 +181525.5409562457 + 31 +0.0 + 0 +LINE + 5 +143E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530235.1318529886 + 20 +180967.1210590397 + 30 +0.0 + 11 +530240.08671063 + 21 +181114.8814870659 + 31 +0.0 + 0 +LINE + 5 +143F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530375.6883102297 + 20 +181052.8292676401 + 30 +0.0 + 11 +529885.4674530158 + 21 +180988.268304624 + 31 +0.0 + 0 +LINE + 5 +1440 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530248.2643181117 + 20 +181083.2761554827 + 30 +0.0 + 11 +530207.1473563143 + 21 +181154.2021289139 + 31 +0.0 + 0 +LINE + 5 +1441 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530313.2478625071 + 20 +181129.4546631625 + 30 +0.0 + 11 +530236.6556469487 + 21 +181086.430704766 + 31 +0.0 + 0 +LINE + 5 +1442 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530302.7309378077 + 20 +181113.6080797556 + 30 +0.0 + 11 +530327.0365308518 + 21 +181310.9997992657 + 31 +0.0 + 0 +LINE + 5 +1443 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530425.0157447808 + 20 +181122.3984354473 + 30 +0.0 + 11 +530008.6308414541 + 21 +181241.0695507227 + 31 +0.0 + 0 +LINE + 5 +1444 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530272.6495276417 + 20 +181324.6466285585 + 30 +0.0 + 11 +530207.1171655377 + 21 +181149.8743530758 + 31 +0.0 + 0 +LINE + 5 +1445 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530330.580248871 + 20 +181306.824020257 + 30 +0.0 + 11 +530271.9023948822 + 21 +181324.2461364468 + 31 +0.0 + 0 +LINE + 5 +1446 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530381.021937737 + 20 +181599.9243260485 + 30 +0.0 + 11 +530291.3346635938 + 21 +181316.5479702797 + 31 +0.0 + 0 +LINE + 5 +1447 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530363.8961214457 + 20 +181533.6795228619 + 30 +0.0 + 11 +530253.9629897674 + 21 +181560.3723660222 + 31 +0.0 + 0 +LINE + 5 +1448 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530279.057127295 + 20 +181637.8777809726 + 30 +0.0 + 11 +530048.2555749861 + 21 +180854.9627992806 + 31 +0.0 + 0 +LINE + 5 +1449 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530062.6450814385 + 20 +181149.7461893054 + 30 +0.0 + 11 +529624.7179966677 + 21 +181182.9672071196 + 31 +0.0 + 0 +LINE + 5 +144A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530046.8518474741 + 20 +181082.0690086005 + 30 +0.0 + 11 +530083.9544910923 + 21 +181272.418455535 + 31 +0.0 + 0 +LINE + 5 +144B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529975.7995744307 + 20 +181097.0347261711 + 30 +0.0 + 11 +529988.6233627915 + 21 +181160.0521535555 + 31 +0.0 + 0 +LINE + 5 +144C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530020.6039639803 + 20 +181066.2153863765 + 30 +0.0 + 11 +529968.4198112056 + 21 +181111.0937745181 + 31 +0.0 + 0 +LINE + 5 +144D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529987.8038513251 + 20 +181104.588180371 + 30 +0.0 + 11 +529584.6093016989 + 21 +181110.1786099761 + 31 +0.0 + 0 +LINE + 5 +144E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529891.407447771 + 20 +180921.3739107299 + 30 +0.0 + 11 +529869.9416690375 + 21 +181328.1304897638 + 31 +0.0 + 0 +LINE + 5 +144F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529883.0140692269 + 20 +181325.5988206547 + 30 +0.0 + 11 +529644.197247677 + 21 +181327.1145507522 + 31 +0.0 + 0 +LINE + 5 +1450 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529976.892035066 + 20 +181491.4081337029 + 30 +0.0 + 11 +529868.3336776149 + 21 +181314.9939479675 + 31 +0.0 + 0 +LINE + 5 +1451 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530021.3585201078 + 20 +181416.4100260595 + 30 +0.0 + 11 +529940.0430461289 + 21 +181442.4698313734 + 31 +0.0 + 0 +LINE + 5 +1452 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529656.6301186837 + 20 +180661.1742274603 + 30 +0.0 + 11 +529783.4049957184 + 21 +180984.8427226674 + 31 +0.0 + 0 +LINE + 5 +1453 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529635.2797641427 + 20 +180857.3255297743 + 30 +0.0 + 11 +529646.3277984724 + 21 +181329.3701150071 + 31 +0.0 + 0 +LINE + 5 +1454 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530052.2973304801 + 20 +181232.0162702387 + 30 +0.0 + 11 +529628.8914339743 + 21 +181255.737002807 + 31 +0.0 + 0 +LINE + 5 +1455 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529811.6546990779 + 20 +181697.3242248847 + 30 +0.0 + 11 +529630.6275680862 + 21 +181248.9813300898 + 31 +0.0 + 0 +LINE + 5 +1456 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529888.3275670068 + 20 +181938.7866450614 + 30 +0.0 + 11 +529708.694419197 + 21 +181430.1615783586 + 31 +0.0 + 0 +LINE + 5 +1457 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529903.2812325341 + 20 +181684.009864405 + 30 +0.0 + 11 +529786.6576949632 + 21 +181670.2811276199 + 31 +0.0 + 0 +LINE + 5 +1458 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529880.3412750034 + 20 +181626.3143881118 + 30 +0.0 + 11 +529799.9115781909 + 21 +181701.1252479569 + 31 +0.0 + 0 +LINE + 5 +1459 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529822.0603907441 + 20 +181445.464678714 + 30 +0.0 + 11 +529866.519758919 + 21 +181642.5194831281 + 31 +0.0 + 0 +LINE + 5 +145A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530070.7006040116 + 20 +181468.6318969595 + 30 +0.0 + 11 +529740.1085727789 + 21 +181523.3935734394 + 31 +0.0 + 0 +LINE + 5 +145B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530060.3345732529 + 20 +181375.631093596 + 30 +0.0 + 11 +530066.4740637235 + 21 +181496.9149432353 + 31 +0.0 + 0 +LINE + 5 +145C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530165.4248362273 + 20 +181471.7605166045 + 30 +0.0 + 11 +530108.9547541151 + 21 +181364.9950690455 + 31 +0.0 + 0 +LINE + 5 +145D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530113.9712455618 + 20 +181369.490559017 + 30 +0.0 + 11 +530058.6420695524 + 21 +181376.9941032111 + 31 +0.0 + 0 +LINE + 5 +145E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530451.983915835 + 20 +181366.5037393104 + 30 +0.0 + 11 +529905.6668498683 + 21 +181500.873497438 + 31 +0.0 + 0 +LINE + 5 +145F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529894.3310124588 + 20 +181494.3521053083 + 30 +0.0 + 11 +529900.3146067254 + 21 +181517.8882726195 + 31 +0.0 + 0 +LINE + 5 +1460 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529731.9521605782 + 20 +181395.4258543422 + 30 +0.0 + 11 +529689.2881019887 + 21 +181410.7201434047 + 31 +0.0 + 0 +LINE + 5 +1461 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529741.3762525003 + 20 +181383.0762722773 + 30 +0.0 + 11 +529725.3059075305 + 21 +181400.9896875065 + 31 +0.0 + 0 +LINE + 5 +1462 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529730.5252408357 + 20 +181319.9040835115 + 30 +0.0 + 11 +529740.6359545888 + 21 +181391.0352007434 + 31 +0.0 + 0 +LINE + 5 +1463 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529954.0963399314 + 20 +181446.2263190318 + 30 +0.0 + 11 +530031.1308153276 + 21 +181873.6873985594 + 31 +0.0 + 0 +LINE + 5 +1464 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530045.6316110478 + 20 +181845.4314955982 + 30 +0.0 + 11 +529844.349988987 + 21 +181845.5760181434 + 31 +0.0 + 0 +LINE + 5 +1465 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530282.1062332428 + 20 +181618.2810391656 + 30 +0.0 + 11 +530013.5500333215 + 21 +181862.1296240347 + 31 +0.0 + 0 +LINE + 5 +1466 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530150.9915726047 + 20 +181836.8800974799 + 30 +0.0 + 11 +529982.3986712572 + 21 +181478.7707205962 + 31 +0.0 + 0 +LINE + 5 +1467 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530107.2600731355 + 20 +181448.3154505321 + 30 +0.0 + 11 +530115.4416801651 + 21 +181482.8850185999 + 31 +0.0 + 0 +LINE + 5 +1468 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529995.7589939005 + 20 +181625.5055781762 + 30 +0.0 + 11 +529907.1951239718 + 21 +181654.9721888375 + 31 +0.0 + 0 +LINE + 5 +1469 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529941.6226574095 + 20 +181647.8812763107 + 30 +0.0 + 11 +529861.1212243257 + 21 +181626.1533791875 + 31 +0.0 + 0 +LINE + 5 +146A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529940.6503530184 + 20 +181634.7921344092 + 30 +0.0 + 11 +529883.4805572988 + 21 +181690.9683044021 + 31 +0.0 + 0 +LINE + 5 +146B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529940.1267632553 + 20 +181848.2680882116 + 30 +0.0 + 11 +529885.0748283349 + 21 +181678.4452763864 + 31 +0.0 + 0 +LINE + 5 +146C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530499.7067164951 + 20 +181670.0269107118 + 30 +0.0 + 11 +530431.0198845195 + 21 +181507.3047441572 + 31 +0.0 + 0 +LINE + 5 +146D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530465.7497934597 + 20 +181560.5761427814 + 30 +0.0 + 11 +530221.4121484268 + 21 +181658.7491352089 + 31 +0.0 + 0 +LINE + 5 +146E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529936.0586576352 + 20 +181233.4894753265 + 30 +0.0 + 11 +529932.6486109173 + 21 +181280.3774430722 + 31 +0.0 + 0 +LINE + 5 +146F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529996.04332569 + 20 +181273.0671257869 + 30 +0.0 + 11 +529931.068716294 + 21 +181279.3199476997 + 31 +0.0 + 0 +LINE + 5 +1470 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530016.2143186337 + 20 +181227.8045961354 + 30 +0.0 + 11 +530037.8743831275 + 21 +181329.8525487859 + 31 +0.0 + 0 +LINE + 5 +1471 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530180.1685787403 + 20 +181279.2053078991 + 30 +0.0 + 11 +529896.9632612126 + 21 +181373.8281353093 + 31 +0.0 + 0 +LINE + 5 +1472 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529812.5960530011 + 20 +181322.917106081 + 30 +0.0 + 11 +529817.2569814127 + 21 +181391.6036367747 + 31 +0.0 + 0 +LINE + 5 +1473 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529848.9453069127 + 20 +181388.47346972 + 30 +0.0 + 11 +529788.9909870235 + 21 +181392.7221734328 + 31 +0.0 + 0 +LINE + 5 +1474 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529843.1416998106 + 20 +181382.1187467608 + 30 +0.0 + 11 +529848.9754071669 + 21 +181453.2133581997 + 31 +0.0 + 0 +LINE + 5 +1475 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529851.5886507226 + 20 +181450.5694416274 + 30 +0.0 + 11 +529795.7074865813 + 21 +181455.9439452276 + 31 +0.0 + 0 +LINE + 5 +1476 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529793.514654658 + 20 +181384.9006469958 + 30 +0.0 + 11 +529798.9941570257 + 21 +181462.2056458788 + 31 +0.0 + 0 +LINE + 5 +1477 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530343.3747185888 + 20 +181464.5652553773 + 30 +0.0 + 11 +530234.0562590772 + 21 +181492.0251343554 + 31 +0.0 + 0 +LINE + 5 +1478 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529887.4667406315 + 20 +181044.4103591459 + 30 +0.0 + 11 +529623.1064784813 + 21 +181033.123129424 + 31 +0.0 + 0 +LINE + 5 +1479 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529387.0340056964 + 20 +180728.3098706004 + 30 +0.0 + 11 +528799.8257840726 + 21 +180655.4140875558 + 31 +0.0 + 0 +LINE + 5 +147A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529486.5268066528 + 20 +180641.3842100841 + 30 +0.0 + 11 +529452.9622144351 + 21 +180884.3232757525 + 31 +0.0 + 0 +LINE + 5 +147B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530403.7387025317 + 20 +180950.4231390571 + 30 +0.0 + 11 +529098.342956821 + 21 +180757.7100933105 + 31 +0.0 + 0 +LINE + 5 +147C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529461.139821917 + 20 +180852.7179441691 + 30 +0.0 + 11 +529420.0228601196 + 21 +180923.6439176005 + 31 +0.0 + 0 +LINE + 5 +147D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529526.1233663122 + 20 +180898.896451849 + 30 +0.0 + 11 +529449.5311507541 + 21 +180855.8724934527 + 31 +0.0 + 0 +LINE + 5 +147E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529515.649079774 + 20 +180884.8716507115 + 30 +0.0 + 11 +529539.954672818 + 21 +181082.2633702215 + 31 +0.0 + 0 +LINE + 5 +147F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529719.7424303435 + 20 +180868.5123586221 + 30 +0.0 + 11 +529221.5063452594 + 21 +181010.5113394093 + 31 +0.0 + 0 +LINE + 5 +1480 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529485.5250314471 + 20 +181094.088417245 + 30 +0.0 + 11 +529419.992669343 + 21 +180919.3161417624 + 31 +0.0 + 0 +LINE + 5 +1481 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529543.4557526762 + 20 +181076.2658089434 + 30 +0.0 + 11 +529484.7778986873 + 21 +181093.6879251331 + 31 +0.0 + 0 +LINE + 5 +1482 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529593.8974415423 + 20 +181369.3661147352 + 30 +0.0 + 11 +529504.210167399 + 21 +181085.9897589662 + 31 +0.0 + 0 +LINE + 5 +1483 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529576.7716252509 + 20 +181303.1213115482 + 30 +0.0 + 11 +529466.8384935727 + 21 +181329.8141547087 + 31 +0.0 + 0 +LINE + 5 +1484 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529491.9326311002 + 20 +181407.3195696592 + 30 +0.0 + 11 +529276.8016459199 + 21 +180683.033535298 + 31 +0.0 + 0 +LINE + 5 +1485 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529275.5205852436 + 20 +180919.1879779918 + 30 +0.0 + 11 +528837.5935004729 + 21 +180952.4089958063 + 31 +0.0 + 0 +LINE + 5 +1486 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529259.7273512793 + 20 +180851.5107972869 + 30 +0.0 + 11 +529296.8299948975 + 21 +181041.8602442213 + 31 +0.0 + 0 +LINE + 5 +1487 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529188.6750782359 + 20 +180866.4765148574 + 30 +0.0 + 11 +529201.498866597 + 21 +180929.4939422421 + 31 +0.0 + 0 +LINE + 5 +1488 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529233.4794677856 + 20 +180835.6571750629 + 30 +0.0 + 11 +529181.2953150109 + 21 +180880.5355632046 + 31 +0.0 + 0 +LINE + 5 +1489 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529200.6793551305 + 20 +180874.0299690574 + 30 +0.0 + 11 +528797.4848055041 + 21 +180879.6203986625 + 31 +0.0 + 0 +LINE + 5 +148A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529104.2829515762 + 20 +180690.8156994162 + 30 +0.0 + 11 +529082.8171728428 + 21 +181097.5722784504 + 31 +0.0 + 0 +LINE + 5 +148B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529095.8895730323 + 20 +181095.0406093412 + 30 +0.0 + 11 +528857.0727514823 + 21 +181096.5563394386 + 31 +0.0 + 0 +LINE + 5 +148C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529189.7675388713 + 20 +181260.8499223896 + 30 +0.0 + 11 +529081.2091814203 + 21 +181084.435736654 + 31 +0.0 + 0 +LINE + 5 +148D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529234.2340239129 + 20 +181185.851814746 + 30 +0.0 + 11 +529152.9185499342 + 21 +181211.9116200599 + 31 +0.0 + 0 +LINE + 5 +148E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528974.9826614881 + 20 +180670.418543214 + 30 +0.0 + 11 +528974.9780985168 + 21 +180760.5411873043 + 31 +0.0 + 0 +LINE + 5 +148F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528848.1552679479 + 20 +180626.7673184608 + 30 +0.0 + 11 +528859.2033022775 + 21 +181098.8119036936 + 31 +0.0 + 0 +LINE + 5 +1490 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529265.1728342852 + 20 +181001.4580589253 + 30 +0.0 + 11 +528841.7669377794 + 21 +181025.1787914937 + 31 +0.0 + 0 +LINE + 5 +1491 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529048.6929366448 + 20 +181521.8496197857 + 30 +0.0 + 11 +528843.5030718915 + 21 +181018.4231187765 + 31 +0.0 + 0 +LINE + 5 +1492 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529116.1567363395 + 20 +181453.4516530914 + 30 +0.0 + 11 +528999.5331987682 + 21 +181439.7229163066 + 31 +0.0 + 0 +LINE + 5 +1493 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529093.2167788087 + 20 +181395.7561767984 + 30 +0.0 + 11 +529012.7870819961 + 21 +181470.5670366435 + 31 +0.0 + 0 +LINE + 5 +1494 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529034.9358945496 + 20 +181214.9064674006 + 30 +0.0 + 11 +529079.3952627241 + 21 +181411.9612718146 + 31 +0.0 + 0 +LINE + 5 +1495 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529283.5761078168 + 20 +181238.073685646 + 30 +0.0 + 11 +528952.9840765841 + 21 +181292.8353621259 + 31 +0.0 + 0 +LINE + 5 +1496 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529273.2100770582 + 20 +181145.0728822825 + 30 +0.0 + 11 +529279.3495675287 + 21 +181266.3567319217 + 31 +0.0 + 0 +LINE + 5 +1497 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529378.3003400324 + 20 +181241.2023052909 + 30 +0.0 + 11 +529321.8302579203 + 21 +181134.4368577321 + 31 +0.0 + 0 +LINE + 5 +1498 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529326.8467493671 + 20 +181138.9323477035 + 30 +0.0 + 11 +529271.5175733577 + 21 +181146.4358918976 + 31 +0.0 + 0 +LINE + 5 +1499 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529664.8594196403 + 20 +181135.9455279969 + 30 +0.0 + 11 +529118.5423536736 + 21 +181270.3152861244 + 31 +0.0 + 0 +LINE + 5 +149A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529107.2065162641 + 20 +181263.7938939947 + 30 +0.0 + 11 +529113.1901105305 + 21 +181287.3300613058 + 31 +0.0 + 0 +LINE + 5 +149B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528944.8276643835 + 20 +181164.8676430287 + 30 +0.0 + 11 +528902.163605794 + 21 +181180.1619320912 + 31 +0.0 + 0 +LINE + 5 +149C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528954.2517563056 + 20 +181152.5180609637 + 30 +0.0 + 11 +528938.1814113358 + 21 +181170.431476193 + 31 +0.0 + 0 +LINE + 5 +149D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528943.4007446409 + 20 +181089.3458721978 + 30 +0.0 + 11 +528953.5114583941 + 21 +181160.4769894299 + 31 +0.0 + 0 +LINE + 5 +149E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529166.9718437365 + 20 +181215.6681077183 + 30 +0.0 + 11 +529223.4415039462 + 21 +181566.1891852296 + 31 +0.0 + 0 +LINE + 5 +149F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529494.9817370479 + 20 +181387.7228278521 + 30 +0.0 + 11 +529346.9736344345 + 21 +181528.1516351163 + 31 +0.0 + 0 +LINE + 5 +14A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529374.1904109175 + 20 +181543.2044757688 + 30 +0.0 + 11 +529195.2741750626 + 21 +181248.2125092826 + 31 +0.0 + 0 +LINE + 5 +14A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529320.1355769406 + 20 +181217.7572392189 + 30 +0.0 + 11 +529328.3171839703 + 21 +181252.3268072863 + 31 +0.0 + 0 +LINE + 5 +14A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529208.6344977056 + 20 +181394.9473668628 + 30 +0.0 + 11 +529120.0706277772 + 21 +181424.4139775238 + 31 +0.0 + 0 +LINE + 5 +14A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529154.4981612148 + 20 +181417.3230649972 + 30 +0.0 + 11 +529073.996728131 + 21 +181395.595167874 + 31 +0.0 + 0 +LINE + 5 +14A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529153.5258568235 + 20 +181404.2339230956 + 30 +0.0 + 11 +529096.3560611041 + 21 +181460.4100930885 + 31 +0.0 + 0 +LINE + 5 +14A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529139.4093974719 + 20 +181566.8543061548 + 30 +0.0 + 11 +529097.9503321401 + 21 +181447.8870650729 + 31 +0.0 + 0 +LINE + 5 +14A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529677.5761621105 + 20 +181312.1744703976 + 30 +0.0 + 11 +529434.287652232 + 21 +181428.1909238953 + 31 +0.0 + 0 +LINE + 5 +14A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529148.9341614404 + 20 +181002.931264013 + 30 +0.0 + 11 +529145.5241147225 + 21 +181049.8192317587 + 31 +0.0 + 0 +LINE + 5 +14A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529208.9188294952 + 20 +181042.5089144736 + 30 +0.0 + 11 +529143.9442200992 + 21 +181048.7617363862 + 31 +0.0 + 0 +LINE + 5 +14A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529229.089822439 + 20 +180997.2463848219 + 30 +0.0 + 11 +529250.7498869326 + 21 +181099.2943374726 + 31 +0.0 + 0 +LINE + 5 +14AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529393.0440825455 + 20 +181048.6470965855 + 30 +0.0 + 11 +529109.8387650178 + 21 +181143.2699239959 + 31 +0.0 + 0 +LINE + 5 +14AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529025.4715568064 + 20 +181092.3588947676 + 30 +0.0 + 11 +529030.132485218 + 21 +181161.0454254612 + 31 +0.0 + 0 +LINE + 5 +14AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529061.8208107179 + 20 +181157.9152584065 + 30 +0.0 + 11 +529001.8664908287 + 21 +181162.1639621192 + 31 +0.0 + 0 +LINE + 5 +14AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529056.0172036158 + 20 +181151.5605354473 + 30 +0.0 + 11 +529061.8509109723 + 21 +181222.6551468862 + 31 +0.0 + 0 +LINE + 5 +14AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529064.4641545279 + 20 +181220.0112303138 + 30 +0.0 + 11 +529008.5829903865 + 21 +181225.3857339141 + 31 +0.0 + 0 +LINE + 5 +14AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529006.3901584631 + 20 +181154.3424356824 + 30 +0.0 + 11 +529011.869660831 + 21 +181231.6474345654 + 31 +0.0 + 0 +LINE + 5 +14B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529556.2502223941 + 20 +181234.0070440637 + 30 +0.0 + 11 +529446.9317628824 + 21 +181261.4669230418 + 31 +0.0 + 0 +LINE + 5 +14B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529100.3422444369 + 20 +180813.8521478327 + 30 +0.0 + 11 +528835.9819822866 + 21 +180802.5649181105 + 31 +0.0 + 0 +LINE + 5 +14B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529045.3514116085 + 20 +181479.3920862135 + 30 +0.0 + 11 +528875.2749760494 + 21 +182028.5885954034 + 31 +0.0 + 0 +LINE + 5 +14B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529273.1578980983 + 20 +181500.2911526591 + 30 +0.0 + 11 +529293.0655504569 + 21 +181668.9226533226 + 31 +0.0 + 0 +LINE + 5 +14B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529727.9161891624 + 20 +181465.2266305704 + 30 +0.0 + 11 +528978.5941736404 + 21 +181562.118928557 + 31 +0.0 + 0 +LINE + 5 +14B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529211.5230500173 + 20 +181601.0380815575 + 30 +0.0 + 11 +529164.4210874387 + 21 +182037.7150136904 + 31 +0.0 + 0 +LINE + 5 +14B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529142.1935067098 + 20 +181605.8382328055 + 30 +0.0 + 11 +529336.0236311505 + 21 +181599.5612135245 + 31 +0.0 + 0 +LINE + 5 +14B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529145.6385750521 + 20 +181678.3677420495 + 30 +0.0 + 11 +529209.8945070248 + 21 +181675.7560551536 + 31 +0.0 + 0 +LINE + 5 +14B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529122.3575251194 + 20 +181629.222470229 + 30 +0.0 + 11 +529158.3410628242 + 21 +181687.894785142 + 31 +0.0 + 0 +LINE + 5 +14B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529155.0094566439 + 20 +181667.7214322521 + 30 +0.0 + 11 +529096.2395799927 + 21 +182066.648993784 + 31 +0.0 + 0 +LINE + 5 +14BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528958.7689201024 + 20 +181733.6713150126 + 30 +0.0 + 11 +529356.8988662861 + 21 +181819.7192097903 + 31 +0.0 + 0 +LINE + 5 +14BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529356.4839619108 + 20 +181806.4103837885 + 30 +0.0 + 11 +529319.9013057859 + 21 +182042.4135214028 + 31 +0.0 + 0 +LINE + 5 +14BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529535.1406554567 + 20 +181740.1715234809 + 30 +0.0 + 11 +529343.6739983511 + 21 +181819.2120265032 + 31 +0.0 + 0 +LINE + 5 +14BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529468.1921718079 + 20 +181684.3155929165 + 30 +0.0 + 11 +529480.9529403677 + 21 +181768.745934306 + 31 +0.0 + 0 +LINE + 5 +14BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528903.8575074511 + 20 +181912.684482759 + 30 +0.0 + 11 +528992.8264165814 + 21 +181927.0589116806 + 31 +0.0 + 0 +LINE + 5 +14BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529291.0906535335 + 20 +181624.3712904532 + 30 +0.0 + 11 +529246.996455296 + 21 +182046.1424701601 + 31 +0.0 + 0 +LINE + 5 +14C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529712.0754532269 + 20 +181936.1278735951 + 30 +0.0 + 11 +529278.1139804708 + 21 +182031.483426149 + 31 +0.0 + 0 +LINE + 5 +14C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529925.5796502365 + 20 +181905.6625871589 + 30 +0.0 + 11 +529431.9139545944 + 21 +181995.1722096143 + 31 +0.0 + 0 +LINE + 5 +14C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529713.5411507648 + 20 +181843.550632553 + 30 +0.0 + 11 +529681.3926029392 + 21 +181956.4930895919 + 31 +0.0 + 0 +LINE + 5 +14C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529652.9260736845 + 20 +181856.9976421366 + 30 +0.0 + 11 +529713.9554234051 + 21 +181948.3268234142 + 31 +0.0 + 0 +LINE + 5 +14C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529465.0973098047 + 20 +181885.696672062 + 30 +0.0 + 11 +529666.720024011 + 21 +181873.2262078698 + 31 +0.0 + 0 +LINE + 5 +14C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529528.3837332418 + 20 +181678.1482808087 + 30 +0.0 + 11 +529528.9621030175 + 21 +181979.0256669608 + 31 +0.0 + 0 +LINE + 5 +14C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529602.9486020106 + 20 +181625.6271380842 + 30 +0.0 + 11 +529485.9619619313 + 21 +181658.2092124433 + 31 +0.0 + 0 +LINE + 5 +14C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529478.4882745172 + 20 +181556.3851261245 + 30 +0.0 + 11 +529597.6412726829 + 21 +181576.1409858726 + 31 +0.0 + 0 +LINE + 5 +14C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529591.7886059378 + 20 +181572.8061832562 + 30 +0.0 + 11 +529602.1916801686 + 21 +181627.6641538704 + 31 +0.0 + 0 +LINE + 5 +14C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529487.5869661725 + 20 +181251.2420300496 + 30 +0.0 + 11 +529487.587972784 + 21 +181251.2544245436 + 31 +0.0 + 0 +LINE + 5 +14CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529499.4347171412 + 20 +181397.1243871717 + 30 +0.0 + 11 +529533.1281695744 + 21 +181811.994709275 + 31 +0.0 + 0 +LINE + 5 +14CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529524.8827278017 + 20 +181822.1456922354 + 30 +0.0 + 11 +529549.0718544475 + 21 +181819.9914582276 + 31 +0.0 + 0 +LINE + 5 +14CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529401.3310440504 + 20 +181966.6734615757 + 30 +0.0 + 11 +529409.6269396648 + 21 +182011.2303385892 + 31 +0.0 + 0 +LINE + 5 +14CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529390.6421172938 + 20 +181955.4008163437 + 30 +0.0 + 11 +529405.7639595057 + 21 +181974.1218291566 + 31 +0.0 + 0 +LINE + 5 +14CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529326.5479602904 + 20 +181956.0402892964 + 30 +0.0 + 11 +529398.3811817222 + 21 +181957.4006826129 + 31 +0.0 + 0 +LINE + 5 +14CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529486.9021456546 + 20 +181755.4714014451 + 30 +0.0 + 11 +529837.9909134975 + 21 +181744.2285632496 + 31 +0.0 + 0 +LINE + 5 +14D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529804.2198961672 + 20 +181650.0413236167 + 30 +0.0 + 11 +529523.542947489 + 21 +181732.7203207542 + 31 +0.0 + 0 +LINE + 5 +14D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529513.3862834716 + 20 +181604.6003171262 + 30 +0.0 + 11 +529548.8181221356 + 21 +181602.0354508805 + 31 +0.0 + 0 +LINE + 5 +14D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529670.5307986297 + 20 +181742.9275861688 + 30 +0.0 + 11 +529685.4990405129 + 21 +181835.0567994266 + 31 +0.0 + 0 +LINE + 5 +14D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529683.9882674731 + 20 +181799.9390878854 + 30 +0.0 + 11 +529649.7025155847 + 21 +181875.946123477 + 31 +0.0 + 0 +LINE + 5 +14D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529670.9115523811 + 20 +181798.8119082378 + 30 +0.0 + 11 +529717.253377332 + 21 +181864.2074958406 + 31 +0.0 + 0 +LINE + 5 +14D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529881.572860625 + 20 +181833.3672292052 + 30 +0.0 + 11 +529705.1447701149 + 21 +181860.6368429481 + 31 +0.0 + 0 +LINE + 5 +14D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529274.0109237178 + 20 +181739.3577341212 + 30 +0.0 + 11 +529319.7552911159 + 21 +181750.200371683 + 31 +0.0 + 0 +LINE + 5 +14D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529322.6466951995 + 20 +181686.4510941786 + 30 +0.0 + 11 +529318.4594131879 + 21 +181751.5914374181 + 31 +0.0 + 0 +LINE + 5 +14D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529281.1794788938 + 20 +181659.3211196363 + 30 +0.0 + 11 +529385.3755203517 + 21 +181654.2095661979 + 31 +0.0 + 0 +LINE + 5 +14D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529358.0648502905 + 20 +181505.6602194628 + 30 +0.0 + 11 +529406.3204206742 + 21 +181800.3297483763 + 31 +0.0 + 0 +LINE + 5 +14DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529342.608506431 + 20 +181875.4998933934 + 30 +0.0 + 11 +529411.1594564413 + 21 +181881.850563048 + 31 +0.0 + 0 +LINE + 5 +14DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529413.1219933337 + 20 +181850.0685497743 + 30 +0.0 + 11 +529407.7567111777 + 21 +181909.9332781541 + 31 +0.0 + 0 +LINE + 5 +14DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529405.9231944706 + 20 +181854.7846556055 + 30 +0.0 + 11 +529477.0384147157 + 21 +181860.3615155338 + 31 +0.0 + 0 +LINE + 5 +14DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529474.8450016534 + 20 +181857.3601365404 + 30 +0.0 + 11 +529471.2405749233 + 21 +181913.3833272983 + 31 +0.0 + 0 +LINE + 5 +14DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529400.7565436811 + 20 +181904.2203542361 + 30 +0.0 + 11 +529477.9462196996 + 21 +181911.1371247718 + 31 +0.0 + 0 +LINE + 5 +14DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529079.6029298196 + 20 +181757.1795881796 + 30 +0.0 + 11 +529026.3082474618 + 21 +182016.3579564733 + 31 +0.0 + 0 +LINE + 5 +14E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530304.0548154939 + 20 +181048.7539546006 + 30 +0.0 + 11 +530588.3653885961 + 21 +180362.1664057763 + 31 +0.0 + 0 +LINE + 5 +14E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530387.586207844 + 20 +180865.0913584818 + 30 +0.0 + 11 +529834.2934995411 + 21 +180781.9679262921 + 31 +0.0 + 0 +LINE + 5 +14E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530250.5880801642 + 20 +180849.7596601176 + 30 +0.0 + 11 +530293.6298891184 + 21 +180708.320283045 + 31 +0.0 + 0 +LINE + 5 +14E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530408.542233124 + 20 +180803.3646145163 + 30 +0.0 + 11 +529429.5724630821 + 21 +180667.1618954379 + 31 +0.0 + 0 +LINE + 5 +14E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530293.3458882066 + 20 +180740.9651845166 + 30 +0.0 + 11 +530271.9939805481 + 21 +180661.812204194 + 31 +0.0 + 0 +LINE + 5 +14E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530368.0695185732 + 20 +180713.1857914608 + 30 +0.0 + 11 +530282.9497682542 + 21 +180734.9126546915 + 31 +0.0 + 0 +LINE + 5 +14E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530353.8084333581 + 20 +180725.7691677678 + 30 +0.0 + 11 +530428.3909564597 + 21 +180541.4007864436 + 31 +0.0 + 0 +LINE + 5 +14E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530474.1995392441 + 20 +180748.9386734418 + 30 +0.0 + 11 +530102.7367198838 + 21 +180526.5098193058 + 31 +0.0 + 0 +LINE + 5 +14E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530379.3916276373 + 20 +180514.1382142453 + 30 +0.0 + 11 +530270.8443368462 + 21 +180665.9845985361 + 31 +0.0 + 0 +LINE + 5 +14E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530430.7327140616 + 20 +180546.3516690988 + 30 +0.0 + 11 +530378.566280631 + 21 +180514.3316143769 + 31 +0.0 + 0 +LINE + 5 +14EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530555.3395872043 + 20 +180276.3048576078 + 30 +0.0 + 11 +530395.3428708616 + 21 +180526.7984042543 + 31 +0.0 + 0 +LINE + 5 +14EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530521.6466092081 + 20 +180335.8569420938 + 30 +0.0 + 11 +530422.3727951547 + 21 +180281.6120238077 + 31 +0.0 + 0 +LINE + 5 +14EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530466.6778245934 + 20 +180213.2463200424 + 30 +0.0 + 11 +530042.9464715477 + 21 +180903.4193199609 + 31 +0.0 + 0 +LINE + 5 +14ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530131.2651613216 + 20 +180628.7038626293 + 30 +0.0 + 11 +529716.8712397313 + 21 +180483.2341223061 + 31 +0.0 + 0 +LINE + 5 +14EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530098.4884788015 + 20 +180689.9844966847 + 30 +0.0 + 11 +530183.6084302914 + 21 +180515.7314853186 + 31 +0.0 + 0 +LINE + 5 +14EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530033.7335854979 + 20 +180657.1332866572 + 30 +0.0 + 11 +530062.4356391981 + 21 +180599.58471747 + 31 +0.0 + 0 +LINE + 5 +14F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530069.0309937571 + 20 +180698.501849582 + 30 +0.0 + 11 +530030.2454078206 + 21 +180641.642955409 + 31 +0.0 + 0 +LINE + 5 +14F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530047.2841766509 + 20 +180652.9453499921 + 30 +0.0 + 11 +529659.2848141497 + 21 +180543.156496049 + 31 +0.0 + 0 +LINE + 5 +14F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529906.7395476128 + 20 +180804.9550288512 + 30 +0.0 + 11 +529991.3169604977 + 21 +180406.5101073454 + 31 +0.0 + 0 +LINE + 5 +14F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530003.2881671689 + 20 +180412.339962063 + 30 +0.0 + 11 +529773.0067559511 + 21 +180349.0450701636 + 31 +0.0 + 0 +LINE + 5 +14F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530136.8940016724 + 20 +180276.4897439913 + 30 +0.0 + 11 +529986.3626820854 + 21 +180418.7824132492 + 31 +0.0 + 0 +LINE + 5 +14F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530160.4269277974 + 20 +180360.44321819 + 30 +0.0 + 11 +530088.6310933923 + 21 +180314.2190045845 + 31 +0.0 + 0 +LINE + 5 +14F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529656.0831902319 + 20 +180747.808326711 + 30 +0.0 + 11 +529775.6486375952 + 21 +180347.4180243195 + 31 +0.0 + 0 +LINE + 5 +14F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530142.5703661036 + 20 +180546.5598761695 + 30 +0.0 + 11 +529739.7428308468 + 21 +180414.0260948585 + 31 +0.0 + 0 +LINE + 5 +14F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530030.6034768476 + 20 +180034.8140560444 + 30 +0.0 + 11 +529739.6706909495 + 21 +180421.000911799 + 31 +0.0 + 0 +LINE + 5 +14F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530167.1778184791 + 20 +179821.435804477 + 30 +0.0 + 11 +529861.9841355233 + 21 +180266.2102890804 + 31 +0.0 + 0 +LINE + 5 +14FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530115.6586507159 + 20 +180071.3969923189 + 30 +0.0 + 11 +529999.4572098697 + 21 +180054.4632132203 + 31 +0.0 + 0 +LINE + 5 +14FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530078.5632398818 + 20 +180121.1859482354 + 30 +0.0 + 11 +530020.2448667559 + 21 +180028.1022856727 + 31 +0.0 + 0 +LINE + 5 +14FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529975.4466945978 + 20 +180280.7799861815 + 30 +0.0 + 11 +530069.4085769443 + 21 +180101.9549431169 + 31 +0.0 + 0 +LINE + 5 +14FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530221.6070836974 + 20 +180322.7768728894 + 30 +0.0 + 11 +529916.4653748503 + 21 +180184.2905203223 + 31 +0.0 + 0 +LINE + 5 +14FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530563.4482295682 + 20 +180520.1388637834 + 30 +0.0 + 11 +530070.5480235035 + 21 +180248.9065734364 + 31 +0.0 + 0 +LINE + 5 +14FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530057.9102858542 + 20 +180252.2707006923 + 30 +0.0 + 11 +530069.7834853323 + 21 +180231.0862321789 + 31 +0.0 + 0 +LINE + 5 +1500 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529875.4556045341 + 20 +180305.7831659003 + 30 +0.0 + 11 +529838.2060363652 + 21 +180279.9644354035 + 31 +0.0 + 0 +LINE + 5 +1501 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529881.3609942497 + 20 +180320.1516055526 + 30 +0.0 + 11 +529870.4764736164 + 21 +180298.6882963201 + 31 +0.0 + 0 +LINE + 5 +1502 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529854.5243826426 + 20 +180378.3604207361 + 30 +0.0 + 11 +529882.7065439429 + 21 +180312.2723873586 + 31 +0.0 + 0 +LINE + 5 +1503 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530103.1777825322 + 20 +180314.2290691114 + 30 +0.0 + 11 +530288.257365063 + 21 +179921.2878100911 + 31 +0.0 + 0 +LINE + 5 +1504 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530464.5492722588 + 20 +180232.9642966499 + 30 +0.0 + 11 +530268.2836737723 + 21 +179927.8997465798 + 31 +0.0 + 0 +LINE + 5 +1505 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530394.5016180104 + 20 +179987.8726226491 + 30 +0.0 + 11 +530138.940988989 + 21 +180290.1219519965 + 31 +0.0 + 0 +LINE + 5 +1506 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530189.8361350755 + 20 +180151.8493923363 + 30 +0.0 + 11 +530111.9210931672 + 21 +180100.4578906554 + 31 +0.0 + 0 +LINE + 5 +1507 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530143.3388728079 + 20 +180116.2204799576 + 30 +0.0 + 11 +530059.9568527525 + 21 +180116.3653020212 + 31 +0.0 + 0 +LINE + 5 +1508 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530139.0108783557 + 20 +180128.6115846532 + 30 +0.0 + 11 +530098.3346968596 + 21 +180059.5493237822 + 31 +0.0 + 0 +LINE + 5 +1509 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530256.6557167706 + 20 +179825.3268424936 + 30 +0.0 + 11 +530096.6323345037 + 21 +180072.058116419 + 31 +0.0 + 0 +LINE + 5 +150A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530688.1274518463 + 20 +180239.3206435547 + 30 +0.0 + 11 +530579.6530818914 + 21 +180378.7110859745 + 31 +0.0 + 0 +LINE + 5 +150B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530626.9910246668 + 20 +180336.2478352728 + 30 +0.0 + 11 +530416.4020727649 + 21 +180178.1620529922 + 31 +0.0 + 0 +LINE + 5 +150C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530030.676524334 + 20 +180515.0421419232 + 30 +0.0 + 11 +530039.5222749266 + 21 +180468.8700439159 + 31 +0.0 + 0 +LINE + 5 +150D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530098.862731711 + 20 +180492.3443019127 + 30 +0.0 + 11 +530037.7224595286 + 21 +180469.4824392266 + 31 +0.0 + 0 +LINE + 5 +150E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530106.6272602049 + 20 +180541.2858756927 + 30 +0.0 + 11 +530153.9694919473 + 21 +180448.3253672619 + 31 +0.0 + 0 +LINE + 5 +150F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530278.2990380709 + 20 +180534.0863436747 + 30 +0.0 + 11 +530029.2485366401 + 21 +180369.3666451558 + 31 +0.0 + 0 +LINE + 5 +1510 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529934.5768977602 + 20 +180396.698668686 + 30 +0.0 + 11 +529956.8621806169 + 21 +180331.5608922397 + 31 +0.0 + 0 +LINE + 5 +1511 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529986.6596079763 + 20 +180342.7885919839 + 30 +0.0 + 11 +529929.8495715699 + 21 +180323.1622902407 + 31 +0.0 + 0 +LINE + 5 +1512 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529979.4086186403 + 20 +180347.4240545212 + 30 +0.0 + 11 +530003.4501558765 + 21 +180280.2639443032 + 31 +0.0 + 0 +LINE + 5 +1513 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530005.289772253 + 20 +180283.4942923202 + 30 +0.0 + 11 +529952.7054835665 + 21 +180263.83513725 + 31 +0.0 + 0 +LINE + 5 +1514 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529932.1939634152 + 20 +180331.8883243654 + 30 +0.0 + 11 +529957.5012727588 + 21 +180258.637878003 + 31 +0.0 + 0 +LINE + 5 +1515 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529486.6508263606 + 20 +180674.9791019966 + 30 +0.0 + 11 +529282.7583007949 + 21 +180545.4162611162 + 31 +0.0 + 0 +LINE + 5 +1516 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529735.3611681152 + 20 +180295.211299418 + 30 +0.0 + 11 +529455.1550969702 + 21 +180733.9066311564 + 31 +0.0 + 0 +LINE + 5 +1517 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529646.6994055041 + 20 +180232.1527618527 + 30 +0.0 + 11 +529251.3825813411 + 21 +180876.0442192342 + 31 +0.0 + 0 +LINE + 5 +1518 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529311.2867422323 + 20 +180647.6103044398 + 30 +0.0 + 11 +528896.8928206421 + 21 +180502.1405641166 + 31 +0.0 + 0 +LINE + 5 +1519 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529278.5100597123 + 20 +180708.8909384949 + 30 +0.0 + 11 +529363.6300112022 + 21 +180534.6379271289 + 31 +0.0 + 0 +LINE + 5 +151A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529213.7551664087 + 20 +180676.0397284676 + 30 +0.0 + 11 +529242.4572201087 + 21 +180618.4911592803 + 31 +0.0 + 0 +LINE + 5 +151B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529249.0525746678 + 20 +180717.4082913922 + 30 +0.0 + 11 +529210.2669887313 + 21 +180660.5493972194 + 31 +0.0 + 0 +LINE + 5 +151C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529227.3057575616 + 20 +180671.8517918025 + 30 +0.0 + 11 +528839.3063950604 + 21 +180562.0629378591 + 31 +0.0 + 0 +LINE + 5 +151D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529109.7181942716 + 20 +180716.2489171899 + 30 +0.0 + 11 +529171.3385414084 + 21 +180425.4165491558 + 31 +0.0 + 0 +LINE + 5 +151E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529183.3097480795 + 20 +180431.2464038735 + 30 +0.0 + 11 +528953.028336862 + 21 +180367.951511974 + 31 +0.0 + 0 +LINE + 5 +151F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529316.9155825832 + 20 +180295.3961858016 + 30 +0.0 + 11 +529166.3842629962 + 21 +180437.6888550596 + 31 +0.0 + 0 +LINE + 5 +1520 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529340.4485087083 + 20 +180379.3496600005 + 30 +0.0 + 11 +529268.6526743031 + 21 +180333.1254463949 + 31 +0.0 + 0 +LINE + 5 +1521 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528860.8199180713 + 20 +180692.1987855913 + 30 +0.0 + 11 +528955.670218506 + 21 +180366.3244661299 + 31 +0.0 + 0 +LINE + 5 +1522 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529322.5919470144 + 20 +180565.4663179799 + 30 +0.0 + 11 +528919.7644117577 + 21 +180432.9325366689 + 31 +0.0 + 0 +LINE + 5 +1523 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529248.2253256548 + 20 +180006.770937361 + 30 +0.0 + 11 +528919.6922718605 + 21 +180439.9073536093 + 31 +0.0 + 0 +LINE + 5 +1524 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529295.6802316267 + 20 +180090.3034341293 + 30 +0.0 + 11 +529179.4787907807 + 21 +180073.3696550306 + 31 +0.0 + 0 +LINE + 5 +1525 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529258.5848207927 + 20 +180140.0923900456 + 30 +0.0 + 11 +529200.2664476667 + 21 +180047.0087274829 + 31 +0.0 + 0 +LINE + 5 +1526 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529155.4682755085 + 20 +180299.686427992 + 30 +0.0 + 11 +529249.4301578551 + 21 +180120.8613849271 + 31 +0.0 + 0 +LINE + 5 +1527 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529401.6286646083 + 20 +180341.6833146997 + 30 +0.0 + 11 +529096.4869557612 + 21 +180203.1969621326 + 31 +0.0 + 0 +LINE + 5 +1528 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529367.5377231179 + 20 +180428.8292367399 + 30 +0.0 + 11 +529404.8688565344 + 21 +180313.2703686059 + 31 +0.0 + 0 +LINE + 5 +1529 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529417.7557216468 + 20 +180448.6471933713 + 30 +0.0 + 11 +529366.2558188828 + 21 +180427.0745044187 + 31 +0.0 + 0 +LINE + 5 +152A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529743.4698104789 + 20 +180539.0453055938 + 30 +0.0 + 11 +529250.5696044141 + 21 +180267.8130152466 + 31 +0.0 + 0 +LINE + 5 +152B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529237.9318667649 + 20 +180271.1771425025 + 30 +0.0 + 11 +529249.8050662433 + 21 +180249.9926739893 + 31 +0.0 + 0 +LINE + 5 +152C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529055.4771854449 + 20 +180324.6896077105 + 30 +0.0 + 11 +529018.227617276 + 21 +180298.8708772138 + 31 +0.0 + 0 +LINE + 5 +152D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529061.3825751605 + 20 +180339.058047363 + 30 +0.0 + 11 +529050.4980545273 + 21 +180317.5947381304 + 31 +0.0 + 0 +LINE + 5 +152E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529034.5459635536 + 20 +180397.2668625465 + 30 +0.0 + 11 +529062.7281248536 + 21 +180331.178829169 + 31 +0.0 + 0 +LINE + 5 +152F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529283.1993634429 + 20 +180333.1355109217 + 30 +0.0 + 11 +529428.495189928 + 21 +180009.1864854411 + 31 +0.0 + 0 +LINE + 5 +1530 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529644.5708531695 + 20 +180251.8707384601 + 30 +0.0 + 11 +529537.9671151138 + 21 +180077.9101355026 + 31 +0.0 + 0 +LINE + 5 +1531 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529568.1531303601 + 20 +180070.417110919 + 30 +0.0 + 11 +529318.9625698996 + 21 +180309.0283938069 + 31 +0.0 + 0 +LINE + 5 +1532 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529431.6815314825 + 20 +180370.7724530625 + 30 +0.0 + 11 +529448.5343991409 + 21 +180339.4998679173 + 31 +0.0 + 0 +LINE + 5 +1533 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529369.8577159862 + 20 +180170.7558341468 + 30 +0.0 + 11 +529291.9426740779 + 21 +180119.3643324658 + 31 +0.0 + 0 +LINE + 5 +1534 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529323.3604537187 + 20 +180135.1269217678 + 30 +0.0 + 11 +529239.9784336633 + 21 +180135.2717438316 + 31 +0.0 + 0 +LINE + 5 +1535 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529319.0324592666 + 20 +180147.5180264635 + 30 +0.0 + 11 +529278.3562777705 + 21 +180078.4557655923 + 31 +0.0 + 0 +LINE + 5 +1536 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529347.5005444616 + 20 +179986.7877196253 + 30 +0.0 + 11 +529276.6539154145 + 21 +180090.9645582292 + 31 +0.0 + 0 +LINE + 5 +1537 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529801.379483573 + 20 +180372.1177002053 + 30 +0.0 + 11 +529596.4236536755 + 21 +180197.0684948025 + 31 +0.0 + 0 +LINE + 5 +1538 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529210.6981052448 + 20 +180533.9485837334 + 30 +0.0 + 11 +529219.5438558373 + 21 +180487.776485726 + 31 +0.0 + 0 +LINE + 5 +1539 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529278.8843126219 + 20 +180511.2507437229 + 30 +0.0 + 11 +529217.7440404395 + 21 +180488.388881037 + 31 +0.0 + 0 +LINE + 5 +153A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529286.648841116 + 20 +180560.1923175028 + 30 +0.0 + 11 +529333.9910728581 + 21 +180467.2318090721 + 31 +0.0 + 0 +LINE + 5 +153B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529458.3206189816 + 20 +180552.9927854849 + 30 +0.0 + 11 +529209.2701175509 + 21 +180388.2730869662 + 31 +0.0 + 0 +LINE + 5 +153C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529114.5984786709 + 20 +180415.6051104964 + 30 +0.0 + 11 +529136.8837615276 + 21 +180350.46733405 + 31 +0.0 + 0 +LINE + 5 +153D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529166.6811888871 + 20 +180361.6950337942 + 30 +0.0 + 11 +529109.8711524805 + 21 +180342.0687320508 + 31 +0.0 + 0 +LINE + 5 +153E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529159.4301995511 + 20 +180366.3304963314 + 30 +0.0 + 11 +529183.4717367871 + 21 +180299.1703861135 + 31 +0.0 + 0 +LINE + 5 +153F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529185.3113531638 + 20 +180302.4007341305 + 30 +0.0 + 11 +529132.7270644774 + 21 +180282.7415790602 + 31 +0.0 + 0 +LINE + 5 +1540 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529112.215544326 + 20 +180350.7947661756 + 30 +0.0 + 11 +529137.5228536697 + 21 +180277.5443198133 + 31 +0.0 + 0 +LINE + 5 +1541 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529663.9524871362 + 20 +180416.2079580638 + 30 +0.0 + 11 +529565.4709759887 + 21 +180361.3812993516 + 31 +0.0 + 0 +LINE + 5 +1542 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529234.0052739636 + 20 +180046.9156515399 + 30 +0.0 + 11 +529211.9176295402 + 21 +179472.4115735709 + 31 +0.0 + 0 +LINE + 5 +1543 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529289.9946326802 + 20 +180006.9883611616 + 30 +0.0 + 11 +529283.3608963961 + 21 +179779.775909238 + 31 +0.0 + 0 +LINE + 5 +1544 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529459.4550720368 + 20 +180085.7093986373 + 30 +0.0 + 11 +529522.3434504139 + 21 +179927.9819454036 + 31 +0.0 + 0 +LINE + 5 +1545 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529889.6290109534 + 20 +180237.3174666211 + 30 +0.0 + 11 +529190.9426539895 + 21 +179949.7257856779 + 31 +0.0 + 0 +LINE + 5 +1546 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529426.0056714986 + 20 +179972.4400921852 + 30 +0.0 + 11 +529562.597765681 + 21 +179470.2487059042 + 31 +0.0 + 0 +LINE + 5 +1547 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529360.2828528293 + 20 +179949.8538544857 + 30 +0.0 + 11 +529545.8787654194 + 21 +180006.1004129726 + 31 +0.0 + 0 +LINE + 5 +1548 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529382.3886989727 + 20 +179880.6893421017 + 30 +0.0 + 11 +529443.7775062827 + 21 +179899.848153108 + 31 +0.0 + 0 +LINE + 5 +1549 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529347.1775158107 + 20 +179922.1313209226 + 30 +0.0 + 11 +529397.1246658042 + 21 +179874.7758805751 + 31 +0.0 + 0 +LINE + 5 +154A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529388.6836782065 + 20 +179893.3988098539 + 30 +0.0 + 11 +529372.4531559766 + 21 +179574.1258653627 + 31 +0.0 + 0 +LINE + 5 +154B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529616.4842112671 + 20 +179993.5565345598 + 30 +0.0 + 11 +529644.9627958351 + 21 +179574.1739714516 + 31 +0.0 + 0 +LINE + 5 +154C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529810.4509426742 + 20 +180050.0314443105 + 30 +0.0 + 11 +529705.8888757529 + 21 +179988.2719131615 + 31 +0.0 + 0 +LINE + 5 +154D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529672.3072657123 + 20 +180084.689110929 + 30 +0.0 + 11 +529792.5123713107 + 21 +180096.4561646946 + 31 +0.0 + 0 +LINE + 5 +154E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529785.9958672843 + 20 +180098.1619758782 + 30 +0.0 + 11 +529810.2472230898 + 21 +180047.8679142512 + 31 +0.0 + 0 +LINE + 5 +154F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529602.0926766144 + 20 +180381.7833834248 + 30 +0.0 + 11 +529602.0968578984 + 21 +180381.7716721647 + 31 +0.0 + 0 +LINE + 5 +1550 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529651.3061089158 + 20 +180243.9426441503 + 30 +0.0 + 11 +529811.9088096871 + 21 +179631.7846855943 + 31 +0.0 + 0 +LINE + 5 +1551 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529603.1557238958 + 20 +179813.6619840299 + 30 +0.0 + 11 +530068.185463361 + 21 +179996.3275982037 + 31 +0.0 + 0 +LINE + 5 +1552 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530011.1804052058 + 20 +180078.5598368081 + 30 +0.0 + 11 +529720.5177057797 + 21 +179934.7647016076 + 31 +0.0 + 0 +LINE + 5 +1553 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529718.4984998654 + 20 +180047.1531873395 + 30 +0.0 + 11 +529752.0581562893 + 21 +180058.8040753184 + 31 +0.0 + 0 +LINE + 5 +1554 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529435.4333691352 + 20 +179735.2093099271 + 30 +0.0 + 11 +529569.1663452307 + 21 +179856.3856726004 + 31 +0.0 + 0 +LINE + 5 +1555 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529555.4541606357 + 20 +179918.709878119 + 30 +0.0 + 11 +529568.2748068141 + 21 +179854.7065291475 + 31 +0.0 + 0 +LINE + 5 +1556 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529542.8570141844 + 20 +180102.5062273532 + 30 +0.0 + 11 +529639.4839479853 + 21 +179888.5549816735 + 31 +0.0 + 0 +LINE + 5 +1557 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530296.9455510268 + 20 +180360.090818716 + 30 +0.0 + 11 +530207.6100940128 + 21 +180500.4133324969 + 31 +0.0 + 0 +LINE + 5 +1558 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530370.2956111029 + 20 +180292.9007332187 + 30 +0.0 + 11 +530482.0169150562 + 21 +180439.7662500494 + 31 +0.0 + 0 +LINE + 5 +1559 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529849.8873611541 + 20 +180179.2781143133 + 30 +0.0 + 11 +529671.7765252076 + 21 +180289.0687592285 + 31 +0.0 + 0 +LINE + 5 +155A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529545.2950098589 + 20 +179904.0897720795 + 30 +0.0 + 11 +529659.0471003351 + 21 +179932.2083697526 + 31 +0.0 + 0 +LINE + 5 +155B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529907.5884870807 + 20 +180800.9556676964 + 30 +0.0 + 11 +529761.3216142649 + 21 +180934.635113062 + 31 +0.0 + 0 +LINE + 5 +155C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528841.0342824628 + 20 +177209.4097422151 + 30 +0.0 + 11 +528278.3732090686 + 21 +180058.8817655076 + 31 +0.0 + 0 +LINE + 5 +155D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528485.8015310987 + 20 +177965.2994590461 + 30 +0.0 + 11 +528596.9717934894 + 21 +177689.7755207768 + 31 +0.0 + 0 +LINE + 5 +155E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529032.856454134 + 20 +177908.0484599054 + 30 +0.0 + 11 +528503.1768036521 + 21 +177872.9737800619 + 31 +0.0 + 0 +LINE + 5 +155F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528906.7072705641 + 20 +177706.0885696858 + 30 +0.0 + 11 +528825.4591571875 + 21 +177923.5636996254 + 31 +0.0 + 0 +LINE + 5 +1560 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528860.3990250182 + 20 +178075.2330047576 + 30 +0.0 + 11 +528542.6989520168 + 21 +178045.8936531997 + 31 +0.0 + 0 +LINE + 5 +1561 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528683.1105900724 + 20 +178484.8759271629 + 30 +0.0 + 11 +528457.5160371857 + 21 +178463.7198493692 + 31 +0.0 + 0 +LINE + 5 +1562 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528837.7525704118 + 20 +177866.8596032536 + 30 +0.0 + 11 +528845.8741515778 + 21 +178110.4093651077 + 31 +0.0 + 0 +LINE + 5 +1563 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528640.1476426235 + 20 +177832.0636059231 + 30 +0.0 + 11 +528597.9887555746 + 21 +178119.0803550255 + 31 +0.0 + 0 +LINE + 5 +1564 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528308.5306784712 + 20 +179869.5117948136 + 30 +0.0 + 11 +527876.8658865468 + 21 +183341.9964196203 + 31 +0.0 + 0 +LINE + 5 +1565 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529200.5279966597 + 20 +179727.7499392975 + 30 +0.0 + 11 +529456.3896473957 + 21 +179741.3193956278 + 31 +0.0 + 0 +LINE + 5 +1566 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528567.0355326954 + 20 +179468.0301035344 + 30 +0.0 + 11 +528446.0992009897 + 21 +179890.2364171706 + 31 +0.0 + 0 +LINE + 5 +1567 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528329.4294157617 + 20 +179431.7414473565 + 30 +0.0 + 11 +528689.4728478268 + 21 +179490.6504418413 + 31 +0.0 + 0 +LINE + 5 +1568 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528487.4440873934 + 20 +179531.1636308236 + 30 +0.0 + 11 +528550.9926992977 + 21 +179541.0236322006 + 31 +0.0 + 0 +LINE + 5 +1569 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528293.4081675153 + 20 +179549.2968853729 + 30 +0.0 + 11 +528667.3917369897 + 21 +179710.6907638414 + 31 +0.0 + 0 +LINE + 5 +156A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528669.5576176427 + 20 +179697.5528052409 + 30 +0.0 + 11 +528588.0392999204 + 21 +179922.0311684939 + 31 +0.0 + 0 +LINE + 5 +156B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528857.6496070828 + 20 +179667.1027761433 + 30 +0.0 + 11 +528654.5144171252 + 21 +179707.6364226865 + 31 +0.0 + 0 +LINE + 5 +156C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528802.7626189134 + 20 +179599.3576436852 + 30 +0.0 + 11 +528798.9599687946 + 21 +179684.662154782 + 31 +0.0 + 0 +LINE + 5 +156D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528230.9063274992 + 20 +179641.3158552055 + 30 +0.0 + 11 +528315.4178125222 + 21 +179672.619208027 + 31 +0.0 + 0 +LINE + 5 +156E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528144.3947346573 + 20 +179767.238579988 + 30 +0.0 + 11 +528590.8943973097 + 21 +179920.8165756824 + 31 +0.0 + 0 +LINE + 5 +156F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528640.591098345 + 20 +179506.3056953474 + 30 +0.0 + 11 +528515.7889399241 + 21 +179911.5952802161 + 31 +0.0 + 0 +LINE + 5 +1570 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528993.3627290027 + 20 +179893.5685844917 + 30 +0.0 + 11 +528510.0567151904 + 21 +179907.6210035374 + 31 +0.0 + 0 +LINE + 5 +1571 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529246.4236587767 + 20 +179905.5266301457 + 30 +0.0 + 11 +528707.0717858409 + 21 +179897.3361826018 + 31 +0.0 + 0 +LINE + 5 +1572 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529012.6984706571 + 20 +179803.0212326646 + 30 +0.0 + 11 +528959.3215812568 + 21 +179907.6177689707 + 31 +0.0 + 0 +LINE + 5 +1573 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528950.6272643358 + 20 +179804.4960146925 + 30 +0.0 + 11 +528992.8488439449 + 21 +179905.9008424644 + 31 +0.0 + 0 +LINE + 5 +1574 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528760.793710597 + 20 +179796.3412164605 + 30 +0.0 + 11 +528961.0235601997 + 21 +179823.0851632388 + 31 +0.0 + 0 +LINE + 5 +1575 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528902.3510568863 + 20 +179387.5366045096 + 30 +0.0 + 11 +528805.4106229107 + 21 +179900.2562983138 + 31 +0.0 + 0 +LINE + 5 +1576 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528831.7373683648 + 20 +179745.5473126478 + 30 +0.0 + 11 +528855.8866233021 + 21 +179748.1101349233 + 31 +0.0 + 0 +LINE + 5 +1577 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528682.5754239966 + 20 +179863.462574682 + 30 +0.0 + 11 +528682.1007574591 + 21 +179908.782679105 + 31 +0.0 + 0 +LINE + 5 +1578 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528674.2674593516 + 20 +179850.3361353631 + 30 +0.0 + 11 +528685.4847378287 + 21 +179871.6274269207 + 31 +0.0 + 0 +LINE + 5 +1579 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528611.2588529547 + 20 +179838.572402642 + 30 +0.0 + 11 +528681.4738928051 + 21 +179853.7944442277 + 31 +0.0 + 0 +LINE + 5 +157A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528807.3632662322 + 20 +179672.788197632 + 30 +0.0 + 11 +529234.9711792036 + 21 +179749.003403953 + 31 +0.0 + 0 +LINE + 5 +157B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529213.5100731744 + 20 +179725.592080696 + 30 +0.0 + 11 +529143.7416550763 + 21 +179914.3953648365 + 31 +0.0 + 0 +LINE + 5 +157C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529242.0818526643 + 20 +179623.8202706216 + 30 +0.0 + 11 +528847.7112173356 + 21 +179657.5499932291 + 31 +0.0 + 0 +LINE + 5 +157D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528989.9527050682 + 20 +179695.9814363166 + 30 +0.0 + 11 +528986.8274817843 + 21 +179789.2663395969 + 31 +0.0 + 0 +LINE + 5 +157E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528992.1344180404 + 20 +179754.519073134 + 30 +0.0 + 11 +528943.8012646047 + 21 +179822.4638192218 + 31 +0.0 + 0 +LINE + 5 +157F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528979.5223181569 + 20 +179750.8850742235 + 30 +0.0 + 11 +529012.3471308522 + 21 +179824.0060649801 + 31 +0.0 + 0 +LINE + 5 +1580 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529179.5288811444 + 20 +179825.5150397874 + 30 +0.0 + 11 +529001.157264609 + 21 +179818.1618520918 + 31 +0.0 + 0 +LINE + 5 +1581 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528601.6035857312 + 20 +179615.8208689909 + 30 +0.0 + 11 +528644.3887794168 + 21 +179635.3025819352 + 31 +0.0 + 0 +LINE + 5 +1582 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528659.5501022991 + 20 +179573.3149631039 + 30 +0.0 + 11 +528642.8484182783 + 21 +179636.4168759029 + 31 +0.0 + 0 +LINE + 5 +1583 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528624.1101531263 + 20 +179538.6800739106 + 30 +0.0 + 11 +528727.328670395 + 21 +179553.8088784535 + 31 +0.0 + 0 +LINE + 5 +1584 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528729.2518578581 + 20 +179402.7821176971 + 30 +0.0 + 11 +528719.6294310883 + 21 +179701.221626218 + 31 +0.0 + 0 +LINE + 5 +1585 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528642.5870527347 + 20 +179762.6563937042 + 30 +0.0 + 11 +528708.6169873843 + 21 +179782.1400145828 + 31 +0.0 + 0 +LINE + 5 +1586 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528716.6868262284 + 20 +179751.3370014214 + 30 +0.0 + 11 +528699.849285463 + 21 +179809.0350878508 + 31 +0.0 + 0 +LINE + 5 +1587 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528708.7120860384 + 20 +179754.5724114705 + 30 +0.0 + 11 +528777.4075127313 + 21 +179773.7925641406 + 31 +0.0 + 0 +LINE + 5 +1588 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528775.8357279267 + 20 +179770.4237617937 + 30 +0.0 + 11 +528761.4684964741 + 21 +179824.6932049007 + 31 +0.0 + 0 +LINE + 5 +1589 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528694.0856440736 + 20 +179802.0766194414 + 30 +0.0 + 11 +528768.4818868498 + 21 +179823.7857617378 + 31 +0.0 + 0 +LINE + 5 +158A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528032.8196453648 + 20 +179780.2768232606 + 30 +0.0 + 11 +527664.9026817615 + 21 +180480.5680652355 + 31 +0.0 + 0 +LINE + 5 +158B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527966.1101532396 + 20 +179900.9142619889 + 30 +0.0 + 11 +528106.3942065767 + 21 +179947.5841568255 + 31 +0.0 + 0 +LINE + 5 +158C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528095.2980045713 + 20 +179798.8725363961 + 30 +0.0 + 11 +527864.5046873172 + 21 +180236.1585429227 + 31 +0.0 + 0 +LINE + 5 +158D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528079.5961462748 + 20 +179928.9392054262 + 30 +0.0 + 11 +528131.8277353538 + 21 +179992.1290729441 + 31 +0.0 + 0 +LINE + 5 +158E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528145.4687386187 + 20 +179884.0380117714 + 30 +0.0 + 11 +528078.5227200158 + 21 +179940.9208657209 + 31 +0.0 + 0 +LINE + 5 +158F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528184.2186491791 + 20 +179691.9183107798 + 30 +0.0 + 11 +528144.3445608914 + 21 +180208.4577227396 + 31 +0.0 + 0 +LINE + 5 +1590 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528542.1229614001 + 20 +179976.9272516323 + 30 +0.0 + 11 +528528.9751991945 + 21 +180089.2879995186 + 31 +0.0 + 0 +LINE + 5 +1591 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528610.3714329076 + 20 +180092.6729991083 + 30 +0.0 + 11 +527856.4539530258 + 21 +180042.873060517 + 31 +0.0 + 0 +LINE + 5 +1592 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528077.4643446711 + 20 +180126.0894573699 + 30 +0.0 + 11 +527913.1918958154 + 21 +180598.8407671337 + 31 +0.0 + 0 +LINE + 5 +1593 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528008.5147488142 + 20 +180117.3957666466 + 30 +0.0 + 11 +528199.9016598025 + 21 +180148.7097956767 + 31 +0.0 + 0 +LINE + 5 +1594 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527997.8728993692 + 20 +180189.2229846591 + 30 +0.0 + 11 +528061.4215112735 + 21 +180199.0829860361 + 31 +0.0 + 0 +LINE + 5 +1595 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527984.5321776591 + 20 +180136.5040111058 + 30 +0.0 + 11 +528008.4939101981 + 21 +180201.0260298027 + 31 +0.0 + 0 +LINE + 5 +1596 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528009.1252140441 + 20 +180180.5891704056 + 30 +0.0 + 11 +527962.1366878985 + 21 +180313.0783112867 + 31 +0.0 + 0 +LINE + 5 +1597 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527803.836979491 + 20 +180207.3562392084 + 30 +0.0 + 11 +528536.4916803161 + 21 +180520.438294822 + 31 +0.0 + 0 +LINE + 5 +1598 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528179.9864296183 + 20 +180355.6121590764 + 30 +0.0 + 11 +528072.0206366862 + 21 +180647.9226835457 + 31 +0.0 + 0 +LINE + 5 +1599 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527738.2754529142 + 20 +180314.0862154856 + 30 +0.0 + 11 +527822.7869379371 + 21 +180345.389568307 + 31 +0.0 + 0 +LINE + 5 +159A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528151.0199103206 + 20 +180164.3650491832 + 30 +0.0 + 11 +528012.2358912885 + 21 +180615.0601186566 + 31 +0.0 + 0 +LINE + 5 +159B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528379.2990357547 + 20 +180229.2825058204 + 30 +0.0 + 11 +528307.1084452349 + 21 +180651.417205561 + 31 +0.0 + 0 +LINE + 5 +159C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528415.9452134922 + 20 +179836.2631906246 + 30 +0.0 + 11 +528352.2185272204 + 21 +180395.2412563144 + 31 +0.0 + 0 +LINE + 5 +159D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528317.7920782079 + 20 +180330.8475514675 + 30 +0.0 + 11 +528836.3191207583 + 21 +180433.2372557007 + 31 +0.0 + 0 +LINE + 5 +159E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528593.0534033489 + 20 +180083.0078457863 + 30 +0.0 + 11 +528673.3390309509 + 21 +180270.5734778979 + 31 +0.0 + 0 +LINE + 5 +159F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528696.9071551498 + 20 +180250.2785411998 + 30 +0.0 + 11 +528358.1400293112 + 21 +180315.6093470646 + 31 +0.0 + 0 +LINE + 5 +15A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528500.3815170438 + 20 +180354.0407901521 + 30 +0.0 + 11 +528492.0712026886 + 21 +180568.5503232738 + 31 +0.0 + 0 +LINE + 5 +15A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528637.5468404127 + 20 +180478.6593455293 + 30 +0.0 + 11 +528473.9315714308 + 21 +180507.4188145933 + 31 +0.0 + 0 +LINE + 5 +15A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528585.6214509289 + 20 +179885.5412803603 + 30 +0.0 + 11 +528609.9239068013 + 21 +180153.9784371766 + 31 +0.0 + 0 +LINE + 5 +15A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528112.0323977069 + 20 +180273.8802228265 + 30 +0.0 + 11 +528154.8175913925 + 21 +180293.3619357707 + 31 +0.0 + 0 +LINE + 5 +15A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528169.9789142748 + 20 +180231.3743169395 + 30 +0.0 + 11 +528153.277230254 + 21 +180294.4762297385 + 31 +0.0 + 0 +LINE + 5 +15A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528134.5389651021 + 20 +180196.7394277462 + 30 +0.0 + 11 +528237.7574823708 + 21 +180211.8682322892 + 31 +0.0 + 0 +LINE + 5 +15A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528470.1836627297 + 20 +179972.1683387392 + 30 +0.0 + 11 +528457.968665224 + 21 +180084.2190610903 + 31 +0.0 + 0 +LINE + 5 +15A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527917.8465889796 + 20 +180253.7815098684 + 30 +0.0 + 11 +527769.6882990085 + 21 +180564.6440479685 + 31 +0.0 + 0 +LINE + 5 +15A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528587.8134982101 + 20 +180513.8955553372 + 30 +0.0 + 11 +528889.8979239679 + 21 +180694.7831536562 + 31 +0.0 + 0 +LINE + 5 +15A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528746.6298662342 + 20 +179891.4887384752 + 30 +0.0 + 11 +528569.28154252 + 21 +180662.4882546429 + 31 +0.0 + 0 +LINE + 5 +15AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528937.5113190281 + 20 +180167.75196714 + 30 +0.0 + 11 +528958.2724492294 + 21 +180403.8740448904 + 31 +0.0 + 0 +LINE + 5 +15AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528861.8812511615 + 20 +180211.1348817101 + 30 +0.0 + 11 +528945.4880698681 + 21 +180228.4905616793 + 31 +0.0 + 0 +LINE + 5 +15AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529096.4131830083 + 20 +180036.3587612945 + 30 +0.0 + 11 +529191.1606691565 + 21 +180105.7305249874 + 31 +0.0 + 0 +LINE + 5 +15AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529087.9719335948 + 20 +180097.870995399 + 30 +0.0 + 11 +529194.8115817942 + 21 +180072.3584405921 + 31 +0.0 + 0 +LINE + 5 +15AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528875.4199148993 + 20 +180169.4182922914 + 30 +0.0 + 11 +529120.3480046597 + 21 +180209.4214413092 + 31 +0.0 + 0 +LINE + 5 +15AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528853.6459178629 + 20 +180064.3840401553 + 30 +0.0 + 11 +528843.571176086 + 21 +180185.404555378 + 31 +0.0 + 0 +LINE + 5 +15B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528745.4894377002 + 20 +180157.0501350272 + 30 +0.0 + 11 +528805.3967661827 + 21 +180052.1747663256 + 31 +0.0 + 0 +LINE + 5 +15B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528800.2369369359 + 20 +180056.5049832557 + 30 +0.0 + 11 +528855.293267494 + 21 +180065.8012921374 + 31 +0.0 + 0 +LINE + 5 +15B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528462.4995255942 + 20 +180042.543345193 + 30 +0.0 + 11 +528462.5114981981 + 21 +180042.5467057729 + 31 +0.0 + 0 +LINE + 5 +15B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528603.4162683148 + 20 +180082.0971432843 + 30 +0.0 + 11 +529004.1650332488 + 21 +180194.5829659595 + 31 +0.0 + 0 +LINE + 5 +15B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528935.105918802 + 20 +180218.3014888331 + 30 +0.0 + 11 +529046.4939790572 + 21 +179885.1612415667 + 31 +0.0 + 0 +LINE + 5 +15B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528946.4408303008 + 20 +179884.1195385687 + 30 +0.0 + 11 +528926.4960903486 + 21 +180176.0400302016 + 31 +0.0 + 0 +LINE + 5 +15B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528802.8234097638 + 20 +180141.0691676066 + 30 +0.0 + 11 +528812.7234634602 + 21 +180106.951977412 + 31 +0.0 + 0 +LINE + 5 +15B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528987.1160488407 + 20 +180041.746183423 + 30 +0.0 + 11 +529078.7091752371 + 21 +180059.7055653025 + 31 +0.0 + 0 +LINE + 5 +15B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529045.2526401881 + 20 +180048.9261236859 + 30 +0.0 + 11 +529104.6214666463 + 21 +180107.4746051942 + 31 +0.0 + 0 +LINE + 5 +15B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529039.6541528286 + 20 +180060.7974315682 + 30 +0.0 + 11 +529117.0735198138 + 21 +180040.0516070889 + 31 +0.0 + 0 +LINE + 5 +15BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529145.2200757285 + 20 +179875.2493436762 + 30 +0.0 + 11 +529109.5198685039 + 21 +180050.1664616459 + 31 +0.0 + 0 +LINE + 5 +15BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528656.0994813299 + 20 +180252.361482507 + 30 +0.0 + 11 +528949.1865447303 + 21 +180309.4465471946 + 31 +0.0 + 0 +LINE + 5 +15BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528556.1696433956 + 20 +179206.5726048524 + 30 +0.0 + 11 +528172.098326215 + 21 +178845.8468364899 + 31 +0.0 + 0 +LINE + 5 +15BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528412.9488724005 + 20 +179064.4555633811 + 30 +0.0 + 11 +528042.393364479 + 21 +179763.3542192984 + 31 +0.0 + 0 +LINE + 5 +15BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528350.9928183259 + 20 +179187.6017989144 + 30 +0.0 + 11 +528233.3053349589 + 21 +179098.1179961152 + 31 +0.0 + 0 +LINE + 5 +15BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528362.3421411069 + 20 +179023.3665786782 + 30 +0.0 + 11 +528131.5488238528 + 21 +179460.6525852049 + 31 +0.0 + 0 +LINE + 5 +15C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528263.8196623647 + 20 +179109.7217055041 + 30 +0.0 + 11 +528182.1780688058 + 21 +179102.2552166527 + 31 +0.0 + 0 +LINE + 5 +15C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528263.7204491684 + 20 +179030.0015338379 + 30 +0.0 + 11 +528254.5333524718 + 21 +179117.3687229567 + 31 +0.0 + 0 +LINE + 5 +15C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528270.5677959786 + 20 +179047.7450890754 + 30 +0.0 + 11 +528123.5772799061 + 21 +178913.7747902436 + 31 +0.0 + 0 +LINE + 5 +15C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528334.1062798096 + 20 +178942.8942166801 + 30 +0.0 + 11 +527996.5153470805 + 21 +179213.9875280292 + 31 +0.0 + 0 +LINE + 5 +15C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528080.9944494109 + 20 +178950.2560815439 + 30 +0.0 + 11 +528185.6914929178 + 21 +179104.7823506414 + 31 +0.0 + 0 +LINE + 5 +15C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528129.0332797841 + 20 +178913.2982054521 + 30 +0.0 + 11 +528080.8891733374 + 21 +178951.0972225784 + 31 +0.0 + 0 +LINE + 5 +15C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527919.0704511244 + 20 +178702.6616373729 + 30 +0.0 + 11 +528098.4063959493 + 21 +178939.6945149362 + 31 +0.0 + 0 +LINE + 5 +15C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527963.2144118462 + 20 +178754.9395319815 + 30 +0.0 + 11 +527877.8686801754 + 21 +178829.1952213407 + 31 +0.0 + 0 +LINE + 5 +15C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527829.1451973728 + 20 +178763.9048904451 + 30 +0.0 + 11 +528367.6663100075 + 21 +179447.3825729228 + 31 +0.0 + 0 +LINE + 5 +15C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528102.2562094361 + 20 +179222.726205845 + 30 +0.0 + 11 +527821.9244401856 + 21 +179560.8058809949 + 31 +0.0 + 0 +LINE + 5 +15CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528148.3393523888 + 20 +179274.7451539584 + 30 +0.0 + 11 +528014.4941754031 + 21 +179134.4063257267 + 31 +0.0 + 0 +LINE + 5 +15CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528095.0439254675 + 20 +179324.060422145 + 30 +0.0 + 11 +528051.0454544846 + 21 +179277.1586071135 + 31 +0.0 + 0 +LINE + 5 +15CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528146.0961385644 + 20 +179305.3271211492 + 30 +0.0 + 11 +528079.3063470841 + 21 +179321.9517798538 + 31 +0.0 + 0 +LINE + 5 +15CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528095.8227038843 + 20 +179309.8988248382 + 30 +0.0 + 11 +527858.117585589 + 21 +179635.618603924 + 31 +0.0 + 0 +LINE + 5 +15CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528189.5603870874 + 20 +179494.4875080394 + 30 +0.0 + 11 +527845.2894322208 + 21 +179276.7968929931 + 31 +0.0 + 0 +LINE + 5 +15CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527854.9139456695 + 20 +179267.5954944 + 30 +0.0 + 11 +527715.583363013 + 21 +179461.5613687941 + 31 +0.0 + 0 +LINE + 5 +15D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527773.9200939974 + 20 +179095.1257963224 + 30 +0.0 + 11 +527855.0772710858 + 21 +179285.7048993431 + 31 +0.0 + 0 +LINE + 5 +15D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527860.8208356485 + 20 +179102.2142053516 + 30 +0.0 + 11 +527792.5395133066 + 21 +179153.4877929055 + 31 +0.0 + 0 +LINE + 5 +15D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528103.2485123857 + 20 +179660.6538035126 + 30 +0.0 + 11 +528029.7179450116 + 21 +179608.5448152255 + 31 +0.0 + 0 +LINE + 5 +15D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528093.7114108572 + 20 +179740.4886445803 + 30 +0.0 + 11 +527714.9751008977 + 21 +179458.5188642339 + 31 +0.0 + 0 +LINE + 5 +15D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528029.1514078468 + 20 +179183.5965476397 + 30 +0.0 + 11 +527764.9673537545 + 21 +179515.3223559707 + 31 +0.0 + 0 +LINE + 5 +15D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527561.7116223148 + 20 +179235.727857901 + 30 +0.0 + 11 +527731.416867063 + 21 +179465.5009430376 + 31 +0.0 + 0 +LINE + 5 +15D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527497.8881053979 + 20 +178896.5468150255 + 30 +0.0 + 11 +527636.6605627178 + 21 +179093.1155555411 + 31 +0.0 + 0 +LINE + 5 +15D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528150.5433908066 + 20 +178779.7398498826 + 30 +0.0 + 11 +527725.0122292528 + 21 +179147.7626739199 + 31 +0.0 + 0 +LINE + 5 +15D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527710.5941368728 + 20 +179350.4647146638 + 30 +0.0 + 11 +527660.2530446807 + 21 +179387.3596132032 + 31 +0.0 + 0 +LINE + 5 +15D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527726.1191382208 + 20 +179349.9169748675 + 30 +0.0 + 11 +527702.2116554058 + 21 +179352.6699183981 + 31 +0.0 + 0 +LINE + 5 +15DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527771.3846162575 + 20 +179395.2987596021 + 30 +0.0 + 11 +527719.1976540189 + 21 +179345.9187702994 + 31 +0.0 + 0 +LINE + 5 +15DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527688.9518843426 + 20 +178680.2527148979 + 30 +0.0 + 11 +527468.4287123164 + 21 +178736.4905809727 + 31 +0.0 + 0 +LINE + 5 +15DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527846.8966185731 + 20 +178772.7488930398 + 30 +0.0 + 11 +527661.1723446485 + 21 +178663.9843583443 + 31 +0.0 + 0 +LINE + 5 +15DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527960.7353715366 + 20 +179277.5797662137 + 30 +0.0 + 11 +527920.5092777147 + 21 +179253.2493055979 + 31 +0.0 + 0 +LINE + 5 +15DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527963.1310070435 + 20 +179205.7548976227 + 30 +0.0 + 11 +527920.45848973 + 21 +179255.1497750304 + 31 +0.0 + 0 +LINE + 5 +15DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528011.7228479952 + 20 +179215.4707887154 + 30 +0.0 + 11 +527940.9902370524 + 21 +179138.7906688454 + 31 +0.0 + 0 +LINE + 5 +15E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528064.5920592017 + 20 +179051.9841559795 + 30 +0.0 + 11 +527823.6313370143 + 21 +179228.3266117468 + 31 +0.0 + 0 +LINE + 5 +15E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527816.3831984929 + 20 +179326.5977835442 + 30 +0.0 + 11 +527763.0393937672 + 21 +179283.0776474026 + 31 +0.0 + 0 +LINE + 5 +15E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527783.9167134486 + 20 +179259.0342399549 + 30 +0.0 + 11 +527745.7822294013 + 21 +179305.4921034771 + 31 +0.0 + 0 +LINE + 5 +15E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527785.7454205332 + 20 +179267.4437696493 + 30 +0.0 + 11 +527731.1150967461 + 21 +179221.5743502057 + 31 +0.0 + 0 +LINE + 5 +15E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527734.7832638241 + 20 +179220.9711197252 + 30 +0.0 + 11 +527698.085549146 + 21 +179263.4548522845 + 31 +0.0 + 0 +LINE + 5 +15E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527754.7793158943 + 20 +179306.3241367128 + 30 +0.0 + 11 +527694.8773368726 + 21 +179257.1525930337 + 31 +0.0 + 0 +LINE + 5 +15E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527996.7755258292 + 20 +179885.2276632219 + 30 +0.0 + 11 +527915.1339322702 + 21 +179877.7611743706 + 31 +0.0 + 0 +LINE + 5 +15E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527996.6763126328 + 20 +179805.5074915559 + 30 +0.0 + 11 +527987.4892159362 + 21 +179892.8746806747 + 31 +0.0 + 0 +LINE + 5 +15E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528002.0619858726 + 20 +179822.162828514 + 30 +0.0 + 11 +527855.0714698003 + 21 +179688.1925296822 + 31 +0.0 + 0 +LINE + 5 +15E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528133.4243398228 + 20 +179665.1097987787 + 30 +0.0 + 11 +527729.4712105449 + 21 +179989.493485747 + 31 +0.0 + 0 +LINE + 5 +15EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527813.9503128752 + 20 +179725.7620392616 + 30 +0.0 + 11 +527918.647356382 + 21 +179880.2883083592 + 31 +0.0 + 0 +LINE + 5 +15EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527861.9891432484 + 20 +179688.8041631699 + 30 +0.0 + 11 +527813.8450368016 + 21 +179726.6031802962 + 31 +0.0 + 0 +LINE + 5 +15EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527652.026314589 + 20 +179478.1675950908 + 30 +0.0 + 11 +527831.3622594136 + 21 +179715.2004726541 + 31 +0.0 + 0 +LINE + 5 +15ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527629.3243400914 + 20 +179620.5471731373 + 30 +0.0 + 11 +528028.6230273386 + 21 +180133.7414422995 + 31 +0.0 + 0 +LINE + 5 +15EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527835.2120729005 + 20 +179998.2321635629 + 30 +0.0 + 11 +527665.7953887408 + 21 +180202.5484196148 + 31 +0.0 + 0 +LINE + 5 +15EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527881.2952158531 + 20 +180050.2511116761 + 30 +0.0 + 11 +527747.4500388677 + 21 +179909.9122834445 + 31 +0.0 + 0 +LINE + 5 +15F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527827.999788932 + 20 +180099.566379863 + 30 +0.0 + 11 +527784.0013179489 + 21 +180052.6645648313 + 31 +0.0 + 0 +LINE + 5 +15F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527879.0520020287 + 20 +180080.8330788671 + 30 +0.0 + 11 +527812.2622105485 + 21 +180097.4577375718 + 31 +0.0 + 0 +LINE + 5 +15F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527828.7785673487 + 20 +180085.4047825559 + 30 +0.0 + 11 +527591.0734490533 + 21 +180411.1245616417 + 31 +0.0 + 0 +LINE + 5 +15F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527829.5747659578 + 20 +180211.0921162493 + 30 +0.0 + 11 +527578.2452956853 + 21 +180052.3028507109 + 31 +0.0 + 0 +LINE + 5 +15F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527587.8698091339 + 20 +180043.1014521177 + 30 +0.0 + 11 +527448.5392264774 + 21 +180237.0673265123 + 31 +0.0 + 0 +LINE + 5 +15F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527769.4617253289 + 20 +179761.6104608084 + 30 +0.0 + 11 +527470.9605082231 + 21 +179966.4096719633 + 31 +0.0 + 0 +LINE + 5 +15F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527762.1072713112 + 20 +179959.1025053575 + 30 +0.0 + 11 +527472.4656967936 + 21 +180317.9957862653 + 31 +0.0 + 0 +LINE + 5 +15F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527343.0535079231 + 20 +179830.5261404157 + 30 +0.0 + 11 +527590.952526175 + 21 +180062.8786122959 + 31 +0.0 + 0 +LINE + 5 +15F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527447.3543171115 + 20 +179807.1752696685 + 30 +0.0 + 11 +527391.1184711135 + 21 +179910.2628894595 + 31 +0.0 + 0 +LINE + 5 +15F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527481.1611980505 + 20 +179859.2531386474 + 30 +0.0 + 11 +527373.6177806362 + 21 +179881.6141370817 + 31 +0.0 + 0 +LINE + 5 +15FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527883.4992542709 + 20 +179555.2458076005 + 30 +0.0 + 11 +527645.8118573582 + 21 +179767.6358265945 + 31 +0.0 + 0 +LINE + 5 +15FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527737.5594578391 + 20 +179726.7548728622 + 30 +0.0 + 11 +527417.4122622993 + 21 +179654.4557690584 + 31 +0.0 + 0 +LINE + 5 +15FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527530.6386112234 + 20 +179657.7533237969 + 30 +0.0 + 11 +527492.133122306 + 21 +179820.0747913089 + 31 +0.0 + 0 +LINE + 5 +15FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527499.0010025659 + 20 +179796.7849077535 + 30 +0.0 + 11 +527470.1787162922 + 21 +179875.0272112465 + 31 +0.0 + 0 +LINE + 5 +15FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527509.1177505392 + 20 +179805.1468705611 + 30 +0.0 + 11 +527430.2275831589 + 21 +179819.3062882198 + 31 +0.0 + 0 +LINE + 5 +15FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527368.2787077643 + 20 +179722.6300393009 + 30 +0.0 + 11 +527441.3665605957 + 21 +179825.2469205501 + 31 +0.0 + 0 +LINE + 5 +1600 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527747.0735497196 + 20 +179442.9676582734 + 30 +0.0 + 11 +527616.7640635243 + 21 +179515.7296088145 + 31 +0.0 + 0 +LINE + 5 +1601 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527693.6912350009 + 20 +180053.0857239316 + 30 +0.0 + 11 +527653.4651411791 + 21 +180028.7552633158 + 31 +0.0 + 0 +LINE + 5 +1602 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527696.0868705079 + 20 +179981.2608553404 + 30 +0.0 + 11 +527653.4143531943 + 21 +180030.6557327483 + 31 +0.0 + 0 +LINE + 5 +1603 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527744.6787114596 + 20 +179990.9767464331 + 30 +0.0 + 11 +527673.9461005169 + 21 +179914.2966265633 + 31 +0.0 + 0 +LINE + 5 +1604 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527797.5479226662 + 20 +179827.4901136973 + 30 +0.0 + 11 +527537.2927043674 + 21 +180019.8184956274 + 31 +0.0 + 0 +LINE + 5 +1605 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527549.3390619573 + 20 +180102.1037412619 + 30 +0.0 + 11 +527495.9952572316 + 21 +180058.5836051206 + 31 +0.0 + 0 +LINE + 5 +1606 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527516.8725769129 + 20 +180034.5401976727 + 30 +0.0 + 11 +527478.7380928657 + 21 +180080.9980611951 + 31 +0.0 + 0 +LINE + 5 +1607 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527740.6918608296 + 20 +179587.1529704054 + 30 +0.0 + 11 +527655.0757606819 + 21 +179660.4636376987 + 31 +0.0 + 0 +LINE + 5 +1608 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527385.2477976351 + 20 +179849.943018257 + 30 +0.0 + 11 +527098.8476690628 + 21 +179756.2214112595 + 31 +0.0 + 0 +LINE + 5 +1609 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527367.2505138509 + 20 +179783.5721316966 + 30 +0.0 + 11 +527151.8767663561 + 21 +179710.8833866505 + 31 +0.0 + 0 +LINE + 5 +160A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527499.9242881051 + 20 +179651.9989130187 + 30 +0.0 + 11 +527373.8551590216 + 21 +179538.2471115796 + 31 +0.0 + 0 +LINE + 5 +160B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527576.8788217952 + 20 +179534.6089957443 + 30 +0.0 + 11 +526615.348353887 + 21 +180575.7118171535 + 31 +0.0 + 0 +LINE + 5 +160C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527382.0885082257 + 20 +179644.0285202604 + 30 +0.0 + 11 +527003.6356507306 + 21 +179421.1895599007 + 31 +0.0 + 0 +LINE + 5 +160D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527338.0829680242 + 20 +179697.8164320882 + 30 +0.0 + 11 +527455.2849165784 + 21 +179543.3068163136 + 31 +0.0 + 0 +LINE + 5 +160E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527280.9007493075 + 20 +179653.0661017021 + 30 +0.0 + 11 +527320.1870217045 + 21 +179602.1521104691 + 31 +0.0 + 0 +LINE + 5 +160F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527307.5345819786 + 20 +179700.4781675243 + 30 +0.0 + 11 +527280.4730801873 + 21 +179637.1936461638 + 31 +0.0 + 0 +LINE + 5 +1610 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527295.0053416338 + 20 +179651.5768705524 + 30 +0.0 + 11 +526935.5510080746 + 21 +179468.8484386185 + 31 +0.0 + 0 +LINE + 5 +1611 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527092.8716803185 + 20 +179855.1358713125 + 30 +0.0 + 11 +527287.7366100949 + 21 +179398.970806405 + 31 +0.0 + 0 +LINE + 5 +1612 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527298.354902861 + 20 +179407.0050365438 + 30 +0.0 + 11 +527084.6545226875 + 21 +179300.3845919441 + 31 +0.0 + 0 +LINE + 5 +1613 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527455.7037134897 + 20 +179299.5473585614 + 30 +0.0 + 11 +527280.5032272824 + 21 +179410.0537906542 + 31 +0.0 + 0 +LINE + 5 +1614 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527462.5621885354 + 20 +179386.46654955 + 30 +0.0 + 11 +527401.0572255213 + 21 +179327.2343008504 + 31 +0.0 + 0 +LINE + 5 +1615 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526919.5354947839 + 20 +179622.1715367483 + 30 +0.0 + 11 +527087.5611156689 + 21 +179299.2989888672 + 31 +0.0 + 0 +LINE + 5 +1616 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527409.0610968798 + 20 +179565.6198368894 + 30 +0.0 + 11 +527039.455546023 + 21 +179357.7088869003 + 31 +0.0 + 0 +LINE + 5 +1617 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527398.1409041258 + 20 +179041.8821944623 + 30 +0.0 + 11 +527038.0363455138 + 21 +179364.5381727657 + 31 +0.0 + 0 +LINE + 5 +1618 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527525.0059336864 + 20 +178885.6477089472 + 30 +0.0 + 11 +527187.9674992323 + 21 +179236.314287511 + 31 +0.0 + 0 +LINE + 5 +1619 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527474.5189813144 + 20 +179094.2184453138 + 30 +0.0 + 11 +527363.7835159692 + 21 +179055.1392380027 + 31 +0.0 + 0 +LINE + 5 +161A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527428.49784197 + 20 +179135.8965495132 + 30 +0.0 + 11 +527389.2752835042 + 21 +179033.2944453069 + 31 +0.0 + 0 +LINE + 5 +161B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527296.4727948656 + 20 +179272.5445125288 + 30 +0.0 + 11 +527423.2337634025 + 21 +179115.2585048334 + 31 +0.0 + 0 +LINE + 5 +161C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527502.3991814606 + 20 +179340.924549142 + 30 +0.0 + 11 +527257.2582309912 + 21 +179166.4726921377 + 31 +0.0 + 0 +LINE + 5 +161D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527571.8810403514 + 20 +179264.5955464387 + 30 +0.0 + 11 +527723.8586542512 + 21 +179262.4553722551 + 31 +0.0 + 0 +LINE + 5 +161E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527686.9264469953 + 20 +179633.2069362727 + 30 +0.0 + 11 +527686.9169168243 + 21 +179633.1989479949 + 31 +0.0 + 0 +LINE + 5 +161F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527600.0914869286 + 20 +179415.8266688129 + 30 +0.0 + 11 +527395.9419716314 + 21 +179259.6580827202 + 31 +0.0 + 0 +LINE + 5 +1620 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527382.8922759684 + 20 +179260.5155255418 + 30 +0.0 + 11 +527398.6370130078 + 21 +179242.0261278335 + 31 +0.0 + 0 +LINE + 5 +1621 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527193.5343081437 + 20 +179277.7449970831 + 30 +0.0 + 11 +527161.9789393307 + 21 +179245.2120004136 + 31 +0.0 + 0 +LINE + 5 +1622 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527196.5504791403 + 20 +179292.9840389905 + 30 +0.0 + 11 +527190.0207427949 + 21 +179269.8213755883 + 31 +0.0 + 0 +LINE + 5 +1623 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527158.9668125681 + 20 +179344.9064608775 + 30 +0.0 + 11 +527199.393911068 + 21 +179285.5135986958 + 31 +0.0 + 0 +LINE + 5 +1624 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527415.3275361311 + 20 +179330.0564456594 + 30 +0.0 + 11 +527627.5144988411 + 21 +179050.1164214183 + 31 +0.0 + 0 +LINE + 5 +1625 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527611.2018236088 + 20 +179193.135292302 + 30 +0.0 + 11 +527455.0766069426 + 21 +179313.318124319 + 31 +0.0 + 0 +LINE + 5 +1626 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527517.997145268 + 20 +179718.8949694971 + 30 +0.0 + 11 +527622.1815325604 + 21 +179026.267323479 + 31 +0.0 + 0 +LINE + 5 +1627 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527531.7434246959 + 20 +179187.4935809829 + 30 +0.0 + 11 +527465.2336741706 + 21 +179122.0085194374 + 31 +0.0 + 0 +LINE + 5 +1628 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527493.0114002093 + 20 +179143.5476474413 + 30 +0.0 + 11 +527411.1744383372 + 21 +179127.5697278805 + 31 +0.0 + 0 +LINE + 5 +1629 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527486.3695190679 + 20 +179154.8682669677 + 30 +0.0 + 11 +527459.8123313106 + 21 +179079.2450999079 + 31 +0.0 + 0 +LINE + 5 +162A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527579.9902820873 + 20 +178963.0156940637 + 30 +0.0 + 11 +527455.7237957266 + 21 +179091.1887931223 + 31 +0.0 + 0 +LINE + 5 +162B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527305.3714396315 + 20 +179513.0645861748 + 30 +0.0 + 11 +527322.9766301279 + 21 +179469.4736788026 + 31 +0.0 + 0 +LINE + 5 +162C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527376.6593787462 + 20 +179503.977201821 + 30 +0.0 + 11 +527321.0923767731 + 21 +179469.7265676699 + 31 +0.0 + 0 +LINE + 5 +162D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527544.6406315378 + 20 +179579.6216649434 + 30 +0.0 + 11 +527332.1334225043 + 21 +179369.8612839087 + 31 +0.0 + 0 +LINE + 5 +162E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527233.9638032789 + 20 +179378.3750715273 + 30 +0.0 + 11 +527320.6271692625 + 21 +179235.9508334586 + 31 +0.0 + 0 +LINE + 5 +162F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527178.4163136899 + 20 +179661.3699555005 + 30 +0.0 + 11 +526916.167627152 + 21 +179585.7363974202 + 31 +0.0 + 0 +LINE + 5 +1630 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527907.9025003525 + 20 +178974.0706314878 + 30 +0.0 + 11 +528008.4651215832 + 21 +179106.5787103545 + 31 +0.0 + 0 +LINE + 5 +1631 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527870.3686323044 + 20 +178881.9514279978 + 30 +0.0 + 11 +528046.8928473712 + 21 +178828.1896266328 + 31 +0.0 + 0 +LINE + 5 +1632 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527359.4210690266 + 20 +179508.4265302118 + 30 +0.0 + 11 +527425.2949029307 + 21 +179411.5202268584 + 31 +0.0 + 0 +LINE + 5 +1633 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528186.1047930786 + 20 +179492.302454742 + 30 +0.0 + 11 +528260.6658836588 + 21 +179675.8912233747 + 31 +0.0 + 0 +LINE + 5 +1634 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529294.8928599667 + 20 +182000.5817697426 + 30 +0.0 + 11 +529368.8051009005 + 21 +182556.3946378973 + 31 +0.0 + 0 +LINE + 5 +1635 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529305.0816559066 + 20 +182018.6352957792 + 30 +0.0 + 11 +528520.6037537193 + 21 +181916.8259805211 + 31 +0.0 + 0 +LINE + 5 +1636 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529168.7853264406 + 20 +181997.9747406915 + 30 +0.0 + 11 +529173.7401840819 + 21 +182145.7351687175 + 31 +0.0 + 0 +LINE + 5 +1637 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529181.9177915637 + 20 +182114.1298371344 + 30 +0.0 + 11 +529140.8008297662 + 21 +182185.0558105655 + 31 +0.0 + 0 +LINE + 5 +1638 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529246.9013359591 + 20 +182160.3083448142 + 30 +0.0 + 11 +529170.3091204007 + 21 +182117.2843864177 + 31 +0.0 + 0 +LINE + 5 +1639 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529236.3844112596 + 20 +182144.4617614073 + 30 +0.0 + 11 +529260.6900043037 + 21 +182341.8534809173 + 31 +0.0 + 0 +LINE + 5 +163A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529358.6692182326 + 20 +182153.2521170987 + 30 +0.0 + 11 +528942.2843149059 + 21 +182271.9232323746 + 31 +0.0 + 0 +LINE + 5 +163B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529206.3030010937 + 20 +182355.5003102103 + 30 +0.0 + 11 +529140.7706389897 + 21 +182180.7280347275 + 31 +0.0 + 0 +LINE + 5 +163C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529264.233722323 + 20 +182337.6777019085 + 30 +0.0 + 11 +529205.5558683341 + 21 +182355.0998180983 + 31 +0.0 + 0 +LINE + 5 +163D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529314.675411189 + 20 +182630.7780077002 + 30 +0.0 + 11 +529224.9881370458 + 21 +182347.4016519313 + 31 +0.0 + 0 +LINE + 5 +163E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529297.5495948976 + 20 +182564.5332045134 + 30 +0.0 + 11 +529187.6164632194 + 21 +182591.2260476738 + 31 +0.0 + 0 +LINE + 5 +163F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529212.7106007468 + 20 +182668.7314626243 + 30 +0.0 + 11 +529031.4484553348 + 21 +181963.4250934025 + 31 +0.0 + 0 +LINE + 5 +1640 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528996.2985548904 + 20 +182180.5998709571 + 30 +0.0 + 11 +528558.3714701195 + 21 +182213.8208887712 + 31 +0.0 + 0 +LINE + 5 +1641 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528980.5053209261 + 20 +182112.922690252 + 30 +0.0 + 11 +529017.6079645442 + 21 +182303.2721371866 + 31 +0.0 + 0 +LINE + 5 +1642 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528909.4530478827 + 20 +182127.8884078224 + 30 +0.0 + 11 +528922.2768362436 + 21 +182190.9058352073 + 31 +0.0 + 0 +LINE + 5 +1643 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528954.2574374323 + 20 +182097.0690680281 + 30 +0.0 + 11 +528902.0732846576 + 21 +182141.9474561697 + 31 +0.0 + 0 +LINE + 5 +1644 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528921.4573247771 + 20 +182135.4418620226 + 30 +0.0 + 11 +528518.2627751507 + 21 +182141.0322916278 + 31 +0.0 + 0 +LINE + 5 +1645 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528825.0609212229 + 20 +181952.2275923816 + 30 +0.0 + 11 +528803.5951424895 + 21 +182358.9841714154 + 31 +0.0 + 0 +LINE + 5 +1646 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528816.6675426789 + 20 +182356.4525023064 + 30 +0.0 + 11 +528577.850721129 + 21 +182357.9682324038 + 31 +0.0 + 0 +LINE + 5 +1647 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528910.5455085181 + 20 +182522.2618153545 + 30 +0.0 + 11 +528801.987151067 + 21 +182345.8476296189 + 31 +0.0 + 0 +LINE + 5 +1648 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528955.0119935594 + 20 +182447.2637077112 + 30 +0.0 + 11 +528873.6965195808 + 21 +182473.323513025 + 31 +0.0 + 0 +LINE + 5 +1649 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528717.0630321416 + 20 +181925.5737602287 + 30 +0.0 + 11 +528717.0584691702 + 21 +182015.6964043191 + 31 +0.0 + 0 +LINE + 5 +164A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528568.9332375947 + 20 +181888.1792114258 + 30 +0.0 + 11 +528579.9812719242 + 21 +182360.2237966586 + 31 +0.0 + 0 +LINE + 5 +164B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528985.9508039319 + 20 +182262.8699518902 + 30 +0.0 + 11 +528562.5449074261 + 21 +182286.5906844586 + 31 +0.0 + 0 +LINE + 5 +164C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528745.3081725296 + 20 +182728.1779065364 + 30 +0.0 + 11 +528564.2810415382 + 21 +182279.8350117414 + 31 +0.0 + 0 +LINE + 5 +164D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528821.9810404587 + 20 +182969.6403267128 + 30 +0.0 + 11 +528642.3478926489 + 21 +182461.0152600103 + 31 +0.0 + 0 +LINE + 5 +164E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528836.9347059861 + 20 +182714.8635460567 + 30 +0.0 + 11 +528720.311168415 + 21 +182701.1348092714 + 31 +0.0 + 0 +LINE + 5 +164F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528813.9947484554 + 20 +182657.1680697636 + 30 +0.0 + 11 +528733.5650516428 + 21 +182731.9789296086 + 31 +0.0 + 0 +LINE + 5 +1650 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528755.7138641961 + 20 +182476.3183603657 + 30 +0.0 + 11 +528800.1732323709 + 21 +182673.3731647797 + 31 +0.0 + 0 +LINE + 5 +1651 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529004.3540774635 + 20 +182499.4855786111 + 30 +0.0 + 11 +528673.7620462308 + 21 +182554.2472550911 + 31 +0.0 + 0 +LINE + 5 +1652 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528993.9880467048 + 20 +182406.4847752476 + 30 +0.0 + 11 +529000.1275371754 + 21 +182527.768624887 + 31 +0.0 + 0 +LINE + 5 +1653 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529099.0783096793 + 20 +182502.614198256 + 30 +0.0 + 11 +529042.608227567 + 21 +182395.8487506972 + 31 +0.0 + 0 +LINE + 5 +1654 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529047.6247190138 + 20 +182400.3442406685 + 30 +0.0 + 11 +528992.2955430044 + 21 +182407.8477848628 + 31 +0.0 + 0 +LINE + 5 +1655 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529385.637389287 + 20 +182397.357420962 + 30 +0.0 + 11 +528839.3203233203 + 21 +182531.7271790895 + 31 +0.0 + 0 +LINE + 5 +1656 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528827.9844859108 + 20 +182525.2057869599 + 30 +0.0 + 11 +528833.9680801772 + 21 +182548.7419542709 + 31 +0.0 + 0 +LINE + 5 +1657 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528665.6056340302 + 20 +182426.2795359938 + 30 +0.0 + 11 +528622.9415754407 + 21 +182441.5738250564 + 31 +0.0 + 0 +LINE + 5 +1658 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528675.0297259523 + 20 +182413.9299539289 + 30 +0.0 + 11 +528658.9593809825 + 21 +182431.8433691579 + 31 +0.0 + 0 +LINE + 5 +1659 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528664.1787142876 + 20 +182350.7577651632 + 30 +0.0 + 11 +528674.2894280408 + 21 +182421.8888823951 + 31 +0.0 + 0 +LINE + 5 +165A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528887.7498133832 + 20 +182477.0800006834 + 30 +0.0 + 11 +528964.7842887796 + 21 +182904.5410802109 + 31 +0.0 + 0 +LINE + 5 +165B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529215.7597066946 + 20 +182649.1347208173 + 30 +0.0 + 11 +528947.2035067732 + 21 +182892.9833056864 + 31 +0.0 + 0 +LINE + 5 +165C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529084.6450460566 + 20 +182867.7337791315 + 30 +0.0 + 11 +528916.0521447092 + 21 +182509.6244022478 + 31 +0.0 + 0 +LINE + 5 +165D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529040.9135465872 + 20 +182479.1691321838 + 30 +0.0 + 11 +529049.095153617 + 21 +182513.7387002515 + 31 +0.0 + 0 +LINE + 5 +165E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528929.4124673524 + 20 +182656.3592598277 + 30 +0.0 + 11 +528840.8485974237 + 21 +182685.825870489 + 31 +0.0 + 0 +LINE + 5 +165F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528875.2761308614 + 20 +182678.7349579624 + 30 +0.0 + 11 +528794.7746977778 + 21 +182657.0070608392 + 31 +0.0 + 0 +LINE + 5 +1660 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528874.3038264703 + 20 +182665.6458160607 + 30 +0.0 + 11 +528817.1340307507 + 21 +182721.8219860538 + 31 +0.0 + 0 +LINE + 5 +1661 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529410.8461557705 + 20 +182845.4371980838 + 30 +0.0 + 11 +529364.6733579714 + 21 +182538.1584258087 + 31 +0.0 + 0 +LINE + 5 +1662 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529399.4032669115 + 20 +182591.429824433 + 30 +0.0 + 11 +529155.0656218786 + 21 +182689.6028168605 + 31 +0.0 + 0 +LINE + 5 +1663 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528869.7121310872 + 20 +182264.3431569781 + 30 +0.0 + 11 +528866.3020843692 + 21 +182311.2311247239 + 31 +0.0 + 0 +LINE + 5 +1664 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528929.6967991418 + 20 +182303.9208074386 + 30 +0.0 + 11 +528864.7221897459 + 21 +182310.1736293514 + 31 +0.0 + 0 +LINE + 5 +1665 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528949.8677920855 + 20 +182258.6582777871 + 30 +0.0 + 11 +528971.5278565793 + 21 +182360.7062304376 + 31 +0.0 + 0 +LINE + 5 +1666 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529113.8220521923 + 20 +182310.0589895508 + 30 +0.0 + 11 +528830.6167346646 + 21 +182404.6818169607 + 31 +0.0 + 0 +LINE + 5 +1667 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528746.2495264531 + 20 +182353.7707877327 + 30 +0.0 + 11 +528750.9104548647 + 21 +182422.4573184263 + 31 +0.0 + 0 +LINE + 5 +1668 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528782.5987803646 + 20 +182419.3271513715 + 30 +0.0 + 11 +528722.6444604755 + 21 +182423.5758550844 + 31 +0.0 + 0 +LINE + 5 +1669 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528776.7951732625 + 20 +182412.9724284125 + 30 +0.0 + 11 +528782.6288806188 + 21 +182484.0670398513 + 31 +0.0 + 0 +LINE + 5 +166A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528785.2421241746 + 20 +182481.4231232787 + 30 +0.0 + 11 +528729.3609600332 + 21 +182486.7976268792 + 31 +0.0 + 0 +LINE + 5 +166B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528727.1681281097 + 20 +182415.7543286476 + 30 +0.0 + 11 +528732.6476304777 + 21 +182493.0593275304 + 31 +0.0 + 0 +LINE + 5 +166C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529277.0281920406 + 20 +182495.4189370289 + 30 +0.0 + 11 +529167.7097325291 + 21 +182522.878816007 + 31 +0.0 + 0 +LINE + 5 +166D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528821.1202140835 + 20 +182075.2640407977 + 30 +0.0 + 11 +528556.7599519333 + 21 +182063.9768110757 + 31 +0.0 + 0 +LINE + 5 +166E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529022.0789531999 + 20 +181853.5018650219 + 30 +0.0 + 11 +527686.7491531824 + 21 +181680.2031497812 + 31 +0.0 + 0 +LINE + 5 +166F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528381.6608302458 + 20 +181767.4165293778 + 30 +0.0 + 11 +528386.6156878871 + 21 +181915.1769574041 + 31 +0.0 + 0 +LINE + 5 +1670 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528522.2172874869 + 20 +181853.1247379782 + 30 +0.0 + 11 +528031.996430273 + 21 +181788.563774962 + 31 +0.0 + 0 +LINE + 5 +1671 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528394.7932953689 + 20 +181883.5716258208 + 30 +0.0 + 11 +528353.6763335714 + 21 +181954.497599252 + 31 +0.0 + 0 +LINE + 5 +1672 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528459.7768397642 + 20 +181929.7501335006 + 30 +0.0 + 11 +528383.1846242059 + 21 +181886.7261751042 + 31 +0.0 + 0 +LINE + 5 +1673 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528449.302553226 + 20 +181915.7253323631 + 30 +0.0 + 11 +528473.60814627 + 21 +182113.117051873 + 31 +0.0 + 0 +LINE + 5 +1674 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528653.3959037955 + 20 +181899.3660402736 + 30 +0.0 + 11 +528155.1598187115 + 21 +182041.3650210609 + 31 +0.0 + 0 +LINE + 5 +1675 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528419.1785048989 + 20 +182124.9420988967 + 30 +0.0 + 11 +528353.6461427949 + 21 +181950.169823414 + 31 +0.0 + 0 +LINE + 5 +1676 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528477.1092261283 + 20 +182107.1194905949 + 30 +0.0 + 11 +528418.4313721394 + 21 +182124.5416067849 + 31 +0.0 + 0 +LINE + 5 +1677 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528527.5509149943 + 20 +182400.2197963869 + 30 +0.0 + 11 +528437.8636408509 + 21 +182116.8434406178 + 31 +0.0 + 0 +LINE + 5 +1678 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528510.4250987028 + 20 +182333.9749932 + 30 +0.0 + 11 +528400.4919670246 + 21 +182360.6678363602 + 31 +0.0 + 0 +LINE + 5 +1679 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528425.5861045521 + 20 +182438.1732513108 + 30 +0.0 + 11 +528210.4551193718 + 21 +181713.8872169497 + 31 +0.0 + 0 +LINE + 5 +167A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528209.1740586957 + 20 +181950.0416596434 + 30 +0.0 + 11 +527771.2469739247 + 21 +181983.2626774577 + 31 +0.0 + 0 +LINE + 5 +167B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528193.3808247313 + 20 +181882.3644789384 + 30 +0.0 + 11 +528230.4834683494 + 21 +182072.7139258729 + 31 +0.0 + 0 +LINE + 5 +167C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528122.328551688 + 20 +181897.330196509 + 30 +0.0 + 11 +528135.1523400488 + 21 +181960.3476238937 + 31 +0.0 + 0 +LINE + 5 +167D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528167.1329412375 + 20 +181866.5108567147 + 30 +0.0 + 11 +528114.9487884628 + 21 +181911.3892448562 + 31 +0.0 + 0 +LINE + 5 +167E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528134.3328285824 + 20 +181904.883650709 + 30 +0.0 + 11 +527731.1382789561 + 21 +181910.4740803142 + 31 +0.0 + 0 +LINE + 5 +167F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527996.1768338681 + 20 +181460.0353403722 + 30 +0.0 + 11 +527948.1823344532 + 21 +182149.6768160842 + 31 +0.0 + 0 +LINE + 5 +1680 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528029.5430464843 + 20 +182125.8942909927 + 30 +0.0 + 11 +527797.7082417475 + 21 +182127.3657074069 + 31 +0.0 + 0 +LINE + 5 +1681 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528123.4210123233 + 20 +182291.7036040411 + 30 +0.0 + 11 +528014.8626548722 + 21 +182115.2894183054 + 31 +0.0 + 0 +LINE + 5 +1682 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528167.8874973648 + 20 +182216.7054963975 + 30 +0.0 + 11 +528086.572023386 + 21 +182242.7653017115 + 31 +0.0 + 0 +LINE + 5 +1683 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527852.4579638684 + 20 +181696.0038806513 + 30 +0.0 + 11 +527852.453400897 + 21 +181786.1265247416 + 31 +0.0 + 0 +LINE + 5 +1684 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527781.8087413998 + 20 +181657.6210001123 + 30 +0.0 + 11 +527782.4804644517 + 21 +182093.9906394431 + 31 +0.0 + 0 +LINE + 5 +1685 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528198.8263077372 + 20 +182032.3117405768 + 30 +0.0 + 11 +527775.4204112313 + 21 +182056.0324731452 + 31 +0.0 + 0 +LINE + 5 +1686 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527910.8695471963 + 20 +182377.3371982609 + 30 +0.0 + 11 +527777.1565453434 + 21 +182049.2768004279 + 31 +0.0 + 0 +LINE + 5 +1687 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528217.2295812688 + 20 +182268.9273672976 + 30 +0.0 + 11 +527886.6375500361 + 21 +182323.6890437774 + 31 +0.0 + 0 +LINE + 5 +1688 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528206.8635505101 + 20 +182175.9265639341 + 30 +0.0 + 11 +528213.0030409806 + 21 +182297.2104135735 + 31 +0.0 + 0 +LINE + 5 +1689 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528311.9538134844 + 20 +182272.0559869425 + 30 +0.0 + 11 +528255.4837313723 + 21 +182165.2905393836 + 31 +0.0 + 0 +LINE + 5 +168A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528260.5002228191 + 20 +182169.786029355 + 30 +0.0 + 11 +528205.1710468096 + 21 +182177.2895735493 + 31 +0.0 + 0 +LINE + 5 +168B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528598.5128930922 + 20 +182166.7992096486 + 30 +0.0 + 11 +528052.1958271254 + 21 +182301.1689677762 + 31 +0.0 + 0 +LINE + 5 +168C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528040.859989716 + 20 +182294.6475756465 + 30 +0.0 + 11 +528046.8435839823 + 21 +182318.1837429574 + 31 +0.0 + 0 +LINE + 5 +168D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527878.4811378353 + 20 +182195.7213246802 + 30 +0.0 + 11 +527671.7558010316 + 21 +182303.4826875344 + 31 +0.0 + 0 +LINE + 5 +168E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527887.9052297575 + 20 +182183.3717426153 + 30 +0.0 + 11 +527871.8348847878 + 21 +182201.2851578445 + 31 +0.0 + 0 +LINE + 5 +168F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527877.0542180927 + 20 +182120.1995538495 + 30 +0.0 + 11 +527887.164931846 + 21 +182191.3306710815 + 31 +0.0 + 0 +LINE + 5 +1690 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528100.6253171885 + 20 +182246.5217893698 + 30 +0.0 + 11 +528157.0949773981 + 21 +182597.0428668813 + 31 +0.0 + 0 +LINE + 5 +1691 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528428.6352104999 + 20 +182418.5765095037 + 30 +0.0 + 11 +528280.6271078863 + 21 +182559.005316768 + 31 +0.0 + 0 +LINE + 5 +1692 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528307.8438843695 + 20 +182574.0581574205 + 30 +0.0 + 11 +528128.9276485144 + 21 +182279.0661909342 + 31 +0.0 + 0 +LINE + 5 +1693 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528253.7890503926 + 20 +182248.6109208704 + 30 +0.0 + 11 +528261.9706574223 + 21 +182283.180488938 + 31 +0.0 + 0 +LINE + 5 +1694 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528611.2296355624 + 20 +182343.028152049 + 30 +0.0 + 11 +528367.9411256838 + 21 +182459.0446055469 + 31 +0.0 + 0 +LINE + 5 +1695 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528082.5876348925 + 20 +182033.7849456645 + 30 +0.0 + 11 +528079.1775881745 + 21 +182080.6729134102 + 31 +0.0 + 0 +LINE + 5 +1696 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528142.5723029471 + 20 +182073.3625961251 + 30 +0.0 + 11 +528077.5976935512 + 21 +182079.6154180378 + 31 +0.0 + 0 +LINE + 5 +1697 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528162.7432958909 + 20 +182028.1000664736 + 30 +0.0 + 11 +528184.4033603846 + 21 +182130.1480191241 + 31 +0.0 + 0 +LINE + 5 +1698 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528326.6975559975 + 20 +182079.5007782372 + 30 +0.0 + 11 +528043.4922384698 + 21 +182174.1236056473 + 31 +0.0 + 0 +LINE + 5 +1699 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528489.9036958461 + 20 +182264.8607257154 + 30 +0.0 + 11 +528380.5852363343 + 21 +182292.3206046936 + 31 +0.0 + 0 +LINE + 5 +169A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527996.0297969854 + 20 +181841.1454156097 + 30 +0.0 + 11 +527769.6354557385 + 21 +181833.4185997619 + 31 +0.0 + 0 +LINE + 5 +169B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528206.8113715502 + 20 +182531.1448343106 + 30 +0.0 + 11 +528226.7190239089 + 21 +182699.7763349743 + 31 +0.0 + 0 +LINE + 5 +169C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528661.5696626142 + 20 +182496.080312222 + 30 +0.0 + 11 +527912.2476470924 + 21 +182592.9726102086 + 31 +0.0 + 0 +LINE + 5 +169D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528145.1765234692 + 20 +182631.8917632092 + 30 +0.0 + 11 +528108.1456837993 + 21 +183069.5131572405 + 31 +0.0 + 0 +LINE + 5 +169E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528075.8469801618 + 20 +182636.6919144571 + 30 +0.0 + 11 +528269.6771046024 + 21 +182630.4148951759 + 31 +0.0 + 0 +LINE + 5 +169F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528079.2920485041 + 20 +182709.2214237011 + 30 +0.0 + 11 +528143.5479804768 + 21 +182706.6097368051 + 31 +0.0 + 0 +LINE + 5 +16A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528056.0109985714 + 20 +182660.0761518805 + 30 +0.0 + 11 +528091.9945362762 + 21 +182718.7484667934 + 31 +0.0 + 0 +LINE + 5 +16A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528088.6629300958 + 20 +182698.5751139037 + 30 +0.0 + 11 +528029.8930534446 + 21 +183097.5026754358 + 31 +0.0 + 0 +LINE + 5 +16A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527892.4223935542 + 20 +182764.5249966642 + 30 +0.0 + 11 +528290.552339738 + 21 +182850.572891442 + 31 +0.0 + 0 +LINE + 5 +16A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528290.1374353627 + 20 +182837.2640654401 + 30 +0.0 + 11 +528256.5027161783 + 21 +183054.2493831048 + 31 +0.0 + 0 +LINE + 5 +16A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528468.7941289087 + 20 +182771.0252051323 + 30 +0.0 + 11 +528277.3274718031 + 21 +182850.0657081549 + 31 +0.0 + 0 +LINE + 5 +16A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528401.8456452598 + 20 +182715.1692745681 + 30 +0.0 + 11 +528414.6064138194 + 21 +182799.5996159577 + 31 +0.0 + 0 +LINE + 5 +16A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527788.3542460773 + 20 +183007.16342335 + 30 +0.0 + 11 +528210.7738302006 + 21 +183067.2709162053 + 31 +0.0 + 0 +LINE + 5 +16A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528224.7441269853 + 20 +182655.224972105 + 30 +0.0 + 11 +528180.649928748 + 21 +183076.9961518119 + 31 +0.0 + 0 +LINE + 5 +16A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529484.7651123115 + 20 +182728.031229721 + 30 +0.0 + 11 +528171.209505827 + 21 +183064.0007175021 + 31 +0.0 + 0 +LINE + 5 +16A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528398.7507832566 + 20 +182916.5503537137 + 30 +0.0 + 11 +528600.373497463 + 21 +182904.0798895212 + 31 +0.0 + 0 +LINE + 5 +16AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528462.0372066938 + 20 +182709.0019624602 + 30 +0.0 + 11 +528462.6155764694 + 21 +183009.8793486124 + 31 +0.0 + 0 +LINE + 5 +16AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528536.6020754626 + 20 +182656.4808197359 + 30 +0.0 + 11 +528419.6154353832 + 21 +182689.0628940951 + 31 +0.0 + 0 +LINE + 5 +16AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528412.1417479692 + 20 +182587.2388077762 + 30 +0.0 + 11 +528531.2947461346 + 21 +182606.9946675243 + 31 +0.0 + 0 +LINE + 5 +16AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528525.4420793897 + 20 +182603.6598649078 + 30 +0.0 + 11 +528535.8451536205 + 21 +182658.517835522 + 31 +0.0 + 0 +LINE + 5 +16AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528421.2404396244 + 20 +182282.0957117013 + 30 +0.0 + 11 +528421.2414462359 + 21 +182282.1081061951 + 31 +0.0 + 0 +LINE + 5 +16AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528433.0881905932 + 20 +182427.9780688233 + 30 +0.0 + 11 +528466.7816430264 + 21 +182842.8483909267 + 31 +0.0 + 0 +LINE + 5 +16B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528458.5362012535 + 20 +182852.9993738869 + 30 +0.0 + 11 +528482.7253278994 + 21 +182850.8451398792 + 31 +0.0 + 0 +LINE + 5 +16B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528420.5556191065 + 20 +182786.3250830966 + 30 +0.0 + 11 +528771.6443869495 + 21 +182775.0822449014 + 31 +0.0 + 0 +LINE + 5 +16B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528737.8733696192 + 20 +182680.8950052683 + 30 +0.0 + 11 +528457.1964209409 + 21 +182763.5740024058 + 31 +0.0 + 0 +LINE + 5 +16B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528447.0397569236 + 20 +182635.4539987776 + 30 +0.0 + 11 +528482.4715955876 + 21 +182632.8891325321 + 31 +0.0 + 0 +LINE + 5 +16B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528604.1842720816 + 20 +182773.7812678206 + 30 +0.0 + 11 +528619.1525139648 + 21 +182865.9104810782 + 31 +0.0 + 0 +LINE + 5 +16B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528617.6417409251 + 20 +182830.7927695371 + 30 +0.0 + 11 +528583.3559890368 + 21 +182906.7998051287 + 31 +0.0 + 0 +LINE + 5 +16B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528604.5650258331 + 20 +182829.6655898895 + 30 +0.0 + 11 +528650.9068507839 + 21 +182895.0611774923 + 31 +0.0 + 0 +LINE + 5 +16B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528815.2263340769 + 20 +182864.2209108569 + 30 +0.0 + 11 +528638.798243567 + 21 +182891.4905245996 + 31 +0.0 + 0 +LINE + 5 +16B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528207.6643971698 + 20 +182770.2114157729 + 30 +0.0 + 11 +528253.4087645679 + 21 +182781.0540533346 + 31 +0.0 + 0 +LINE + 5 +16B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528256.3001686514 + 20 +182717.3047758302 + 30 +0.0 + 11 +528252.1128866399 + 21 +182782.4451190698 + 31 +0.0 + 0 +LINE + 5 +16BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528214.8329523457 + 20 +182690.174801288 + 30 +0.0 + 11 +528319.0289938037 + 21 +182685.0632478495 + 31 +0.0 + 0 +LINE + 5 +16BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528291.7183237425 + 20 +182536.5139011146 + 30 +0.0 + 11 +528339.9738941262 + 21 +182831.183430028 + 31 +0.0 + 0 +LINE + 5 +16BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528276.2619798829 + 20 +182906.3535750451 + 30 +0.0 + 11 +528344.8129298933 + 21 +182912.7042446996 + 31 +0.0 + 0 +LINE + 5 +16BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528346.7754667857 + 20 +182880.9222314257 + 30 +0.0 + 11 +528341.4101846297 + 21 +182940.7869598057 + 31 +0.0 + 0 +LINE + 5 +16BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528339.5766679224 + 20 +182885.6383372573 + 30 +0.0 + 11 +528410.6918881676 + 21 +182891.2151971855 + 31 +0.0 + 0 +LINE + 5 +16BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528408.4984751054 + 20 +182888.213818192 + 30 +0.0 + 11 +528404.8940483753 + 21 +182944.2370089496 + 31 +0.0 + 0 +LINE + 5 +16C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528334.410017133 + 20 +182935.0740358879 + 30 +0.0 + 11 +528411.5996931515 + 21 +182941.9908064232 + 31 +0.0 + 0 +LINE + 5 +16C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528989.1832316477 + 20 +181787.7273625354 + 30 +0.0 + 11 +528851.974849362 + 21 +181769.6573331517 + 31 +0.0 + 0 +LINE + 5 +16C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529064.9186347733 + 20 +181659.5575442809 + 30 +0.0 + 11 +528650.5247131833 + 21 +181514.0878039578 + 31 +0.0 + 0 +LINE + 5 +16C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528980.9376501028 + 20 +181683.7990316437 + 30 +0.0 + 11 +528592.9382876016 + 21 +181574.0101777006 + 31 +0.0 + 0 +LINE + 5 +16C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528840.3930210647 + 20 +181835.8087105029 + 30 +0.0 + 11 +528913.2932495596 + 21 +181492.3751053638 + 31 +0.0 + 0 +LINE + 5 +16C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528654.593928897 + 20 +181812.577808336 + 30 +0.0 + 11 +528677.9227151468 + 21 +181725.5269109787 + 31 +0.0 + 0 +LINE + 5 +16C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528576.4161301284 + 20 +181831.3605113784 + 30 +0.0 + 11 +528709.3021110472 + 21 +181378.271705971 + 31 +0.0 + 0 +LINE + 5 +16C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529076.2238395554 + 20 +181577.4135578212 + 30 +0.0 + 11 +528673.3963042988 + 21 +181444.8797765102 + 31 +0.0 + 0 +LINE + 5 +16C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528907.1951827109 + 20 +181141.4120527991 + 30 +0.0 + 11 +528673.3241644014 + 21 +181451.8545934505 + 31 +0.0 + 0 +LINE + 5 +16C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528964.3299977859 + 20 +181545.8958235747 + 30 +0.0 + 11 +528973.1757483785 + 21 +181499.7237255672 + 31 +0.0 + 0 +LINE + 5 +16CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529032.516205163 + 20 +181523.1979835643 + 30 +0.0 + 11 +528971.3759329806 + 21 +181500.3361208781 + 31 +0.0 + 0 +LINE + 5 +16CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528660.8951822511 + 20 +181842.4229195187 + 30 +0.0 + 11 +528216.4117742468 + 21 +181576.2699427678 + 31 +0.0 + 0 +LINE + 5 +16CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528669.0146415672 + 20 +181326.0649810698 + 30 +0.0 + 11 +528461.5209524132 + 21 +181650.9205861786 + 31 +0.0 + 0 +LINE + 5 +16CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528580.3528789561 + 20 +181263.0064435044 + 30 +0.0 + 11 +528185.0360547931 + 21 +181906.897900886 + 31 +0.0 + 0 +LINE + 5 +16CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528244.9402156842 + 20 +181678.4639860913 + 30 +0.0 + 11 +527830.546294094 + 21 +181532.9942457681 + 31 +0.0 + 0 +LINE + 5 +16CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528212.1635331643 + 20 +181739.7446201465 + 30 +0.0 + 11 +528297.2834846542 + 21 +181565.4916087805 + 31 +0.0 + 0 +LINE + 5 +16D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528147.4086398607 + 20 +181706.8934101192 + 30 +0.0 + 11 +528176.1106935607 + 21 +181649.3448409319 + 31 +0.0 + 0 +LINE + 5 +16D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528182.7060481197 + 20 +181748.2619730439 + 30 +0.0 + 11 +528143.9204621834 + 21 +181691.403078871 + 31 +0.0 + 0 +LINE + 5 +16D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528274.1019821601 + 20 +181410.2033416521 + 30 +0.0 + 11 +528202.306147755 + 21 +181363.9791280465 + 31 +0.0 + 0 +LINE + 5 +16D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527794.473391523 + 20 +181723.0524672429 + 30 +0.0 + 11 +527877.5480466762 + 21 +181522.7459140839 + 31 +0.0 + 0 +LINE + 5 +16D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528256.2454204663 + 20 +181596.3199996316 + 30 +0.0 + 11 +527853.4178852097 + 21 +181463.7862183204 + 31 +0.0 + 0 +LINE + 5 +16D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528335.2821380603 + 20 +181372.5369963514 + 30 +0.0 + 11 +528030.1404292131 + 21 +181234.0506437841 + 31 +0.0 + 0 +LINE + 5 +16D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528301.1911965698 + 20 +181459.6829183916 + 30 +0.0 + 11 +528338.5223299863 + 21 +181344.1240502575 + 31 +0.0 + 0 +LINE + 5 +16D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528351.4091950987 + 20 +181479.500875023 + 30 +0.0 + 11 +528299.9092923348 + 21 +181457.9281860703 + 31 +0.0 + 0 +LINE + 5 +16D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528677.1232839307 + 20 +181569.8989872454 + 30 +0.0 + 11 +528184.2230778662 + 21 +181298.6666968981 + 31 +0.0 + 0 +LINE + 5 +16D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528171.5853402168 + 20 +181302.0308241542 + 30 +0.0 + 11 +528183.4585396952 + 21 +181280.8463556411 + 31 +0.0 + 0 +LINE + 5 +16DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528216.8528368949 + 20 +181363.9891925735 + 30 +0.0 + 11 +528362.1486633801 + 21 +181040.0401670928 + 31 +0.0 + 0 +LINE + 5 +16DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528578.2243266215 + 20 +181282.7244201118 + 30 +0.0 + 11 +528471.6205885658 + 21 +181108.7638171541 + 31 +0.0 + 0 +LINE + 5 +16DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528501.806603812 + 20 +181101.2707925706 + 30 +0.0 + 11 +528252.6160433516 + 21 +181339.8820754586 + 31 +0.0 + 0 +LINE + 5 +16DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528735.032957025 + 20 +181402.9713818568 + 30 +0.0 + 11 +528530.0771271274 + 21 +181227.9221764542 + 31 +0.0 + 0 +LINE + 5 +16DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528144.3515786968 + 20 +181564.8022653851 + 30 +0.0 + 11 +528153.1973292892 + 21 +181518.6301673776 + 31 +0.0 + 0 +LINE + 5 +16DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528212.5377860739 + 20 +181542.1044253746 + 30 +0.0 + 11 +528151.3975138914 + 21 +181519.2425626885 + 31 +0.0 + 0 +LINE + 5 +16E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528220.302314568 + 20 +181591.0459991545 + 30 +0.0 + 11 +528267.6445463101 + 21 +181498.0854907237 + 31 +0.0 + 0 +LINE + 5 +16E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528597.6059605881 + 20 +181447.0616397155 + 30 +0.0 + 11 +528499.1244494406 + 21 +181392.2349810032 + 31 +0.0 + 0 +LINE + 5 +16E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528393.1085454885 + 20 +181116.5630802888 + 30 +0.0 + 11 +528455.9969238659 + 21 +180958.8356270552 + 31 +0.0 + 0 +LINE + 5 +16E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528823.2824844054 + 20 +181268.1711482727 + 30 +0.0 + 11 +528124.5961274414 + 21 +180980.5794673295 + 31 +0.0 + 0 +LINE + 5 +16E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528359.6591449503 + 20 +181003.2937738368 + 30 +0.0 + 11 +528496.251239133 + 21 +180501.1023875558 + 31 +0.0 + 0 +LINE + 5 +16E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528293.9363262813 + 20 +180980.7075361373 + 30 +0.0 + 11 +528479.5322388713 + 21 +181036.9540946242 + 31 +0.0 + 0 +LINE + 5 +16E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528261.5482504279 + 20 +181051.651746213 + 30 +0.0 + 11 +528330.7781392561 + 21 +180905.6295622267 + 31 +0.0 + 0 +LINE + 5 +16E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528322.3371516584 + 20 +180924.2524915057 + 30 +0.0 + 11 +528306.1066294286 + 21 +180604.9795470143 + 31 +0.0 + 0 +LINE + 5 +16E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528550.137684719 + 20 +181024.4102162114 + 30 +0.0 + 11 +528578.6162692871 + 21 +180605.0276531032 + 31 +0.0 + 0 +LINE + 5 +16E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528744.1044161262 + 20 +181080.8851259622 + 30 +0.0 + 11 +528639.5423492048 + 21 +181019.1255948131 + 31 +0.0 + 0 +LINE + 5 +16EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528605.9607391642 + 20 +181115.5427925806 + 30 +0.0 + 11 +528726.1658447626 + 21 +181127.3098463461 + 31 +0.0 + 0 +LINE + 5 +16EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528719.6493407362 + 20 +181129.0156575297 + 30 +0.0 + 11 +528743.9006965419 + 21 +181078.7215959029 + 31 +0.0 + 0 +LINE + 5 +16EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528535.7461500664 + 20 +181412.6370650762 + 30 +0.0 + 11 +528535.7503313503 + 21 +181412.6253538163 + 31 +0.0 + 0 +LINE + 5 +16ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528584.9595823676 + 20 +181274.796325802 + 30 +0.0 + 11 +528850.6481789077 + 21 +180262.0898888091 + 31 +0.0 + 0 +LINE + 5 +16EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528536.8091973477 + 20 +180844.5156656816 + 30 +0.0 + 11 +528882.5862303128 + 21 +180959.2072697967 + 31 +0.0 + 0 +LINE + 5 +16EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528887.8023072455 + 20 +181104.0651430399 + 30 +0.0 + 11 +528654.1711792317 + 21 +180965.6183832592 + 31 +0.0 + 0 +LINE + 5 +16F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528652.1519733174 + 20 +181078.006868991 + 30 +0.0 + 11 +528685.7116297412 + 21 +181089.6577569701 + 31 +0.0 + 0 +LINE + 5 +16F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528369.086842587 + 20 +180766.0629915787 + 30 +0.0 + 11 +528502.8198186826 + 21 +180887.2393542519 + 31 +0.0 + 0 +LINE + 5 +16F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528489.1076340876 + 20 +180949.5635597706 + 30 +0.0 + 11 +528501.9282802661 + 21 +180885.5602107991 + 31 +0.0 + 0 +LINE + 5 +16F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528476.5104876363 + 20 +181133.3599090048 + 30 +0.0 + 11 +528573.1374214369 + 21 +180919.4086633252 + 31 +0.0 + 0 +LINE + 5 +16F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528783.5408346061 + 20 +181210.1317959648 + 30 +0.0 + 11 +528605.4299986597 + 21 +181319.9224408801 + 31 +0.0 + 0 +LINE + 5 +16F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528478.9484833108 + 20 +180934.9434537312 + 30 +0.0 + 11 +528592.700573787 + 21 +180963.0620514041 + 31 +0.0 + 0 +LINE + 5 +16F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528841.2419605326 + 20 +181831.809349348 + 30 +0.0 + 11 +528694.9750877169 + 21 +181965.4887947136 + 31 +0.0 + 0 +LINE + 5 +16F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527559.6352817407 + 20 +178984.0106022821 + 30 +0.0 + 11 +527670.8055441313 + 21 +178708.4866640128 + 31 +0.0 + 0 +LINE + 5 +16F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527841.850379535 + 20 +178909.2222632197 + 30 +0.0 + 11 +527577.010554294 + 21 +178891.6849232979 + 31 +0.0 + 0 +LINE + 5 +16F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527868.0342853392 + 20 +178636.461298328 + 30 +0.0 + 11 +527759.1126306393 + 21 +178954.417381277 + 31 +0.0 + 0 +LINE + 5 +16FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527796.601578126 + 20 +179043.1395445016 + 30 +0.0 + 11 +527616.5327026586 + 21 +179064.6047964356 + 31 +0.0 + 0 +LINE + 5 +16FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527694.8464714251 + 20 +179497.7635815927 + 30 +0.0 + 11 +527531.3497878276 + 21 +179482.4309926053 + 31 +0.0 + 0 +LINE + 5 +16FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527771.4060438636 + 20 +178897.713284905 + 30 +0.0 + 11 +527779.5276250298 + 21 +179141.2630467593 + 31 +0.0 + 0 +LINE + 5 +16FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527573.8011160755 + 20 +178862.9172875747 + 30 +0.0 + 11 +527531.6422290265 + 21 +179149.9340366772 + 31 +0.0 + 0 +LINE + 5 +16FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528437.3553301 + 20 +180754.5273863803 + 30 +0.0 + 11 +528875.2647654894 + 21 +180805.9507894455 + 31 +0.0 + 0 +LINE + 5 +16FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528966.2110071292 + 20 +180712.3251185517 + 30 +0.0 + 11 +529125.0585334791 + 21 +180393.6913294563 + 31 +0.0 + 0 +LINE + 5 +1700 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528779.8311440291 + 20 +181528.9781279204 + 30 +0.0 + 11 +528976.924057618 + 21 +181278.1016776676 + 31 +0.0 + 0 +LINE + 5 +1701 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528610.0466290963 + 20 +178898.6744360602 + 30 +0.0 + 11 +528381.6542351669 + 21 +178837.4677158369 + 31 +0.0 + 0 +LINE + 5 +1702 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527499.6368574303 + 20 +180238.8424938624 + 30 +0.0 + 11 +527408.8582457727 + 21 +180625.7233147637 + 31 +0.0 + 0 +LINE + 5 +1703 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526325.5493438983 + 20 +179990.7231208413 + 30 +0.0 + 11 +528521.0807331772 + 21 +180775.9064331124 + 31 +0.0 + 0 +LINE + 5 +1704 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527907.5126679384 + 20 +181542.9682871881 + 30 +0.0 + 11 +527873.9480757209 + 21 +181785.9073528567 + 31 +0.0 + 0 +LINE + 5 +1705 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527907.6366876462 + 20 +181576.5631791007 + 30 +0.0 + 11 +527703.7441620805 + 21 +181447.0003382203 + 31 +0.0 + 0 +LINE + 5 +1706 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528067.6852667896 + 20 +181133.7368389568 + 30 +0.0 + 11 +527435.8092670268 + 21 +182162.9355310014 + 31 +0.0 + 0 +LINE + 5 +1707 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527732.2726035179 + 20 +181549.194381544 + 30 +0.0 + 11 +527317.8786819276 + 21 +181403.7246412206 + 31 +0.0 + 0 +LINE + 5 +1708 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527699.4959209979 + 20 +181610.4750155991 + 30 +0.0 + 11 +527784.6158724877 + 21 +181436.2220042331 + 31 +0.0 + 0 +LINE + 5 +1709 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527634.7410276944 + 20 +181577.6238055718 + 30 +0.0 + 11 +527663.4430813943 + 21 +181520.0752363844 + 31 +0.0 + 0 +LINE + 5 +170A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527486.3805875073 + 20 +181827.0284917456 + 30 +0.0 + 11 +527592.3244026941 + 21 +181327.0006262598 + 31 +0.0 + 0 +LINE + 5 +170B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527604.2956093652 + 20 +181332.8304809776 + 30 +0.0 + 11 +527374.0141981476 + 21 +181269.5355890781 + 31 +0.0 + 0 +LINE + 5 +170C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527737.901443869 + 20 +181196.9802629057 + 30 +0.0 + 11 +527587.3701242818 + 21 +181339.2729321637 + 31 +0.0 + 0 +LINE + 5 +170D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527761.4343699937 + 20 +181280.9337371047 + 30 +0.0 + 11 +527689.6385355888 + 21 +181234.7095234988 + 31 +0.0 + 0 +LINE + 5 +170E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527281.8057793569 + 20 +181593.7828626954 + 30 +0.0 + 11 +527376.6560797916 + 21 +181267.9085432339 + 31 +0.0 + 0 +LINE + 5 +170F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527743.5778082999 + 20 +181467.0503950839 + 30 +0.0 + 11 +527340.7502730433 + 21 +181334.516613773 + 31 +0.0 + 0 +LINE + 5 +1710 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527669.2111869405 + 20 +180908.3550144651 + 30 +0.0 + 11 +527340.678133146 + 21 +181341.4914307134 + 31 +0.0 + 0 +LINE + 5 +1711 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527716.6660929125 + 20 +180991.8875112333 + 30 +0.0 + 11 +527600.4646520663 + 21 +180974.9537321347 + 31 +0.0 + 0 +LINE + 5 +1712 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527679.5706820783 + 20 +181041.6764671496 + 30 +0.0 + 11 +527621.2523089522 + 21 +180948.592804587 + 31 +0.0 + 0 +LINE + 5 +1713 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527576.4541367941 + 20 +181201.2705050961 + 30 +0.0 + 11 +527670.4160191407 + 21 +181022.4454620314 + 31 +0.0 + 0 +LINE + 5 +1714 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527822.614525894 + 20 +181243.2673918037 + 30 +0.0 + 11 +527517.4728170468 + 21 +181104.7810392368 + 31 +0.0 + 0 +LINE + 5 +1715 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527788.5235844035 + 20 +181330.413313844 + 30 +0.0 + 11 +527825.8547178198 + 21 +181214.8544457102 + 31 +0.0 + 0 +LINE + 5 +1716 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527838.7415829323 + 20 +181350.2312704753 + 30 +0.0 + 11 +527787.2416801685 + 21 +181328.658581523 + 31 +0.0 + 0 +LINE + 5 +1717 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528508.8212567543 + 20 +181633.8112238231 + 30 +0.0 + 11 +527671.5554656998 + 21 +181169.3970923505 + 31 +0.0 + 0 +LINE + 5 +1718 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527658.9177280506 + 20 +181172.7612196068 + 30 +0.0 + 11 +527670.7909275288 + 21 +181151.5767510934 + 31 +0.0 + 0 +LINE + 5 +1719 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527476.4630467304 + 20 +181226.2736848147 + 30 +0.0 + 11 +527439.2134785617 + 21 +181200.4549543179 + 31 +0.0 + 0 +LINE + 5 +171A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527482.3684364462 + 20 +181240.642124467 + 30 +0.0 + 11 +527471.4839158129 + 21 +181219.1788152345 + 31 +0.0 + 0 +LINE + 5 +171B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527455.5318248391 + 20 +181298.8509396505 + 30 +0.0 + 11 +527483.7139861392 + 21 +181232.7629062729 + 31 +0.0 + 0 +LINE + 5 +171C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527704.1852247286 + 20 +181234.7195880258 + 30 +0.0 + 11 +527849.4810512137 + 21 +180910.7705625452 + 31 +0.0 + 0 +LINE + 5 +171D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528065.5567144552 + 20 +181153.4548155641 + 30 +0.0 + 11 +527958.9529763994 + 21 +180979.4942126066 + 31 +0.0 + 0 +LINE + 5 +171E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527989.1389916457 + 20 +180972.0011880231 + 30 +0.0 + 11 +527739.9484311853 + 21 +181210.612470911 + 31 +0.0 + 0 +LINE + 5 +171F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527852.6673927681 + 20 +181272.3565301665 + 30 +0.0 + 11 +527869.5202604264 + 21 +181241.0839450215 + 31 +0.0 + 0 +LINE + 5 +1720 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527790.8435772719 + 20 +181072.3399112507 + 30 +0.0 + 11 +527712.9285353634 + 21 +181020.9484095699 + 31 +0.0 + 0 +LINE + 5 +1721 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527744.3463150042 + 20 +181036.710998872 + 30 +0.0 + 11 +527660.964294949 + 21 +181036.8558209355 + 31 +0.0 + 0 +LINE + 5 +1722 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527740.0183205521 + 20 +181049.1021035675 + 30 +0.0 + 11 +527699.3421390562 + 21 +180980.0398426965 + 31 +0.0 + 0 +LINE + 5 +1723 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527768.4864057471 + 20 +180888.3717967293 + 30 +0.0 + 11 +527697.6397767001 + 21 +180992.5486353334 + 31 +0.0 + 0 +LINE + 5 +1724 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528305.2549142606 + 20 +181222.4813618912 + 30 +0.0 + 11 +528017.4095149611 + 21 +181098.6525719066 + 31 +0.0 + 0 +LINE + 5 +1725 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527631.6839665303 + 20 +181435.5326608375 + 30 +0.0 + 11 +527640.529717123 + 21 +181389.3605628302 + 31 +0.0 + 0 +LINE + 5 +1726 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527699.8701739076 + 20 +181412.834820827 + 30 +0.0 + 11 +527638.7299017251 + 21 +181389.9729581412 + 31 +0.0 + 0 +LINE + 5 +1727 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527707.6347024016 + 20 +181461.7763946069 + 30 +0.0 + 11 +527754.9769341437 + 21 +181368.8158861762 + 31 +0.0 + 0 +LINE + 5 +1728 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527879.3064802673 + 20 +181454.5768625892 + 30 +0.0 + 11 +527630.2559788366 + 21 +181289.8571640703 + 31 +0.0 + 0 +LINE + 5 +1729 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527535.5843399566 + 20 +181317.1891876006 + 30 +0.0 + 11 +527557.8696228134 + 21 +181252.0514111541 + 31 +0.0 + 0 +LINE + 5 +172A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527587.6670501727 + 20 +181263.2791108984 + 30 +0.0 + 11 +527530.8570137664 + 21 +181243.6528091551 + 31 +0.0 + 0 +LINE + 5 +172B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527580.4160608368 + 20 +181267.9145734355 + 30 +0.0 + 11 +527604.4575980728 + 21 +181200.7544632176 + 31 +0.0 + 0 +LINE + 5 +172C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527606.2972144495 + 20 +181203.9848112346 + 30 +0.0 + 11 +527553.712925763 + 21 +181184.3256561642 + 31 +0.0 + 0 +LINE + 5 +172D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527533.2014056115 + 20 +181252.3788432797 + 30 +0.0 + 11 +527558.5087149551 + 21 +181179.1283969175 + 31 +0.0 + 0 +LINE + 5 +172E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528084.9383484219 + 20 +181317.7920351681 + 30 +0.0 + 11 +527986.4568372743 + 21 +181262.9653764555 + 31 +0.0 + 0 +LINE + 5 +172F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527654.9911352492 + 20 +180948.4997286438 + 30 +0.0 + 11 +527667.4434421974 + 21 +180450.2901774473 + 31 +0.0 + 0 +LINE + 5 +1730 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527710.9804939659 + 20 +180908.5724382659 + 30 +0.0 + 11 +527704.3467576817 + 21 +180681.3599863421 + 31 +0.0 + 0 +LINE + 5 +1731 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527880.4409333225 + 20 +180987.2934757415 + 30 +0.0 + 11 +527943.3293116995 + 21 +180829.5660225076 + 31 +0.0 + 0 +LINE + 5 +1732 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528194.5290345232 + 20 +181091.1185565957 + 30 +0.0 + 11 +527611.9285152752 + 21 +180851.309862782 + 31 +0.0 + 0 +LINE + 5 +1733 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527781.268714115 + 20 +180851.4379315898 + 30 +0.0 + 11 +527966.864626705 + 21 +180907.6844900767 + 31 +0.0 + 0 +LINE + 5 +1734 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527803.3745602582 + 20 +180782.2734192058 + 30 +0.0 + 11 +527864.7633675682 + 21 +180801.4322302122 + 31 +0.0 + 0 +LINE + 5 +1735 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527768.1633770963 + 20 +180823.7153980267 + 30 +0.0 + 11 +527818.1105270899 + 21 +180776.3599576792 + 31 +0.0 + 0 +LINE + 5 +1736 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527809.669539492 + 20 +180794.9828869581 + 30 +0.0 + 11 +527793.4390172622 + 21 +180475.7099424668 + 31 +0.0 + 0 +LINE + 5 +1737 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528037.4700725527 + 20 +180895.1406116638 + 30 +0.0 + 11 +528087.9867389572 + 21 +180589.0534814345 + 31 +0.0 + 0 +LINE + 5 +1738 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528023.0785379001 + 20 +181283.3674605286 + 30 +0.0 + 11 +528023.0827191841 + 21 +181283.3557492687 + 31 +0.0 + 0 +LINE + 5 +1739 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528340.439197865 + 20 +180924.8250785686 + 30 +0.0 + 11 +527957.9105047284 + 21 +180793.3770014409 + 31 +0.0 + 0 +LINE + 5 +173A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527856.4192304206 + 20 +180636.7933870313 + 30 +0.0 + 11 +527990.1522065163 + 21 +180757.9697497044 + 31 +0.0 + 0 +LINE + 5 +173B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527976.4400219213 + 20 +180820.2939552231 + 30 +0.0 + 11 +527989.2606680998 + 21 +180756.2906062517 + 31 +0.0 + 0 +LINE + 5 +173C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527963.8428754701 + 20 +181004.0903044574 + 30 +0.0 + 11 +528060.4698092707 + 21 +180790.1390587778 + 31 +0.0 + 0 +LINE + 5 +173D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527621.5138579452 + 20 +180629.3340164016 + 30 +0.0 + 11 +527877.3755086813 + 21 +180642.9034727321 + 31 +0.0 + 0 +LINE + 5 +173E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527667.4095200623 + 20 +180807.1107072498 + 30 +0.0 + 11 +527128.0576471266 + 21 +180798.9202597059 + 31 +0.0 + 0 +LINE + 5 +173F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527433.6843319427 + 20 +180704.6053097688 + 30 +0.0 + 11 +527380.3074425424 + 21 +180809.2018460748 + 31 +0.0 + 0 +LINE + 5 +1740 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527371.6131256215 + 20 +180706.0800917967 + 30 +0.0 + 11 +527413.8347052304 + 21 +180807.4849195685 + 31 +0.0 + 0 +LINE + 5 +1741 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527181.7795718828 + 20 +180697.9252935647 + 30 +0.0 + 11 +527382.0094214852 + 21 +180724.6692403429 + 31 +0.0 + 0 +LINE + 5 +1742 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527379.8248971851 + 20 +180601.3707391883 + 30 +0.0 + 11 +527655.9570404891 + 21 +180650.5874810572 + 31 +0.0 + 0 +LINE + 5 +1743 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527634.49593446 + 20 +180627.1761578001 + 30 +0.0 + 11 +527564.727516362 + 21 +180815.9794419407 + 31 +0.0 + 0 +LINE + 5 +1744 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527680.2763528484 + 20 +180527.0181601985 + 30 +0.0 + 11 +527085.8869598081 + 21 +180596.2012948931 + 31 +0.0 + 0 +LINE + 5 +1745 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527410.9385663538 + 20 +180597.5655134207 + 30 +0.0 + 11 +527407.81334307 + 21 +180690.8504167008 + 31 +0.0 + 0 +LINE + 5 +1746 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527413.120279326 + 20 +180656.1031502381 + 30 +0.0 + 11 +527364.7871258904 + 21 +180724.0478963259 + 31 +0.0 + 0 +LINE + 5 +1747 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527400.5081794425 + 20 +180652.4691513277 + 30 +0.0 + 11 +527433.3329921378 + 21 +180725.5901420843 + 31 +0.0 + 0 +LINE + 5 +1748 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527600.5147424299 + 20 +180727.0991168916 + 30 +0.0 + 11 +527422.1431258947 + 21 +180719.7459291959 + 31 +0.0 + 0 +LINE + 5 +1749 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527358.4971803137 + 20 +181069.3360442441 + 30 +0.0 + 11 +527379.258310515 + 21 +181305.4581219943 + 31 +0.0 + 0 +LINE + 5 +174A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527517.3990442939 + 20 +180937.9428383985 + 30 +0.0 + 11 +527612.146530442 + 21 +181007.3146020915 + 31 +0.0 + 0 +LINE + 5 +174B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527508.9577948804 + 20 +180999.4550725032 + 30 +0.0 + 11 +527615.7974430798 + 21 +180973.9425176962 + 31 +0.0 + 0 +LINE + 5 +174C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527296.4057761851 + 20 +181071.0023693953 + 30 +0.0 + 11 +527541.3338659454 + 21 +181111.0055184133 + 31 +0.0 + 0 +LINE + 5 +174D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527356.0917800875 + 20 +181119.8855659372 + 30 +0.0 + 11 +527467.4798403427 + 21 +180786.7453186707 + 31 +0.0 + 0 +LINE + 5 +174E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527367.4266915865 + 20 +180785.7036156728 + 30 +0.0 + 11 +527347.4819516342 + 21 +181077.6241073057 + 31 +0.0 + 0 +LINE + 5 +174F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527408.1019101263 + 20 +180943.3302605271 + 30 +0.0 + 11 +527499.6950365228 + 21 +180961.2896424068 + 31 +0.0 + 0 +LINE + 5 +1750 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527466.2385014737 + 20 +180950.5102007901 + 30 +0.0 + 11 +527525.6073279321 + 21 +181009.0586822982 + 31 +0.0 + 0 +LINE + 5 +1751 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527460.6400141142 + 20 +180962.3815086723 + 30 +0.0 + 11 +527538.0593810993 + 21 +180941.635684193 + 31 +0.0 + 0 +LINE + 5 +1752 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527566.2059370142 + 20 +180776.8334207803 + 30 +0.0 + 11 +527530.5057297896 + 21 +180951.7505387501 + 31 +0.0 + 0 +LINE + 5 +1753 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527077.0853426155 + 20 +181153.9455596111 + 30 +0.0 + 11 +527370.172406016 + 21 +181211.0306242986 + 31 +0.0 + 0 +LINE + 5 +1754 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527387.1968684147 + 20 +181613.9091956559 + 30 +0.0 + 11 +527546.0443947647 + 21 +181295.2754065605 + 31 +0.0 + 0 +LINE + 5 +1755 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529864.0625938844 + 20 +179850.1100024555 + 30 +0.0 + 11 +530689.4088798159 + 21 +179901.2472741166 + 31 +0.0 + 0 +LINE + 5 +1756 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526146.3666421647 + 20 +183861.9215044605 + 30 +0.0 + 11 +526295.0595649951 + 21 +183266.6983786453 + 31 +0.0 + 0 +LINE + 5 +1757 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526156.7676960638 + 20 +183757.2998493608 + 30 +0.0 + 11 +526872.0452317546 + 21 +184095.1589363041 + 31 +0.0 + 0 +LINE + 5 +1758 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526280.1281120633 + 20 +183818.8283446044 + 30 +0.0 + 11 +526320.8011047294 + 21 +183676.6896715689 + 31 +0.0 + 0 +LINE + 5 +1759 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526172.6945403687 + 20 +183694.0884457485 + 30 +0.0 + 11 +526619.3832154593 + 21 +183906.1116386753 + 31 +0.0 + 0 +LINE + 5 +175A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526303.3104941537 + 20 +183704.2550264607 + 30 +0.0 + 11 +526364.2262575479 + 21 +183649.3882056604 + 31 +0.0 + 0 +LINE + 5 +175B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526255.6535841598 + 20 +183640.3477925701 + 30 +0.0 + 11 +526315.3269201439 + 21 +183704.818882624 + 31 +0.0 + 0 +LINE + 5 +175C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526260.794374798 + 20 +183658.6587778636 + 30 +0.0 + 11 +526298.2976688607 + 21 +183463.3442732338 + 31 +0.0 + 0 +LINE + 5 +175D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526147.1218396106 + 20 +183612.73058267 + 30 +0.0 + 11 +526579.828602082 + 21 +183627.6998522125 + 31 +0.0 + 0 +LINE + 5 +175E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526354.247191199 + 20 +183467.0635497783 + 30 +0.0 + 11 +526362.9256044818 + 21 +183653.5160206742 + 31 +0.0 + 0 +LINE + 5 +175F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526293.6425841297 + 20 +183466.2296248381 + 30 +0.0 + 11 +526354.8351812499 + 21 +183467.6741797741 + 31 +0.0 + 0 +LINE + 5 +1760 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526441.1573141331 + 20 +183292.5913131285 + 30 +0.0 + 11 +526423.5172909697 + 21 +183982.9678032511 + 31 +0.0 + 0 +LINE + 5 +1761 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526500.3735382098 + 20 +183698.0161894802 + 30 +0.0 + 11 +526927.332856658 + 21 +183800.9215245747 + 31 +0.0 + 0 +LINE + 5 +1762 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526494.6144850082 + 20 +183767.2726717287 + 30 +0.0 + 11 +526517.7762170607 + 21 +183574.729034389 + 31 +0.0 + 0 +LINE + 5 +1763 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526566.8286919588 + 20 +183774.8559771781 + 30 +0.0 + 11 +526573.9822678175 + 21 +183710.9461027097 + 31 +0.0 + 0 +LINE + 5 +1764 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526514.7235287358 + 20 +183790.4225115961 + 30 +0.0 + 11 +526578.1702533896 + 21 +183763.7435188542 + 31 +0.0 + 0 +LINE + 5 +1765 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526557.7250167089 + 20 +183763.9802964612 + 30 +0.0 + 11 +526943.1435876271 + 21 +183882.5114018416 + 31 +0.0 + 0 +LINE + 5 +1766 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526593.1821208949 + 20 +183967.9472765855 + 30 +0.0 + 11 +526738.5555161251 + 21 +183587.449878167 + 31 +0.0 + 0 +LINE + 5 +1767 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526725.3374610824 + 20 +183585.8436353218 + 30 +0.0 + 11 +526953.0738168576 + 21 +183657.7597249765 + 31 +0.0 + 0 +LINE + 5 +1768 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526686.9306696731 + 20 +183399.2137364918 + 30 +0.0 + 11 +526736.0505498801 + 21 +183600.4452431444 + 31 +0.0 + 0 +LINE + 5 +1769 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526621.5764646847 + 20 +183456.9269267728 + 30 +0.0 + 11 +526706.9655038702 + 21 +183457.1051075179 + 31 +0.0 + 0 +LINE + 5 +176A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526687.7712547906 + 20 +184026.4867210937 + 30 +0.0 + 11 +526715.4590134472 + 21 +183940.72263176 + 31 +0.0 + 0 +LINE + 5 +176B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526817.252760931 + 20 +184107.5751165661 + 30 +0.0 + 11 +526951.7391244286 + 21 +183654.9587585502 + 31 +0.0 + 0 +LINE + 5 +176C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526535.4923129867 + 20 +183622.9021839629 + 30 +0.0 + 11 +526945.7142486438 + 21 +183730.3879497893 + 31 +0.0 + 0 +LINE + 5 +176D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526907.4315473432 + 20 +183254.0098220853 + 30 +0.0 + 11 +526941.9868780364 + 21 +183736.2837096106 + 31 +0.0 + 0 +LINE + 5 +176E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526816.1450377863 + 20 +183238.5351007249 + 30 +0.0 + 11 +526922.9130617307 + 21 +183287.4239214544 + 31 +0.0 + 0 +LINE + 5 +176F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526820.2533152976 + 20 +183300.4877575854 + 30 +0.0 + 11 +526919.7745033624 + 21 +183253.9997590661 + 31 +0.0 + 0 +LINE + 5 +1770 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526820.164002127 + 20 +183490.4963649759 + 30 +0.0 + 11 +526838.3844023372 + 21 +183289.3117523006 + 31 +0.0 + 0 +LINE + 5 +1771 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526590.6611682273 + 20 +183392.0731721455 + 30 +0.0 + 11 +526922.0915035857 + 21 +183441.5086364376 + 31 +0.0 + 0 +LINE + 5 +1772 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526571.9585185818 + 20 +183483.7618569228 + 30 +0.0 + 11 +526603.371210842 + 21 +183366.4558115051 + 31 +0.0 + 0 +LINE + 5 +1773 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526501.4775952947 + 20 +183359.9989028833 + 30 +0.0 + 11 +526522.4218541533 + 21 +183478.9487620135 + 31 +0.0 + 0 +LINE + 5 +1774 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526519.0287964525 + 20 +183473.1296748034 + 30 +0.0 + 11 +526573.9878772992 + 21 +183482.9846393319 + 31 +0.0 + 0 +LINE + 5 +1775 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526196.4405248281 + 20 +183372.1430748632 + 30 +0.0 + 11 +526757.6198582386 + 21 +183412.0845848348 + 31 +0.0 + 0 +LINE + 5 +1776 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526766.4044345876 + 20 +183421.7727726658 + 30 +0.0 + 11 +526767.9398491217 + 21 +183397.536496668 + 31 +0.0 + 0 +LINE + 5 +1777 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526890.5451039946 + 20 +183565.7949545252 + 30 +0.0 + 11 +526935.8445084186 + 21 +183564.3454263059 + 31 +0.0 + 0 +LINE + 5 +1778 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526877.7831560563 + 20 +183574.6526275019 + 30 +0.0 + 11 +526898.5791011399 + 21 +183562.5416778816 + 31 +0.0 + 0 +LINE + 5 +1779 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526868.7046423821 + 20 +183638.1037935833 + 30 +0.0 + 11 +526880.9324460784 + 21 +183567.3058897442 + 31 +0.0 + 0 +LINE + 5 +177A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526694.7455424822 + 20 +183449.2134150571 + 30 +0.0 + 11 +526718.8337582751 + 21 +183114.217383739 + 31 +0.0 + 0 +LINE + 5 +177B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526797.9205867572 + 20 +183062.9766257928 + 30 +0.0 + 11 +526965.7571857292 + 21 +183122.9233535809 + 31 +0.0 + 0 +LINE + 5 +177C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526644.3091041178 + 20 +183148.8166298903 + 30 +0.0 + 11 +526677.8083660316 + 21 +183409.5486689271 + 31 +0.0 + 0 +LINE + 5 +177D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526549.6285343083 + 20 +183400.1772286422 + 30 +0.0 + 11 +526552.4613872791 + 21 +183364.7658085349 + 31 +0.0 + 0 +LINE + 5 +177E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526689.3727600271 + 20 +183265.9906037531 + 30 +0.0 + 11 +526803.5007252154 + 21 +183264.9666445346 + 31 +0.0 + 0 +LINE + 5 +177F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526768.5595068004 + 20 +183261.1394582676 + 30 +0.0 + 11 +526838.494677635 + 21 +183306.5448998165 + 31 +0.0 + 0 +LINE + 5 +1780 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526765.464147099 + 20 +183273.8944478745 + 30 +0.0 + 11 +526837.1258694434 + 21 +183237.9953508338 + 31 +0.0 + 0 +LINE + 5 +1781 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526831.5368826524 + 20 +183070.9002346203 + 30 +0.0 + 11 +526831.7619163459 + 21 +183249.4232088129 + 31 +0.0 + 0 +LINE + 5 +1782 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526646.5637345624 + 20 +183657.2058092401 + 30 +0.0 + 11 +526664.2117238904 + 21 +183613.6322116076 + 31 +0.0 + 0 +LINE + 5 +1783 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526601.6364027762 + 20 +183601.1158308463 + 30 +0.0 + 11 +526665.3903993997 + 21 +183615.1238843356 + 31 +0.0 + 0 +LINE + 5 +1784 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526568.5371013311 + 20 +183637.9940329533 + 30 +0.0 + 11 +526579.2708064839 + 21 +183534.2263568313 + 31 +0.0 + 0 +LINE + 5 +1785 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526428.2985359867 + 20 +183538.715750499 + 30 +0.0 + 11 +526726.8775057319 + 21 +183535.6612179669 + 31 +0.0 + 0 +LINE + 5 +1786 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526791.5272269688 + 20 +183610.0263459667 + 30 +0.0 + 11 +526808.1904199362 + 21 +183543.2288778073 + 31 +0.0 + 0 +LINE + 5 +1787 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526777.0726188523 + 20 +183536.4738519391 + 30 +0.0 + 11 +526835.4334266978 + 21 +183550.8470236224 + 31 +0.0 + 0 +LINE + 5 +1788 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526780.6436278328 + 20 +183544.3040661218 + 30 +0.0 + 11 +526796.9304441347 + 21 +183474.8546922448 + 31 +0.0 + 0 +LINE + 5 +1789 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526793.6313980108 + 20 +183476.56806068 + 30 +0.0 + 11 +526848.4617921767 + 21 +183488.6186901389 + 31 +0.0 + 0 +LINE + 5 +178A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526828.72588772 + 20 +183556.9008460126 + 30 +0.0 + 11 +526847.2574595743 + 21 +183481.6501407461 + 31 +0.0 + 0 +LINE + 5 +178B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526634.7260185561 + 20 +183852.0697490888 + 30 +0.0 + 11 +526882.8381198066 + 21 +183944.016119175 + 31 +0.0 + 0 +LINE + 5 +178C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526958.3758547891 + 20 +184280.0246811046 + 30 +0.0 + 11 +526999.0488474554 + 21 +184137.8860080692 + 31 +0.0 + 0 +LINE + 5 +178D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526850.9422830945 + 20 +184155.2847822487 + 30 +0.0 + 11 +527297.6309581853 + 21 +184367.3079751753 + 31 +0.0 + 0 +LINE + 5 +178E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526981.5582368797 + 20 +184165.4513629608 + 30 +0.0 + 11 +527042.4740002738 + 21 +184110.5845421606 + 31 +0.0 + 0 +LINE + 5 +178F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526933.9013268857 + 20 +184101.5441290703 + 30 +0.0 + 11 +526993.5746628696 + 21 +184166.0152191241 + 31 +0.0 + 0 +LINE + 5 +1790 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526939.5611466158 + 20 +184118.1083122997 + 30 +0.0 + 11 +526977.0644406785 + 21 +183922.79380767 + 31 +0.0 + 0 +LINE + 5 +1791 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526740.309918598 + 20 +184070.9843235278 + 30 +0.0 + 11 +527258.076344808 + 21 +184088.8961887127 + 31 +0.0 + 0 +LINE + 5 +1792 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527032.4949339247 + 20 +183928.2598862781 + 30 +0.0 + 11 +527041.1733472075 + 21 +184114.7123571743 + 31 +0.0 + 0 +LINE + 5 +1793 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526971.8903268556 + 20 +183927.4259613383 + 30 +0.0 + 11 +527033.0829239759 + 21 +183928.8705162743 + 31 +0.0 + 0 +LINE + 5 +1794 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527013.9204027358 + 20 +183633.0017334758 + 30 +0.0 + 11 +527012.2254621887 + 21 +183930.2273940919 + 31 +0.0 + 0 +LINE + 5 +1795 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527009.8694960516 + 20 +183701.3044251353 + 30 +0.0 + 11 +527122.6870704073 + 21 +183709.6708002807 + 31 +0.0 + 0 +LINE + 5 +1796 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527122.6138772766 + 20 +183628.2042443963 + 30 +0.0 + 11 +527104.861432775 + 21 +184383.5561167509 + 31 +0.0 + 0 +LINE + 5 +1797 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527178.6212809359 + 20 +184159.2125259804 + 30 +0.0 + 11 +527813.577229433 + 21 +184288.3144994509 + 31 +0.0 + 0 +LINE + 5 +1798 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527172.862227734 + 20 +184228.4690082291 + 30 +0.0 + 11 +527196.0239597866 + 21 +184035.925370889 + 31 +0.0 + 0 +LINE + 5 +1799 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527245.0764346846 + 20 +184236.052313678 + 30 +0.0 + 11 +527252.2300105434 + 21 +184172.14243921 + 31 +0.0 + 0 +LINE + 5 +179A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527192.9712714617 + 20 +184251.6188480962 + 30 +0.0 + 11 +527256.4179961154 + 21 +184224.9398553542 + 31 +0.0 + 0 +LINE + 5 +179B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527235.9727594348 + 20 +184225.1766329612 + 30 +0.0 + 11 +527370.3370712806 + 21 +184266.4988514751 + 31 +0.0 + 0 +LINE + 5 +179C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527271.4298636206 + 20 +184429.1436130856 + 30 +0.0 + 11 +527416.803258851 + 21 +184048.6462146672 + 31 +0.0 + 0 +LINE + 5 +179D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527403.5852038083 + 20 +184047.0399718219 + 30 +0.0 + 11 +527631.3215595834 + 21 +184118.9560614766 + 31 +0.0 + 0 +LINE + 5 +179E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527365.1784123991 + 20 +183860.4100729922 + 30 +0.0 + 11 +527414.298292606 + 21 +184061.6415796445 + 31 +0.0 + 0 +LINE + 5 +179F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527299.8242074107 + 20 +183918.1232632729 + 30 +0.0 + 11 +527385.2132465961 + 21 +183918.301444018 + 31 +0.0 + 0 +LINE + 5 +17A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527380.8466232018 + 20 +184490.1155273246 + 30 +0.0 + 11 +527408.5343818584 + 21 +184404.3514379912 + 31 +0.0 + 0 +LINE + 5 +17A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527213.7400557126 + 20 +184084.0985204632 + 30 +0.0 + 11 +527623.9619913699 + 21 +184191.5842862895 + 31 +0.0 + 0 +LINE + 5 +17A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527494.3927805122 + 20 +183699.7314372251 + 30 +0.0 + 11 +527601.1608044566 + 21 +183748.6202579545 + 31 +0.0 + 0 +LINE + 5 +17A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527498.5010580233 + 20 +183761.6840940857 + 30 +0.0 + 11 +527598.0222460883 + 21 +183715.1960955663 + 31 +0.0 + 0 +LINE + 5 +17A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527498.4117448529 + 20 +183951.6927014761 + 30 +0.0 + 11 +527516.6321450631 + 21 +183750.5080888008 + 31 +0.0 + 0 +LINE + 5 +17A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527268.9089109532 + 20 +183853.2695086456 + 30 +0.0 + 11 +527693.7275002586 + 21 +183907.4760789607 + 31 +0.0 + 0 +LINE + 5 +17A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527250.2062613076 + 20 +183944.9581934229 + 30 +0.0 + 11 +527281.6189535678 + 21 +183827.6521480053 + 31 +0.0 + 0 +LINE + 5 +17A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527179.7253380207 + 20 +183821.1952393834 + 30 +0.0 + 11 +527200.6695968792 + 21 +183940.1450985137 + 31 +0.0 + 0 +LINE + 5 +17A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527197.2765391785 + 20 +183934.3260113036 + 30 +0.0 + 11 +527252.235620025 + 21 +183944.180975832 + 31 +0.0 + 0 +LINE + 5 +17A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526874.6882675539 + 20 +183833.3394113636 + 30 +0.0 + 11 +527435.8676009643 + 21 +183873.280921335 + 31 +0.0 + 0 +LINE + 5 +17AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527444.6521773135 + 20 +183882.969109166 + 30 +0.0 + 11 +527446.1875918474 + 21 +183858.7328331681 + 31 +0.0 + 0 +LINE + 5 +17AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527568.7928467203 + 20 +184026.9912910253 + 30 +0.0 + 11 +527646.2080503886 + 21 +184027.1825246443 + 31 +0.0 + 0 +LINE + 5 +17AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527556.0308987824 + 20 +184035.8489640022 + 30 +0.0 + 11 +527576.8268438658 + 21 +184023.7380143818 + 31 +0.0 + 0 +LINE + 5 +17AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527546.9523851079 + 20 +184099.3001300833 + 30 +0.0 + 11 +527559.1801888044 + 21 +184028.5022262444 + 31 +0.0 + 0 +LINE + 5 +17AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527372.9932852081 + 20 +183910.4097515571 + 30 +0.0 + 11 +527426.9250448026 + 21 +183559.489228346 + 31 +0.0 + 0 +LINE + 5 +17AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527113.6925585766 + 20 +183645.9169350216 + 30 +0.0 + 11 +527297.6811319859 + 21 +183557.7418069882 + 31 +0.0 + 0 +LINE + 5 +17B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527276.4040582523 + 20 +183535.0564137323 + 30 +0.0 + 11 +527356.0561087577 + 21 +183870.7450054275 + 31 +0.0 + 0 +LINE + 5 +17B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527227.8762770341 + 20 +183861.3735651424 + 30 +0.0 + 11 +527230.7091300049 + 21 +183825.962145035 + 31 +0.0 + 0 +LINE + 5 +17B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527388.414985323 + 20 +183727.0003715881 + 30 +0.0 + 11 +527481.7484679412 + 21 +183726.1629810347 + 31 +0.0 + 0 +LINE + 5 +17B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527446.8072495261 + 20 +183722.3357947676 + 30 +0.0 + 11 +527516.7424203608 + 21 +183767.7412363167 + 31 +0.0 + 0 +LINE + 5 +17B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527443.7118898248 + 20 +183735.0907843745 + 30 +0.0 + 11 +527515.3736121694 + 21 +183699.1916873341 + 31 +0.0 + 0 +LINE + 5 +17B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527507.0987654129 + 20 +183584.6688198411 + 30 +0.0 + 11 +527510.0096590718 + 21 +183710.619545313 + 31 +0.0 + 0 +LINE + 5 +17B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526916.7194524115 + 20 +183661.7243328356 + 30 +0.0 + 11 +527183.8830550492 + 21 +183626.0490480191 + 31 +0.0 + 0 +LINE + 5 +17B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527324.8114772883 + 20 +184118.4021457402 + 30 +0.0 + 11 +527342.4594666163 + 21 +184074.8285481079 + 31 +0.0 + 0 +LINE + 5 +17B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527279.8841455021 + 20 +184062.3121673466 + 30 +0.0 + 11 +527343.6381421257 + 21 +184076.3202208358 + 31 +0.0 + 0 +LINE + 5 +17B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527246.7848440569 + 20 +184099.1903694535 + 30 +0.0 + 11 +527257.5185492098 + 21 +183995.4226933316 + 31 +0.0 + 0 +LINE + 5 +17BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527106.5462787125 + 20 +183999.912086999 + 30 +0.0 + 11 +527405.1252484577 + 21 +183996.857554467 + 31 +0.0 + 0 +LINE + 5 +17BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527469.7749696947 + 20 +184071.2226824668 + 30 +0.0 + 11 +527486.438162662 + 21 +184004.4252143077 + 31 +0.0 + 0 +LINE + 5 +17BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527455.3203615782 + 20 +183997.6701884394 + 30 +0.0 + 11 +527513.6811694236 + 21 +184012.0433601225 + 31 +0.0 + 0 +LINE + 5 +17BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527458.8913705585 + 20 +184005.500402622 + 30 +0.0 + 11 +527475.1781868609 + 21 +183936.0510287449 + 31 +0.0 + 0 +LINE + 5 +17BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527471.8791407367 + 20 +183937.7643971802 + 30 +0.0 + 11 +527526.7095349025 + 21 +183949.815026639 + 31 +0.0 + 0 +LINE + 5 +17BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527506.9736304459 + 20 +184018.0971825126 + 30 +0.0 + 11 +527525.5052023 + 21 +183942.8464772463 + 31 +0.0 + 0 +LINE + 5 +17C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527008.1685822724 + 20 +183773.3808903472 + 30 +0.0 + 11 +527120.6368161418 + 21 +183780.828501626 + 31 +0.0 + 0 +LINE + 5 +17C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527312.973761282 + 20 +184313.2660855889 + 30 +0.0 + 11 +527561.0858625324 + 21 +184405.2124556752 + 31 +0.0 + 0 +LINE + 5 +17C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527335.8734279835 + 20 +185040.8666845549 + 30 +0.0 + 11 +527919.0477671159 + 21 +183166.9809628446 + 31 +0.0 + 0 +LINE + 5 +17C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527544.4143172993 + 20 +183632.8616138635 + 30 +0.0 + 11 +527673.3810309673 + 21 +183445.6796394856 + 31 +0.0 + 0 +LINE + 5 +17C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527359.3700625528 + 20 +183606.9296638141 + 30 +0.0 + 11 +527392.2242523522 + 21 +183440.3358468486 + 31 +0.0 + 0 +LINE + 5 +17C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526915.8269966726 + 20 +183500.6085807193 + 30 +0.0 + 11 +527693.6597362677 + 21 +183645.0693403355 + 31 +0.0 + 0 +LINE + 5 +17C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527448.9719851374 + 20 +183529.9862193265 + 30 +0.0 + 11 +527643.2933316129 + 21 +183069.7323576719 + 31 +0.0 + 0 +LINE + 5 +17C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527516.4241439892 + 20 +183546.7144378046 + 30 +0.0 + 11 +527330.0369680068 + 21 +183493.1482288574 + 31 +0.0 + 0 +LINE + 5 +17C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527535.4248805666 + 20 +183476.6332690318 + 30 +0.0 + 11 +527473.4732808892 + 21 +183459.3808779063 + 31 +0.0 + 0 +LINE + 5 +17C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527542.4841681129 + 20 +183530.5538725857 + 30 +0.0 + 11 +527526.2629878082 + 21 +183463.6649435127 + 31 +0.0 + 0 +LINE + 5 +17CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527523.236772931 + 20 +183483.8863626044 + 30 +0.0 + 11 +527721.4676373326 + 21 +183085.4501236723 + 31 +0.0 + 0 +LINE + 5 +17CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527733.0237619601 + 20 +183484.0319248232 + 30 +0.0 + 11 +527377.7980020232 + 21 +183277.2218469782 + 31 +0.0 + 0 +LINE + 5 +17CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527374.1047094388 + 20 +183290.0146803263 + 30 +0.0 + 11 +527481.4129521734 + 21 +183076.6588443756 + 31 +0.0 + 0 +LINE + 5 +17CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527183.7386016345 + 20 +183298.1722389731 + 30 +0.0 + 11 +527390.2276942121 + 21 +183281.7668573049 + 31 +0.0 + 0 +LINE + 5 +17CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527230.2927904696 + 20 +183371.8926021298 + 30 +0.0 + 11 +527244.0838495338 + 21 +183287.6244204047 + 31 +0.0 + 0 +LINE + 5 +17CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528134.8774861161 + 20 +183393.6977037461 + 30 +0.0 + 11 +527478.4350058732 + 21 +183077.5298510543 + 31 +0.0 + 0 +LINE + 5 +17D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527380.4186075985 + 20 +183483.339926926 + 30 +0.0 + 11 +527551.9385165398 + 21 +183095.5047207027 + 31 +0.0 + 0 +LINE + 5 +17D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527214.3653902986 + 20 +183070.3577530247 + 30 +0.0 + 11 +527557.1645236159 + 21 +183100.1244745444 + 31 +0.0 + 0 +LINE + 5 +17D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526863.0108382376 + 20 +183020.7490917978 + 30 +0.0 + 11 +527360.3044246794 + 21 +183087.2087069777 + 31 +0.0 + 0 +LINE + 5 +17D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527295.0972429494 + 20 +183181.1983438331 + 30 +0.0 + 11 +527099.3917540238 + 21 +183131.1324575882 + 31 +0.0 + 0 +LINE + 5 +17D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527171.1168625928 + 20 +183359.2724053633 + 30 +0.0 + 11 +527262.9884432511 + 21 +183072.7638563169 + 31 +0.0 + 0 +LINE + 5 +17D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527084.0237982917 + 20 +183386.3498542505 + 30 +0.0 + 11 +527205.3628897168 + 21 +183391.2783853459 + 31 +0.0 + 0 +LINE + 5 +17D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527181.1974413807 + 20 +183490.4753190934 + 30 +0.0 + 11 +527073.8736295296 + 21 +183435.073781426 + 31 +0.0 + 0 +LINE + 5 +17D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527078.4189700695 + 20 +183440.0451490341 + 30 +0.0 + 11 +527085.3698454549 + 21 +183384.6438293321 + 31 +0.0 + 0 +LINE + 5 +17D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527078.8063363808 + 20 +183778.070793482 + 30 +0.0 + 11 +527078.8091857135 + 21 +183778.0586890183 + 31 +0.0 + 0 +LINE + 5 +17D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527112.3427896616 + 20 +183635.6020684094 + 30 +0.0 + 11 +527207.7160715952 + 21 +183230.4396688804 + 31 +0.0 + 0 +LINE + 5 +17DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527218.6809989879 + 20 +183223.312247723 + 30 +0.0 + 11 +527194.9996156784 + 21 +183217.9320380072 + 31 +0.0 + 0 +LINE + 5 +17DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527380.6546446571 + 20 +183123.7239312546 + 30 +0.0 + 11 +527386.4465854053 + 21 +183078.7729513362 + 31 +0.0 + 0 +LINE + 5 +17DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527387.3641206894 + 20 +183137.7349489587 + 30 +0.0 + 11 +527378.7239987938 + 21 +183115.2739889114 + 31 +0.0 + 0 +LINE + 5 +17DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527448.5559520536 + 20 +183156.8145103248 + 30 +0.0 + 11 +527380.6135250315 + 21 +183133.4545235604 + 31 +0.0 + 0 +LINE + 5 +17DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527234.3446664419 + 20 +183298.4297236824 + 30 +0.0 + 11 +526896.7764445693 + 21 +183201.283339818 + 31 +0.0 + 0 +LINE + 5 +17DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526899.9827787879 + 20 +183301.2905252701 + 30 +0.0 + 11 +527192.4867734056 + 21 +183308.8257239823 + 31 +0.0 + 0 +LINE + 5 +17E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527162.7971416081 + 20 +183433.8713913096 + 30 +0.0 + 11 +527128.2904609601 + 21 +183425.4284818214 + 31 +0.0 + 0 +LINE + 5 +17E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526882.6827136528 + 20 +183103.0669733985 + 30 +0.0 + 11 +527058.9575892087 + 21 +183131.310046931 + 31 +0.0 + 0 +LINE + 5 +17E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527431.9935369405 + 20 +183379.1591894488 + 30 +0.0 + 11 +527391.7913556132 + 21 +183354.7892375719 + 31 +0.0 + 0 +LINE + 5 +17E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527369.457562608 + 20 +183414.568266419 + 30 +0.0 + 11 +527393.4518823327 + 21 +183353.8634867969 + 31 +0.0 + 0 +LINE + 5 +17E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527400.5863184767 + 20 +183453.1242789833 + 30 +0.0 + 11 +527299.8576946609 + 21 +183425.9822934587 + 31 +0.0 + 0 +LINE + 5 +17E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527280.2173434821 + 20 +183575.7388883725 + 30 +0.0 + 11 +527324.8098717205 + 21 +183280.4928252855 + 31 +0.0 + 0 +LINE + 5 +17E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527408.5318940674 + 20 +183228.5276283497 + 30 +0.0 + 11 +527345.2459384735 + 21 +183201.4268612583 + 31 +0.0 + 0 +LINE + 5 +17E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527333.6156467227 + 20 +183231.0694696553 + 30 +0.0 + 11 +527357.1104773119 + 21 +183175.7470972171 + 31 +0.0 + 0 +LINE + 5 +17E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527341.9150752116 + 20 +183228.7926635495 + 30 +0.0 + 11 +527275.9511290317 + 21 +183201.640615347 + 31 +0.0 + 0 +LINE + 5 +17E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527277.1165489448 + 20 +183205.1706483711 + 30 +0.0 + 11 +527297.7556320369 + 21 +183152.9631963756 + 31 +0.0 + 0 +LINE + 5 +17EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527362.0173412369 + 20 +183183.3340947189 + 30 +0.0 + 11 +527290.6842075074 + 21 +183153.0409959863 + 31 +0.0 + 0 +LINE + 5 +17EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527622.4769279048 + 20 +183421.9162279387 + 30 +0.0 + 11 +527752.8080714243 + 21 +183191.6391279312 + 31 +0.0 + 0 +LINE + 5 +17EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526172.6398658639 + 20 +183798.7108105307 + 30 +0.0 + 11 +525758.1454340727 + 21 +184286.030813627 + 31 +0.0 + 0 +LINE + 5 +17ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525540.2138584358 + 20 +183597.7464136007 + 30 +0.0 + 11 +527616.4438770662 + 21 +184597.5557938863 + 31 +0.0 + 0 +LINE + 5 +17EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526229.3686672956 + 20 +183925.7679148408 + 30 +0.0 + 11 +526144.9611678353 + 21 +184047.147767945 + 31 +0.0 + 0 +LINE + 5 +17EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526064.799718067 + 20 +183921.4003476109 + 30 +0.0 + 11 +526511.4883931579 + 21 +184133.4235405376 + 31 +0.0 + 0 +LINE + 5 +17F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526155.2591332825 + 20 +184016.1683851839 + 30 +0.0 + 11 +526151.2649311015 + 21 +184098.0533325403 + 31 +0.0 + 0 +LINE + 5 +17F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526075.6150280776 + 20 +184019.6515044495 + 30 +0.0 + 11 +526163.2934473707 + 21 +184025.1217211256 + 31 +0.0 + 0 +LINE + 5 +17F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526093.0519312629 + 20 +184012.0571435086 + 30 +0.0 + 11 +525965.44190075 + 21 +184164.6019988687 + 31 +0.0 + 0 +LINE + 5 +17F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525985.5984568236 + 20 +183953.0266835703 + 30 +0.0 + 11 +526270.7776231972 + 21 +184278.805848628 + 31 +0.0 + 0 +LINE + 5 +17F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526003.6978839475 + 20 +184205.5978744847 + 30 +0.0 + 11 +526153.6406479724 + 21 +184094.4358023696 + 31 +0.0 + 0 +LINE + 5 +17F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525964.7341469383 + 20 +184159.1711469766 + 30 +0.0 + 11 +526004.542735631 + 21 +184205.6673505589 + 31 +0.0 + 0 +LINE + 5 +17F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525763.2000248929 + 20 +184377.885917585 + 30 +0.0 + 11 +525992.4067272518 + 21 +184188.6499438754 + 31 +0.0 + 0 +LINE + 5 +17F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525813.5569578426 + 20 +184331.5626314666 + 30 +0.0 + 11 +525891.368509183 + 21 +184413.6794007321 + 31 +0.0 + 0 +LINE + 5 +17F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525828.2052620678 + 20 +184465.1304386105 + 30 +0.0 + 11 +526443.4543435843 + 21 +183938.4848300049 + 31 +0.0 + 0 +LINE + 5 +17F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526275.019891734 + 20 +184172.7893517072 + 30 +0.0 + 11 +526624.6944832488 + 21 +184438.5174978444 + 31 +0.0 + 0 +LINE + 5 +17FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526325.0357963618 + 20 +184124.5396230914 + 30 +0.0 + 11 +526190.5049777605 + 21 +184264.2213218149 + 31 +0.0 + 0 +LINE + 5 +17FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526376.5689214775 + 20 +184175.693657369 + 30 +0.0 + 11 +526331.5770466168 + 21 +184221.6433787894 + 31 +0.0 + 0 +LINE + 5 +17FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526355.6854196749 + 20 +184125.4826587656 + 30 +0.0 + 11 +526375.1302151602 + 21 +184191.5065593739 + 31 +0.0 + 0 +LINE + 5 +17FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526362.3870306762 + 20 +184175.5167183563 + 30 +0.0 + 11 +526697.9034325305 + 21 +184399.1812927491 + 31 +0.0 + 0 +LINE + 5 +17FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526542.8303198861 + 20 +184074.0280263877 + 30 +0.0 + 11 +526339.9496769996 + 21 +184427.2292990156 + 31 +0.0 + 0 +LINE + 5 +17FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526330.3480265903 + 20 +184418.0040453817 + 30 +0.0 + 11 +526530.0534350708 + 21 +184548.9754984417 + 31 +0.0 + 0 +LINE + 5 +1800 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526161.4718436333 + 20 +184506.245960555 + 30 +0.0 + 11 +526348.4341758878 + 21 +184417.0721515127 + 31 +0.0 + 0 +LINE + 5 +1801 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526164.8650642328 + 20 +184419.1226542814 + 30 +0.0 + 11 +526218.990871217 + 21 +184485.1659490183 + 31 +0.0 + 0 +LINE + 5 +1802 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526712.5106458383 + 20 +184153.2086076598 + 30 +0.0 + 11 +526663.56988205 + 21 +184228.8848432855 + 31 +0.0 + 0 +LINE + 5 +1803 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526792.6783634435 + 20 +184159.3482499835 + 30 +0.0 + 11 +526527.03949261 + 21 +184549.7123618235 + 31 +0.0 + 0 +LINE + 5 +1804 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526239.0286861463 + 20 +184247.4892532267 + 30 +0.0 + 11 +526581.6696928112 + 21 +184497.3539504156 + 31 +0.0 + 0 +LINE + 5 +1805 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526310.9550896549 + 20 +184712.2948244993 + 30 +0.0 + 11 +526583.880833825 + 21 +184490.7385040259 + 31 +0.0 + 0 +LINE + 5 +1806 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525992.8709973916 + 20 +184929.997010199 + 30 +0.0 + 11 +526183.3718907056 + 21 +184783.0056012491 + 31 +0.0 + 0 +LINE + 5 +1807 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525830.383102649 + 20 +184143.3497653357 + 30 +0.0 + 11 +526216.1373391672 + 21 +184552.8753902649 + 31 +0.0 + 0 +LINE + 5 +1808 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526229.1974565366 + 20 +184553.5559043262 + 30 +0.0 + 11 +526211.3909523055 + 21 +184570.0690196928 + 31 +0.0 + 0 +LINE + 5 +1809 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526419.2687016282 + 20 +184558.6761052552 + 30 +0.0 + 11 +526458.2672452309 + 21 +184607.4056927582 + 31 +0.0 + 0 +LINE + 5 +180A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526418.0624437224 + 20 +184543.1883479094 + 30 +0.0 + 11 +526421.8277408346 + 21 +184566.9574238335 + 31 +0.0 + 0 +LINE + 5 +180B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526461.4818759007 + 20 +184496.0372843275 + 30 +0.0 + 11 +526414.3616489805 + 21 +184550.2733109726 + 31 +0.0 + 0 +LINE + 5 +180C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525750.5794705347 + 20 +184608.7482925879 + 30 +0.0 + 11 +525816.1275078263 + 21 +184826.6854894777 + 31 +0.0 + 0 +LINE + 5 +180D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525836.2877733857 + 20 +184447.0196035297 + 30 +0.0 + 11 +525735.5049749351 + 21 +184637.1933595237 + 31 +0.0 + 0 +LINE + 5 +180E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525625.4714226731 + 20 +184372.2929563019 + 30 +0.0 + 11 +525771.5186383708 + 21 +184272.9622200615 + 31 +0.0 + 0 +LINE + 5 +180F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525713.4256940008 + 20 +184298.8314740285 + 30 +0.0 + 11 +525865.2733286215 + 21 +184513.9619392872 + 31 +0.0 + 0 +LINE + 5 +1810 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526335.831346627 + 20 +184311.854184065 + 30 +0.0 + 11 +526313.2303502487 + 21 +184353.0768101416 + 31 +0.0 + 0 +LINE + 5 +1811 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526263.9695257499 + 20 +184312.5095601781 + 30 +0.0 + 11 +526315.1312625812 + 21 +184353.0468804205 + 31 +0.0 + 0 +LINE + 5 +1812 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526271.614012543 + 20 +184263.5490927737 + 30 +0.0 + 11 +526198.0054952921 + 21 +184337.4728996437 + 31 +0.0 + 0 +LINE + 5 +1813 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526106.0305223349 + 20 +184217.6672843158 + 30 +0.0 + 11 +526292.442435946 + 21 +184450.9253598606 + 31 +0.0 + 0 +LINE + 5 +1814 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526390.9327040018 + 20 +184453.9955091639 + 30 +0.0 + 11 +526349.7161546585 + 21 +184509.1385940667 + 31 +0.0 + 0 +LINE + 5 +1815 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526324.8082092294 + 20 +184489.3006966659 + 30 +0.0 + 11 +526372.8429470729 + 21 +184525.42874556 + 31 +0.0 + 0 +LINE + 5 +1816 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526333.1325333442 + 20 +184487.1166666029 + 30 +0.0 + 11 +526289.6234289066 + 21 +184543.6448343446 + 31 +0.0 + 0 +LINE + 5 +1817 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526288.8650342379 + 20 +184540.0055797161 + 30 +0.0 + 11 +526332.868234571 + 21 +184574.8668498478 + 31 +0.0 + 0 +LINE + 5 +1818 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526373.2923182385 + 20 +184516.4044500072 + 30 +0.0 + 11 +526326.7078393501 + 21 +184578.3396913904 + 31 +0.0 + 0 +LINE + 5 +1819 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526897.6134313817 + 20 +184224.2046449315 + 30 +0.0 + 11 +526750.5592740903 + 21 +184399.9929827601 + 31 +0.0 + 0 +LINE + 5 +181A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526842.5800905745 + 20 +184263.4335107758 + 30 +0.0 + 11 +527056.9201882246 + 21 +184512.6902832656 + 31 +0.0 + 0 +LINE + 5 +181B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526789.8404489752 + 20 +184439.4823091223 + 30 +0.0 + 11 +526939.783213 + 21 +184328.3202370075 + 31 +0.0 + 0 +LINE + 5 +181C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526750.8767119656 + 20 +184393.0555816145 + 30 +0.0 + 11 +526790.6853006583 + 21 +184439.5517851969 + 31 +0.0 + 0 +LINE + 5 +181D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526549.3425899203 + 20 +184611.7703522228 + 30 +0.0 + 11 +526778.5492922794 + 21 +184422.5343785133 + 31 +0.0 + 0 +LINE + 5 +181E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526692.5574984854 + 20 +184628.4080760892 + 30 +0.0 + 11 +527188.3396056741 + 21 +184207.6850059707 + 31 +0.0 + 0 +LINE + 5 +181F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527061.1624567615 + 20 +184406.6737863451 + 30 +0.0 + 11 +527272.4860252165 + 21 +184567.2648657181 + 31 +0.0 + 0 +LINE + 5 +1820 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527111.1783613893 + 20 +184358.4240577295 + 30 +0.0 + 11 +526976.6475427879 + 21 +184498.1057564528 + 31 +0.0 + 0 +LINE + 5 +1821 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527162.711486505 + 20 +184409.5780920069 + 30 +0.0 + 11 +527117.7196116441 + 21 +184455.5278134274 + 31 +0.0 + 0 +LINE + 5 +1822 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527141.8279847026 + 20 +184359.3670934034 + 30 +0.0 + 11 +527161.2727801879 + 21 +184425.3909940119 + 31 +0.0 + 0 +LINE + 5 +1823 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527148.5295957035 + 20 +184409.4011529941 + 30 +0.0 + 11 +527484.0459975578 + 21 +184633.065727387 + 31 +0.0 + 0 +LINE + 5 +1824 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527274.0698449415 + 20 +184403.2704430421 + 30 +0.0 + 11 +527126.0922420271 + 21 +184661.1137336536 + 31 +0.0 + 0 +LINE + 5 +1825 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527116.490591618 + 20 +184651.8884800196 + 30 +0.0 + 11 +527316.1960000983 + 21 +184782.8599330798 + 31 +0.0 + 0 +LINE + 5 +1826 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526978.3772804878 + 20 +184725.4576938802 + 30 +0.0 + 11 +527134.5767409155 + 21 +184650.9565861506 + 31 +0.0 + 0 +LINE + 5 +1827 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526827.5450292298 + 20 +184482.4090883761 + 30 +0.0 + 11 +527005.1334362445 + 21 +184719.0503836559 + 31 +0.0 + 0 +LINE + 5 +1828 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527025.1712511737 + 20 +184481.3736878646 + 30 +0.0 + 11 +527367.8122578385 + 21 +184731.2383850533 + 31 +0.0 + 0 +LINE + 5 +1829 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526932.5809737569 + 20 +185045.0461003779 + 30 +0.0 + 11 +527135.858719686 + 21 +184743.0230287044 + 31 +0.0 + 0 +LINE + 5 +182A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526904.8237453241 + 20 +184941.8305093475 + 30 +0.0 + 11 +527010.2055709973 + 21 +184993.6397609068 + 31 +0.0 + 0 +LINE + 5 +182B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526955.4196256611 + 20 +184905.843476556 + 30 +0.0 + 11 +526982.3255175957 + 21 +185012.3407716361 + 31 +0.0 + 0 +LINE + 5 +182C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526616.5256676765 + 20 +184377.2341999736 + 30 +0.0 + 11 +526838.8137058941 + 21 +184605.691738446 + 31 +0.0 + 0 +LINE + 5 +182D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526825.3214585717 + 20 +184582.8102803995 + 30 +0.0 + 11 +526753.5128899614 + 21 +184978.2282779938 + 31 +0.0 + 0 +LINE + 5 +182E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526752.0011926325 + 20 +184864.9640085656 + 30 +0.0 + 11 +526915.8108504811 + 21 +184896.5445007636 + 31 +0.0 + 0 +LINE + 5 +182F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526892.2504283604 + 20 +184890.6714296093 + 30 +0.0 + 11 +526971.645669471 + 21 +184916.1464748675 + 31 +0.0 + 0 +LINE + 5 +1830 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526900.1754142045 + 20 +184880.2088481438 + 30 +0.0 + 11 +526917.6708325288 + 21 +184958.426863686 + 31 +0.0 + 0 +LINE + 5 +1831 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526823.7113538355 + 20 +185024.4236562697 + 30 +0.0 + 11 +526923.1332783114 + 21 +184947.0457557922 + 31 +0.0 + 0 +LINE + 5 +1832 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526510.1397750775 + 20 +184518.3029687869 + 30 +0.0 + 11 +526588.3675743969 + 21 +184645.4063717812 + 31 +0.0 + 0 +LINE + 5 +1833 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527121.9739116546 + 20 +184545.7386187029 + 30 +0.0 + 11 +527099.3729152762 + 21 +184586.9612447796 + 31 +0.0 + 0 +LINE + 5 +1834 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527050.1120907775 + 20 +184546.3939948161 + 30 +0.0 + 11 +527101.2738276086 + 21 +184586.9313150585 + 31 +0.0 + 0 +LINE + 5 +1835 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527057.7565775703 + 20 +184497.4335274115 + 30 +0.0 + 11 +526984.1480603196 + 21 +184571.3573342815 + 31 +0.0 + 0 +LINE + 5 +1836 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526892.1730873623 + 20 +184451.5517189536 + 30 +0.0 + 11 +527078.5850009737 + 21 +184684.8097944985 + 31 +0.0 + 0 +LINE + 5 +1837 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527177.0752690295 + 20 +184687.8799438017 + 30 +0.0 + 11 +527135.858719686 + 21 +184743.0230287044 + 31 +0.0 + 0 +LINE + 5 +1838 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526976.7466853434 + 20 +184707.544365911 + 30 +0.0 + 11 +527158.9855121005 + 21 +184759.3131801978 + 31 +0.0 + 0 +LINE + 5 +1839 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526654.4660197752 + 20 +184518.5584666173 + 30 +0.0 + 11 +526731.3448775517 + 21 +184600.9854753612 + 31 +0.0 + 0 +LINE + 5 +183A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526950.1892693617 + 20 +185002.0656262611 + 30 +0.0 + 11 +526794.7357978775 + 21 +185555.5789665183 + 31 +0.0 + 0 +LINE + 5 +183B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526884.6421618659 + 20 +185022.8640277708 + 30 +0.0 + 11 +526821.1612098639 + 21 +185241.1291727191 + 31 +0.0 + 0 +LINE + 5 +183C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526747.5557430888 + 20 +184895.8949132786 + 30 +0.0 + 11 +526639.2579063532 + 21 +185026.6789956317 + 31 +0.0 + 0 +LINE + 5 +183D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526627.0050355719 + 20 +184823.9927585792 + 30 +0.0 + 11 +527362.5387850584 + 21 +185447.5890790977 + 31 +0.0 + 0 +LINE + 5 +183E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526744.594477287 + 20 +185013.962813596 + 30 +0.0 + 11 +526538.0210973291 + 21 +185401.533718455 + 31 +0.0 + 0 +LINE + 5 +183F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526800.2018736364 + 20 +185055.6454778395 + 30 +0.0 + 11 +526640.8564858529 + 21 +184945.1078575293 + 31 +0.0 + 0 +LINE + 5 +1840 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526757.9191734891 + 20 +185114.6757368199 + 30 +0.0 + 11 +526705.3834328252 + 21 +185077.5860933195 + 31 +0.0 + 0 +LINE + 5 +1841 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526804.1579407269 + 20 +185086.0533429193 + 30 +0.0 + 11 +526742.0791783166 + 21 +185115.7767811565 + 31 +0.0 + 0 +LINE + 5 +1842 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526755.8325669559 + 20 +185100.647073046 + 30 +0.0 + 11 +526588.5271048182 + 21 +185467.5339494677 + 31 +0.0 + 0 +LINE + 5 +1843 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526884.7942566758 + 20 +185262.5995901697 + 30 +0.0 + 11 +526503.7627330624 + 21 +185118.6319818105 + 31 +0.0 + 0 +LINE + 5 +1844 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526511.3389918514 + 20 +185107.6822193495 + 30 +0.0 + 11 +526413.8858925074 + 21 +185325.7158523542 + 31 +0.0 + 0 +LINE + 5 +1845 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526397.2989610982 + 20 +184955.0366424418 + 30 +0.0 + 11 +526515.1427734561 + 21 +185125.3883896891 + 31 +0.0 + 0 +LINE + 5 +1846 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526483.8486768585 + 20 +184944.4947667127 + 30 +0.0 + 11 +526427.2806052112 + 21 +185008.4586083068 + 31 +0.0 + 0 +LINE + 5 +1847 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526840.4035060879 + 20 +185522.8553234135 + 30 +0.0 + 11 +526412.677887643 + 21 +185322.8579613402 + 31 +0.0 + 0 +LINE + 5 +1848 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526665.1115230083 + 20 +184990.3428613132 + 30 +0.0 + 11 +526473.077143995 + 21 +185368.4407634845 + 31 +0.0 + 0 +LINE + 5 +1849 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526142.309491468 + 20 +185023.4850477535 + 30 +0.0 + 11 +526479.960517171 + 21 +185369.568792402 + 31 +0.0 + 0 +LINE + 5 +184A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525980.8306060982 + 20 +184903.3662741616 + 30 +0.0 + 11 +526345.4878643996 + 21 +185225.2156793015 + 31 +0.0 + 0 +LINE + 5 +184B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526191.356440681 + 20 +184944.954221952 + 30 +0.0 + 11 +526157.0130028118 + 21 +185057.2487276261 + 31 +0.0 + 0 +LINE + 5 +184C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526234.9505034651 + 20 +184989.1647108225 + 30 +0.0 + 11 +526134.1058144044 + 21 +185032.7072138333 + 31 +0.0 + 0 +LINE + 5 +184D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526377.0795550635 + 20 +185115.2702679994 + 30 +0.0 + 11 +526214.5545125192 + 21 +184995.3000970941 + 31 +0.0 + 0 +LINE + 5 +184E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526436.6567078091 + 20 +184906.6268665365 + 30 +0.0 + 11 +526272.7679378563 + 21 +185158.9520676018 + 31 +0.0 + 0 +LINE + 5 +184F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526357.4471082533 + 20 +184840.4476801803 + 30 +0.0 + 11 +526327.8126399383 + 21 +184553.7179558004 + 31 +0.0 + 0 +LINE + 5 +1850 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526702.7607323182 + 20 +184570.3205013269 + 30 +0.0 + 11 +526702.7531557811 + 21 +184570.3303619977 + 31 +0.0 + 0 +LINE + 5 +1851 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526507.3444309529 + 20 +184805.8431383081 + 30 +0.0 + 11 +526359.9824307177 + 21 +185016.4377554403 + 31 +0.0 + 0 +LINE + 5 +1852 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526361.3930396807 + 20 +185029.4392917895 + 30 +0.0 + 11 +526342.251967972 + 21 +185014.4935918768 + 31 +0.0 + 0 +LINE + 5 +1853 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526386.6449285419 + 20 +185217.8952197336 + 30 +0.0 + 11 +526355.4807307931 + 21 +185250.8031207893 + 31 +0.0 + 0 +LINE + 5 +1854 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526401.7422031849 + 20 +185214.2348940512 + 30 +0.0 + 11 +526378.8775942331 + 21 +185221.7419633934 + 31 +0.0 + 0 +LINE + 5 +1855 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526455.2131926328 + 20 +185249.5806600645 + 30 +0.0 + 11 +526394.1577971015 + 21 +185211.7111334264 + 31 +0.0 + 0 +LINE + 5 +1856 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526429.4944541394 + 20 +184994.0813645118 + 30 +0.0 + 11 +526140.7997494224 + 21 +184793.968666802 + 31 +0.0 + 0 +LINE + 5 +1857 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526284.3821589323 + 20 +184804.1957133648 + 30 +0.0 + 11 +526411.0839343908 + 21 +184955.0786364757 + 31 +0.0 + 0 +LINE + 5 +1858 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526813.624339175 + 20 +184874.9987138734 + 30 +0.0 + 11 +526117.198523644 + 21 +184800.3091828398 + 31 +0.0 + 0 +LINE + 5 +1859 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526282.1184163698 + 20 +184883.8219749501 + 30 +0.0 + 11 +526219.5156131227 + 21 +184953.0515150769 + 31 +0.0 + 0 +LINE + 5 +185A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526239.8562063999 + 20 +184924.3845242305 + 30 +0.0 + 11 +526227.366538283 + 21 +185006.8259606097 + 31 +0.0 + 0 +LINE + 5 +185B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526251.4485595676 + 20 +184930.5398763398 + 30 +0.0 + 11 +526177.0208654439 + 21 +184960.2832111424 + 31 +0.0 + 0 +LINE + 5 +185C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526055.79485749 + 20 +184845.1473364929 + 30 +0.0 + 11 +526189.1273452085 + 21 +184963.8610706331 + 31 +0.0 + 0 +LINE + 5 +185D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526617.0051048034 + 20 +185096.1699463408 + 30 +0.0 + 11 +526572.7061751235 + 21 +185080.4309893497 + 31 +0.0 + 0 +LINE + 5 +185E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526604.8998507491 + 20 +185025.3320070574 + 30 +0.0 + 11 +526573.0388196335 + 21 +185082.3028096171 + 31 +0.0 + 0 +LINE + 5 +185F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526673.3455933371 + 20 +184854.2911744704 + 30 +0.0 + 11 +526472.7948735252 + 21 +185075.5108393422 + 31 +0.0 + 0 +LINE + 5 +1860 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526485.4681327537 + 20 +185173.2305774661 + 30 +0.0 + 11 +526339.4935442785 + 21 +185092.6910088522 + 31 +0.0 + 0 +LINE + 5 +1861 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526770.5658452664 + 20 +185216.7153135767 + 30 +0.0 + 11 +526674.5592140982 + 21 +185463.2847288145 + 31 +0.0 + 0 +LINE + 5 +1862 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526034.838448984 + 20 +184377.5229186959 + 30 +0.0 + 11 +526162.9583683656 + 21 +184271.426179767 + 31 +0.0 + 0 +LINE + 5 +1863 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525944.3955297334 + 20 +184418.9332707799 + 30 +0.0 + 11 +525883.1890116699 + 21 +184244.8502677682 + 31 +0.0 + 0 +LINE + 5 +1864 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526610.0769078264 + 20 +185042.3659122216 + 30 +0.0 + 11 +526510.4617097421 + 21 +184980.6649727358 + 31 +0.0 + 0 +LINE + 5 +1865 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526540.7939205786 + 20 +184077.5732577944 + 30 +0.0 + 11 +526721.0522125807 + 21 +183995.2863186054 + 31 +0.0 + 0 +LINE + 5 +1866 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529002.4945046415 + 20 +182989.4166194158 + 30 +0.0 + 11 +529149.9114243247 + 21 +182978.1940307746 + 31 +0.0 + 0 +LINE + 5 +1867 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529082.1590611431 + 20 +182845.3486731855 + 30 +0.0 + 11 +529038.4653913891 + 21 +183337.8681855062 + 31 +0.0 + 0 +LINE + 5 +1868 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529117.9874533724 + 20 +182971.3653905561 + 30 +0.0 + 11 +529190.5948485013 + 21 +183009.4345963159 + 31 +0.0 + 0 +LINE + 5 +1869 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529161.3658895741 + 20 +182904.4802136752 + 30 +0.0 + 11 +529121.6319291057 + 21 +182982.8296927146 + 31 +0.0 + 0 +LINE + 5 +186A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529145.9800161928 + 20 +182915.6603215054 + 30 +0.0 + 11 +529342.1620844844 + 21 +182882.9976690538 + 31 +0.0 + 0 +LINE + 5 +186B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529149.5716516822 + 20 +182793.1125980499 + 30 +0.0 + 11 +529285.810685997 + 21 +183204.0847952215 + 31 +0.0 + 0 +LINE + 5 +186C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529358.1052558049 + 20 +182936.7563646868 + 30 +0.0 + 11 +529186.2722550136 + 21 +183009.6484671357 + 31 +0.0 + 0 +LINE + 5 +186D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529337.839644036 + 20 +182879.6344003608 + 30 +0.0 + 11 +529357.7368392796 + 21 +182937.5198242835 + 31 +0.0 + 0 +LINE + 5 +186E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529628.5345965598 + 20 +182816.7965311425 + 30 +0.0 + 11 +529349.2207426371 + 21 +182918.4318456688 + 31 +0.0 + 0 +LINE + 5 +186F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529563.0764663739 + 20 +182836.7188986079 + 30 +0.0 + 11 +529594.4117381667 + 21 +182945.4198740323 + 31 +0.0 + 0 +LINE + 5 +1870 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529670.7820878086 + 20 +182917.0583723003 + 30 +0.0 + 11 +528898.3699407844 + 21 +183180.8853994138 + 31 +0.0 + 0 +LINE + 5 +1871 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529192.2768187649 + 20 +183153.9957730478 + 30 +0.0 + 11 +529244.0572068602 + 21 +183590.1179566264 + 31 +0.0 + 0 +LINE + 5 +1872 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529125.3310361034 + 20 +183172.6475614621 + 30 +0.0 + 11 +529313.9339647009 + 21 +183127.4983262947 + 31 +0.0 + 0 +LINE + 5 +1873 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529143.2993213422 + 20 +183243.00052112 + 30 +0.0 + 11 +529205.7155989878 + 21 +183227.5133010033 + 31 +0.0 + 0 +LINE + 5 +1874 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529110.6058846278 + 20 +183199.5447479236 + 30 +0.0 + 11 +529157.6589570039 + 21 +183249.7768482477 + 31 +0.0 + 0 +LINE + 5 +1875 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529150.3364046958 + 20 +183230.6864319542 + 30 +0.0 + 11 +529173.0367678382 + 21 +183633.2802610981 + 31 +0.0 + 0 +LINE + 5 +1876 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528971.3791487153 + 20 +183334.7731061746 + 30 +0.0 + 11 +529378.6802900167 + 21 +183338.9533619875 + 31 +0.0 + 0 +LINE + 5 +1877 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529375.5960000428 + 20 +183326.0002098403 + 30 +0.0 + 11 +529387.2477611892 + 21 +183564.537435772 + 31 +0.0 + 0 +LINE + 5 +1878 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529537.2708909291 + 20 +183225.1685163086 + 30 +0.0 + 11 +529365.6238454158 + 21 +183341.117529533 + 31 +0.0 + 0 +LINE + 5 +1879 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529460.4528499908 + 20 +183183.9256620372 + 30 +0.0 + 11 +529489.9408801077 + 21 +183264.0616454732 + 31 +0.0 + 0 +LINE + 5 +187A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528721.379921109 + 20 +183580.3838869297 + 30 +0.0 + 11 +529039.3752873129 + 21 +183439.9840603285 + 31 +0.0 + 0 +LINE + 5 +187B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528918.2607131755 + 20 +183593.3886842624 + 30 +0.0 + 11 +529389.4108538934 + 21 +183562.3130601848 + 31 +0.0 + 0 +LINE + 5 +187C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529274.9119920447 + 20 +183160.8419620406 + 30 +0.0 + 11 +529316.5842563571 + 21 +183582.8593180066 + 31 +0.0 + 0 +LINE + 5 +187D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529750.0154457829 + 20 +183381.516104049 + 30 +0.0 + 11 +529309.7609766477 + 21 +183581.4115163893 + 31 +0.0 + 0 +LINE + 5 +187E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529988.005583848 + 20 +183294.6626457544 + 30 +0.0 + 11 +529487.4641051801 + 21 +183495.7242144426 + 31 +0.0 + 0 +LINE + 5 +187F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529732.8236843104 + 20 +183290.5373308892 + 30 +0.0 + 11 +529724.0578069372 + 21 +183407.6385141588 + 31 +0.0 + 0 +LINE + 5 +1880 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529676.1539762847 + 20 +183315.9056936367 + 30 +0.0 + 11 +529754.3115197908 + 21 +183393.0872929542 + 31 +0.0 + 0 +LINE + 5 +1881 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529497.9412056234 + 20 +183381.8108317713 + 30 +0.0 + 11 +529692.9311665412 + 21 +183329.0268711166 + 31 +0.0 + 0 +LINE + 5 +1882 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529510.5331576017 + 20 +183132.4113161336 + 30 +0.0 + 11 +529579.2785852399 + 21 +183460.3808246315 + 31 +0.0 + 0 +LINE + 5 +1883 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529418.0562012752 + 20 +183146.715740923 + 30 +0.0 + 11 +529538.9701211892 + 21 +183135.4334761842 + 31 +0.0 + 0 +LINE + 5 +1884 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529509.6380631061 + 20 +183037.6396577352 + 30 +0.0 + 11 +529405.3659134461 + 21 +183098.5908658569 + 31 +0.0 + 0 +LINE + 5 +1885 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529409.6444093042 + 20 +183093.3880695214 + 30 +0.0 + 11 +529419.489826466 + 21 +183148.3488614938 + 31 +0.0 + 0 +LINE + 5 +1886 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529392.3121772476 + 20 +182755.8068495324 + 30 +0.0 + 11 +529549.751119872 + 21 +183295.9277136093 + 31 +0.0 + 0 +LINE + 5 +1887 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529543.7167941479 + 20 +183307.5301563754 + 30 +0.0 + 11 +529566.9777532239 + 21 +183300.5528822005 + 31 +0.0 + 0 +LINE + 5 +1888 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529451.7724354552 + 20 +183473.9619128789 + 30 +0.0 + 11 +529468.8639611219 + 21 +183515.9382981882 + 31 +0.0 + 0 +LINE + 5 +1889 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529439.0339467371 + 20 +183465.070535544 + 30 +0.0 + 11 +529457.6133766657 + 21 +183480.3659994512 + 31 +0.0 + 0 +LINE + 5 +188A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529376.3793059448 + 20 +183478.5933264844 + 30 +0.0 + 11 +529447.0171259769 + 21 +183465.4723222404 + 31 +0.0 + 0 +LINE + 5 +188B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529493.0974417447 + 20 +183249.8615614997 + 30 +0.0 + 11 +529916.9032413744 + 21 +183154.751472073 + 31 +0.0 + 0 +LINE + 5 +188C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529888.0572707052 + 20 +183141.4631650017 + 30 +0.0 + 11 +529896.7457502339 + 21 +183342.5572290356 + 31 +0.0 + 0 +LINE + 5 +188D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529651.0735796021 + 20 +182914.8438654025 + 30 +0.0 + 11 +529906.1021607946 + 21 +183172.8070170999 + 31 +0.0 + 0 +LINE + 5 +188E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529875.041216191 + 20 +183036.5611619992 + 30 +0.0 + 11 +529524.4111204172 + 21 +183220.203281717 + 31 +0.0 + 0 +LINE + 5 +188F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529488.683131434 + 20 +183096.7472006318 + 30 +0.0 + 11 +529522.8742442423 + 21 +183087.1055443997 + 31 +0.0 + 0 +LINE + 5 +1890 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529670.4465953165 + 20 +183200.6263381069 + 30 +0.0 + 11 +529703.6460430593 + 21 +183287.8595707087 + 31 +0.0 + 0 +LINE + 5 +1891 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529695.1001273892 + 20 +183253.764066248 + 30 +0.0 + 11 +529676.8089733075 + 21 +183335.1152550795 + 31 +0.0 + 0 +LINE + 5 +1892 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529682.0640560481 + 20 +183255.2911076818 + 30 +0.0 + 11 +529740.6163598035 + 21 +183310.0247841765 + 31 +0.0 + 0 +LINE + 5 +1893 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529895.369820892 + 20 +183246.7525081241 + 30 +0.0 + 11 +529728.0369450099 + 21 +183308.9635329003 + 31 +0.0 + 0 +LINE + 5 +1894 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529693.5360133447 + 20 +182695.2429836775 + 30 +0.0 + 11 +529533.8761624989 + 21 +182770.7752046368 + 31 +0.0 + 0 +LINE + 5 +1895 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529585.6253156224 + 20 +182733.8153123566 + 30 +0.0 + 11 +529694.0815682416 + 21 +182973.7654373622 + 31 +0.0 + 0 +LINE + 5 +1896 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529281.3180175185 + 20 +183276.9133290334 + 30 +0.0 + 11 +529328.3084743434 + 21 +183278.3299818934 + 31 +0.0 + 0 +LINE + 5 +1897 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529318.3137405335 + 20 +183215.3027187767 + 30 +0.0 + 11 +529327.3189961681 + 21 +183279.9533415037 + 31 +0.0 + 0 +LINE + 5 +1898 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529272.2357810101 + 20 +183197.0712297279 + 30 +0.0 + 11 +529373.2723181507 + 21 +183171.0989137618 + 31 +0.0 + 0 +LINE + 5 +1899 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529316.6305635991 + 20 +183031.0828691245 + 30 +0.0 + 11 +529423.1897224751 + 21 +183310.0163325214 + 31 +0.0 + 0 +LINE + 5 +189A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529375.9058362808 + 20 +183396.4685900099 + 30 +0.0 + 11 +529444.3326079678 + 21 +183388.8962278366 + 31 +0.0 + 0 +LINE + 5 +189B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529439.860142844 + 20 +183357.3693349594 + 30 +0.0 + 11 +529446.6499833035 + 21 +183417.089264825 + 31 +0.0 + 0 +LINE + 5 +189C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529433.7575016177 + 20 +183363.4374589976 + 30 +0.0 + 11 +529504.5404009335 + 21 +183354.5911557249 + 31 +0.0 + 0 +LINE + 5 +189D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529501.7879393648 + 20 +183352.0924976781 + 30 +0.0 + 11 +529509.5296659485 + 21 +183407.695154667 + 31 +0.0 + 0 +LINE + 5 +189E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529438.6434841719 + 20 +183412.9016860105 + 30 +0.0 + 11 +529515.6462087013 + 21 +183404.1456473196 + 31 +0.0 + 0 +LINE + 5 +189F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529494.895595546 + 20 +182860.1555962907 + 30 +0.0 + 11 +529526.9711199328 + 21 +182968.2098941174 + 31 +0.0 + 0 +LINE + 5 +18A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529094.4719762004 + 20 +183333.4875583031 + 30 +0.0 + 11 +529094.416596101 + 21 +183598.0886669403 + 31 +0.0 + 0 +LINE + 5 +18A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528799.8989817682 + 20 +183846.8871999126 + 30 +0.0 + 11 +528751.9949650761 + 21 +184436.6604579644 + 31 +0.0 + 0 +LINE + 5 +18A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528708.8283584604 + 20 +183751.1739329707 + 30 +0.0 + 11 +528952.9732172928 + 21 +183774.3958920667 + 31 +0.0 + 0 +LINE + 5 +18A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528978.6545404572 + 20 +182821.6705424059 + 30 +0.0 + 11 +528841.5271843571 + 21 +184134.0700467983 + 31 +0.0 + 0 +LINE + 5 +18A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528921.0492463402 + 20 +183767.5672518482 + 30 +0.0 + 11 +528993.6566414693 + 21 +183805.636457608 + 31 +0.0 + 0 +LINE + 5 +18A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528964.4276825422 + 20 +183700.6820749673 + 30 +0.0 + 11 +528924.6937220741 + 21 +183779.0315540066 + 31 +0.0 + 0 +LINE + 5 +18A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528950.8601394615 + 20 +183711.7422512852 + 30 +0.0 + 11 +529147.042207753 + 21 +183679.0795988337 + 31 +0.0 + 0 +LINE + 5 +18A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528925.852151978 + 20 +183508.5272844486 + 30 +0.0 + 11 +529088.8724789651 + 21 +184000.2866565134 + 31 +0.0 + 0 +LINE + 5 +18A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529161.1670487729 + 20 +183732.9582259788 + 30 +0.0 + 11 +528989.3340479817 + 21 +183805.8503284278 + 31 +0.0 + 0 +LINE + 5 +18A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529140.901437004 + 20 +183675.836261653 + 30 +0.0 + 11 +529160.7986322474 + 21 +183733.7216855758 + 31 +0.0 + 0 +LINE + 5 +18AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529431.5963895281 + 20 +183612.9983924347 + 30 +0.0 + 11 +529152.2825356053 + 21 +183714.633706961 + 31 +0.0 + 0 +LINE + 5 +18AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529366.1382593417 + 20 +183632.9207599 + 30 +0.0 + 11 +529397.4735311349 + 21 +183741.6217353242 + 31 +0.0 + 0 +LINE + 5 +18AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529473.8438807766 + 20 +183713.2602335924 + 30 +0.0 + 11 +528759.3426455927 + 21 +183958.9421117921 + 31 +0.0 + 0 +LINE + 5 +18AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528995.3386117331 + 20 +183950.19763434 + 30 +0.0 + 11 +529047.1189998285 + 21 +184386.3198179183 + 31 +0.0 + 0 +LINE + 5 +18AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528928.3928290715 + 20 +183968.8494227541 + 30 +0.0 + 11 +529116.9957576689 + 21 +183923.7001875868 + 31 +0.0 + 0 +LINE + 5 +18AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528946.36111431 + 20 +184039.202382412 + 30 +0.0 + 11 +529008.777391956 + 21 +184023.7151622953 + 31 +0.0 + 0 +LINE + 5 +18B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528913.6676775958 + 20 +183995.7466092156 + 30 +0.0 + 11 +528960.720749972 + 21 +184045.9787095397 + 31 +0.0 + 0 +LINE + 5 +18B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528953.3981976639 + 20 +184026.8882932462 + 30 +0.0 + 11 +528976.0985608062 + 21 +184429.48212239 + 31 +0.0 + 0 +LINE + 5 +18B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528774.4409416834 + 20 +184130.9749674667 + 30 +0.0 + 11 +529181.7420829849 + 21 +184135.1552232796 + 31 +0.0 + 0 +LINE + 5 +18B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529178.657793011 + 20 +184122.2020711322 + 30 +0.0 + 11 +529190.3095541572 + 21 +184360.739297064 + 31 +0.0 + 0 +LINE + 5 +18B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529340.3326838975 + 20 +184021.3703776007 + 30 +0.0 + 11 +529168.6856383837 + 21 +184137.3193908248 + 31 +0.0 + 0 +LINE + 5 +18B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529263.514642959 + 20 +183980.1275233293 + 30 +0.0 + 11 +529293.0026730755 + 21 +184060.2635067652 + 31 +0.0 + 0 +LINE + 5 +18B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528759.5507635506 + 20 +184261.0245410653 + 30 +0.0 + 11 +528849.5923701449 + 21 +184257.2035358896 + 31 +0.0 + 0 +LINE + 5 +18B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528721.3225061437 + 20 +184389.5905455545 + 30 +0.0 + 11 +529192.4726468614 + 21 +184358.5149214769 + 31 +0.0 + 0 +LINE + 5 +18B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529077.9737850126 + 20 +183957.0438233327 + 30 +0.0 + 11 +529119.6460493255 + 21 +184379.0611792988 + 31 +0.0 + 0 +LINE + 5 +18B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529607.0855259606 + 20 +184151.2387982638 + 30 +0.0 + 11 +529112.8227696159 + 21 +184377.6133776814 + 31 +0.0 + 0 +LINE + 5 +18BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529535.8854772784 + 20 +184086.7391921813 + 30 +0.0 + 11 +529527.1195999053 + 21 +184203.8403754511 + 31 +0.0 + 0 +LINE + 5 +18BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529479.2157692527 + 20 +184112.1075549288 + 30 +0.0 + 11 +529557.3733127589 + 21 +184189.2891542463 + 31 +0.0 + 0 +LINE + 5 +18BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529301.0029985914 + 20 +184178.0126930631 + 30 +0.0 + 11 +529495.9929595092 + 21 +184125.2287324086 + 31 +0.0 + 0 +LINE + 5 +18BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529313.59495057 + 20 +183928.6131774258 + 30 +0.0 + 11 +529382.340378208 + 21 +184256.5826859235 + 31 +0.0 + 0 +LINE + 5 +18BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529221.1179942434 + 20 +183942.917602215 + 30 +0.0 + 11 +529342.0319141572 + 21 +183931.6353374763 + 31 +0.0 + 0 +LINE + 5 +18BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529312.699856074 + 20 +183833.8415190274 + 30 +0.0 + 11 +529208.4277064143 + 21 +183894.792727149 + 31 +0.0 + 0 +LINE + 5 +18C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529212.7062022725 + 20 +183889.5899308134 + 30 +0.0 + 11 +529222.5516194342 + 21 +183944.5507227859 + 31 +0.0 + 0 +LINE + 5 +18C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529195.3739702155 + 20 +183552.0087108246 + 30 +0.0 + 11 +529352.8129128399 + 21 +184092.1295749014 + 31 +0.0 + 0 +LINE + 5 +18C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529346.7785871158 + 20 +184103.7320176673 + 30 +0.0 + 11 +529370.0395461917 + 21 +184096.7547434928 + 31 +0.0 + 0 +LINE + 5 +18C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529254.8342284231 + 20 +184270.163774171 + 30 +0.0 + 11 +529271.9257540901 + 21 +184312.1401594801 + 31 +0.0 + 0 +LINE + 5 +18C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529242.0957397047 + 20 +184261.272396836 + 30 +0.0 + 11 +529260.6751696339 + 21 +184276.5678607432 + 31 +0.0 + 0 +LINE + 5 +18C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529179.4410989126 + 20 +184274.7951877764 + 30 +0.0 + 11 +529250.0789189447 + 21 +184261.6741835324 + 31 +0.0 + 0 +LINE + 5 +18C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529296.1592347129 + 20 +184046.0634227918 + 30 +0.0 + 11 +529643.9673254191 + 21 +183974.7655943309 + 31 +0.0 + 0 +LINE + 5 +18C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529454.1353725699 + 20 +183711.0457266946 + 30 +0.0 + 11 +529600.7203160754 + 21 +183852.9594423334 + 31 +0.0 + 0 +LINE + 5 +18C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529614.6042797779 + 20 +183825.1282280992 + 30 +0.0 + 11 +529327.4729133852 + 21 +184016.405143009 + 31 +0.0 + 0 +LINE + 5 +18C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529291.7449244022 + 20 +183892.949061924 + 30 +0.0 + 11 +529325.9360372104 + 21 +183883.3074056918 + 31 +0.0 + 0 +LINE + 5 +18CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529473.5083882844 + 20 +183996.828199399 + 30 +0.0 + 11 +529506.7078360274 + 21 +184084.0614320004 + 31 +0.0 + 0 +LINE + 5 +18CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529498.1619203571 + 20 +184049.9659275401 + 30 +0.0 + 11 +529479.8707662756 + 21 +184131.3171163717 + 31 +0.0 + 0 +LINE + 5 +18CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529485.1258490162 + 20 +184051.4929689739 + 30 +0.0 + 11 +529543.6781527715 + 21 +184106.2266454686 + 31 +0.0 + 0 +LINE + 5 +18CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529648.1988771667 + 20 +184058.6937259326 + 30 +0.0 + 11 +529531.0987379779 + 21 +184105.1653941923 + 31 +0.0 + 0 +LINE + 5 +18CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529370.9042646857 + 20 +183531.8227899418 + 30 +0.0 + 11 +529497.1433612095 + 21 +183769.9672986542 + 31 +0.0 + 0 +LINE + 5 +18CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529084.3798104866 + 20 +184073.1151903254 + 30 +0.0 + 11 +529131.3702673114 + 21 +184074.5318431856 + 31 +0.0 + 0 +LINE + 5 +18D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529121.3755335018 + 20 +184011.5045800688 + 30 +0.0 + 11 +529130.3807891362 + 21 +184076.1552027958 + 31 +0.0 + 0 +LINE + 5 +18D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529075.2975739782 + 20 +183993.2730910198 + 30 +0.0 + 11 +529176.3341111189 + 21 +183967.3007750539 + 31 +0.0 + 0 +LINE + 5 +18D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529119.6923565671 + 20 +183827.2847304165 + 30 +0.0 + 11 +529226.2515154431 + 21 +184106.2181938137 + 31 +0.0 + 0 +LINE + 5 +18D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529178.9676292489 + 20 +184192.670451302 + 30 +0.0 + 11 +529247.3944009359 + 21 +184185.0980891285 + 31 +0.0 + 0 +LINE + 5 +18D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529242.9219358122 + 20 +184153.5711962515 + 30 +0.0 + 11 +529249.7117762716 + 21 +184213.291126117 + 31 +0.0 + 0 +LINE + 5 +18D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529236.8192945857 + 20 +184159.6393202897 + 30 +0.0 + 11 +529307.6021939016 + 21 +184150.793017017 + 31 +0.0 + 0 +LINE + 5 +18D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529304.8497323328 + 20 +184148.2943589701 + 30 +0.0 + 11 +529312.5914589166 + 21 +184203.8970159591 + 31 +0.0 + 0 +LINE + 5 +18D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529241.70527714 + 20 +184209.1035473026 + 30 +0.0 + 11 +529318.7080016693 + 21 +184200.3475086117 + 31 +0.0 + 0 +LINE + 5 +18D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529297.9573885139 + 20 +183656.3574575827 + 30 +0.0 + 11 +529330.0329129007 + 21 +183764.4117554094 + 31 +0.0 + 0 +LINE + 5 +18D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528897.5337691688 + 20 +184129.6894195952 + 30 +0.0 + 11 +528897.478389069 + 21 +184394.2905282322 + 31 +0.0 + 0 +LINE + 5 +18DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529564.8081035469 + 20 +184156.3795667532 + 30 +0.0 + 11 +530120.7290760145 + 21 +184302.9901803174 + 31 +0.0 + 0 +LINE + 5 +18DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529576.0183069298 + 20 +183927.891279077 + 30 +0.0 + 11 +529743.6527647668 + 21 +183900.8434291773 + 31 +0.0 + 0 +LINE + 5 +18DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529521.6816180366 + 20 +183475.0313137005 + 30 +0.0 + 11 +529650.2941202522 + 21 +184219.5650098007 + 31 +0.0 + 0 +LINE + 5 +18DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529679.2907305889 + 20 +183985.1940250151 + 30 +0.0 + 11 +530117.5734721159 + 21 +184013.717285966 + 31 +0.0 + 0 +LINE + 5 +18DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529687.0294849822 + 20 +184054.2573199527 + 30 +0.0 + 11 +529672.5303405014 + 21 +183860.8683520123 + 31 +0.0 + 0 +LINE + 5 +18DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529759.3473827288 + 20 +184047.7365935693 + 30 +0.0 + 11 +529754.0104869314 + 21 +183983.6494400565 + 31 +0.0 + 0 +LINE + 5 +18E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529711.2346513648 + 20 +184073.0827985901 + 30 +0.0 + 11 +529768.3266381497 + 21 +184034.6411471173 + 31 +0.0 + 0 +LINE + 5 +18E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529748.3128897444 + 20 +184038.8260773843 + 30 +0.0 + 11 +530149.3755702474 + 21 +184080.6091368607 + 31 +0.0 + 0 +LINE + 5 +18E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529822.5334303282 + 20 +184232.0902659284 + 30 +0.0 + 11 +529891.6037786624 + 21 +183830.6665730242 + 31 +0.0 + 0 +LINE + 5 +18E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529878.3245604799 + 20 +183831.6460420928 + 30 +0.0 + 11 +530115.6678549417 + 21 +183858.1777639944 + 31 +0.0 + 0 +LINE + 5 +18E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529804.5617092055 + 20 +183655.9621141555 + 30 +0.0 + 11 +529891.6584272959 + 21 +183843.9010499806 + 31 +0.0 + 0 +LINE + 5 +18E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529751.5979813427 + 20 +183725.2212505417 + 30 +0.0 + 11 +529835.4105477586 + 21 +183708.8880490126 + 31 +0.0 + 0 +LINE + 5 +18E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530003.7161490814 + 20 +184279.3533582009 + 30 +0.0 + 11 +530014.3010319426 + 21 +184189.8544685236 + 31 +0.0 + 0 +LINE + 5 +18E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529699.2253891022 + 20 +183904.7076811009 + 30 +0.0 + 11 +530122.488138511 + 21 +183930.8586144009 + 31 +0.0 + 0 +LINE + 5 +18E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529992.8308329559 + 20 +183470.8687570237 + 30 +0.0 + 11 +530106.5214174473 + 21 +183900.3913899983 + 31 +0.0 + 0 +LINE + 5 +18E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529953.3300898477 + 20 +183258.8502033253 + 30 +0.0 + 11 +530063.7143634662 + 21 +183748.2713958617 + 31 +0.0 + 0 +LINE + 5 +18EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529900.2748189806 + 20 +183473.3341383796 + 30 +0.0 + 11 +530014.4801315384 + 21 +183500.6594803322 + 31 +0.0 + 0 +LINE + 5 +18EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529916.2827226056 + 20 +183533.3237762995 + 30 +0.0 + 11 +530004.9389856002 + 21 +183468.472655168 + 31 +0.0 + 0 +LINE + 5 +18EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529952.9289195793 + 20 +183719.7650139767 + 30 +0.0 + 11 +529931.9111294502 + 21 +183518.8533820108 + 31 +0.0 + 0 +LINE + 5 +18ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529742.8811912783 + 20 +183665.3457348656 + 30 +0.0 + 11 +530043.46283358 + 21 +183651.9961161206 + 31 +0.0 + 0 +LINE + 5 +18EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529687.2422269649 + 20 +183593.0775140649 + 30 +0.0 + 11 +529724.7608320558 + 21 +183708.5756517063 + 31 +0.0 + 0 +LINE + 5 +18EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529623.3457701452 + 20 +183720.3648745762 + 30 +0.0 + 11 +529638.0259663806 + 21 +183600.4806687575 + 31 +0.0 + 0 +LINE + 5 +18F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529634.9426060249 + 20 +183606.469617366 + 30 +0.0 + 11 +529689.309536844 + 21 +183593.7472855568 + 31 +0.0 + 0 +LINE + 5 +18F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529318.09148679 + 20 +183724.2272268729 + 30 +0.0 + 11 +529318.1038273831 + 21 +183724.225695042 + 31 +0.0 + 0 +LINE + 5 +18F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529463.3394359053 + 20 +183706.1976788945 + 30 +0.0 + 11 +529876.4055847055 + 21 +183654.9240051979 + 31 +0.0 + 0 +LINE + 5 +18F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529886.8974241664 + 20 +183662.7311218112 + 30 +0.0 + 11 +529883.7183415998 + 21 +183638.6552416385 + 31 +0.0 + 0 +LINE + 5 +18F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530036.5394987975 + 20 +183780.0364676758 + 30 +0.0 + 11 +530080.7040672157 + 21 +183769.8566803663 + 31 +0.0 + 0 +LINE + 5 +18F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530025.7307421312 + 20 +183791.1942660727 + 30 +0.0 + 11 +530043.7929825967 + 21 +183775.2913763358 + 31 +0.0 + 0 +LINE + 5 +18F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530029.0903345296 + 20 +183855.2035078002 + 30 +0.0 + 11 +530027.4002947669 + 21 +183783.3772860089 + 31 +0.0 + 0 +LINE + 5 +18F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529821.8954453944 + 20 +183703.5076889587 + 30 +0.0 + 11 +529795.7595766237 + 21 +183353.2126123737 + 31 +0.0 + 0 +LINE + 5 +18F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529703.0907581594 + 20 +183390.9512902205 + 30 +0.0 + 11 +529797.6095269524 + 21 +183667.8656604379 + 31 +0.0 + 0 +LINE + 5 +18F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529670.0361374302 + 20 +183683.451661832 + 30 +0.0 + 11 +529665.9695573602 + 21 +183648.1606338434 + 31 +0.0 + 0 +LINE + 5 +18FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529801.5681898015 + 20 +183520.5770130863 + 30 +0.0 + 11 +529892.9789850213 + 21 +183501.7115229562 + 31 +0.0 + 0 +LINE + 5 +18FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529857.9570564266 + 20 +183504.7116257166 + 30 +0.0 + 11 +529935.3509598677 + 21 +183535.7400957423 + 31 +0.0 + 0 +LINE + 5 +18FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529857.3859786731 + 20 +183517.8244012334 + 30 +0.0 + 11 +529920.755485241 + 21 +183468.7484065412 + 31 +0.0 + 0 +LINE + 5 +18FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529882.9679134057 + 20 +183305.8861517042 + 30 +0.0 + 11 +529917.7020419922 + 21 +183480.9976683616 + 31 +0.0 + 0 +LINE + 5 +18FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529814.8331984142 + 20 +183916.8910231721 + 30 +0.0 + 11 +529823.7242868534 + 21 +183870.7276341683 + 31 +0.0 + 0 +LINE + 5 +18FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529759.9097336122 + 20 +183870.5448924621 + 30 +0.0 + 11 +529825.1691067379 + 21 +183871.9632955235 + 31 +0.0 + 0 +LINE + 5 +1900 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529734.5644303138 + 20 +183913.1263572974 + 30 +0.0 + 11 +529725.0345265799 + 21 +183809.2412093268 + 31 +0.0 + 0 +LINE + 5 +1901 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529577.7783682334 + 20 +183842.8329485435 + 30 +0.0 + 11 +529870.1339267547 + 21 +183782.112616325 + 31 +0.0 + 0 +LINE + 5 +1902 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529947.940788104 + 20 +183842.5762503987 + 30 +0.0 + 11 +529951.375853984 + 21 +183773.8175122284 + 31 +0.0 + 0 +LINE + 5 +1903 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529919.539180531 + 20 +183773.2058405635 + 30 +0.0 + 11 +529979.5776981694 + 21 +183776.0251235164 + 31 +0.0 + 0 +LINE + 5 +1904 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529924.5566131975 + 20 +183780.197959607 + 30 +0.0 + 11 +529927.109717592 + 21 +183708.9101094842 + 31 +0.0 + 0 +LINE + 5 +1905 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529924.2041507862 + 20 +183711.2289493369 + 30 +0.0 + 11 +529980.3298478019 + 21 +183712.4520312043 + 31 +0.0 + 0 +LINE + 5 +1906 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529974.1670696054 + 20 +183783.2614860843 + 30 +0.0 + 11 +529977.8010258291 + 21 +183705.8477782501 + 31 +0.0 + 0 +LINE + 5 +1907 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529840.8913014926 + 20 +184110.3672796936 + 30 +0.0 + 11 +530102.0983370033 + 21 +184152.6122126289 + 31 +0.0 + 0 +LINE + 5 +1908 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528668.7913145144 + 20 +183107.5549678178 + 30 +0.0 + 11 +528541.0430600417 + 21 +183527.7503403289 + 31 +0.0 + 0 +LINE + 5 +1909 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528804.4113192836 + 20 +182893.6556957394 + 30 +0.0 + 11 +528671.5138685195 + 21 +183589.133053046 + 31 +0.0 + 0 +LINE + 5 +190A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528854.4143764418 + 20 +183324.3966236097 + 30 +0.0 + 11 +528250.610854468 + 21 +183222.7979014137 + 31 +0.0 + 0 +LINE + 5 +190B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528458.0548529516 + 20 +183244.6009172969 + 30 +0.0 + 11 +528404.5920938378 + 21 +183477.3615348441 + 31 +0.0 + 0 +LINE + 5 +190C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528531.3448267208 + 20 +183079.5639227049 + 30 +0.0 + 11 +528245.4138924677 + 21 +183131.629383617 + 31 +0.0 + 0 +LINE + 5 +190D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528807.9591497892 + 20 +183577.2528416022 + 30 +0.0 + 11 +528402.8543708085 + 21 +183474.7910999636 + 31 +0.0 + 0 +LINE + 5 +190E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528586.2414796501 + 20 +183099.7468354818 + 30 +0.0 + 11 +528470.9265496374 + 21 +183507.8371358638 + 31 +0.0 + 0 +LINE + 5 +190F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527866.6651222174 + 20 +183086.587611023 + 30 +0.0 + 11 +528477.8981421178 + 21 +183507.6131407652 + 31 +0.0 + 0 +LINE + 5 +1910 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528254.4293880732 + 20 +183027.6427082953 + 30 +0.0 + 11 +528291.0664511334 + 21 +183410.0281326049 + 31 +0.0 + 0 +LINE + 5 +1911 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528357.0203913149 + 20 +183376.8414271265 + 30 +0.0 + 11 +528332.8061176764 + 21 +183415.1533851214 + 31 +0.0 + 0 +LINE + 5 +1912 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528371.1252056358 + 20 +183370.331442587 + 30 +0.0 + 11 +528350.1432728785 + 21 +183382.1172361704 + 31 +0.0 + 0 +LINE + 5 +1913 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528430.4207266745 + 20 +183394.6729929148 + 30 +0.0 + 11 +528363.1959728388 + 21 +183369.3215660714 + 31 +0.0 + 0 +LINE + 5 +1914 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528559.5018706355 + 20 +183212.8777008889 + 30 +0.0 + 11 +528512.9959012541 + 21 +183205.9998560331 + 31 +0.0 + 0 +LINE + 5 +1915 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528533.9300921969 + 20 +183145.716439993 + 30 +0.0 + 11 +528513.6841439121 + 21 +183207.77205397 + 31 +0.0 + 0 +LINE + 5 +1916 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528989.8411163921 + 20 +183174.0817346289 + 30 +0.0 + 11 +528487.6116385765 + 21 +183092.5278840273 + 31 +0.0 + 0 +LINE + 5 +1917 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528568.0177221007 + 20 +182964.6699830321 + 30 +0.0 + 11 +528384.4060132413 + 21 +183269.6789120271 + 31 +0.0 + 0 +LINE + 5 +1918 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528742.3877054963 + 20 +183749.6239748958 + 30 +0.0 + 11 +528621.5965608299 + 21 +183958.8324620295 + 31 +0.0 + 0 +LINE + 5 +1919 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528352.40484145 + 20 +183517.2583498101 + 30 +0.0 + 11 +528802.5990649035 + 21 +183778.5899352814 + 31 +0.0 + 0 +LINE + 5 +191A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528293.1666930174 + 20 +183608.5169334034 + 30 +0.0 + 11 +528953.2583603691 + 21 +183976.1452661638 + 31 +0.0 + 0 +LINE + 5 +191B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528722.4875052028 + 20 +183925.9917585473 + 30 +0.0 + 11 +528594.7392507302 + 21 +184346.1871310584 + 31 +0.0 + 0 +LINE + 5 +191C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528785.1042229958 + 20 +183956.1376318977 + 30 +0.0 + 11 +528607.3950652944 + 21 +183878.4911678382 + 31 +0.0 + 0 +LINE + 5 +191D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528755.0313661355 + 20 +184022.2286410237 + 30 +0.0 + 11 +528696.3163109133 + 21 +183995.9953036005 + 31 +0.0 + 0 +LINE + 5 +191E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528794.8643226163 + 20 +183985.207017528 + 30 +0.0 + 11 +528739.703064588 + 21 +184026.371214784 + 31 +0.0 + 0 +LINE + 5 +191F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528750.2720030147 + 20 +184008.8680348702 + 30 +0.0 + 11 +528657.0520669105 + 21 +184401.178041452 + 31 +0.0 + 0 +LINE + 5 +1920 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528799.6205179925 + 20 +184124.465023813 + 30 +0.0 + 11 +528506.43460244 + 21 +184075.2455926983 + 31 +0.0 + 0 +LINE + 5 +1921 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528511.7510436402 + 20 +184063.0377080264 + 30 +0.0 + 11 +528458.2882845263 + 21 +184295.7983255736 + 31 +0.0 + 0 +LINE + 5 +1922 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528370.3519160148 + 20 +183935.3189252638 + 30 +0.0 + 11 +528518.9061481188 + 21 +184079.674465598 + 31 +0.0 + 0 +LINE + 5 +1923 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528453.2307839687 + 20 +183908.2435178108 + 30 +0.0 + 11 +528410.0958539993 + 21 +183981.9367846534 + 31 +0.0 + 0 +LINE + 5 +1924 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528786.1574028308 + 20 +184374.1598480596 + 30 +0.0 + 11 +528456.5505614972 + 21 +184293.2278906931 + 31 +0.0 + 0 +LINE + 5 +1925 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528639.9376703386 + 20 +183918.1836262113 + 30 +0.0 + 11 +528524.6227403257 + 21 +184326.2739265931 + 31 +0.0 + 0 +LINE + 5 +1926 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528084.9026102108 + 20 +184016.1989552483 + 30 +0.0 + 11 +528531.5943328062 + 21 +184326.0499314945 + 31 +0.0 + 0 +LINE + 5 +1927 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528166.3454298809 + 20 +183965.2409996249 + 30 +0.0 + 11 +528154.3594816886 + 21 +184082.0565156114 + 31 +0.0 + 0 +LINE + 5 +1928 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528217.6641506519 + 20 +184000.1895122487 + 30 +0.0 + 11 +528127.1399110786 + 21 +184062.4065752605 + 31 +0.0 + 0 +LINE + 5 +1929 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528381.4914746685 + 20 +184096.4385993347 + 30 +0.0 + 11 +528198.839080213 + 21 +184010.15224954 + 31 +0.0 + 0 +LINE + 5 +192A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528413.0013877898 + 20 +183848.7173829846 + 30 +0.0 + 11 +528287.5926426249 + 21 +184159.4625824032 + 31 +0.0 + 0 +LINE + 5 +192B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528501.5158683562 + 20 +183879.0783900494 + 30 +0.0 + 11 +528384.4765103999 + 21 +183846.6861963027 + 31 +0.0 + 0 +LINE + 5 +192C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528519.1842874642 + 20 +183828.0644140476 + 30 +0.0 + 11 +528499.8171324582 + 21 +183880.4336244704 + 31 +0.0 + 0 +LINE + 5 +192D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528595.6748710933 + 20 +183498.8066472854 + 30 +0.0 + 11 +528345.6098893717 + 21 +184002.7759651829 + 31 +0.0 + 0 +LINE + 5 +192E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528349.5074364252 + 20 +184015.2595100341 + 30 +0.0 + 11 +528327.8380637481 + 21 +184004.2962596118 + 31 +0.0 + 0 +LINE + 5 +192F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528410.7165820031 + 20 +184195.2782178561 + 30 +0.0 + 11 +528386.5023083646 + 21 +184233.5901758509 + 31 +0.0 + 0 +LINE + 5 +1930 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528424.8213963242 + 20 +184188.7682333163 + 30 +0.0 + 11 +528403.8394635669 + 21 +184200.5540268997 + 31 +0.0 + 0 +LINE + 5 +1931 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528484.1169173629 + 20 +184213.1097836442 + 30 +0.0 + 11 +528416.8921635274 + 21 +184187.7583568011 + 31 +0.0 + 0 +LINE + 5 +1932 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528409.4884254542 + 20 +183967.4027798099 + 30 +0.0 + 11 +528079.6638097751 + 21 +183835.989039296 + 31 +0.0 + 0 +LINE + 5 +1933 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528312.9572507023 + 20 +183609.8065701943 + 30 +0.0 + 11 +528143.6786059444 + 21 +183723.6985750834 + 31 +0.0 + 0 +LINE + 5 +1934 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528134.9109864112 + 20 +183693.8578347845 + 30 +0.0 + 11 +528383.8849453777 + 21 +183932.6951172608 + 31 +0.0 + 0 +LINE + 5 +1935 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528440.7886101574 + 20 +183817.4568159531 + 30 +0.0 + 11 +528408.8288346195 + 21 +183801.9466103597 + 31 +0.0 + 0 +LINE + 5 +1936 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528243.5765977299 + 20 +183887.7152970022 + 30 +0.0 + 11 +528195.5387878738 + 21 +183967.7415990835 + 31 +0.0 + 0 +LINE + 5 +1937 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528209.9535345455 + 20 +183935.6830405157 + 30 +0.0 + 11 +528213.6376612554 + 21 +184018.9837575135 + 31 +0.0 + 0 +LINE + 5 +1938 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528222.5171871721 + 20 +183939.4811511292 + 30 +0.0 + 11 +528155.2438146322 + 21 +183983.0522535347 + 31 +0.0 + 0 +LINE + 5 +1939 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528060.7233277694 + 20 +183917.8614732753 + 30 +0.0 + 11 +528167.8135951839 + 21 +183984.2221029732 + 31 +0.0 + 0 +LINE + 5 +193A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528426.4395500667 + 20 +183448.0349839718 + 30 +0.0 + 11 +528260.2481751706 + 21 +183660.2366414376 + 31 +0.0 + 0 +LINE + 5 +193B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528613.1980613237 + 20 +184031.3144916184 + 30 +0.0 + 11 +528566.6920919425 + 21 +184024.4366467629 + 31 +0.0 + 0 +LINE + 5 +193C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528587.6262828853 + 20 +183964.1532307225 + 30 +0.0 + 11 +528567.3803346004 + 21 +184026.2088446995 + 31 +0.0 + 0 +LINE + 5 +193D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528636.194151661 + 20 +183954.3182081319 + 30 +0.0 + 11 +528541.3078292647 + 21 +183910.9646747567 + 31 +0.0 + 0 +LINE + 5 +193E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528621.7139127892 + 20 +183783.1067737617 + 30 +0.0 + 11 +528467.7144836024 + 21 +184038.9248871805 + 31 +0.0 + 0 +LINE + 5 +193F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528499.0405333586 + 20 +184132.3509934097 + 30 +0.0 + 11 +528433.0154931339 + 21 +184112.8507930077 + 31 +0.0 + 0 +LINE + 5 +1940 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528442.9682191248 + 20 +184082.6036251381 + 30 +0.0 + 11 +528425.7711037648 + 21 +184140.1955618993 + 31 +0.0 + 0 +LINE + 5 +1941 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528447.9072965878 + 20 +184089.6513107935 + 30 +0.0 + 11 +528379.7871951758 + 21 +184068.4822838726 + 31 +0.0 + 0 +LINE + 5 +1942 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528382.936542737 + 20 +184066.5072024408 + 30 +0.0 + 11 +528365.5272273391 + 21 +184119.8785948911 + 31 +0.0 + 0 +LINE + 5 +1943 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528434.389757027 + 20 +184137.4828767697 + 30 +0.0 + 11 +528360.1310789086 + 21 +184115.3077437919 + 31 +0.0 + 0 +LINE + 5 +1944 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528476.3236267395 + 20 +183583.4665500198 + 30 +0.0 + 11 +528425.7267702648 + 21 +183684.1866009447 + 31 +0.0 + 0 +LINE + 5 +1945 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528125.6147590899 + 20 +184028.7021100603 + 30 +0.0 + 11 +527552.5660905527 + 21 +184075.1566375765 + 31 +0.0 + 0 +LINE + 5 +1946 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528083.3467968647 + 20 +183974.4580672929 + 30 +0.0 + 11 +527856.6207323578 + 21 +183990.7306343801 + 31 +0.0 + 0 +LINE + 5 +1947 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528154.8035516293 + 20 +183801.8087856649 + 30 +0.0 + 11 +527994.5487521048 + 21 +183745.6723726351 + 31 +0.0 + 0 +LINE + 5 +1948 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528288.0147642038 + 20 +183365.5870566724 + 30 +0.0 + 11 +528030.3404346557 + 21 +184075.8514723987 + 31 +0.0 + 0 +LINE + 5 +1949 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528043.0562136596 + 20 +183840.0361402322 + 30 +0.0 + 11 +527535.5193539366 + 21 +183724.884393956 + 31 +0.0 + 0 +LINE + 5 +194A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528023.2801637968 + 20 +183906.6584704155 + 30 +0.0 + 11 +528071.5977713523 + 21 +183718.842265279 + 31 +0.0 + 0 +LINE + 5 +194B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527953.2396338999 + 20 +183887.5084735797 + 30 +0.0 + 11 +527969.7753182916 + 21 +183825.3617371906 + 31 +0.0 + 0 +LINE + 5 +194C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527996.1389185524 + 20 +183920.9287728688 + 30 +0.0 + 11 +527946.7059838759 + 21 +183873.0368059822 + 31 +0.0 + 0 +LINE + 5 +194D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527965.6704341591 + 20 +183880.6796714141 + 30 +0.0 + 11 +527647.3742233534 + 21 +183910.4481971195 + 31 +0.0 + 0 +LINE + 5 +194E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528056.0681094791 + 20 +183648.8329268226 + 30 +0.0 + 11 +527635.8546818722 + 21 +183638.182139202 + 31 +0.0 + 0 +LINE + 5 +194F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528104.2585344263 + 20 +183452.6437546761 + 30 +0.0 + 11 +528046.9931643914 + 21 +183559.7331702191 + 31 +0.0 + 0 +LINE + 5 +1950 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528144.7489437926 + 20 +183589.19175389 + 30 +0.0 + 11 +528151.4028743793 + 21 +183468.5955011539 + 31 +0.0 + 0 +LINE + 5 +1951 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528153.3837633594 + 20 +183475.0337225985 + 30 +0.0 + 11 +528102.1056020192 + 21 +183452.9391290769 + 31 +0.0 + 0 +LINE + 5 +1952 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528444.5559317088 + 20 +183646.7318726641 + 30 +0.0 + 11 +528444.5440535158 + 21 +183646.7281922736 + 31 +0.0 + 0 +LINE + 5 +1953 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528304.7504013262 + 20 +183603.4139203 + 30 +0.0 + 11 +527686.3268742882 + 21 +183468.9411166398 + 31 +0.0 + 0 +LINE + 5 +1954 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527876.9014784467 + 20 +183669.7856404972 + 30 +0.0 + 11 +528039.6626700543 + 21 +183197.4211840708 + 31 +0.0 + 0 +LINE + 5 +1955 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528196.1692423678 + 20 +183033.7410272279 + 30 +0.0 + 11 +527992.9132103017 + 21 +183547.3888224487 + 31 +0.0 + 0 +LINE + 5 +1956 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528105.2861078474 + 20 +183544.635494493 + 30 +0.0 + 11 +528115.501939949 + 21 +183510.6115249354 + 31 +0.0 + 0 +LINE + 5 +1957 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527805.6390662193 + 20 +183840.6870125336 + 30 +0.0 + 11 +527921.0294539186 + 21 +183701.9308299949 + 31 +0.0 + 0 +LINE + 5 +1958 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527983.8795447074 + 20 +183712.985091062 + 30 +0.0 + 11 +527919.3896683446 + 21 +183702.8928418217 + 31 +0.0 + 0 +LINE + 5 +1959 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528168.0449598422 + 20 +183717.7690181888 + 30 +0.0 + 11 +527950.1848962111 + 21 +183630.3110709327 + 31 +0.0 + 0 +LINE + 5 +195A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528231.7146954377 + 20 +183407.7565646374 + 30 +0.0 + 11 +528348.9669055398 + 21 +183581.0464224438 + 31 +0.0 + 0 +LINE + 5 +195B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527969.7038562812 + 20 +183723.7556854169 + 30 +0.0 + 11 +527992.9685127766 + 21 +183608.912534202 + 31 +0.0 + 0 +LINE + 5 +195C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528850.3825839323 + 20 +183323.7182158954 + 30 +0.0 + 11 +528990.1503365547 + 21 +183464.1787709401 + 31 +0.0 + 0 +LINE + 5 +195D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525307.3474071975 + 20 +184541.7665493575 + 30 +0.0 + 11 +528178.1351607463 + 21 +184982.9648824393 + 31 +0.0 + 0 +LINE + 5 +195E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526077.6348797937 + 20 +184864.5927893283 + 30 +0.0 + 11 +525797.6402801826 + 21 +184765.2182856161 + 31 +0.0 + 0 +LINE + 5 +195F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525997.2138650289 + 20 +184320.4611636129 + 30 +0.0 + 11 +525984.6548647781 + 21 +184851.1522572005 + 31 +0.0 + 0 +LINE + 5 +1960 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525800.7908432205 + 20 +184455.0695224782 + 30 +0.0 + 11 +526021.5188082319 + 21 +184527.0129275369 + 31 +0.0 + 0 +LINE + 5 +1961 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526171.5682654237 + 20 +184485.6664297445 + 30 +0.0 + 11 +526155.7412254004 + 21 +184804.3255559893 + 31 +0.0 + 0 +LINE + 5 +1962 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526588.3675743969 + 20 +184645.4063717812 + 30 +0.0 + 11 +526576.8066982293 + 21 +184871.6956292857 + 31 +0.0 + 0 +LINE + 5 +1963 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525964.343985564 + 20 +184517.1375942794 + 30 +0.0 + 11 +526207.3294778549 + 21 +184498.6850303378 + 31 +0.0 + 0 +LINE + 5 +1964 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525937.9673686516 + 20 +184716.0414479291 + 30 +0.0 + 11 +526226.5149961723 + 21 +184745.9789273604 + 31 +0.0 + 0 +LINE + 5 +1965 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527987.6557398821 + 20 +184960.8730516275 + 30 +0.0 + 11 +530791.2460484537 + 21 +185189.0669865992 + 31 +0.0 + 0 +LINE + 5 +1966 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527808.157781419 + 20 +184075.6972938018 + 30 +0.0 + 11 +527810.8540837077 + 21 +183819.4902595181 + 31 +0.0 + 0 +LINE + 5 +1967 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527575.5627971427 + 20 +184719.6434625751 + 30 +0.0 + 11 +528002.5221155909 + 21 +184822.5487976695 + 31 +0.0 + 0 +LINE + 5 +1968 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527549.3928541368 + 20 +184958.5758116922 + 30 +0.0 + 11 +527592.9654759936 + 21 +184596.3563074837 + 31 +0.0 + 0 +LINE + 5 +1969 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527642.0179508916 + 20 +184796.483250273 + 30 +0.0 + 11 +527649.1715267503 + 21 +184732.5733758048 + 31 +0.0 + 0 +LINE + 5 +196A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527668.3713798277 + 20 +184989.5745496803 + 30 +0.0 + 11 +527813.7447750579 + 21 +184609.0771512619 + 31 +0.0 + 0 +LINE + 5 +196B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527800.5267200151 + 20 +184607.4709084165 + 30 +0.0 + 11 +528028.2630757902 + 21 +184679.3869980712 + 31 +0.0 + 0 +LINE + 5 +196C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527762.119928606 + 20 +184420.8410095866 + 30 +0.0 + 11 +527811.2398088129 + 21 +184622.0725162393 + 31 +0.0 + 0 +LINE + 5 +196D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527696.7657236177 + 20 +184478.5541998675 + 30 +0.0 + 11 +527782.1547628032 + 21 +184478.7323806127 + 31 +0.0 + 0 +LINE + 5 +196E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527762.9605137232 + 20 +185048.1139941885 + 30 +0.0 + 11 +527790.6482723803 + 21 +184962.3499048549 + 31 +0.0 + 0 +LINE + 5 +196F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527892.4420198638 + 20 +185129.2023896609 + 30 +0.0 + 11 +528026.9283833614 + 21 +184676.586031645 + 31 +0.0 + 0 +LINE + 5 +1970 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527610.6815719196 + 20 +184644.5294570579 + 30 +0.0 + 11 +528020.9035075767 + 21 +184752.0152228841 + 31 +0.0 + 0 +LINE + 5 +1971 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527982.6208062758 + 20 +184275.6370951802 + 30 +0.0 + 11 +528017.1761369693 + 21 +184757.9109827055 + 31 +0.0 + 0 +LINE + 5 +1972 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527983.8260365036 + 20 +184022.296659296 + 30 +0.0 + 11 +527998.5376072865 + 21 +184561.5100641322 + 31 +0.0 + 0 +LINE + 5 +1973 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527891.334296719 + 20 +184260.1623738197 + 30 +0.0 + 11 +527998.1023206634 + 21 +184309.0511945493 + 31 +0.0 + 0 +LINE + 5 +1974 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527895.4425742306 + 20 +184322.1150306804 + 30 +0.0 + 11 +527994.9637622951 + 21 +184275.6270321611 + 31 +0.0 + 0 +LINE + 5 +1975 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527895.3532610598 + 20 +184512.1236380707 + 30 +0.0 + 11 +527913.57366127 + 21 +184310.9390253954 + 31 +0.0 + 0 +LINE + 5 +1976 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527480.90823527 + 20 +184388.0469938584 + 30 +0.0 + 11 +527997.2807625187 + 21 +184463.1359095324 + 31 +0.0 + 0 +LINE + 5 +1977 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527841.5936935205 + 20 +184443.4000457608 + 30 +0.0 + 11 +527843.1291080543 + 21 +184419.1637697629 + 31 +0.0 + 0 +LINE + 5 +1978 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527965.7343629274 + 20 +184587.42222762 + 30 +0.0 + 11 +528011.0337673516 + 21 +184585.9726994008 + 31 +0.0 + 0 +LINE + 5 +1979 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527952.9724149893 + 20 +184596.2799005969 + 30 +0.0 + 11 +527973.7683600728 + 21 +184584.1689509764 + 31 +0.0 + 0 +LINE + 5 +197A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527943.8939013147 + 20 +184659.7310666782 + 30 +0.0 + 11 +527956.1217050114 + 21 +184588.9331628391 + 31 +0.0 + 0 +LINE + 5 +197B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527769.934801415 + 20 +184470.840688152 + 30 +0.0 + 11 +527827.9300307166 + 21 +184040.3829802543 + 31 +0.0 + 0 +LINE + 5 +197C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527805.4507991196 + 20 +184062.8185162508 + 30 +0.0 + 11 +527997.0454664766 + 21 +184124.5096477568 + 31 +0.0 + 0 +LINE + 5 +197D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527702.5578931418 + 20 +184038.5925424107 + 30 +0.0 + 11 +527752.9976249645 + 21 +184431.175942022 + 31 +0.0 + 0 +LINE + 5 +197E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527785.35650153 + 20 +184287.4313081827 + 30 +0.0 + 11 +527878.6899841483 + 21 +184286.5939176294 + 31 +0.0 + 0 +LINE + 5 +197F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527843.748765733 + 20 +184282.7667313624 + 30 +0.0 + 11 +527913.6839365679 + 21 +184328.1721729113 + 31 +0.0 + 0 +LINE + 5 +1980 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527840.6534060318 + 20 +184295.5217209693 + 30 +0.0 + 11 +527912.3151283762 + 21 +184259.6226239287 + 31 +0.0 + 0 +LINE + 5 +1981 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527906.7261415853 + 20 +184092.5275077153 + 30 +0.0 + 11 +527906.9511752789 + 21 +184271.0504819078 + 31 +0.0 + 0 +LINE + 5 +1982 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527721.7529934951 + 20 +184678.8330823348 + 30 +0.0 + 11 +527739.4009828234 + 21 +184635.2594847026 + 31 +0.0 + 0 +LINE + 5 +1983 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527676.8256617091 + 20 +184622.7431039412 + 30 +0.0 + 11 +527740.5796583324 + 21 +184636.7511574304 + 31 +0.0 + 0 +LINE + 5 +1984 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527643.7263602637 + 20 +184659.6213060481 + 30 +0.0 + 11 +527654.4600654166 + 21 +184555.8536299263 + 31 +0.0 + 0 +LINE + 5 +1985 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527503.4877949194 + 20 +184560.3430235939 + 30 +0.0 + 11 +527802.0667646647 + 21 +184557.2884910617 + 31 +0.0 + 0 +LINE + 5 +1986 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527866.7164859016 + 20 +184631.6536190617 + 30 +0.0 + 11 +527883.379678869 + 21 +184564.8561509022 + 31 +0.0 + 0 +LINE + 5 +1987 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527852.2618777851 + 20 +184558.101125034 + 30 +0.0 + 11 +527910.6226856307 + 21 +184572.4742967173 + 31 +0.0 + 0 +LINE + 5 +1988 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527855.8328867656 + 20 +184565.9313392166 + 30 +0.0 + 11 +527872.1197030677 + 21 +184496.4819653397 + 31 +0.0 + 0 +LINE + 5 +1989 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527868.8206569435 + 20 +184498.1953337749 + 30 +0.0 + 11 +527923.6510511095 + 21 +184510.2459632337 + 31 +0.0 + 0 +LINE + 5 +198A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527903.9151466527 + 20 +184578.5281191074 + 30 +0.0 + 11 +527922.4467185071 + 21 +184503.2774138411 + 31 +0.0 + 0 +LINE + 5 +198B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527910.2046977225 + 20 +185240.1234589559 + 30 +0.0 + 11 +528625.4822334132 + 21 +185577.9825458991 + 31 +0.0 + 0 +LINE + 5 +198C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528033.5651137221 + 20 +185301.6519541995 + 30 +0.0 + 11 +528074.238106388 + 21 +185159.5132811641 + 31 +0.0 + 0 +LINE + 5 +198D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527926.1315420274 + 20 +185176.9120553437 + 30 +0.0 + 11 +528372.8202171181 + 21 +185388.9352482703 + 31 +0.0 + 0 +LINE + 5 +198E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528056.7474958125 + 20 +185187.0786360558 + 30 +0.0 + 11 +528117.6632592067 + 21 +185132.2118152555 + 31 +0.0 + 0 +LINE + 5 +198F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528009.0905858184 + 20 +185123.1714021653 + 30 +0.0 + 11 +528068.7639218026 + 21 +185187.6424922191 + 31 +0.0 + 0 +LINE + 5 +1990 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527815.499177531 + 20 +185092.6115966227 + 30 +0.0 + 11 +528333.2656037408 + 21 +185110.5234618076 + 31 +0.0 + 0 +LINE + 5 +1991 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528085.0587549844 + 20 +184722.9316982304 + 30 +0.0 + 11 +528197.8763293401 + 21 +184731.2980733757 + 31 +0.0 + 0 +LINE + 5 +1992 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528197.8031362093 + 20 +184649.8315174913 + 30 +0.0 + 11 +528180.0506917082 + 21 +185405.1833898459 + 31 +0.0 + 0 +LINE + 5 +1993 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528253.8105398686 + 20 +185180.8397990754 + 30 +0.0 + 11 +528733.1088459851 + 21 +185324.8966353942 + 31 +0.0 + 0 +LINE + 5 +1994 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528248.0514866669 + 20 +185250.0962813238 + 30 +0.0 + 11 +528271.2132187195 + 21 +185057.552643984 + 31 +0.0 + 0 +LINE + 5 +1995 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528320.2656936174 + 20 +185257.679586773 + 30 +0.0 + 11 +528327.4192694761 + 21 +185193.7697123049 + 31 +0.0 + 0 +LINE + 5 +1996 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528268.1605303945 + 20 +185273.2461211912 + 30 +0.0 + 11 +528331.6072550481 + 21 +185246.5671284493 + 31 +0.0 + 0 +LINE + 5 +1997 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528311.1620183674 + 20 +185246.8039060563 + 30 +0.0 + 11 +528445.5263302135 + 21 +185288.12612457 + 31 +0.0 + 0 +LINE + 5 +1998 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528346.6191225535 + 20 +185450.7708861805 + 30 +0.0 + 11 +528628.3189486684 + 21 +184705.4867174532 + 31 +0.0 + 0 +LINE + 5 +1999 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528478.774462741 + 20 +185068.6672449169 + 30 +0.0 + 11 +528775.4044934505 + 21 +185164.1276033924 + 31 +0.0 + 0 +LINE + 5 +199A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528456.0358821345 + 20 +185511.7428004195 + 30 +0.0 + 11 +528483.7236407914 + 21 +185425.9787110862 + 31 +0.0 + 0 +LINE + 5 +199B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528288.9293146456 + 20 +185105.7257935582 + 30 +0.0 + 11 +528745.1093170271 + 21 +185225.2534264041 + 31 +0.0 + 0 +LINE + 5 +199C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528344.0981698862 + 20 +184874.8967817407 + 30 +0.0 + 11 +528768.9167591915 + 21 +184929.1033520555 + 31 +0.0 + 0 +LINE + 5 +199D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527949.8775264869 + 20 +184854.9666844584 + 30 +0.0 + 11 +528511.0568598971 + 21 +184894.9081944299 + 31 +0.0 + 0 +LINE + 5 +199E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528448.1825441407 + 20 +184932.0370246522 + 30 +0.0 + 11 +528528.469305634 + 21 +184409.6310701323 + 31 +0.0 + 0 +LINE + 5 +199F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528188.8818175094 + 20 +184667.5442081165 + 30 +0.0 + 11 +528372.8703909186 + 21 +184579.3690800832 + 31 +0.0 + 0 +LINE + 5 +19A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528351.5933171851 + 20 +184556.6836868273 + 30 +0.0 + 11 +528431.2453676903 + 21 +184892.3722785223 + 31 +0.0 + 0 +LINE + 5 +19A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528463.6042442558 + 20 +184748.6276446831 + 30 +0.0 + 11 +528678.2731909844 + 21 +184747.8248774162 + 31 +0.0 + 0 +LINE + 5 +19A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528582.2880243458 + 20 +184606.2960929359 + 30 +0.0 + 11 +528617.9667813305 + 21 +184768.5430947721 + 31 +0.0 + 0 +LINE + 5 +19A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527991.9087113443 + 20 +184683.3516059304 + 30 +0.0 + 11 +528259.0723139821 + 21 +184647.6763211142 + 31 +0.0 + 0 +LINE + 5 +19A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528400.0007362211 + 20 +185140.0294188351 + 30 +0.0 + 11 +528417.6487255491 + 21 +185096.4558212028 + 31 +0.0 + 0 +LINE + 5 +19A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528355.073404435 + 20 +185083.9394404415 + 30 +0.0 + 11 +528418.8274010583 + 21 +185097.9474939306 + 31 +0.0 + 0 +LINE + 5 +19A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528321.9741029895 + 20 +185120.8176425483 + 30 +0.0 + 11 +528332.7078081425 + 21 +185017.0499664265 + 31 +0.0 + 0 +LINE + 5 +19A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528083.3578412053 + 20 +184795.0081634422 + 30 +0.0 + 11 +528195.8260750748 + 21 +184802.455774721 + 31 +0.0 + 0 +LINE + 5 +19A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528388.1630202148 + 20 +185334.8933586839 + 30 +0.0 + 11 +528705.0344509524 + 21 +185469.7224833694 + 31 +0.0 + 0 +LINE + 5 +19A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528619.6035762321 + 20 +184654.4888869583 + 30 +0.0 + 11 +528787.5051260328 + 21 +184344.9983490001 + 31 +0.0 + 0 +LINE + 5 +19AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527991.0162556054 + 20 +184522.2358538144 + 30 +0.0 + 11 +528768.8489952007 + 21 +184666.6966134304 + 31 +0.0 + 0 +LINE + 5 +19AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528258.9278605673 + 20 +184319.7995120679 + 30 +0.0 + 11 +528493.9558347146 + 21 +184289.0340850979 + 31 +0.0 + 0 +LINE + 5 +19AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528305.4820494023 + 20 +184393.5198752249 + 30 +0.0 + 11 +528319.2731084667 + 21 +184309.2516934997 + 31 +0.0 + 0 +LINE + 5 +19AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528120.907951347 + 20 +184166.6183070277 + 30 +0.0 + 11 +528186.1953061795 + 21 +184069.0114987191 + 31 +0.0 + 0 +LINE + 5 +19AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528182.7230597031 + 20 +184172.4408507259 + 30 +0.0 + 11 +528152.6983259142 + 21 +184066.7804691202 + 31 +0.0 + 0 +LINE + 5 +19AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528263.2283659217 + 20 +184381.7642178277 + 30 +0.0 + 11 +528292.7986475518 + 21 +184135.3588211145 + 31 +0.0 + 0 +LINE + 5 +19B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528159.2130572247 + 20 +184407.9771273453 + 30 +0.0 + 11 +528280.5521486496 + 21 +184412.9056584408 + 31 +0.0 + 0 +LINE + 5 +19B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528256.3867003138 + 20 +184512.1025921885 + 30 +0.0 + 11 +528149.0628884625 + 21 +184456.7010545208 + 31 +0.0 + 0 +LINE + 5 +19B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528153.6082290024 + 20 +184461.6724221288 + 30 +0.0 + 11 +528160.5591043877 + 21 +184406.2711024269 + 31 +0.0 + 0 +LINE + 5 +19B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528153.9955953136 + 20 +184799.6980665769 + 30 +0.0 + 11 +528153.9984446465 + 21 +184799.6859621131 + 31 +0.0 + 0 +LINE + 5 +19B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528187.5320485945 + 20 +184657.2293415045 + 30 +0.0 + 11 +528282.9053305279 + 21 +184252.0669419752 + 31 +0.0 + 0 +LINE + 5 +19B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528309.5339253747 + 20 +184320.0569967773 + 30 +0.0 + 11 +527971.965703502 + 21 +184222.9106129128 + 31 +0.0 + 0 +LINE + 5 +19B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527975.1720377207 + 20 +184322.9177983651 + 30 +0.0 + 11 +528267.6760323384 + 21 +184330.4529970771 + 31 +0.0 + 0 +LINE + 5 +19B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528237.986400541 + 20 +184455.4986644045 + 30 +0.0 + 11 +528203.4797198928 + 21 +184447.0557549162 + 31 +0.0 + 0 +LINE + 5 +19B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528130.9300084558 + 20 +184275.5882396961 + 30 +0.0 + 11 +528144.9852191297 + 21 +184183.3153224697 + 31 +0.0 + 0 +LINE + 5 +19B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528135.6356705808 + 20 +184217.1992720769 + 30 +0.0 + 11 +528191.6112669698 + 21 +184155.3986664904 + 31 +0.0 + 0 +LINE + 5 +19BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528147.7339253272 + 20 +184222.2887950057 + 30 +0.0 + 11 +528123.7204699332 + 21 +184145.8198367432 + 31 +0.0 + 0 +LINE + 5 +19BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527957.8719725857 + 20 +184124.6942464935 + 30 +0.0 + 11 +528134.1468481414 + 21 +184152.9373200259 + 31 +0.0 + 0 +LINE + 5 +19BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528355.4066024149 + 20 +184597.3661614674 + 30 +0.0 + 11 +528399.9991306533 + 21 +184302.1200983803 + 31 +0.0 + 0 +LINE + 5 +19BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527314.8022005422 + 20 +184741.5980162658 + 30 +0.0 + 11 +526970.7047902906 + 21 +185140.6353940886 + 31 +0.0 + 0 +LINE + 5 +19BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527178.8927506483 + 20 +184890.7223407424 + 30 +0.0 + 11 +527892.8909575186 + 21 +185231.2767068576 + 31 +0.0 + 0 +LINE + 5 +19BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527304.5579262283 + 20 +184947.3951879357 + 30 +0.0 + 11 +527220.1504267684 + 21 +185068.77504104 + 31 +0.0 + 0 +LINE + 5 +19C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527139.9889769999 + 20 +184943.0276207057 + 30 +0.0 + 11 +527586.6776520906 + 21 +185155.0508136324 + 31 +0.0 + 0 +LINE + 5 +19C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527230.4483922155 + 20 +185037.7956582788 + 30 +0.0 + 11 +527226.4541900343 + 21 +185119.6806056352 + 31 +0.0 + 0 +LINE + 5 +19C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527150.8042870103 + 20 +185041.2787775443 + 30 +0.0 + 11 +527238.4827063035 + 21 +185046.7489942205 + 31 +0.0 + 0 +LINE + 5 +19C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527168.2411901958 + 20 +185033.6844166035 + 30 +0.0 + 11 +527040.6311596829 + 21 +185186.2292719635 + 31 +0.0 + 0 +LINE + 5 +19C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527060.7877157567 + 20 +184974.6539566652 + 30 +0.0 + 11 +527345.9668821299 + 21 +185300.4331217227 + 31 +0.0 + 0 +LINE + 5 +19C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527078.8871428805 + 20 +185227.2251475794 + 30 +0.0 + 11 +527228.8299069052 + 21 +185116.0630754644 + 31 +0.0 + 0 +LINE + 5 +19C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527039.9234058711 + 20 +185180.7984200714 + 30 +0.0 + 11 +527079.7319945638 + 21 +185227.2946236537 + 31 +0.0 + 0 +LINE + 5 +19C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526838.3892838256 + 20 +185399.5131906798 + 30 +0.0 + 11 +527067.5959861845 + 21 +185210.2772169702 + 31 +0.0 + 0 +LINE + 5 +19C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526888.7462167753 + 20 +185353.1899045615 + 30 +0.0 + 11 +526966.5577681158 + 21 +185435.3066738271 + 31 +0.0 + 0 +LINE + 5 +19C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526903.3945210007 + 20 +185486.7577117054 + 30 +0.0 + 11 +527563.396785898 + 21 +184919.709440807 + 31 +0.0 + 0 +LINE + 5 +19CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527350.2091506667 + 20 +185194.4166248022 + 30 +0.0 + 11 +527699.8837421815 + 21 +185460.1447709393 + 31 +0.0 + 0 +LINE + 5 +19CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527400.2250552947 + 20 +185146.1668961864 + 30 +0.0 + 11 +527265.6942366933 + 21 +185285.8485949097 + 31 +0.0 + 0 +LINE + 5 +19CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527451.7581804101 + 20 +185197.3209304638 + 30 +0.0 + 11 +527406.7663055494 + 21 +185243.270651884 + 31 +0.0 + 0 +LINE + 5 +19CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527430.8746786076 + 20 +185147.1099318603 + 30 +0.0 + 11 +527450.3194740931 + 21 +185213.1338324689 + 31 +0.0 + 0 +LINE + 5 +19CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527437.5762896092 + 20 +185197.1439914512 + 30 +0.0 + 11 +527773.0926914633 + 21 +185420.8085658439 + 31 +0.0 + 0 +LINE + 5 +19CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527618.0195788189 + 20 +185095.6552994826 + 30 +0.0 + 11 +527415.1389359325 + 21 +185448.8565721106 + 31 +0.0 + 0 +LINE + 5 +19D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527405.5372855231 + 20 +185439.6313184767 + 30 +0.0 + 11 +527605.2426940034 + 21 +185570.6027715367 + 31 +0.0 + 0 +LINE + 5 +19D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527236.6611025661 + 20 +185527.8732336498 + 30 +0.0 + 11 +527423.6234348207 + 21 +185438.6994246076 + 31 +0.0 + 0 +LINE + 5 +19D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527240.0543231658 + 20 +185440.7499273761 + 30 +0.0 + 11 +527294.18013015 + 21 +185506.7932221131 + 31 +0.0 + 0 +LINE + 5 +19D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527787.6999047709 + 20 +185174.8358807547 + 30 +0.0 + 11 +527738.7591409829 + 21 +185250.5121163805 + 31 +0.0 + 0 +LINE + 5 +19D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527867.8676223761 + 20 +185180.9755230782 + 30 +0.0 + 11 +527602.2287515429 + 21 +185571.3396349185 + 31 +0.0 + 0 +LINE + 5 +19D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527314.2179450792 + 20 +185269.1165263216 + 30 +0.0 + 11 +527656.8589517441 + 21 +185518.9812235104 + 31 +0.0 + 0 +LINE + 5 +19D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527386.1443485876 + 20 +185733.9220975941 + 30 +0.0 + 11 +527608.5066100865 + 21 +185554.6163101546 + 31 +0.0 + 0 +LINE + 5 +19D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527049.9782308985 + 20 +185812.0857878571 + 30 +0.0 + 11 +527240.4791242125 + 21 +185665.0943789074 + 31 +0.0 + 0 +LINE + 5 +19D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526905.5723615818 + 20 +185164.9770384304 + 30 +0.0 + 11 +527291.3265981003 + 21 +185574.5026633598 + 31 +0.0 + 0 +LINE + 5 +19D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527494.4579605611 + 20 +185580.3033783502 + 30 +0.0 + 11 +527533.4565041639 + 21 +185629.032965853 + 31 +0.0 + 0 +LINE + 5 +19DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527493.2517026551 + 20 +185564.8156210044 + 30 +0.0 + 11 +527497.0169997674 + 21 +185588.5846969284 + 31 +0.0 + 0 +LINE + 5 +19DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527536.6711348336 + 20 +185517.6645574225 + 30 +0.0 + 11 +527489.5509079133 + 21 +185571.9005840673 + 31 +0.0 + 0 +LINE + 5 +19DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526825.7687294675 + 20 +185630.3755656826 + 30 +0.0 + 11 +526891.3167667593 + 21 +185848.3127625726 + 31 +0.0 + 0 +LINE + 5 +19DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526911.4770323184 + 20 +185468.6468766246 + 30 +0.0 + 11 +526810.6942338679 + 21 +185658.8206326186 + 31 +0.0 + 0 +LINE + 5 +19DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527411.0206055598 + 20 +185333.4814571598 + 30 +0.0 + 11 +527388.4196091816 + 21 +185374.7040832365 + 31 +0.0 + 0 +LINE + 5 +19DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527339.1587846829 + 20 +185334.1368332729 + 30 +0.0 + 11 +527390.3205215139 + 21 +185374.6741535153 + 31 +0.0 + 0 +LINE + 5 +19E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527346.8032714759 + 20 +185285.1763658685 + 30 +0.0 + 11 +527273.1947542249 + 21 +185359.1001727385 + 31 +0.0 + 0 +LINE + 5 +19E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527181.2197812676 + 20 +185239.2945574107 + 30 +0.0 + 11 +527367.6316948791 + 21 +185472.5526329555 + 31 +0.0 + 0 +LINE + 5 +19E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527466.121962935 + 20 +185475.6227822589 + 30 +0.0 + 11 +527424.9054135911 + 21 +185530.7658671615 + 31 +0.0 + 0 +LINE + 5 +19E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527399.9974681621 + 20 +185510.9279697606 + 30 +0.0 + 11 +527448.0322060059 + 21 +185547.0560186549 + 31 +0.0 + 0 +LINE + 5 +19E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527408.3217922771 + 20 +185508.7439396979 + 30 +0.0 + 11 +527364.8126878394 + 21 +185565.2721074394 + 31 +0.0 + 0 +LINE + 5 +19E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527364.0542931707 + 20 +185561.6328528111 + 30 +0.0 + 11 +527408.0574935037 + 21 +185596.4941229428 + 31 +0.0 + 0 +LINE + 5 +19E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527448.4815771714 + 20 +185538.0317231022 + 30 +0.0 + 11 +527401.8970982832 + 21 +185599.9669644852 + 31 +0.0 + 0 +LINE + 5 +19E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528016.5909572429 + 20 +185271.6800929167 + 30 +0.0 + 11 +528012.5967550619 + 21 +185353.5650402731 + 31 +0.0 + 0 +LINE + 5 +19E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527936.946852038 + 20 +185275.1632121824 + 30 +0.0 + 11 +528024.6252713311 + 21 +185280.6334288583 + 31 +0.0 + 0 +LINE + 5 +19E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527953.3585635359 + 20 +185269.0754004951 + 30 +0.0 + 11 +527825.7485330229 + 21 +185421.620255855 + 31 +0.0 + 0 +LINE + 5 +19EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527790.870967409 + 20 +185144.4981020443 + 30 +0.0 + 11 +528132.1094471575 + 21 +185534.3175563607 + 31 +0.0 + 0 +LINE + 5 +19EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527865.0297079079 + 20 +185461.1095822174 + 30 +0.0 + 11 +528014.9724719328 + 21 +185349.9475101025 + 31 +0.0 + 0 +LINE + 5 +19EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527826.0659708985 + 20 +185414.6828547094 + 30 +0.0 + 11 +527865.8745595912 + 21 +185461.1790582917 + 31 +0.0 + 0 +LINE + 5 +19ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527624.531848853 + 20 +185633.3976253178 + 30 +0.0 + 11 +527853.7385512123 + 21 +185444.161651608 + 31 +0.0 + 0 +LINE + 5 +19EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527767.7467574182 + 20 +185650.035349184 + 30 +0.0 + 11 +528263.528864607 + 21 +185229.3122790655 + 31 +0.0 + 0 +LINE + 5 +19EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528136.3517156943 + 20 +185428.30105944 + 30 +0.0 + 11 +528347.6752841493 + 21 +185588.892138813 + 31 +0.0 + 0 +LINE + 5 +19F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528186.367620322 + 20 +185380.0513308243 + 30 +0.0 + 11 +528051.8368017208 + 21 +185519.7330295476 + 31 +0.0 + 0 +LINE + 5 +19F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528237.9007454377 + 20 +185431.2053651018 + 30 +0.0 + 11 +528192.908870577 + 21 +185477.1550865222 + 31 +0.0 + 0 +LINE + 5 +19F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528217.0172436352 + 20 +185380.9943664984 + 30 +0.0 + 11 +528236.4620391206 + 21 +185447.0182671067 + 31 +0.0 + 0 +LINE + 5 +19F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528223.7188546365 + 20 +185431.0284260889 + 30 +0.0 + 11 +528559.2352564908 + 21 +185654.693000482 + 31 +0.0 + 0 +LINE + 5 +19F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528349.2591038744 + 20 +185424.8977161368 + 30 +0.0 + 11 +528201.2815009599 + 21 +185682.7410067485 + 31 +0.0 + 0 +LINE + 5 +19F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528191.6798505507 + 20 +185673.5157531144 + 30 +0.0 + 11 +528391.3852590313 + 21 +185804.4872061746 + 31 +0.0 + 0 +LINE + 5 +19F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528022.8036675936 + 20 +185761.7576682877 + 30 +0.0 + 11 +528209.7659998483 + 21 +185672.5838592456 + 31 +0.0 + 0 +LINE + 5 +19F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527902.7342881627 + 20 +185504.0363614708 + 30 +0.0 + 11 +528080.3226951775 + 21 +185740.677656751 + 31 +0.0 + 0 +LINE + 5 +19F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528100.3605101067 + 20 +185503.0009609594 + 30 +0.0 + 11 +528471.2251337772 + 21 +185777.1470163376 + 31 +0.0 + 0 +LINE + 5 +19F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527989.6882072637 + 20 +185927.1348780362 + 30 +0.0 + 11 +528192.9659531929 + 21 +185625.1118063627 + 31 +0.0 + 0 +LINE + 5 +19FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527961.9309788312 + 20 +185823.9192870058 + 30 +0.0 + 11 +528067.3128045042 + 21 +185875.7285385648 + 31 +0.0 + 0 +LINE + 5 +19FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528012.5268591681 + 20 +185787.9322542143 + 30 +0.0 + 11 +528039.4327511025 + 21 +185894.4295492943 + 31 +0.0 + 0 +LINE + 5 +19FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527691.7149266093 + 20 +185398.8614730684 + 30 +0.0 + 11 +527914.0029648269 + 21 +185627.3190115407 + 31 +0.0 + 0 +LINE + 5 +19FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527869.2643178839 + 20 +185537.3894388642 + 30 +0.0 + 11 +527810.6201234687 + 21 +185860.3170556521 + 31 +0.0 + 0 +LINE + 5 +19FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527809.1084261395 + 20 +185747.0527862236 + 30 +0.0 + 11 +527972.918083988 + 21 +185778.6332784218 + 31 +0.0 + 0 +LINE + 5 +19FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527949.3576618674 + 20 +185772.7602072676 + 30 +0.0 + 11 +528028.7529029781 + 21 +185798.2352525258 + 31 +0.0 + 0 +LINE + 5 +1A00 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527957.2826477116 + 20 +185762.2976258021 + 30 +0.0 + 11 +527974.7780660359 + 21 +185840.5156413443 + 31 +0.0 + 0 +LINE + 5 +1A01 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527880.8185873425 + 20 +185906.512433928 + 30 +0.0 + 11 +527980.2405118185 + 21 +185829.1345334503 + 31 +0.0 + 0 +LINE + 5 +1A02 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527585.3290340103 + 20 +185539.930241882 + 30 +0.0 + 11 +527663.5568333297 + 21 +185667.0336448759 + 31 +0.0 + 0 +LINE + 5 +1A03 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528197.1631705874 + 20 +185567.3658917978 + 30 +0.0 + 11 +528174.562174209 + 21 +185608.5885178743 + 31 +0.0 + 0 +LINE + 5 +1A04 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528125.3013497101 + 20 +185568.0212679109 + 30 +0.0 + 11 +528176.4630865414 + 21 +185608.5585881534 + 31 +0.0 + 0 +LINE + 5 +1A05 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528132.9458365035 + 20 +185519.0608005063 + 30 +0.0 + 11 +528059.3373192524 + 21 +185592.9846073763 + 31 +0.0 + 0 +LINE + 5 +1A06 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527967.3623462952 + 20 +185473.1789920484 + 30 +0.0 + 11 +528153.7742599065 + 21 +185706.4370675933 + 31 +0.0 + 0 +LINE + 5 +1A07 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528252.2645279622 + 20 +185709.5072168967 + 30 +0.0 + 11 +528211.0479786187 + 21 +185764.6503017994 + 31 +0.0 + 0 +LINE + 5 +1A08 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528186.1400331898 + 20 +185744.8124043986 + 30 +0.0 + 11 +528234.1747710333 + 21 +185780.9404532926 + 31 +0.0 + 0 +LINE + 5 +1A09 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527729.6552787081 + 20 +185540.1857397122 + 30 +0.0 + 11 +527806.5341364845 + 21 +185622.6127484563 + 31 +0.0 + 0 +LINE + 5 +1A0A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528007.2965028686 + 20 +185884.1544039194 + 30 +0.0 + 11 +527851.8430313845 + 21 +186437.6677441766 + 31 +0.0 + 0 +LINE + 5 +1A0B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527941.7493953729 + 20 +185904.9528054292 + 30 +0.0 + 11 +527878.2684433706 + 21 +186123.2179503772 + 31 +0.0 + 0 +LINE + 5 +1A0C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527804.6629765957 + 20 +185777.9836909368 + 30 +0.0 + 11 +527696.3651398602 + 21 +185908.7677732899 + 31 +0.0 + 0 +LINE + 5 +1A0D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527684.112269079 + 20 +185706.0815362376 + 30 +0.0 + 11 +528665.054318946 + 21 +186537.7386197715 + 31 +0.0 + 0 +LINE + 5 +1A0E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527801.7017107939 + 20 +185896.0515912543 + 30 +0.0 + 11 +527595.1283308359 + 21 +186283.6224961132 + 31 +0.0 + 0 +LINE + 5 +1A0F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527857.3091071436 + 20 +185937.7342554978 + 30 +0.0 + 11 +527697.9637193599 + 21 +185827.1966351875 + 31 +0.0 + 0 +LINE + 5 +1A10 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527815.0264069962 + 20 +185996.7645144781 + 30 +0.0 + 11 +527762.4906663322 + 21 +185959.6748709776 + 31 +0.0 + 0 +LINE + 5 +1A11 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527861.265174234 + 20 +185968.1421205775 + 30 +0.0 + 11 +527799.1864118238 + 21 +185997.8655588148 + 31 +0.0 + 0 +LINE + 5 +1A12 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527812.9398004629 + 20 +185982.7358507043 + 30 +0.0 + 11 +527645.6343383252 + 21 +186349.6227271258 + 31 +0.0 + 0 +LINE + 5 +1A13 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527941.9014901828 + 20 +186144.688367828 + 30 +0.0 + 11 +527560.8699665694 + 21 +186000.7207594688 + 31 +0.0 + 0 +LINE + 5 +1A14 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527568.4462253584 + 20 +185989.7709970077 + 30 +0.0 + 11 +527470.9931260145 + 21 +186207.8046300123 + 31 +0.0 + 0 +LINE + 5 +1A15 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527454.4061946053 + 20 +185837.1254201002 + 30 +0.0 + 11 +527572.250006963 + 21 +186007.4771673475 + 31 +0.0 + 0 +LINE + 5 +1A16 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527540.9559103656 + 20 +185826.5835443709 + 30 +0.0 + 11 +527484.3878387183 + 21 +185890.5473859652 + 31 +0.0 + 0 +LINE + 5 +1A19 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527722.2187565154 + 20 +185872.4316389714 + 30 +0.0 + 11 +527530.1843775018 + 21 +186250.5295411427 + 31 +0.0 + 0 +LINE + 5 +1A1A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527199.4167249749 + 20 +185905.5738254118 + 30 +0.0 + 11 +527537.0677506778 + 21 +186251.6575700604 + 31 +0.0 + 0 +LINE + 5 +1A1B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527037.937839605 + 20 +185785.4550518199 + 30 +0.0 + 11 +527402.5950979067 + 21 +186107.3044569597 + 31 +0.0 + 0 +LINE + 5 +1A1C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527248.4636741881 + 20 +185827.0429996101 + 30 +0.0 + 11 +527214.1202363191 + 21 +185939.3375052844 + 31 +0.0 + 0 +LINE + 5 +1A1D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527292.057736972 + 20 +185871.2534884808 + 30 +0.0 + 11 +527191.2130479115 + 21 +185914.7959914915 + 31 +0.0 + 0 +LINE + 5 +1A1E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527434.1867885707 + 20 +185997.3590456579 + 30 +0.0 + 11 +527271.6617460263 + 21 +185877.3888747525 + 31 +0.0 + 0 +LINE + 5 +1A1F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527493.7639413161 + 20 +185788.7156441948 + 30 +0.0 + 11 +527329.8751713632 + 21 +186041.0408452601 + 31 +0.0 + 0 +LINE + 5 +1A20 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527414.5543417604 + 20 +185722.5364578387 + 30 +0.0 + 11 +527405.9648867027 + 21 +185570.7866745304 + 31 +0.0 + 0 +LINE + 5 +1A21 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527777.9499912509 + 20 +185591.9477744219 + 30 +0.0 + 11 +527777.9424147139 + 21 +185591.9576350925 + 31 +0.0 + 0 +LINE + 5 +1A22 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527564.4516644597 + 20 +185687.9319159665 + 30 +0.0 + 11 +527417.0896642248 + 21 +185898.5265330985 + 31 +0.0 + 0 +LINE + 5 +1A23 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527418.5002731879 + 20 +185911.5280694478 + 30 +0.0 + 11 +527399.359201479 + 21 +185896.5823695351 + 31 +0.0 + 0 +LINE + 5 +1A24 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527443.7521620491 + 20 +186099.9839973919 + 30 +0.0 + 11 +527412.5879643001 + 21 +186132.8918984475 + 31 +0.0 + 0 +LINE + 5 +1A25 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527458.8494366919 + 20 +186096.3236717095 + 30 +0.0 + 11 +527435.98482774 + 21 +186103.8307410518 + 31 +0.0 + 0 +LINE + 5 +1A26 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527512.3204261397 + 20 +186131.6694377228 + 30 +0.0 + 11 +527451.2650306086 + 21 +186093.7999110848 + 31 +0.0 + 0 +LINE + 5 +1A27 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527486.6016876462 + 20 +185876.1701421699 + 30 +0.0 + 11 +527197.9069829295 + 21 +185676.0574444601 + 31 +0.0 + 0 +LINE + 5 +1A28 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527341.4893924392 + 20 +185686.2844910231 + 30 +0.0 + 11 +527468.1911678976 + 21 +185837.1674141337 + 31 +0.0 + 0 +LINE + 5 +1A29 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527870.7315726819 + 20 +185757.0874915315 + 30 +0.0 + 11 +527174.3057571509 + 21 +185682.3979604978 + 31 +0.0 + 0 +LINE + 5 +1A2A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527339.2256498769 + 20 +185765.9107526084 + 30 +0.0 + 11 +527276.6228466298 + 21 +185835.140292735 + 31 +0.0 + 0 +LINE + 5 +1A2B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527296.9634399069 + 20 +185806.4733018887 + 30 +0.0 + 11 +527284.4737717901 + 21 +185888.914738268 + 31 +0.0 + 0 +LINE + 5 +1A2C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527308.5557930746 + 20 +185812.628653998 + 30 +0.0 + 11 +527234.1280989511 + 21 +185842.3719888006 + 31 +0.0 + 0 +LINE + 5 +1A2D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527112.9020909969 + 20 +185727.2361141512 + 30 +0.0 + 11 +527246.2345787155 + 21 +185845.9498482914 + 31 +0.0 + 0 +LINE + 5 +1A2E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527674.1123383103 + 20 +185978.258723999 + 30 +0.0 + 11 +527629.8134086306 + 21 +185962.5197670078 + 31 +0.0 + 0 +LINE + 5 +1A2F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527662.0070842561 + 20 +185907.4207847158 + 30 +0.0 + 11 +527630.1460531406 + 21 +185964.3915872753 + 31 +0.0 + 0 +LINE + 5 +1A30 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527730.4528268442 + 20 +185736.3799521287 + 30 +0.0 + 11 +527529.9021070324 + 21 +185957.5996170005 + 31 +0.0 + 0 +LINE + 5 +1A31 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527542.5753662606 + 20 +186055.3193551242 + 30 +0.0 + 11 +527396.6007777854 + 21 +185974.7797865106 + 31 +0.0 + 0 +LINE + 5 +1A32 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527827.6730787736 + 20 +186098.8040912351 + 30 +0.0 + 11 +527731.6664476053 + 21 +186345.3735064728 + 31 +0.0 + 0 +LINE + 5 +1A33 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527110.0277079166 + 20 +185399.1501917908 + 30 +0.0 + 11 +527238.1476272985 + 21 +185293.0534528619 + 31 +0.0 + 0 +LINE + 5 +1A34 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527019.584788666 + 20 +185440.5605438748 + 30 +0.0 + 11 +526958.3782706025 + 21 +185266.4775408631 + 31 +0.0 + 0 +LINE + 5 +1A35 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527667.1841413337 + 20 +185924.4546898795 + 30 +0.0 + 11 +527567.5689432492 + 21 +185862.7537503939 + 31 +0.0 + 0 +LINE + 5 +1A36 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527615.9831795112 + 20 +185099.2005308893 + 30 +0.0 + 11 +527796.2414715133 + 21 +185016.9135917002 + 31 +0.0 + 0 +LINE + 5 +1A37 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530074.9353769958 + 20 +183884.9393605395 + 30 +0.0 + 11 +530627.1098105166 + 21 +183787.5003604821 + 31 +0.0 + 0 +LINE + 5 +1A38 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530092.5401323481 + 20 +183873.9934044805 + 30 +0.0 + 11 +530024.122431041 + 21 +184662.0858697672 + 31 +0.0 + 0 +LINE + 5 +1A39 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530077.6837635742 + 20 +184011.0438925107 + 30 +0.0 + 11 +530225.1006832576 + 21 +183999.8213038695 + 31 +0.0 + 0 +LINE + 5 +1A3A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530193.1767123051 + 20 +183992.992663651 + 30 +0.0 + 11 +530265.7841074339 + 21 +184031.0618694109 + 31 +0.0 + 0 +LINE + 5 +1A3B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530236.5551485069 + 20 +183926.10748677 + 30 +0.0 + 11 +530196.8211880385 + 21 +184004.4569658093 + 31 +0.0 + 0 +LINE + 5 +1A3C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530221.1692751257 + 20 +183937.2875946002 + 30 +0.0 + 11 +530417.3513434172 + 21 +183904.6249421486 + 31 +0.0 + 0 +LINE + 5 +1A3D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530224.7609106149 + 20 +183814.7398711447 + 30 +0.0 + 11 +530360.99994493 + 21 +184225.7120683164 + 31 +0.0 + 0 +LINE + 5 +1A3E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530433.2945147376 + 20 +183958.3836377817 + 30 +0.0 + 11 +530261.4615139464 + 21 +184031.2757402305 + 31 +0.0 + 0 +LINE + 5 +1A3F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530413.0289029687 + 20 +183901.2616734557 + 30 +0.0 + 11 +530432.9260982123 + 21 +183959.1470973785 + 31 +0.0 + 0 +LINE + 5 +1A40 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530703.7238554928 + 20 +183838.4238042374 + 30 +0.0 + 11 +530424.4100015701 + 21 +183940.0591187636 + 31 +0.0 + 0 +LINE + 5 +1A41 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530638.2657253066 + 20 +183858.3461717027 + 30 +0.0 + 11 +530669.6009970998 + 21 +183967.0471471273 + 31 +0.0 + 0 +LINE + 5 +1A42 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530745.9713467414 + 20 +183938.6856453953 + 30 +0.0 + 11 +530048.9949907507 + 21 +184149.7235543463 + 31 +0.0 + 0 +LINE + 5 +1A43 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530267.4660776979 + 20 +184175.6230461426 + 30 +0.0 + 11 +530319.246465793 + 21 +184611.7452297214 + 31 +0.0 + 0 +LINE + 5 +1A44 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530200.5202950364 + 20 +184194.2748345569 + 30 +0.0 + 11 +530389.1232236338 + 21 +184149.1255993895 + 31 +0.0 + 0 +LINE + 5 +1A47 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530180.4056919937 + 20 +184329.153562387 + 30 +0.0 + 11 +530198.7734187687 + 21 +184654.907534193 + 31 +0.0 + 0 +LINE + 5 +1A48 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530046.5684076484 + 20 +184356.4003792694 + 30 +0.0 + 11 +530453.8695489496 + 21 +184360.5806350824 + 31 +0.0 + 0 +LINE + 5 +1A49 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530450.7852589756 + 20 +184347.6274829353 + 30 +0.0 + 11 +530385.9506331715 + 21 +184610.7077117975 + 31 +0.0 + 0 +LINE + 5 +1A4A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530612.460149862 + 20 +184246.7957894036 + 30 +0.0 + 11 +530440.8131043484 + 21 +184362.7448026278 + 31 +0.0 + 0 +LINE + 5 +1A4B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530535.6421089239 + 20 +184205.5529351321 + 30 +0.0 + 11 +530565.1301390405 + 21 +184285.688918568 + 31 +0.0 + 0 +LINE + 5 +1A4C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530024.5229396512 + 20 +184465.432338599 + 30 +0.0 + 11 +530114.5645462456 + 21 +184461.6113334234 + 31 +0.0 + 0 +LINE + 5 +1A4D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529993.4499721084 + 20 +184615.0159573572 + 30 +0.0 + 11 +530483.024820749 + 21 +184583.9403332796 + 31 +0.0 + 0 +LINE + 5 +1A55 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530493.2454602082 + 20 +184168.3430140179 + 30 +0.0 + 11 +530614.159380122 + 21 +184157.0607492791 + 31 +0.0 + 0 +LINE + 5 +1A56 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530584.827322039 + 20 +184059.2669308301 + 30 +0.0 + 11 +530480.5551723789 + 21 +184120.2181389518 + 31 +0.0 + 0 +LINE + 5 +1A57 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530484.8336682371 + 20 +184115.0153426162 + 30 +0.0 + 11 +530494.679085399 + 21 +184169.9761345888 + 31 +0.0 + 0 +LINE + 5 +1A58 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530467.5014361801 + 20 +183777.4341226273 + 30 +0.0 + 11 +530624.9403788047 + 21 +184317.5549867041 + 31 +0.0 + 0 +LINE + 5 +1A61 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530563.872390367 + 20 +184118.3744737268 + 30 +0.0 + 11 +530598.0635031751 + 21 +184108.7328174946 + 31 +0.0 + 0 +LINE + 5 +1A66 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530768.7252722775 + 20 +183716.8702567725 + 30 +0.0 + 11 +530609.0654214319 + 21 +183792.4024777319 + 31 +0.0 + 0 +LINE + 5 +1A6A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530347.425039943 + 20 +184218.6985028227 + 30 +0.0 + 11 +530448.4615770839 + 21 +184192.7261868566 + 31 +0.0 + 0 +LINE + 5 +1A6B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530391.819822532 + 20 +184052.7101422193 + 30 +0.0 + 11 +530498.3789814079 + 21 +184331.6436056164 + 31 +0.0 + 0 +LINE + 5 +1A71 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530570.0848544786 + 20 +183881.7828693857 + 30 +0.0 + 11 +530602.1603788654 + 21 +183989.8371672121 + 31 +0.0 + 0 +LINE + 5 +1A73 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529939.5685612063 + 20 +184163.7506789629 + 30 +0.0 + 11 +529827.1842240089 + 21 +185458.2877310593 + 31 +0.0 + 0 +LINE + 5 +1A74 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529880.7455565422 + 20 +184807.2457538028 + 30 +0.0 + 11 +530028.1624762256 + 21 +184796.0231651615 + 31 +0.0 + 0 +LINE + 5 +1A75 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529960.4101130438 + 20 +184663.1778075725 + 30 +0.0 + 11 +529916.71644329 + 21 +185155.697319893 + 31 +0.0 + 0 +LINE + 5 +1A76 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529996.238505273 + 20 +184789.1945249431 + 30 +0.0 + 11 +530068.8459004022 + 21 +184827.263730703 + 31 +0.0 + 0 +LINE + 5 +1A77 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530039.6169414749 + 20 +184722.3093480621 + 30 +0.0 + 11 +529999.8829810068 + 21 +184800.6588271014 + 31 +0.0 + 0 +LINE + 5 +1A78 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530026.0493983941 + 20 +184733.36952438 + 30 +0.0 + 11 +530222.2314666858 + 21 +184700.7068719285 + 31 +0.0 + 0 +LINE + 5 +1A79 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530001.0414109108 + 20 +184530.1545575434 + 30 +0.0 + 11 +530164.0617378978 + 21 +185021.9139296083 + 31 +0.0 + 0 +LINE + 5 +1A7A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530236.3563077058 + 20 +184754.5854990738 + 30 +0.0 + 11 +530064.5233069145 + 21 +184827.4776015228 + 31 +0.0 + 0 +LINE + 5 +1A7B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530216.0906959366 + 20 +184697.4635347478 + 30 +0.0 + 11 +530235.9878911803 + 21 +184755.3489586706 + 31 +0.0 + 0 +LINE + 5 +1A7C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530407.4403198415 + 20 +184689.2318219746 + 30 +0.0 + 11 +530227.4717945381 + 21 +184736.2609800559 + 31 +0.0 + 0 +LINE + 5 +1A7F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530070.5278706658 + 20 +184971.8249074348 + 30 +0.0 + 11 +530122.3082587611 + 21 +185407.9470910134 + 31 +0.0 + 0 +LINE + 5 +1A80 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530003.5820880041 + 20 +184990.476695849 + 30 +0.0 + 11 +530192.1850166016 + 21 +184945.3274606815 + 31 +0.0 + 0 +LINE + 5 +1A81 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530021.5503732429 + 20 +185060.8296555069 + 30 +0.0 + 11 +530083.9666508887 + 21 +185045.3424353904 + 31 +0.0 + 0 +LINE + 5 +1A82 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529988.8569365287 + 20 +185017.3738823104 + 30 +0.0 + 11 +530035.9100089048 + 21 +185067.6059826347 + 31 +0.0 + 0 +LINE + 5 +1A83 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530028.5874565967 + 20 +185048.5155663411 + 30 +0.0 + 11 +530051.2878197391 + 21 +185451.109395485 + 31 +0.0 + 0 +LINE + 5 +1A84 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529590.0046100221 + 20 +185205.4301442984 + 30 +0.0 + 11 +530281.0617747266 + 21 +185224.1071918924 + 31 +0.0 + 0 +LINE + 5 +1A85 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530253.8470519436 + 20 +185143.829344227 + 30 +0.0 + 11 +530265.4988130901 + 21 +185382.3665701588 + 31 +0.0 + 0 +LINE + 5 +1A88 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529831.8611015576 + 20 +185339.0029824713 + 30 +0.0 + 11 +529921.902708152 + 21 +185335.1819772955 + 31 +0.0 + 0 +LINE + 5 +1A89 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529796.5117650765 + 20 +185411.2178186492 + 30 +0.0 + 11 +530267.6619057944 + 21 +185380.1421945718 + 31 +0.0 + 0 +LINE + 5 +1A8A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530153.1630439457 + 20 +184978.6710964276 + 30 +0.0 + 11 +530194.8353082583 + 21 +185400.6884523936 + 31 +0.0 + 0 +LINE + 5 +1A9A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530159.5690694193 + 20 +185094.7424634202 + 30 +0.0 + 11 +530206.5595262442 + 21 +185096.1591162804 + 31 +0.0 + 0 +LINE + 5 +1A9B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530196.5647924344 + 20 +185033.1318531638 + 30 +0.0 + 11 +530205.5700480689 + 21 +185097.7824758906 + 31 +0.0 + 0 +LINE + 5 +1A9C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530150.4868329109 + 20 +185014.9003641146 + 30 +0.0 + 11 +530251.5233700519 + 21 +184988.9280481487 + 31 +0.0 + 0 +LINE + 5 +1A9D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +530194.8816155 + 20 +184848.9120035113 + 30 +0.0 + 11 +530301.4407743759 + 21 +185127.8454669085 + 31 +0.0 + 0 +LINE + 5 +1A9F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529970.7774168067 + 20 +185189.3995273232 + 30 +0.0 + 11 +529972.6676480018 + 21 +185415.9178013272 + 31 +0.0 + 0 +LINE + 5 +1ACD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529875.2497154139 + 20 +184199.4087741126 + 30 +0.0 + 11 +529863.0202526016 + 21 +184337.2605291638 + 31 +0.0 + 0 +LINE + 5 +1ACE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529743.980573447 + 20 +184129.1822409128 + 30 +0.0 + 11 +529616.2323189746 + 21 +184549.3776134238 + 31 +0.0 + 0 +LINE + 5 +1ACF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529771.7650712592 + 20 +184212.0585172357 + 30 +0.0 + 11 +529678.5451351549 + 21 +184604.3685238173 + 31 +0.0 + 0 +LINE + 5 +1AD0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529929.6036353747 + 20 +184346.0238967045 + 30 +0.0 + 11 +529583.3850811765 + 21 +184287.767590759 + 31 +0.0 + 0 +LINE + 5 +1AD1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529914.2805504444 + 20 +184532.6416357702 + 30 +0.0 + 11 +529826.3178454189 + 21 +184513.0290499321 + 31 +0.0 + 0 +LINE + 5 +1AD2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529936.3648480746 + 20 +184609.9516736181 + 30 +0.0 + 11 +529478.0436297417 + 21 +184496.4183730585 + 31 +0.0 + 0 +LINE + 5 +1AD3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529661.430738583 + 20 +184121.3741085768 + 30 +0.0 + 11 +529546.1158085704 + 21 +184529.4644089586 + 31 +0.0 + 0 +LINE + 5 +1AD4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529232.9972191319 + 20 +184308.7579889585 + 30 +0.0 + 11 +529553.0874010506 + 21 +184529.24041386 + 31 +0.0 + 0 +LINE + 5 +1AD5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529634.6911295682 + 20 +184234.5049739838 + 30 +0.0 + 11 +529588.1851601869 + 21 +184227.6271291281 + 31 +0.0 + 0 +LINE + 5 +1AD6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529609.1193511298 + 20 +184167.343713088 + 30 +0.0 + 11 +529588.8734028448 + 21 +184229.3993270648 + 31 +0.0 + 0 +LINE + 5 +1AD7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529943.8312827582 + 20 +184525.0791841147 + 30 +0.0 + 11 +529696.7858197628 + 21 +184980.4597351244 + 31 +0.0 + 0 +LINE + 5 +1AD8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529427.594100383 + 20 +184538.885622905 + 30 +0.0 + 11 +529760.9646796797 + 21 +184732.402681762 + 31 +0.0 + 0 +LINE + 5 +1AD9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529368.3559519504 + 20 +184630.1442064984 + 30 +0.0 + 11 +530028.4476193018 + 21 +184997.7725392588 + 31 +0.0 + 0 +LINE + 5 +1ADA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529797.6767641356 + 20 +184947.6190316421 + 30 +0.0 + 11 +529669.928509663 + 21 +185367.8144041533 + 31 +0.0 + 0 +LINE + 5 +1ADB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529860.2934819285 + 20 +184977.7649049925 + 30 +0.0 + 11 +529682.5843242276 + 21 +184900.118440933 + 31 +0.0 + 0 +LINE + 5 +1ADC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529830.2206250684 + 20 +185043.8559141184 + 30 +0.0 + 11 +529771.5055698461 + 21 +185017.6225766955 + 31 +0.0 + 0 +LINE + 5 +1ADD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529870.0535815491 + 20 +185006.8342906227 + 30 +0.0 + 11 +529814.8923235209 + 21 +185047.9984878788 + 31 +0.0 + 0 +LINE + 5 +1ADE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529787.3488705874 + 20 +185190.8888152999 + 30 +0.0 + 11 +529732.2413258432 + 21 +185422.8053145468 + 31 +0.0 + 0 +LINE + 5 +1ADF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529528.4200429016 + 20 +184929.8707909057 + 30 +0.0 + 11 +529485.2851129321 + 21 +185003.5640577484 + 31 +0.0 + 0 +LINE + 5 +1AE0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529861.3466617636 + 20 +185395.7871211546 + 30 +0.0 + 11 +529657.6942649834 + 21 +185321.2900416619 + 31 +0.0 + 0 +LINE + 5 +1AE1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529715.1269292716 + 20 +184939.8108993062 + 30 +0.0 + 11 +529599.8119992587 + 21 +185347.9011996878 + 31 +0.0 + 0 +LINE + 5 +1AE2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529488.1906467225 + 20 +184870.3446560795 + 30 +0.0 + 11 +529362.7819015576 + 21 +185181.0898554979 + 31 +0.0 + 0 +LINE + 5 +1AE3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529576.7051272891 + 20 +184900.7056631444 + 30 +0.0 + 11 +529459.6657693327 + 21 +184868.3134693976 + 31 +0.0 + 0 +LINE + 5 +1AE4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529594.3735463972 + 20 +184849.6916871425 + 30 +0.0 + 11 +529575.0063913913 + 21 +184902.0608975654 + 31 +0.0 + 0 +LINE + 5 +1AE5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529670.8641300261 + 20 +184520.4339203804 + 30 +0.0 + 11 +529420.7991483043 + 21 +185024.4032382779 + 31 +0.0 + 0 +LINE + 5 +1AE6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529424.696695358 + 20 +185036.8867831289 + 30 +0.0 + 11 +529403.0273226811 + 21 +185025.9235327067 + 31 +0.0 + 0 +LINE + 5 +1AE7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529484.6776843873 + 20 +184989.0300529047 + 30 +0.0 + 11 +529154.8530687077 + 21 +184857.6163123908 + 31 +0.0 + 0 +LINE + 5 +1AE8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529388.1465096351 + 20 +184631.4338432891 + 30 +0.0 + 11 +529218.8678648771 + 21 +184745.3258481783 + 31 +0.0 + 0 +LINE + 5 +1AE9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529210.1002453442 + 20 +184715.4851078794 + 30 +0.0 + 11 +529459.0742043105 + 21 +184954.3223903557 + 31 +0.0 + 0 +LINE + 5 +1AEA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529501.6288089996 + 20 +184469.6622570667 + 30 +0.0 + 11 +529335.4374341035 + 21 +184681.8639145324 + 31 +0.0 + 0 +LINE + 5 +1AEB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529688.3873202567 + 20 +185052.9417647131 + 30 +0.0 + 11 +529641.8813508754 + 21 +185046.0639198577 + 31 +0.0 + 0 +LINE + 5 +1AEC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529662.8155418183 + 20 +184985.7805038173 + 30 +0.0 + 11 +529642.5695935333 + 21 +185047.8361177944 + 31 +0.0 + 0 +LINE + 5 +1AED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529711.3834105942 + 20 +184975.9454812266 + 30 +0.0 + 11 +529616.4970881978 + 21 +184932.5919478516 + 31 +0.0 + 0 +LINE + 5 +1AEE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529551.5128856724 + 20 +184605.0938231147 + 30 +0.0 + 11 +529500.9160291978 + 21 +184705.8138740395 + 31 +0.0 + 0 +LINE + 5 +1AEF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529229.9928105621 + 20 +184823.4360587599 + 30 +0.0 + 11 +529069.7380110376 + 21 +184767.29964573 + 31 +0.0 + 0 +LINE + 5 +1AF0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529363.2040231364 + 20 +184387.2143297671 + 30 +0.0 + 11 +529105.5296935886 + 21 +185097.4787454935 + 31 +0.0 + 0 +LINE + 5 +1AF1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529118.2454725926 + 20 +184861.663413327 + 30 +0.0 + 11 +528610.7086128694 + 21 +184746.5116670509 + 31 +0.0 + 0 +LINE + 5 +1AF2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529098.4694227296 + 20 +184928.2857435104 + 30 +0.0 + 11 +529146.7870302851 + 21 +184740.469538374 + 31 +0.0 + 0 +LINE + 5 +1AF3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529170.724510631 + 20 +184957.6331569076 + 30 +0.0 + 11 +529021.8952428087 + 21 +184894.6640790772 + 31 +0.0 + 0 +LINE + 5 +1AF4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529040.859693092 + 20 +184902.3069445089 + 30 +0.0 + 11 +528722.5634822862 + 21 +184932.0754702145 + 31 +0.0 + 0 +LINE + 5 +1AF5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529131.2573684122 + 20 +184670.4601999175 + 30 +0.0 + 11 +528711.0439408052 + 21 +184659.8094122968 + 31 +0.0 + 0 +LINE + 5 +1AF6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529179.4477933593 + 20 +184474.2710277709 + 30 +0.0 + 11 +529122.1824233242 + 21 +184581.3604433139 + 31 +0.0 + 0 +LINE + 5 +1AF7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529219.9382027254 + 20 +184610.819026985 + 30 +0.0 + 11 +529226.5921333122 + 21 +184490.2227742489 + 31 +0.0 + 0 +LINE + 5 +1AF8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529228.5730222924 + 20 +184496.6609956934 + 30 +0.0 + 11 +529177.2948609519 + 21 +184474.5664021717 + 31 +0.0 + 0 +LINE + 5 +1AF9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529519.7451906417 + 20 +184668.359145759 + 30 +0.0 + 11 +529519.7333124487 + 21 +184668.3554653684 + 31 +0.0 + 0 +LINE + 5 +1AFA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529379.9396602592 + 20 +184625.041193395 + 30 +0.0 + 11 +528356.8679548832 + 21 +184402.5798630084 + 31 +0.0 + 0 +LINE + 5 +1AFB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528952.0907373794 + 20 +184691.4129135921 + 30 +0.0 + 11 +529052.0012758732 + 21 +184341.0790658432 + 31 +0.0 + 0 +LINE + 5 +1AFC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529196.5071686171 + 20 +184329.7187022287 + 30 +0.0 + 11 +529068.1024692344 + 21 +184569.0160955433 + 31 +0.0 + 0 +LINE + 5 +1AFD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529180.47536678 + 20 +184566.2627675879 + 30 +0.0 + 11 +529190.6911988818 + 21 +184532.2387980305 + 31 +0.0 + 0 +LINE + 5 +1AFE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528880.8283251523 + 20 +184862.3142856285 + 30 +0.0 + 11 +528996.2187128513 + 21 +184723.5581030898 + 31 +0.0 + 0 +LINE + 5 +1AFF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529059.0688036402 + 20 +184734.6123641568 + 30 +0.0 + 11 +528994.5789272775 + 21 +184724.5201149165 + 31 +0.0 + 0 +LINE + 5 +1B00 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529243.2342187749 + 20 +184739.3962912836 + 30 +0.0 + 11 +529025.374155144 + 21 +184651.9383440277 + 31 +0.0 + 0 +LINE + 5 +1B01 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529306.9039543703 + 20 +184429.3838377322 + 30 +0.0 + 11 +529424.1561644725 + 21 +184602.6736955386 + 31 +0.0 + 0 +LINE + 5 +1B02 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529044.8931152141 + 20 +184745.3829585117 + 30 +0.0 + 11 +529068.1577717093 + 21 +184630.5398072969 + 31 +0.0 + 0 +LINE + 5 +1B03 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529925.571842865 + 20 +184345.3454889904 + 30 +0.0 + 11 +530065.3395954874 + 21 +184485.8060440349 + 31 +0.0 + 0 +LINE + 5 +1B04 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527134.7421133008 + 20 +185746.6815669867 + 30 +0.0 + 11 +526854.7475136897 + 21 +185647.3070632744 + 31 +0.0 + 0 +LINE + 5 +1B05 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527048.0415984104 + 20 +185467.8954880649 + 30 +0.0 + 11 +527041.7620982851 + 21 +185733.2410348589 + 31 +0.0 + 0 +LINE + 5 +1B06 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526774.4150185317 + 20 +185453.3134554358 + 30 +0.0 + 11 +527096.7080671646 + 21 +185548.6402006319 + 31 +0.0 + 0 +LINE + 5 +1B07 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527183.7589148466 + 20 +185507.4189276198 + 30 +0.0 + 11 +527212.8484589074 + 21 +185686.4143336474 + 31 +0.0 + 0 +LINE + 5 +1B08 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527642.2925246087 + 20 +185589.7842453163 + 30 +0.0 + 11 +527633.9139317363 + 21 +185753.7844069439 + 31 +0.0 + 0 +LINE + 5 +1B09 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527039.5332444966 + 20 +185538.7648673743 + 30 +0.0 + 11 +527282.5187367876 + 21 +185520.3123034324 + 31 +0.0 + 0 +LINE + 5 +1B0A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527013.1566275844 + 20 +185737.6687210239 + 30 +0.0 + 11 +527301.7042551051 + 21 +185767.6062004553 + 31 +0.0 + 0 +LINE + 5 +1B0B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528866.4052278898 + 20 +184794.5969995048 + 30 +0.0 + 11 +528899.1937164198 + 21 +184354.8994272966 + 31 +0.0 + 0 +LINE + 5 +1B0C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528801.7919096823 + 20 +184268.0094211798 + 30 +0.0 + 11 +528476.702491275 + 21 +184122.8305720991 + 31 +0.0 + 0 +LINE + 5 +1B0D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529625.620367733 + 20 +184419.5556609415 + 30 +0.0 + 11 +529366.6037593966 + 21 +184233.2897046201 + 31 +0.0 + 0 +LINE + 5 +1B0E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527004.8945598029 + 20 +184700.8393834953 + 30 +0.0 + 11 +526953.4379044082 + 21 +184931.6240468094 + 31 +0.0 + 0 +LINE + 5 +1B0F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528390.9898125458 + 20 +185753.3602785319 + 30 +0.0 + 11 +528781.3753309265 + 21 +185827.6345873771 + 31 +0.0 + 0 +LINE + 5 +1B10 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528106.4157938656 + 20 +187215.6255117142 + 30 +0.0 + 11 +528884.2109935742 + 21 +184710.0395547231 + 31 +0.0 + 0 +LINE + 5 +1B11 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529676.6264599539 + 20 +185290.4940208969 + 30 +0.0 + 11 +529920.7713187865 + 21 +185313.7159799931 + 31 +0.0 + 0 +LINE + 5 +1B12 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529710.1858069896 + 20 +185288.9440628221 + 30 +0.0 + 11 +529589.3946623234 + 21 +185498.1525499557 + 31 +0.0 + 0 +LINE + 5 +1B13 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529260.9647945109 + 20 +185147.8370213298 + 30 +0.0 + 11 +529921.0564618626 + 21 +185515.4653540902 + 31 +0.0 + 0 +LINE + 5 +1B14 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529690.2856066964 + 20 +185465.3118464734 + 30 +0.0 + 11 +529562.5373522235 + 21 +185885.5072189847 + 31 +0.0 + 0 +LINE + 5 +1B15 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529752.9023244892 + 20 +185495.4577198239 + 30 +0.0 + 11 +529575.1931667881 + 21 +185417.8112557643 + 31 +0.0 + 0 +LINE + 5 +1B16 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529722.829467629 + 20 +185561.5487289499 + 30 +0.0 + 11 +529664.1144124067 + 21 +185535.3153915267 + 31 +0.0 + 0 +LINE + 5 +1B17 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529718.0701045081 + 20 +185548.1881227963 + 30 +0.0 + 11 +529624.8501684037 + 21 +185940.498129378 + 31 +0.0 + 0 +LINE + 5 +1B18 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529767.4186194858 + 20 +185663.7851117391 + 30 +0.0 + 11 +529474.2327039333 + 21 +185614.5656806243 + 31 +0.0 + 0 +LINE + 5 +1B19 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529479.5491451336 + 20 +185602.3577959528 + 30 +0.0 + 11 +529426.0863860198 + 21 +185835.1184134999 + 31 +0.0 + 0 +LINE + 5 +1B1A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529338.1500175083 + 20 +185474.63901319 + 30 +0.0 + 11 +529486.7042496121 + 21 +185618.9945535243 + 31 +0.0 + 0 +LINE + 5 +1B1B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529421.0288854622 + 20 +185447.5636057371 + 30 +0.0 + 11 +529377.8939554926 + 21 +185521.2568725796 + 31 +0.0 + 0 +LINE + 5 +1B1C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529753.9555043243 + 20 +185913.4799359859 + 30 +0.0 + 11 +529424.3486629905 + 21 +185832.5479786192 + 31 +0.0 + 0 +LINE + 5 +1B1D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529607.735771832 + 20 +185457.5037141376 + 30 +0.0 + 11 +529492.4208418194 + 21 +185865.5940145193 + 31 +0.0 + 0 +LINE + 5 +1B1E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529052.7007117045 + 20 +185555.5190431744 + 30 +0.0 + 11 +529499.3924342998 + 21 +185865.3700194207 + 31 +0.0 + 0 +LINE + 5 +1B1F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529134.1435313744 + 20 +185504.561087551 + 30 +0.0 + 11 +529122.1575831819 + 21 +185621.3766035377 + 31 +0.0 + 0 +LINE + 5 +1B20 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529185.4622521453 + 20 +185539.5096001749 + 30 +0.0 + 11 +529094.9380125719 + 21 +185601.7266631869 + 31 +0.0 + 0 +LINE + 5 +1B21 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529349.289576162 + 20 +185635.758687261 + 30 +0.0 + 11 +529166.6371817065 + 21 +185549.4723374663 + 31 +0.0 + 0 +LINE + 5 +1B22 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529380.7994892831 + 20 +185388.0374709109 + 30 +0.0 + 11 +529255.3907441184 + 21 +185698.7826703294 + 31 +0.0 + 0 +LINE + 5 +1B23 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529469.3139698497 + 20 +185418.3984779757 + 30 +0.0 + 11 +529352.2746118934 + 21 +185386.006284229 + 31 +0.0 + 0 +LINE + 5 +1B24 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529486.9823889578 + 20 +185367.3845019738 + 30 +0.0 + 11 +529467.6152339519 + 21 +185419.7537123967 + 31 +0.0 + 0 +LINE + 5 +1B25 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529741.8629154026 + 20 +184685.8712765344 + 30 +0.0 + 11 +529313.4079908648 + 21 +185542.0960531091 + 31 +0.0 + 0 +LINE + 5 +1B26 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529317.3055379187 + 20 +185554.5795979603 + 30 +0.0 + 11 +529295.6361652416 + 21 +185543.6163475381 + 31 +0.0 + 0 +LINE + 5 +1B27 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529378.5146834967 + 20 +185734.5983057824 + 30 +0.0 + 11 +529354.3004098581 + 21 +185772.910263777 + 31 +0.0 + 0 +LINE + 5 +1B28 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529392.6194978177 + 20 +185728.0883212426 + 30 +0.0 + 11 +529371.6375650604 + 21 +185739.8741148262 + 31 +0.0 + 0 +LINE + 5 +1B29 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529451.9150188564 + 20 +185752.4298715705 + 30 +0.0 + 11 +529384.6902650206 + 21 +185727.0784447274 + 31 +0.0 + 0 +LINE + 5 +1B2A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529377.2865269477 + 20 +185506.7228677362 + 30 +0.0 + 11 +529047.4619112686 + 21 +185375.3091272221 + 31 +0.0 + 0 +LINE + 5 +1B2B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529280.7553521956 + 20 +185149.1266581205 + 30 +0.0 + 11 +529111.4767074376 + 21 +185263.0186630097 + 31 +0.0 + 0 +LINE + 5 +1B2C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529102.7090879047 + 20 +185233.1779227109 + 30 +0.0 + 11 +529351.6830468711 + 21 +185472.0152051871 + 31 +0.0 + 0 +LINE + 5 +1B2D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529408.5867116509 + 20 +185356.7769038792 + 30 +0.0 + 11 +529376.626936113 + 21 +185341.2666982859 + 31 +0.0 + 0 +LINE + 5 +1B2E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529211.3746992233 + 20 +185427.0353849283 + 30 +0.0 + 11 +529163.3368893673 + 21 +185507.06168701 + 31 +0.0 + 0 +LINE + 5 +1B2F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529177.751636039 + 20 +185475.0031284419 + 30 +0.0 + 11 +529181.4357627487 + 21 +185558.3038454395 + 31 +0.0 + 0 +LINE + 5 +1B30 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529190.3152886656 + 20 +185478.8012390553 + 30 +0.0 + 11 +529123.0419161259 + 21 +185522.372341461 + 31 +0.0 + 0 +LINE + 5 +1B31 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529028.5214292627 + 20 +185457.1815612015 + 30 +0.0 + 11 +529135.6116966774 + 21 +185523.5421908994 + 31 +0.0 + 0 +LINE + 5 +1B32 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529339.5448717486 + 20 +184906.714440032 + 30 +0.0 + 11 +529228.0462766641 + 21 +185199.5567293637 + 31 +0.0 + 0 +LINE + 5 +1B33 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529580.9961628172 + 20 +185570.6345795445 + 30 +0.0 + 11 +529534.4901934361 + 21 +185563.7567346888 + 31 +0.0 + 0 +LINE + 5 +1B34 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529555.4243843787 + 20 +185503.4733186487 + 30 +0.0 + 11 +529535.1784360941 + 21 +185565.5289326257 + 31 +0.0 + 0 +LINE + 5 +1B35 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529603.9922531548 + 20 +185493.638296058 + 30 +0.0 + 11 +529509.1059307583 + 21 +185450.2847626829 + 31 +0.0 + 0 +LINE + 5 +1B36 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529589.5120142827 + 20 +185322.4268616879 + 30 +0.0 + 11 +529435.5125850959 + 21 +185578.2449751067 + 31 +0.0 + 0 +LINE + 5 +1B37 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529466.8386348521 + 20 +185671.6710813359 + 30 +0.0 + 11 +529400.8135946273 + 21 +185652.1708809338 + 31 +0.0 + 0 +LINE + 5 +1B38 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529410.7663206183 + 20 +185621.9237130644 + 30 +0.0 + 11 +529393.5692052581 + 21 +185679.5156498254 + 31 +0.0 + 0 +LINE + 5 +1B39 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529415.7053980812 + 20 +185628.9713987198 + 30 +0.0 + 11 +529347.5852966691 + 21 +185607.802371799 + 31 +0.0 + 0 +LINE + 5 +1B3A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529350.7346442304 + 20 +185605.8272903669 + 30 +0.0 + 11 +529333.3253288324 + 21 +185659.1986828176 + 31 +0.0 + 0 +LINE + 5 +1B3B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529402.1878585207 + 20 +185676.8029646959 + 30 +0.0 + 11 +529327.9291804021 + 21 +185654.6278317182 + 31 +0.0 + 0 +LINE + 5 +1B3C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529444.121728233 + 20 +185122.7866379459 + 30 +0.0 + 11 +529393.5248717581 + 21 +185223.5066888709 + 31 +0.0 + 0 +LINE + 5 +1B3D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529093.4128605832 + 20 +185568.0221979865 + 30 +0.0 + 11 +528595.1237850393 + 21 +185576.7293241136 + 31 +0.0 + 0 +LINE + 5 +1B3E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529051.144898358 + 20 +185513.7781552191 + 30 +0.0 + 11 +528824.4188338513 + 21 +185530.0507223063 + 31 +0.0 + 0 +LINE + 5 +1B3F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529122.6016531229 + 20 +185341.1288735912 + 30 +0.0 + 11 +528962.3468535983 + 21 +185284.9924605613 + 31 +0.0 + 0 +LINE + 5 +1B40 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529213.0006079433 + 20 +185022.9166618555 + 30 +0.0 + 11 +528998.1385361492 + 21 +185615.1715603249 + 31 +0.0 + 0 +LINE + 5 +1B41 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528991.0782652902 + 20 +185445.9785583417 + 30 +0.0 + 11 +529039.3958728458 + 21 +185258.1623532054 + 31 +0.0 + 0 +LINE + 5 +1B42 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528921.0377353934 + 20 +185426.828561506 + 30 +0.0 + 11 +528937.5734197853 + 21 +185364.6818251168 + 31 +0.0 + 0 +LINE + 5 +1B43 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528963.9370200458 + 20 +185460.2488607951 + 30 +0.0 + 11 +528914.5040853694 + 21 +185412.3568939084 + 31 +0.0 + 0 +LINE + 5 +1B44 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528933.4685356528 + 20 +185419.9997593404 + 30 +0.0 + 11 +528615.1723248469 + 21 +185449.7682850459 + 31 +0.0 + 0 +LINE + 5 +1B45 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529023.8662109728 + 20 +185188.1530147488 + 30 +0.0 + 11 +528715.9106166859 + 21 +185150.6747967539 + 31 +0.0 + 0 +LINE + 5 +1B46 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529412.354033202 + 20 +185186.0519605904 + 30 +0.0 + 11 +529412.3421550092 + 21 +185186.0482801997 + 31 +0.0 + 0 +LINE + 5 +1B47 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529040.6633607615 + 20 +184884.196908992 + 30 +0.0 + 11 +528925.5715025252 + 21 +185271.9605769922 + 31 +0.0 + 0 +LINE + 5 +1B48 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528773.4371677128 + 20 +185380.00710046 + 30 +0.0 + 11 +528888.8275554119 + 21 +185241.2509179212 + 31 +0.0 + 0 +LINE + 5 +1B49 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528951.6776462008 + 20 +185252.3051789882 + 30 +0.0 + 11 +528887.1877698381 + 21 +185242.212929748 + 31 +0.0 + 0 +LINE + 5 +1B4A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529135.8430613358 + 20 +185257.0891061149 + 30 +0.0 + 11 +528917.9829977046 + 21 +185169.6311588591 + 31 +0.0 + 0 +LINE + 5 +1B4B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528775.9558829125 + 20 +185615.017381728 + 30 +0.0 + 11 +528778.6521852016 + 21 +185358.8103474443 + 31 +0.0 + 0 +LINE + 5 +1B4C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528729.9180300995 + 20 +185960.161097513 + 30 +0.0 + 11 +528779.0379103066 + 21 +186161.3926041654 + 31 +0.0 + 0 +LINE + 5 +1B4D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528950.4189077693 + 20 +185814.9571831064 + 30 +0.0 + 11 +528984.9742384628 + 21 +186297.2310706317 + 31 +0.0 + 0 +LINE + 5 +1B4E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528951.624137997 + 20 +185561.616747222 + 30 +0.0 + 11 +528966.33570878 + 21 +186100.8301520585 + 31 +0.0 + 0 +LINE + 5 +1B4F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528859.1323982127 + 20 +185799.482461746 + 30 +0.0 + 11 +528965.9004221569 + 21 +185848.3712824754 + 31 +0.0 + 0 +LINE + 5 +1B50 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528863.2406757241 + 20 +185861.4351186065 + 30 +0.0 + 11 +528962.7618637885 + 21 +185814.9471200873 + 31 +0.0 + 0 +LINE + 5 +1B51 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528863.1513625532 + 20 +186051.4437259971 + 30 +0.0 + 11 +528881.3717627635 + 21 +185850.2591133216 + 31 +0.0 + 0 +LINE + 5 +1B52 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528448.7063367634 + 20 +185927.3670817845 + 30 +0.0 + 11 +528965.078864012 + 21 +186002.4559974586 + 31 +0.0 + 0 +LINE + 5 +1B53 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528809.391795014 + 20 +185982.7201336871 + 30 +0.0 + 11 +528810.9272095478 + 21 +185958.4838576892 + 31 +0.0 + 0 +LINE + 5 +1B54 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528737.7329029084 + 20 +186010.1607760782 + 30 +0.0 + 11 +528795.7281322101 + 21 +185579.7030681805 + 31 +0.0 + 0 +LINE + 5 +1B55 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528773.2489006129 + 20 +185602.138604177 + 30 +0.0 + 11 +528964.8435679701 + 21 +185663.829735683 + 31 +0.0 + 0 +LINE + 5 +1B56 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528671.2378729466 + 20 +185560.6509984881 + 30 +0.0 + 11 +528720.795726458 + 21 +185970.4960299483 + 31 +0.0 + 0 +LINE + 5 +1B57 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528753.1546030234 + 20 +185826.7513961091 + 30 +0.0 + 11 +528846.4880856416 + 21 +185825.9140055556 + 31 +0.0 + 0 +LINE + 5 +1B58 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528811.5468672264 + 20 +185822.0868192886 + 30 +0.0 + 11 +528881.4820380612 + 21 +185867.4922608376 + 31 +0.0 + 0 +LINE + 5 +1B59 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528808.4515075253 + 20 +185834.8418088954 + 30 +0.0 + 11 +528880.1132298697 + 21 +185798.942711855 + 31 +0.0 + 0 +LINE + 5 +1B5A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528874.5242430786 + 20 +185631.8475956416 + 30 +0.0 + 11 +528874.7492767722 + 21 +185810.370569834 + 31 +0.0 + 0 +LINE + 5 +1B5B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529226.7259620609 + 20 +185859.1195999941 + 30 +0.0 + 11 +529461.753936208 + 21 +185828.3541730241 + 31 +0.0 + 0 +LINE + 5 +1B5C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529273.2801508957 + 20 +185932.8399631512 + 30 +0.0 + 11 +529287.0712099601 + 21 +185848.5717814258 + 31 +0.0 + 0 +LINE + 5 +1B5D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529088.7060528404 + 20 +185705.938394954 + 30 +0.0 + 11 +529153.993407673 + 21 +185608.3315866453 + 31 +0.0 + 0 +LINE + 5 +1B5E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529150.5211611966 + 20 +185711.7609386521 + 30 +0.0 + 11 +529120.4964274076 + 21 +185606.1005570466 + 31 +0.0 + 0 +LINE + 5 +1B5F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529231.026467415 + 20 +185921.0843057538 + 30 +0.0 + 11 +529260.5967490455 + 21 +185674.6789090408 + 31 +0.0 + 0 +LINE + 5 +1B60 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529127.0111587181 + 20 +185947.2972152716 + 30 +0.0 + 11 +529248.350250143 + 21 +185952.225746367 + 31 +0.0 + 0 +LINE + 5 +1B61 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529224.1848018071 + 20 +186051.4226801147 + 30 +0.0 + 11 +529116.8609899559 + 21 +185996.021142447 + 31 +0.0 + 0 +LINE + 5 +1B62 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529121.4063304959 + 20 +186000.9925100552 + 30 +0.0 + 11 +529128.3572058809 + 21 +185945.5911903531 + 31 +0.0 + 0 +LINE + 5 +1B63 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529155.3301500879 + 20 +186196.5494294306 + 30 +0.0 + 11 +529250.7034320214 + 21 +185791.3870299013 + 31 +0.0 + 0 +LINE + 5 +1B64 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529277.3320268682 + 20 +185859.3770847035 + 30 +0.0 + 11 +528939.7638049955 + 21 +185762.2307008389 + 31 +0.0 + 0 +LINE + 5 +1B65 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528942.970139214 + 20 +185862.2378862911 + 30 +0.0 + 11 +529235.4741338318 + 21 +185869.7730850032 + 31 +0.0 + 0 +LINE + 5 +1B66 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529205.7845020345 + 20 +185994.8187523307 + 30 +0.0 + 11 +529171.2778213867 + 21 +185986.3758428427 + 31 +0.0 + 0 +LINE + 5 +1B67 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529098.7281099492 + 20 +185814.9083276223 + 30 +0.0 + 11 +529112.7833206234 + 21 +185722.6354103959 + 31 +0.0 + 0 +LINE + 5 +1B68 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529103.4337720745 + 20 +185756.5193600031 + 30 +0.0 + 11 +529159.4093684629 + 21 +185694.7187544166 + 31 +0.0 + 0 +LINE + 5 +1B69 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529115.5320268205 + 20 +185761.6088829318 + 30 +0.0 + 11 +529091.5185714267 + 21 +185685.1399246696 + 31 +0.0 + 0 +LINE + 5 +1B6A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528925.6700740792 + 20 +185664.0143344197 + 30 +0.0 + 11 +529101.9449496349 + 21 +185692.2574079522 + 31 +0.0 + 0 +LINE + 5 +1B6B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529323.2047039083 + 20 +186136.6862493935 + 30 +0.0 + 11 +529367.797232147 + 21 +185841.4401863067 + 31 +0.0 + 0 +LINE + 5 +1B6C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +529769.5900111758 + 20 +185807.3295091061 + 30 +0.0 + 11 +529444.5005927685 + 21 +185662.1506600254 + 31 +0.0 + 0 +LINE + 5 +1B6D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528763.7395908349 + 20 +183029.8856650012 + 30 +0.0 + 11 +528976.162882365 + 21 +183032.3786083496 + 31 +0.0 + 0 +LINE + 5 +1B6E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527025.2812095881 + 20 +183263.6346011901 + 30 +0.0 + 11 +526897.1265927663 + 21 +182483.0277155677 + 31 +0.0 + 0 +LINE + 5 +1B6F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526964.2083557769 + 20 +183286.4261005596 + 30 +0.0 + 11 +526885.0249361946 + 21 +182798.3537771728 + 31 +0.0 + 0 +LINE + 5 +1B70 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526777.074562552 + 20 +183143.2710983985 + 30 +0.0 + 11 +526678.3375863469 + 21 +182989.0315936426 + 31 +0.0 + 0 +LINE + 5 +1B71 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526376.0911853841 + 20 +183362.1726671961 + 30 +0.0 + 11 +527059.5232641422 + 21 +182915.9150971422 + 31 +0.0 + 0 +LINE + 5 +1B72 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526781.3386109241 + 20 +183014.4930036137 + 30 +0.0 + 11 +526623.5488075315 + 21 +182604.6318740274 + 31 +0.0 + 0 +LINE + 5 +1B73 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526841.6122685247 + 20 +182979.8994604785 + 30 +0.0 + 11 +526669.981091038 + 21 +183070.1893105516 + 31 +0.0 + 0 +LINE + 5 +1B74 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526806.8403955176 + 20 +182916.1553230647 + 30 +0.0 + 11 +526750.1753566118 + 21 +182946.5645168706 + 31 +0.0 + 0 +LINE + 5 +1B75 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526849.2454166972 + 20 +182950.2005754067 + 30 +0.0 + 11 +526791.2527324742 + 21 +182913.1316652581 + 31 +0.0 + 0 +LINE + 5 +1B76 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526803.0593180441 + 20 +182929.825026326 + 30 +0.0 + 11 +526681.7233194259 + 21 +182545.2802653542 + 31 +0.0 + 0 +LINE + 5 +1B77 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526950.8006147146 + 20 +182784.8000475242 + 30 +0.0 + 11 +526555.0614632221 + 21 +182881.2480553835 + 31 +0.0 + 0 +LINE + 5 +1B78 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526561.2464987034 + 20 +182893.0396766159 + 30 +0.0 + 11 +526491.097430139 + 21 +182664.75283978 + 31 +0.0 + 0 +LINE + 5 +1B79 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526429.450063369 + 20 +183030.6460005865 + 30 +0.0 + 11 +526567.1802176478 + 21 +182875.9292060764 + 31 +0.0 + 0 +LINE + 5 +1B7A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526514.0693656086 + 20 +183051.6592852067 + 30 +0.0 + 11 +526465.7200294525 + 21 +182981.2770327941 + 31 +0.0 + 0 +LINE + 5 +1B7B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526945.2614984458 + 20 +182673.699691965 + 30 +0.0 + 11 +526858.9467190832 + 21 +182699.6197587514 + 31 +0.0 + 0 +LINE + 5 +1B7C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526938.4648895453 + 20 +182521.0740243328 + 30 +0.0 + 11 +526489.5500694043 + 21 +182667.4421689821 + 31 +0.0 + 0 +LINE + 5 +1B7D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526699.5692000325 + 20 +183028.2482065977 + 30 +0.0 + 11 +526555.0552630549 + 21 +182629.5616776445 + 31 +0.0 + 0 +LINE + 5 +1B7E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526184.705617505 + 20 +182931.6259519551 + 30 +0.0 + 11 +526562.0248081487 + 21 +182629.2811126734 + 31 +0.0 + 0 +LINE + 5 +1B7F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525975.5045021903 + 20 +183074.5165478142 + 30 +0.0 + 11 +526410.9589320396 + 21 +182756.1661656958 + 31 +0.0 + 0 +LINE + 5 +1B80 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526223.8142669609 + 20 +183015.5497707789 + 30 +0.0 + 11 +526203.4151242994 + 21 +182899.9063416185 + 31 +0.0 + 0 +LINE + 5 +1B81 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526272.4723055687 + 20 +182976.9828819357 + 30 +0.0 + 11 +526177.6872562321 + 21 +182921.4725648552 + 31 +0.0 + 0 +LINE + 5 +1B82 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526428.9131914558 + 20 +182869.1425922379 + 30 +0.0 + 11 +526252.9762846761 + 21 +182968.4070682298 + 31 +0.0 + 0 +LINE + 5 +1B83 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526478.2483462436 + 20 +183113.9378498654 + 30 +0.0 + 11 +526330.704046688 + 21 +182813.0714143925 + 31 +0.0 + 0 +LINE + 5 +1B84 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526580.5570010577 + 20 +183271.4185264061 + 30 +0.0 + 11 +526399.896323525 + 21 +182965.1540424672 + 31 +0.0 + 0 +LINE + 5 +1B85 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526402.8812421781 + 20 +182952.4214062233 + 30 +0.0 + 11 +526382.0610931183 + 21 +182964.9224447871 + 31 +0.0 + 0 +LINE + 5 +1B86 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526450.9167544769 + 20 +182768.4488967919 + 30 +0.0 + 11 +526423.9962748326 + 21 +182731.9876166585 + 31 +0.0 + 0 +LINE + 5 +1B87 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526465.4552706402 + 20 +182773.9222169457 + 30 +0.0 + 11 +526443.6762423573 + 21 +182763.6840354824 + 31 +0.0 + 0 +LINE + 5 +1B88 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526522.8360133179 + 20 +182745.3578990408 + 30 +0.0 + 11 +526457.6197868785 + 21 +182775.5026528175 + 31 +0.0 + 0 +LINE + 5 +1B89 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526466.1648483548 + 20 +182995.8169228339 + 30 +0.0 + 11 +526078.9306227268 + 21 +183192.5577152809 + 31 +0.0 + 0 +LINE + 5 +1B8A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526110.1635046939 + 20 +183198.3175948517 + 30 +0.0 + 11 +526052.1249617262 + 21 +183005.5850345606 + 31 +0.0 + 0 +LINE + 5 +1B8B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526395.7367372402 + 20 +183359.4557518874 + 30 +0.0 + 11 +526084.9426491088 + 21 +183172.395334799 + 31 +0.0 + 0 +LINE + 5 +1B8C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526148.6610269019 + 20 +183296.7644774479 + 30 +0.0 + 11 +526443.1373601789 + 21 +183032.2846458226 + 31 +0.0 + 0 +LINE + 5 +1B8D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526306.4476798011 + 20 +183087.2896267643 + 30 +0.0 + 11 +526252.7504783172 + 21 +183010.9453358622 + 31 +0.0 + 0 +LINE + 5 +1B8E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526269.4450135935 + 20 +183041.8779819008 + 30 +0.0 + 11 +526267.0977212187 + 21 +182958.5288819632 + 31 +0.0 + 0 +LINE + 5 +1B8F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526281.7012315749 + 20 +183037.1815862247 + 30 +0.0 + 11 +526211.4541276583 + 21 +182998.5876487597 + 31 +0.0 + 0 +LINE + 5 +1B90 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526077.0975650373 + 20 +183098.088044319 + 30 +0.0 + 11 +526223.9064536299 + 21 +182996.5121949012 + 31 +0.0 + 0 +LINE + 5 +1B91 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526664.7213589688 + 20 +182917.3463248682 + 30 +0.0 + 11 +526618.8342611189 + 21 +182927.568075641 + 31 +0.0 + 0 +LINE + 5 +1B92 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526644.0715489711 + 20 +182986.1804455111 + 30 +0.0 + 11 +526619.3925915336 + 21 +182925.7507615153 + 31 +0.0 + 0 +LINE + 5 +1B93 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526693.2233190768 + 20 +182992.4787819791 + 30 +0.0 + 11 +526601.7192616864 + 21 +183042.5781883141 + 31 +0.0 + 0 +LINE + 5 +1B94 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526691.1577809463 + 20 +183164.2890439809 + 30 +0.0 + 11 +526519.0682599293 + 21 +182920.2727984166 + 31 +0.0 + 0 +LINE + 5 +1B95 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526543.5586095794 + 20 +182824.8265753773 + 30 +0.0 + 11 +526479.1159747663 + 21 +182849.0486845077 + 31 +0.0 + 0 +LINE + 5 +1B96 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526491.2292186234 + 20 +182878.4972369685 + 30 +0.0 + 11 +526469.913795082 + 21 +182822.2991526963 + 31 +0.0 + 0 +LINE + 5 +1B97 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526495.6458991038 + 20 +182871.1109460985 + 30 +0.0 + 11 +526429.2343233493 + 21 +182897.1489668176 + 31 +0.0 + 0 +LINE + 5 +1B98 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526432.5182091687 + 20 +182898.891215551 + 30 +0.0 + 11 +526411.2962424721 + 21 +182846.9179731636 + 31 +0.0 + 0 +LINE + 5 +1B99 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526478.7059982679 + 20 +182824.3817010889 + 30 +0.0 + 11 +526406.244637348 + 21 +182851.8669511721 + 31 +0.0 + 0 +LINE + 5 +1B9A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526831.8309248414 + 20 +182816.4182337956 + 30 +0.0 + 11 +526766.5959213014 + 21 +182559.9847257041 + 31 +0.0 + 0 +LINE + 5 +1B9B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527000.2530682652 + 20 +182306.9787163504 + 30 +0.0 + 11 +526860.1632714045 + 21 +182354.2285155059 + 31 +0.0 + 0 +LINE + 5 +1B9C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526958.5995454632 + 20 +182466.2489230176 + 30 +0.0 + 11 +526879.4161258808 + 21 +181978.1765996306 + 31 +0.0 + 0 +LINE + 5 +1B9D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526892.7851017648 + 20 +182352.9689788648 + 30 +0.0 + 11 +526813.0293333185 + 21 +182333.9922653943 + 31 +0.0 + 0 +LINE + 5 +1B9E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526867.2513936017 + 20 +182428.4894751634 + 30 +0.0 + 11 +526886.42456548 + 21 +182342.7583958494 + 31 +0.0 + 0 +LINE + 5 +1B9F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526877.6704091146 + 20 +182414.4235645573 + 30 +0.0 + 11 +526695.6134468584 + 21 +182494.4830129586 + 31 +0.0 + 0 +LINE + 5 +1BA0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526952.0471927737 + 20 +182605.1847142627 + 30 +0.0 + 11 +526672.7287760333 + 21 +182168.8544161005 + 31 +0.0 + 0 +LINE + 5 +1BA1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526668.6311203727 + 20 +182445.7554883518 + 30 +0.0 + 11 +526817.1655042102 + 21 +182332.718434346 + 31 +0.0 + 0 +LINE + 5 +1BA2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526702.3646228387 + 20 +182496.1108717801 + 30 +0.0 + 11 +526668.7997668507 + 21 +182444.9247298686 + 31 +0.0 + 0 +LINE + 5 +1BA3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526436.1625892373 + 20 +182628.7330061977 + 30 +0.0 + 11 +526681.7623917887 + 21 +182461.3212290171 + 31 +0.0 + 0 +LINE + 5 +1BA4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526494.6810839999 + 20 +182593.2752383091 + 30 +0.0 + 11 +526437.4933880692 + 21 +182495.666997106 + 31 +0.0 + 0 +LINE + 5 +1BA5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526370.4823750703 + 20 +182541.9954896542 + 30 +0.0 + 11 +527002.2713055748 + 21 +182127.6111901839 + 31 +0.0 + 0 +LINE + 5 +1BA6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526775.7298006102 + 20 +182194.3158260718 + 30 +0.0 + 11 +526521.3716858642 + 21 +181598.3809927647 + 31 +0.0 + 0 +LINE + 5 +1BA7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526836.0034582111 + 20 +182159.7222829365 + 30 +0.0 + 11 +526664.3722807242 + 21 +182250.0121330097 + 31 +0.0 + 0 +LINE + 5 +1BA8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526801.2315852038 + 20 +182095.9781455227 + 30 +0.0 + 11 +526744.5665462982 + 21 +182126.3873393285 + 31 +0.0 + 0 +LINE + 5 +1BA9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526843.6366063836 + 20 +182130.0233978648 + 30 +0.0 + 11 +526785.6439221603 + 21 +182092.9544877161 + 31 +0.0 + 0 +LINE + 5 +1BAA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526797.4505077304 + 20 +182109.6478487839 + 30 +0.0 + 11 +526755.1504495946 + 21 +181975.5881638581 + 31 +0.0 + 0 +LINE + 5 +1BAB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526945.1918044008 + 20 +181964.6228699824 + 30 +0.0 + 11 +526549.4526529084 + 21 +182061.0708778416 + 31 +0.0 + 0 +LINE + 5 +1BAC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526555.6376883897 + 20 +182072.8624990739 + 30 +0.0 + 11 +526485.4886198253 + 21 +181844.5756622381 + 31 +0.0 + 0 +LINE + 5 +1BAD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526423.8412530552 + 20 +182210.4688230445 + 30 +0.0 + 11 +526561.5714073341 + 21 +182055.7520285342 + 31 +0.0 + 0 +LINE + 5 +1BAE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526508.4605552949 + 20 +182231.4821076646 + 30 +0.0 + 11 +526460.1112191387 + 21 +182161.0998552523 + 31 +0.0 + 0 +LINE + 5 +1BAF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526933.2335520479 + 20 +181839.9368571187 + 30 +0.0 + 11 +526846.9187726854 + 21 +181865.856923905 + 31 +0.0 + 0 +LINE + 5 +1BB0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526693.9603897188 + 20 +182208.0710290557 + 30 +0.0 + 11 +526549.4464527412 + 21 +181809.3845001026 + 31 +0.0 + 0 +LINE + 5 +1BB1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526218.2054566471 + 20 +182195.3725932368 + 30 +0.0 + 11 +526197.8063139856 + 21 +182079.7291640766 + 31 +0.0 + 0 +LINE + 5 +1BB2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526266.863495255 + 20 +182156.8057043941 + 30 +0.0 + 11 +526172.0784459183 + 21 +182101.2953873133 + 31 +0.0 + 0 +LINE + 5 +1BB3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526423.3043811421 + 20 +182048.9654146958 + 30 +0.0 + 11 +526247.3674743625 + 21 +182148.2298906876 + 31 +0.0 + 0 +LINE + 5 +1BB4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526472.6395359299 + 20 +182293.7606723235 + 30 +0.0 + 11 +526275.9831066587 + 21 +181913.3195666171 + 31 +0.0 + 0 +LINE + 5 +1BB5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526558.7276475325 + 20 +182257.0804179532 + 30 +0.0 + 11 +526444.3361225294 + 21 +182297.8485983638 + 31 +0.0 + 0 +LINE + 5 +1BB6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526496.8912697186 + 20 +182385.3812040725 + 30 +0.0 + 11 +526582.9000737242 + 21 +182300.5860591656 + 31 +0.0 + 0 +LINE + 5 +1BB7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526580.0376232157 + 20 +182306.6836811287 + 30 +0.0 + 11 +526556.93538664 + 21 +182255.8515302934 + 31 +0.0 + 0 +LINE + 5 +1BB8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526680.130013927 + 20 +182629.5505262505 + 30 +0.0 + 11 +526394.2875132112 + 21 +182144.9768649251 + 31 +0.0 + 0 +LINE + 5 +1BB9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526397.2724318643 + 20 +182132.2442286813 + 30 +0.0 + 11 +526376.4522828047 + 21 +182144.7452672451 + 31 +0.0 + 0 +LINE + 5 +1BBA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526445.3079441631 + 20 +181948.2717192499 + 30 +0.0 + 11 +526401.4980246618 + 21 +181884.4450689966 + 31 +0.0 + 0 +LINE + 5 +1BBB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526459.8464603266 + 20 +181953.7450394038 + 30 +0.0 + 11 +526438.0674320437 + 21 +181943.5068579403 + 31 +0.0 + 0 +LINE + 5 +1BBC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526517.2272030042 + 20 +181925.1807214987 + 30 +0.0 + 11 +526452.0109765648 + 21 +181955.3254752755 + 31 +0.0 + 0 +LINE + 5 +1BBD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526460.556038041 + 20 +182175.639745292 + 30 +0.0 + 11 +526141.0942032139 + 21 +182330.5525736593 + 31 +0.0 + 0 +LINE + 5 +1BBE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526390.1279269266 + 20 +182539.2785743455 + 30 +0.0 + 11 +526213.0589553081 + 21 +182437.9216424716 + 31 +0.0 + 0 +LINE + 5 +1BBF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526206.4714515425 + 20 +182468.3181180565 + 30 +0.0 + 11 +526437.5285498651 + 21 +182212.1074682804 + 31 +0.0 + 0 +LINE + 5 +1BC0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526502.6138736954 + 20 +182322.9307229501 + 30 +0.0 + 11 +526471.8589425878 + 21 +182340.7107100859 + 31 +0.0 + 0 +LINE + 5 +1BC1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526300.8388694875 + 20 +182267.1124492223 + 30 +0.0 + 11 +526247.1416680035 + 21 +182190.7681583202 + 31 +0.0 + 0 +LINE + 5 +1BC2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526263.8362032798 + 20 +182221.700804359 + 30 +0.0 + 11 +526261.488910905 + 21 +182138.3517044211 + 31 +0.0 + 0 +LINE + 5 +1BC3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526276.0924212611 + 20 +182217.0044086828 + 30 +0.0 + 11 +526205.8453173446 + 21 +182178.4104712177 + 31 +0.0 + 0 +LINE + 5 +1BC4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526116.2847454244 + 20 +182250.2635450903 + 30 +0.0 + 11 +526218.2976433162 + 21 +182176.3350173591 + 31 +0.0 + 0 +LINE + 5 +1BC5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526515.0077327294 + 20 +182692.4233179073 + 30 +0.0 + 11 +526333.9111826571 + 21 +182492.7907652685 + 31 +0.0 + 0 +LINE + 5 +1BC6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526659.1125486551 + 20 +182097.1691473261 + 30 +0.0 + 11 +526613.2254508053 + 21 +182107.3908980991 + 31 +0.0 + 0 +LINE + 5 +1BC7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526638.4627386574 + 20 +182166.0032679689 + 30 +0.0 + 11 +526613.7837812198 + 21 +182105.5735839731 + 31 +0.0 + 0 +LINE + 5 +1BC8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526687.6145087632 + 20 +182172.301604437 + 30 +0.0 + 11 +526596.1104513726 + 21 +182222.401010772 + 31 +0.0 + 0 +LINE + 5 +1BC9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526685.5489706326 + 20 +182344.1118664388 + 30 +0.0 + 11 +526513.4594496156 + 21 +182100.0956208746 + 31 +0.0 + 0 +LINE + 5 +1BCA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526537.9497992656 + 20 +182004.6493978354 + 30 +0.0 + 11 +526473.5071644527 + 21 +182028.8715069656 + 31 +0.0 + 0 +LINE + 5 +1BCB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526485.6204083097 + 20 +182058.3200594264 + 30 +0.0 + 11 +526464.3049847683 + 21 +182002.1219751545 + 31 +0.0 + 0 +LINE + 5 +1BCC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526490.0370887901 + 20 +182050.9337685565 + 30 +0.0 + 11 +526423.6255130356 + 21 +182076.9717892756 + 31 +0.0 + 0 +LINE + 5 +1BCD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526426.9093988549 + 20 +182078.7140380091 + 30 +0.0 + 11 +526405.6874321583 + 21 +182026.7407956217 + 31 +0.0 + 0 +LINE + 5 +1BCE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526473.0971879541 + 20 +182004.204523547 + 30 +0.0 + 11 +526400.6358270344 + 21 +182031.68977363 + 31 +0.0 + 0 +LINE + 5 +1BCF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526554.9709952949 + 20 +182553.7399813713 + 30 +0.0 + 11 +526497.225498478 + 21 +182456.9410756913 + 31 +0.0 + 0 +LINE + 5 +1BD0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526826.2221145276 + 20 +181996.2410562537 + 30 +0.0 + 11 +526760.9871109879 + 21 +181739.8075481622 + 31 +0.0 + 0 +LINE + 5 +1BD1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527412.0818102422 + 20 +181564.1583751753 + 30 +0.0 + 11 +525538.5358990799 + 21 +182148.4234918985 + 31 +0.0 + 0 +LINE + 5 +1BD2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526134.7576759403 + 20 +182192.179583049 + 30 +0.0 + 11 +525907.4484610363 + 21 +182192.3395395591 + 31 +0.0 + 0 +LINE + 5 +1BD3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526218.5082342736 + 20 +182359.2115746763 + 30 +0.0 + 11 +526062.7307945771 + 21 +182426.7858813327 + 31 +0.0 + 0 +LINE + 5 +1BD4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526382.9052427298 + 20 +182784.6622153052 + 30 +0.0 + 11 +526060.0427866276 + 21 +182062.4070552026 + 31 +0.0 + 0 +LINE + 5 +1BD5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526104.2898207399 + 20 +182329.1624117874 + 30 +0.0 + 11 +525674.5130014083 + 21 +182419.581730331 + 31 +0.0 + 0 +LINE + 5 +1BD6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526079.7494059731 + 20 +182264.1439907801 + 30 +0.0 + 11 +526141.5177681991 + 21 +182447.9759454006 + 31 +0.0 + 0 +LINE + 5 +1BD7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526011.276471197 + 20 +182288.3070909581 + 30 +0.0 + 11 +526032.2614591864 + 21 +182349.0958726634 + 31 +0.0 + 0 +LINE + 5 +1BD8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526051.6475756412 + 20 +182251.8730553012 + 30 +0.0 + 11 +526005.8060671727 + 21 +182303.2132113621 + 31 +0.0 + 0 +LINE + 5 +1BD9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526024.1684002717 + 20 +182294.2194085108 + 30 +0.0 + 11 +525625.1965641057 + 21 +182352.687961578 + 31 +0.0 + 0 +LINE + 5 +1BDA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525905.1414408565 + 20 +182121.4676071119 + 30 +0.0 + 11 +525936.6700146762 + 21 +182531.2989112529 + 31 +0.0 + 0 +LINE + 5 +1BDB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525949.296971645 + 20 +182527.0731624555 + 30 +0.0 + 11 +525712.7456148091 + 21 +182559.9247571213 + 31 +0.0 + 0 +LINE + 5 +1BDC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526064.1280438116 + 20 +182679.1245538622 + 30 +0.0 + 11 +525933.351531187 + 21 +182518.4871184777 + 31 +0.0 + 0 +LINE + 5 +1BDD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526098.3649140155 + 20 +182598.9383882181 + 30 +0.0 + 11 +526021.1738839632 + 21 +182635.4468069849 + 31 +0.0 + 0 +LINE + 5 +1BDE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525602.5606954889 + 20 +181842.0189004617 + 30 +0.0 + 11 +525715.1538129658 + 21 +182561.8811309198 + 31 +0.0 + 0 +LINE + 5 +1BDF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526104.8310295083 + 20 +182412.0789316116 + 30 +0.0 + 11 +525688.2026632234 + 21 +182491.1740057715 + 31 +0.0 + 0 +LINE + 5 +1BE0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525927.3506884325 + 20 +182904.9491957143 + 30 +0.0 + 11 +525689.0369715465 + 21 +182484.2488916828 + 31 +0.0 + 0 +LINE + 5 +1BE1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526017.9443528103 + 20 +183100.6657351099 + 30 +0.0 + 11 +525790.2114538591 + 21 +182653.6137042441 + 31 +0.0 + 0 +LINE + 5 +1BE2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526016.436623323 + 20 +182879.722423568 + 30 +0.0 + 11 +525899.0200947565 + 21 +182881.4214081781 + 31 +0.0 + 0 +LINE + 5 +1BE3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525986.1216033472 + 20 +182825.5374699364 + 30 +0.0 + 11 +525916.2081338395 + 21 +182910.2588229799 + 31 +0.0 + 0 +LINE + 5 +1BE4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525904.605267724 + 20 +182653.9030739494 + 30 +0.0 + 11 +525974.5468944026 + 21 +182843.4166624298 + 31 +0.0 + 0 +LINE + 5 +1BE5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526121.5860971713 + 20 +182654.811784923 + 30 +0.0 + 11 +525833.5921459401 + 21 +182741.9152869398 + 31 +0.0 + 0 +LINE + 5 +1BE6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526193.3364792057 + 20 +182711.1169602223 + 30 +0.0 + 11 +526128.4794766109 + 21 +182608.447418775 + 31 +0.0 + 0 +LINE + 5 +1BE7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526223.8499447324 + 20 +182571.9991764507 + 30 +0.0 + 11 +526239.204328213 + 21 +182691.798900466 + 31 +0.0 + 0 +LINE + 5 +1BE8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526240.7146177363 + 20 +182685.2343256837 + 30 +0.0 + 11 +526191.167827044 + 21 +182710.97799336 + 31 +0.0 + 0 +LINE + 5 +1BE9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526518.7129862614 + 20 +182492.9366568091 + 30 +0.0 + 11 +526518.7014051999 + 21 +182492.9411862413 + 31 +0.0 + 0 +LINE + 5 +1BEA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526382.4046717591 + 20 +182546.2477693468 + 30 +0.0 + 11 +525994.7616732592 + 21 +182697.8575929502 + 31 +0.0 + 0 +LINE + 5 +1BEB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525982.6678762281 + 20 +182692.8806623247 + 30 +0.0 + 11 +525991.6892370746 + 21 +182715.4277158023 + 31 +0.0 + 0 +LINE + 5 +1BEC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525808.7082592372 + 20 +182616.1255561446 + 30 +0.0 + 11 +525768.4210246726 + 21 +182636.8879236488 + 31 +0.0 + 0 +LINE + 5 +1BED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525816.4297002768 + 20 +182602.6457551815 + 30 +0.0 + 11 +525802.8498693046 + 21 +182622.5136847008 + 31 +0.0 + 0 +LINE + 5 +1BEE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525797.3801032143 + 20 +182541.4445890212 + 30 +0.0 + 11 +525816.7405599603 + 21 +182610.6329918491 + 31 +0.0 + 0 +LINE + 5 +1BEF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526035.598679878 + 20 +182637.3260432762 + 30 +0.0 + 11 +526147.3595702719 + 21 +182970.3413998211 + 31 +0.0 + 0 +LINE + 5 +1BF0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526227.8513561675 + 20 +182910.9041209083 + 30 +0.0 + 11 +526067.9281441547 + 21 +182665.8736486268 + 31 +0.0 + 0 +LINE + 5 +1BF1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526187.7113128795 + 20 +182619.2916172854 + 30 +0.0 + 11 +526200.3599981748 + 21 +182652.4880702626 + 31 +0.0 + 0 +LINE + 5 +1BF2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526100.4344341845 + 20 +182809.5850182491 + 30 +0.0 + 11 +526016.5049331899 + 21 +182850.4222446896 + 31 +0.0 + 0 +LINE + 5 +1BF3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526049.7037537386 + 20 +182838.873460631 + 30 +0.0 + 11 +525967.0467297591 + 21 +182827.900829733 + 31 +0.0 + 0 +LINE + 5 +1BF4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526047.0216787222 + 20 +182826.0252123005 + 30 +0.0 + 11 +525997.7207043991 + 21 +182889.2198445766 + 31 +0.0 + 0 +LINE + 5 +1BF5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526074.5251576573 + 20 +183037.7226748375 + 30 +0.0 + 11 +525997.6573086355 + 21 +182876.5959025693 + 31 +0.0 + 0 +LINE + 5 +1BF6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525989.7915622426 + 20 +182428.7977942877 + 30 +0.0 + 11 +525992.5659074848 + 21 +182475.7276669322 + 31 +0.0 + 0 +LINE + 5 +1BF7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526054.4524535999 + 20 +182460.1589158632 + 30 +0.0 + 11 +525990.8608686098 + 21 +182474.886711572 + 31 +0.0 + 0 +LINE + 5 +1BF8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526068.5073888174 + 20 +182412.6402422408 + 30 +0.0 + 11 +526103.3756467485 + 21 +182510.9618961269 + 31 +0.0 + 0 +LINE + 5 +1BF9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526237.7902046644 + 20 +182442.0742503921 + 30 +0.0 + 11 +525969.4564207093 + 21 +182573.0540646057 + 31 +0.0 + 0 +LINE + 5 +1BFA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525879.1362642368 + 20 +182533.658277353 + 30 +0.0 + 11 +525892.7731972832 + 21 +182601.1386286375 + 31 +0.0 + 0 +LINE + 5 +1BFB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525923.7764311459 + 20 +182593.8758875 + 30 +0.0 + 11 +525864.898618392 + 21 +182605.9579039674 + 31 +0.0 + 0 +LINE + 5 +1BFC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525917.1888719714 + 20 +182588.3379796451 + 30 +0.0 + 11 +525932.304539506 + 21 +182658.0516261728 + 31 +0.0 + 0 +LINE + 5 +1BFD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525934.5481091393 + 20 +182655.0875526203 + 30 +0.0 + 11 +525879.8559882184 + 21 +182667.7509527922 + 31 +0.0 + 0 +LINE + 5 +1BFE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525868.3564271535 + 20 +182597.610245419 + 30 +0.0 + 11 +525883.9361791152 + 21 +182673.5270362318 + 31 +0.0 + 0 +LINE + 5 +1BFF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525916.8000977243 + 20 +182247.7333508397 + 30 +0.0 + 11 +525653.2457118757 + 21 +182271.245804112 + 31 +0.0 + 0 +LINE + 5 +1C00 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527244.1243499752 + 20 +183861.7178842388 + 30 +0.0 + 11 +526887.8587946553 + 21 +181585.0043007456 + 31 +0.0 + 0 +LINE + 5 +1C01 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527212.5796583467 + 20 +183246.1310702512 + 30 +0.0 + 11 +527133.3962387643 + 21 +182758.0587468642 + 31 +0.0 + 0 +LINE + 5 +1C02 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527346.8091104488 + 20 +183038.3259333679 + 30 +0.0 + 11 +527389.7655543316 + 21 +182873.6116105945 + 31 +0.0 + 0 +LINE + 5 +1C03 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527794.4787894083 + 20 +183132.0576301447 + 30 +0.0 + 11 +527011.5876332116 + 21 +182924.7692635655 + 31 +0.0 + 0 +LINE + 5 +1C04 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527300.0973198231 + 20 +182930.3311150156 + 30 +0.0 + 11 +527320.2151109535 + 21 +182491.6067800618 + 31 +0.0 + 0 +LINE + 5 +1C05 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527231.9783573573 + 20 +182916.5676132878 + 30 +0.0 + 11 +527423.3516630881 + 21 +182947.964682665 + 31 +0.0 + 0 +LINE + 5 +1C06 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527244.8138405172 + 20 +182845.0997983003 + 30 +0.0 + 11 +527308.1863830451 + 21 +182856.0344476155 + 31 +0.0 + 0 +LINE + 5 +1C07 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527215.3473432128 + 20 +182890.805274612 + 30 +0.0 + 11 +527258.6460484188 + 21 +182837.3031470795 + 31 +0.0 + 0 +LINE + 5 +1C08 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527252.7226938883 + 20 +182856.8729615311 + 30 +0.0 + 11 +527246.2602959411 + 21 +182453.6914451339 + 31 +0.0 + 0 +LINE + 5 +1C09 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527066.7092573773 + 20 +182765.9953699274 + 30 +0.0 + 11 +527472.6425793829 + 21 +182732.3823913409 + 31 +0.0 + 0 +LINE + 5 +1C0A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527470.5027378193 + 20 +182745.5246161631 + 30 +0.0 + 11 +527464.8802400704 + 21 +182506.7691780846 + 31 +0.0 + 0 +LINE + 5 +1C0B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527639.0437239939 + 20 +182834.4050793871 + 30 +0.0 + 11 +527459.4638476878 + 21 +182731.1677318473 + 31 +0.0 + 0 +LINE + 5 +1C0C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527565.4080953913 + 20 +182881.0931789668 + 30 +0.0 + 11 +527589.0259726629 + 21 +182799.0351773181 + 31 +0.0 + 0 +LINE + 5 +1C0D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527035.5118023315 + 20 +182581.3668340386 + 30 +0.0 + 11 +527125.5940504404 + 21 +182578.6687654175 + 31 +0.0 + 0 +LINE + 5 +1C0E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526995.0345653063 + 20 +182511.8963263632 + 30 +0.0 + 11 +527467.1984727799 + 21 +182508.8313647648 + 31 +0.0 + 0 +LINE + 5 +1C0F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527382.0213844116 + 20 +182917.5291695387 + 30 +0.0 + 11 +527393.0771309889 + 21 +182493.6034722552 + 31 +0.0 + 0 +LINE + 5 +1C10 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527723.7383600434 + 20 +182594.346349493 + 30 +0.0 + 11 +527386.376364243 + 21 +182495.5407385079 + 31 +0.0 + 0 +LINE + 5 +1C11 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528083.5754440563 + 20 +182732.5093126143 + 30 +0.0 + 11 +527854.3980075514 + 21 +182659.1965084425 + 31 +0.0 + 0 +LINE + 5 +1C12 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527528.3942624024 + 20 +183313.0177615849 + 30 +0.0 + 11 +527646.3761425884 + 21 +182762.9288193099 + 31 +0.0 + 0 +LINE + 5 +1C13 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527639.5188679864 + 20 +182751.7929515791 + 30 +0.0 + 11 +527663.2233537091 + 21 +182757.070444228 + 31 +0.0 + 0 +LINE + 5 +1C14 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527535.7837706053 + 20 +182592.4432598958 + 30 +0.0 + 11 +527553.7426780206 + 21 +182532.6692124688 + 31 +0.0 + 0 +LINE + 5 +1C15 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527523.7213644617 + 20 +182602.2322355196 + 30 +0.0 + 11 +527541.1464808263 + 21 +182585.6336888271 + 31 +0.0 + 0 +LINE + 5 +1C16 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527460.2530903324 + 20 +182593.2741069957 + 30 +0.0 + 11 +527531.6546121294 + 21 +182601.2543987397 + 31 +0.0 + 0 +LINE + 5 +1C17 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527380.0198904067 + 20 +182801.2983929789 + 30 +0.0 + 11 +527426.7849958205 + 21 +182796.4885225456 + 31 +0.0 + 0 +LINE + 5 +1C18 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527421.3726306412 + 20 +182860.0734020617 + 30 +0.0 + 11 +527425.6807543277 + 21 +182794.940939201 + 31 +0.0 + 0 +LINE + 5 +1C19 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527376.733173879 + 20 +182881.5881515784 + 30 +0.0 + 11 +527479.3828969314 + 21 +182900.1886190805 + 31 +0.0 + 0 +LINE + 5 +1C1A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527433.0110471161 + 20 +183043.9329499576 + 30 +0.0 + 11 +527519.127408857 + 21 +182758.0261406934 + 31 +0.0 + 0 +LINE + 5 +1C1B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527465.7176284195 + 20 +182675.2182058559 + 30 +0.0 + 11 +527534.5127772507 + 21 +182677.824208477 + 31 +0.0 + 0 +LINE + 5 +1C1C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527532.3310817872 + 20 +182709.5919298885 + 30 +0.0 + 11 +527534.7860246275 + 21 +182649.5374112223 + 31 +0.0 + 0 +LINE + 5 +1C1D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527525.8057444187 + 20 +182703.9808398422 + 30 +0.0 + 11 +527597.0429492604 + 21 +182707.687126868 + 31 +0.0 + 0 +LINE + 5 +1C1E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527594.4783161435 + 20 +182710.3782221283 + 30 +0.0 + 11 +527598.1802909119 + 21 +182654.3613927147 + 31 +0.0 + 0 +LINE + 5 +1C1F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527527.1031916927 + 20 +182654.2928210643 + 30 +0.0 + 11 +527604.5374235002 + 21 +182657.4594506405 + 31 +0.0 + 0 +LINE + 5 +1C20 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526988.8188472393 + 20 +182388.6928958193 + 30 +0.0 + 11 +527217.0229275381 + 21 +182409.8910709357 + 31 +0.0 + 0 +LINE + 5 +1C21 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527052.3626297287 + 20 +182411.7094164673 + 30 +0.0 + 11 +527135.7854414482 + 21 +182093.7294633607 + 31 +0.0 + 0 +LINE + 5 +1C22 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527227.2159459994 + 20 +182355.1323276016 + 30 +0.0 + 11 +527050.5631702309 + 21 +182294.8526828323 + 31 +0.0 + 0 +LINE + 5 +1C23 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527211.1326827404 + 20 +182413.5698367184 + 30 +0.0 + 11 +527226.7933031375 + 21 +182354.3974981635 + 31 +0.0 + 0 +LINE + 5 +1C24 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527505.6096122967 + 20 +182455.2290636664 + 30 +0.0 + 11 +527219.6793507476 + 21 +182374.0511622241 + 31 +0.0 + 0 +LINE + 5 +1C25 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527437.9658937181 + 20 +182327.9040809348 + 30 +0.0 + 11 +526810.1065464444 + 21 +182158.7874360434 + 31 +0.0 + 0 +LINE + 5 +1C26 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527046.1172069397 + 20 +182150.4489677819 + 30 +0.0 + 11 +527058.2752633564 + 21 +181885.3087652044 + 31 +0.0 + 0 +LINE + 5 +1C27 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526977.9982444741 + 20 +182136.6854660542 + 30 +0.0 + 11 +527169.3715502046 + 21 +182168.0825354316 + 31 +0.0 + 0 +LINE + 5 +1C28 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526990.8337276338 + 20 +182065.2176510666 + 30 +0.0 + 11 +527054.2062701618 + 21 +182076.152300382 + 31 +0.0 + 0 +LINE + 5 +1C29 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526961.3672303293 + 20 +182110.9231273783 + 30 +0.0 + 11 +527004.6659355352 + 21 +182057.4209998459 + 31 +0.0 + 0 +LINE + 5 +1C2A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526998.7425810051 + 20 +182076.9908142976 + 30 +0.0 + 11 +526992.2801830577 + 21 +181673.8092979005 + 31 +0.0 + 0 +LINE + 5 +1C2B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526922.3970494072 + 20 +181977.1444343519 + 30 +0.0 + 11 +527218.6624664996 + 21 +181952.5002441074 + 31 +0.0 + 0 +LINE + 5 +1C2C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527216.5226249359 + 20 +181965.6424689295 + 30 +0.0 + 11 +527210.900127187 + 21 +181726.8870308509 + 31 +0.0 + 0 +LINE + 5 +1C2D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527510.2724370283 + 20 +182121.4202003876 + 30 +0.0 + 11 +527205.4837348044 + 21 +181951.2855846136 + 31 +0.0 + 0 +LINE + 5 +1C2E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527241.1336385168 + 20 +182299.7189575159 + 30 +0.0 + 11 +527335.0458597796 + 21 +182019.1530300846 + 31 +0.0 + 0 +LINE + 5 +1C2F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527128.0412715281 + 20 +182137.647022305 + 30 +0.0 + 11 +527139.0970181055 + 21 +181713.7213250218 + 31 +0.0 + 0 +LINE + 5 +1C30 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527644.5683360037 + 20 +181893.7221573058 + 30 +0.0 + 11 +527280.5326643672 + 21 +181897.9420612434 + 31 +0.0 + 0 +LINE + 5 +1C31 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527274.414149519 + 20 +182533.1356143514 + 30 +0.0 + 11 +527336.2037937141 + 21 +182220.4267102733 + 31 +0.0 + 0 +LINE + 5 +1C32 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527325.0335880328 + 20 +182244.5270912905 + 30 +0.0 + 11 +527691.2728910904 + 21 +182079.0561384222 + 31 +0.0 + 0 +LINE + 5 +1C33 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527598.9071578056 + 20 +182144.6278645905 + 30 +0.0 + 11 +527531.865750263 + 21 +181991.8653653745 + 31 +0.0 + 0 +LINE + 5 +1C34 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527450.9444338949 + 20 +182540.5796976902 + 30 +0.0 + 11 +527511.1304576061 + 21 +182404.0055193513 + 31 +0.0 + 0 +LINE + 5 +1C35 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527126.0397775233 + 20 +182021.4162457452 + 30 +0.0 + 11 +527172.8048829372 + 21 +182016.6063753122 + 31 +0.0 + 0 +LINE + 5 +1C36 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527167.3925177578 + 20 +182080.1912548282 + 30 +0.0 + 11 +527171.7006414443 + 21 +182015.0587919673 + 31 +0.0 + 0 +LINE + 5 +1C37 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527122.7530609956 + 20 +182101.7060043448 + 30 +0.0 + 11 +527225.4027840479 + 21 +182120.3064718471 + 31 +0.0 + 0 +LINE + 5 +1C38 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527179.0309342328 + 20 +182264.0508027241 + 30 +0.0 + 11 +527265.1472959734 + 21 +181978.1439934599 + 31 +0.0 + 0 +LINE + 5 +1C39 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527211.737515536 + 20 +181895.3360586223 + 30 +0.0 + 11 +527280.5326643672 + 21 +181897.9420612434 + 31 +0.0 + 0 +LINE + 5 +1C3A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527369.1858417139 + 20 +182421.6441571977 + 30 +0.0 + 11 +527393.3662381814 + 21 +182311.5538353243 + 31 +0.0 + 0 +LINE + 5 +1C3B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527802.8122269755 + 20 +182483.2968750188 + 30 +0.0 + 11 +527583.6445782589 + 21 +182670.5338326724 + 31 +0.0 + 0 +LINE + 5 +1C3C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527384.3609804307 + 20 +182352.4964698768 + 30 +0.0 + 11 +527384.3733994724 + 21 +182352.4971056026 + 31 +0.0 + 0 +LINE + 5 +1C3D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527689.197375687 + 20 +182379.5744221103 + 30 +0.0 + 11 +527946.2242562205 + 21 +182381.2580377173 + 31 +0.0 + 0 +LINE + 5 +1C3E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527886.3906322288 + 20 +182282.7998223323 + 30 +0.0 + 11 +527887.5998568822 + 21 +182688.0099292871 + 31 +0.0 + 0 +LINE + 5 +1C3F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527814.4709905778 + 20 +182564.0233585824 + 30 +0.0 + 11 +527866.6988063393 + 21 +182374.0463819468 + 31 +0.0 + 0 +LINE + 5 +1C40 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527572.1680598442 + 20 +182088.2086467597 + 30 +0.0 + 11 +527906.2226569025 + 21 +182703.8343193632 + 31 +0.0 + 0 +LINE + 5 +1C41 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527881.2945578066 + 20 +182520.6635047166 + 30 +0.0 + 11 +527993.0588859202 + 21 +182481.5747727534 + 31 +0.0 + 0 +LINE + 5 +1C42 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527605.0161793467 + 20 +183011.740254553 + 30 +0.0 + 11 +527444.9266236437 + 21 +182966.5454992318 + 31 +0.0 + 0 +LINE + 5 +1C43 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527070.7837827931 + 20 +182765.6579821643 + 30 +0.0 + 11 +526900.6797779977 + 21 +182664.0271809811 + 31 +0.0 + 0 +LINE + 5 +1C44 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524802.1481827238 + 20 +181562.0366289828 + 30 +0.0 + 11 +524281.0200600184 + 21 +181032.262673504 + 31 +0.0 + 0 +LINE + 5 +1C45 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524777.053703827 + 20 +181357.5184435995 + 30 +0.0 + 11 +524684.092533473 + 21 +181242.5579481624 + 31 +0.0 + 0 +LINE + 5 +1C46 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524613.2310495336 + 20 +181373.7712167126 + 30 +0.0 + 11 +525043.4239603823 + 21 +181130.0117733084 + 31 +0.0 + 0 +LINE + 5 +1C47 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524696.6030450924 + 20 +181272.7118425649 + 30 +0.0 + 11 +524686.699858292 + 21 +181191.3298719215 + 31 +0.0 + 0 +LINE + 5 +1C48 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524616.9155208406 + 20 +181274.995281273 + 30 +0.0 + 11 +524703.9691052645 + 21 +181263.2011336066 + 31 +0.0 + 0 +LINE + 5 +1C49 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524634.8557972559 + 20 +181281.3092651929 + 30 +0.0 + 11 +524496.5522201735 + 21 +181138.3884012488 + 31 +0.0 + 0 +LINE + 5 +1C4A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524531.9507471499 + 20 +181347.9530573438 + 30 +0.0 + 11 +524792.8333296382 + 21 +181002.4107307421 + 31 +0.0 + 0 +LINE + 5 +1C4B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524531.7445357123 + 20 +181094.7342720634 + 30 +0.0 + 11 +524689.3308695419 + 21 +181194.7661977195 + 31 +0.0 + 0 +LINE + 5 +1C4C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524496.2389124904 + 20 +181143.8562075754 + 30 +0.0 + 11 +524532.5821545919 + 21 +181094.6039037225 + 31 +0.0 + 0 +LINE + 5 +1C4D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524279.4212524852 + 20 +180940.2824972378 + 30 +0.0 + 11 +524521.708080378 + 21 +181112.4540953071 + 31 +0.0 + 0 +LINE + 5 +1C4E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524332.9951300431 + 20 +180982.8443014322 + 30 +0.0 + 11 +524404.6669084259 + 21 +180895.3174055657 + 31 +0.0 + 0 +LINE + 5 +1C4F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524337.9495387016 + 20 +180848.5670295033 + 30 +0.0 + 11 +524993.7823634268 + 21 +181334.4770326099 + 31 +0.0 + 0 +LINE + 5 +1C50 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524804.7283952061 + 20 +181107.8431824673 + 30 +0.0 + 11 +525134.2787297177 + 21 +180817.5324099774 + 31 +0.0 + 0 +LINE + 5 +1C51 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524858.1013985478 + 20 +181152.3510417901 + 30 +0.0 + 11 +524713.8250135487 + 21 +181022.7599817463 + 31 +0.0 + 0 +LINE + 5 +1C52 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524905.8017889537 + 20 +181097.6055309042 + 30 +0.0 + 11 +524857.6059376409 + 21 +181055.0284758354 + 31 +0.0 + 0 +LINE + 5 +1C53 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524888.6026609199 + 20 +181149.1948226532 + 30 +0.0 + 11 +524903.2237374958 + 21 +181081.9380040936 + 31 +0.0 + 0 +LINE + 5 +1C54 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524891.6697933747 + 20 +181098.8072110047 + 30 +0.0 + 11 +525210.1397417366 + 21 +180851.473449173 + 31 +0.0 + 0 +LINE + 5 +1C55 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525078.9775679318 + 20 +181186.9861926767 + 30 +0.0 + 11 +524851.094926959 + 21 +180849.375179546 + 31 +0.0 + 0 +LINE + 5 +1C56 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524842.1852879555 + 20 +180859.2703969775 + 30 +0.0 + 11 +525031.9003218494 + 21 +180714.2049717113 + 31 +0.0 + 0 +LINE + 5 +1C57 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524667.3719613483 + 20 +180783.4673521569 + 30 +0.0 + 11 +524860.2914843905 + 21 +180858.8924111912 + 31 +0.0 + 0 +LINE + 5 +1C58 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524677.0544180947 + 20 +180870.1174212477 + 30 +0.0 + 11 +524726.2643675579 + 21 +180800.3341808871 + 31 +0.0 + 0 +LINE + 5 +1C59 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525423.1171166157 + 20 +181253.2601729294 + 30 +0.0 + 11 +525126.9555856972 + 21 +181071.2670086604 + 31 +0.0 + 0 +LINE + 5 +1C5A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525322.0041594378 + 20 +181083.8277647864 + 30 +0.0 + 11 +525028.8409972251 + 21 +180713.6879130657 + 31 +0.0 + 0 +LINE + 5 +1C5B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524763.431323889 + 20 +181035.9405116734 + 30 +0.0 + 11 +525087.1132389359 + 21 +180761.9601397101 + 31 +0.0 + 0 +LINE + 5 +1C5C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524675.2302947439 + 20 +180519.5676355819 + 30 +0.0 + 11 +525089.7968232458 + 21 +180768.3984353517 + 31 +0.0 + 0 +LINE + 5 +1C5D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524468.5794109521 + 20 +180373.0130680584 + 30 +0.0 + 11 +524918.345269609 + 21 +180670.801917173 + 31 +0.0 + 0 +LINE + 5 +1C5E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524610.1124200717 + 20 +180585.388272364 + 30 +0.0 + 11 +524711.4732601816 + 21 +180526.0965543799 + 31 +0.0 + 0 +LINE + 5 +1C5F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524663.1774156499 + 20 +180617.6235927516 + 30 +0.0 + 11 +524682.3142602708 + 21 +180509.4599109629 + 31 +0.0 + 0 +LINE + 5 +1C60 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524818.6363339504 + 20 +180726.8746960876 + 30 +0.0 + 11 +524664.4485827883 + 21 +180596.3627473906 + 31 +0.0 + 0 +LINE + 5 +1C61 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524606.2118737778 + 20 +180858.155023537 + 30 +0.0 + 11 +524837.1099606695 + 21 +180615.3052638189 + 31 +0.0 + 0 +LINE + 5 +1C62 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524670.5069143573 + 20 +180926.1458448061 + 30 +0.0 + 11 +524592.5487836899 + 21 +180833.0330347883 + 31 +0.0 + 0 +LINE + 5 +1C63 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524528.7166376978 + 20 +180912.716519252 + 30 +0.0 + 11 +524638.1041728994 + 21 +180963.9229456919 + 31 +0.0 + 0 +LINE + 5 +1C64 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524631.3919774674 + 20 +180963.3563338301 + 30 +0.0 + 11 +524671.0368695406 + 21 +180924.0383554253 + 31 +0.0 + 0 +LINE + 5 +1C65 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524363.3830957445 + 20 +181169.3483862856 + 30 +0.0 + 11 +524718.5236090007 + 21 +180733.0081700438 + 31 +0.0 + 0 +LINE + 5 +1C66 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524731.5003627983 + 20 +180731.3853250246 + 30 +0.0 + 11 +524712.5467186364 + 21 +180716.2026393256 + 31 +0.0 + 0 +LINE + 5 +1C67 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524920.7041831621 + 20 +180712.5383351309 + 30 +0.0 + 11 +524945.5466481336 + 21 +180674.6306959616 + 31 +0.0 + 0 +LINE + 5 +1C68 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524920.6206858733 + 20 +180728.0727715202 + 30 +0.0 + 11 +524922.6578734268 + 21 +180704.0936910647 + 31 +0.0 + 0 +LINE + 5 +1C69 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524967.3350531292 + 20 +180771.9616969969 + 30 +0.0 + 11 +524916.4174040469 + 21 +180721.2738741675 + 31 +0.0 + 0 +LINE + 5 +1C6A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524712.7839783264 + 20 +180805.8009324259 + 30 +0.0 + 11 +524393.8048668058 + 21 +180510.9965713254 + 31 +0.0 + 0 +LINE + 5 +1C6B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524399.2505034822 + 20 +180542.2857734541 + 30 +0.0 + 11 +524559.8302091394 + 21 +180420.9248637786 + 31 +0.0 + 0 +LINE + 5 +1C6C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524347.3201296349 + 20 +180866.0461988797 + 30 +0.0 + 11 +524414.8002064813 + 21 +180509.6321081265 + 31 +0.0 + 0 +LINE + 5 +1C6D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524320.3012945151 + 20 +180612.5770980434 + 30 +0.0 + 11 +524670.5888307349 + 21 +180796.8717918515 + 31 +0.0 + 0 +LINE + 5 +1C6E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524589.2673918903 + 20 +180896.3942352395 + 30 +0.0 + 11 +524561.9130884548 + 21 +180873.7284942734 + 31 +0.0 + 0 +LINE + 5 +1C6F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524571.5360312731 + 20 +180687.7931066333 + 30 +0.0 + 11 +524624.479636645 + 21 +180610.9242907791 + 31 +0.0 + 0 +LINE + 5 +1C70 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524601.2702712349 + 20 +180637.3224243558 + 30 +0.0 + 11 +524678.6162067298 + 21 +180606.1745752426 + 31 +0.0 + 0 +LINE + 5 +1C71 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524609.9308592037 + 20 +180647.1847378564 + 30 +0.0 + 11 +524621.7261504309 + 21 +180567.9066278729 + 31 +0.0 + 0 +LINE + 5 +1C72 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524481.7577776428 + 20 +180476.4688388858 + 30 +0.0 + 11 +524627.9970410905 + 21 +180578.8630808189 + 31 +0.0 + 0 +LINE + 5 +1C73 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524142.4573055844 + 20 +180955.8171789115 + 30 +0.0 + 11 +524295.3029998789 + 21 +181044.3303311023 + 31 +0.0 + 0 +LINE + 5 +1C74 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524235.4919657421 + 20 +181022.7282783792 + 30 +0.0 + 11 +524371.3906109211 + 21 +180797.1836498444 + 31 +0.0 + 0 +LINE + 5 +1C75 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524855.327798902 + 20 +180964.7461489882 + 30 +0.0 + 11 +524829.8059644724 + 21 +180925.2651927524 + 31 +0.0 + 0 +LINE + 5 +1C76 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524783.6066146152 + 20 +180969.2873539066 + 30 +0.0 + 11 +524831.7040670197 + 21 +180925.1576278679 + 31 +0.0 + 0 +LINE + 5 +1C77 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524794.7704363647 + 20 +181017.5671077454 + 30 +0.0 + 11 +524716.0105759171 + 21 +180949.1578436337 + 31 +0.0 + 0 +LINE + 5 +1C78 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524632.9369456995 + 20 +181075.2988483744 + 30 +0.0 + 11 +524801.9989999381 + 21 +180829.1753973185 + 31 +0.0 + 0 +LINE + 5 +1C79 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524900.0096459172 + 20 +180818.993452846 + 30 +0.0 + 11 +524854.9146575729 + 21 +180766.9741700884 + 31 +0.0 + 0 +LINE + 5 +1C7A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524831.5059540864 + 20 +180788.5607520285 + 30 +0.0 + 11 +524876.8033334446 + 21 +180749.0548109575 + 31 +0.0 + 0 +LINE + 5 +1C7B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524839.9663818906 + 20 +180790.1373054382 + 30 +0.0 + 11 +524792.4847093471 + 21 +180736.9022916819 + 31 +0.0 + 0 +LINE + 5 +1C7C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524791.9913793488 + 20 +180740.5868489466 + 30 +0.0 + 11 +524833.3593439895 + 21 +180702.6358108023 + 31 +0.0 + 0 +LINE + 5 +1C7D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524877.9038921384 + 20 +180758.0230111801 + 30 +0.0 + 11 +524826.9640158099 + 21 +180699.6173881792 + 31 +0.0 + 0 +LINE + 5 +1C7E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524391.0079010363 + 20 +181025.6511740913 + 30 +0.0 + 11 +524461.7269989744 + 21 +180937.8822745294 + 31 +0.0 + 0 +LINE + 5 +1C7F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525008.009930925 + 20 +181086.4024399666 + 30 +0.0 + 11 +525225.8263071603 + 21 +180936.1700333339 + 31 +0.0 + 0 +LINE + 5 +1C80 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525597.873440998 + 20 +181037.2752526085 + 30 +0.0 + 11 +526110.5041094252 + 21 +180741.7467624144 + 31 +0.0 + 0 +LINE + 5 +1C81 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525570.8176342342 + 20 +181166.5921935663 + 30 +0.0 + 11 +525451.2708726696 + 21 +180952.4554538928 + 31 +0.0 + 0 +LINE + 5 +1C82 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524652.5268457475 + 20 +181472.4103574203 + 30 +0.0 + 11 +525810.6022995788 + 21 +180839.9092790389 + 31 +0.0 + 0 +LINE + 5 +1C83 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525463.7813842892 + 20 +180982.6093482953 + 30 +0.0 + 11 +525453.8781974885 + 21 +180901.2273776519 + 31 +0.0 + 0 +LINE + 5 +1C84 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525384.0938600372 + 20 +180984.8927870034 + 30 +0.0 + 11 +525471.1474444611 + 21 +180973.0986393367 + 31 +0.0 + 0 +LINE + 5 +1C85 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525400.9027190662 + 20 +180989.7782740392 + 30 +0.0 + 11 +525262.5991419836 + 21 +180846.8574100953 + 31 +0.0 + 0 +LINE + 5 +1C86 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525247.8458925852 + 20 +181125.7758109726 + 30 +0.0 + 11 +525560.0116688346 + 21 +180712.3082364724 + 31 +0.0 + 0 +LINE + 5 +1C87 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525298.922874909 + 20 +180804.6317777938 + 30 +0.0 + 11 +525456.5092087385 + 21 +180904.6637034498 + 31 +0.0 + 0 +LINE + 5 +1C88 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525263.4172516872 + 20 +180853.7537133059 + 30 +0.0 + 11 +525299.7604937888 + 21 +180804.5014094529 + 31 +0.0 + 0 +LINE + 5 +1C89 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525046.5995916819 + 20 +180650.180002968 + 30 +0.0 + 11 +525288.8864195746 + 21 +180822.3516010374 + 31 +0.0 + 0 +LINE + 5 +1C8A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525100.1734692398 + 20 +180692.7418071628 + 30 +0.0 + 11 +525171.8452476225 + 21 +180605.214911296 + 31 +0.0 + 0 +LINE + 5 +1C8B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525105.1278778982 + 20 +180558.4645352336 + 30 +0.0 + 11 +525713.1359778347 + 21 +181007.015257858 + 31 +0.0 + 0 +LINE + 5 +1C8C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525571.9067344027 + 20 +180817.7406881978 + 30 +0.0 + 11 +525901.4570689142 + 21 +180527.4299157075 + 31 +0.0 + 0 +LINE + 5 +1C8D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525625.2797377445 + 20 +180862.2485475206 + 30 +0.0 + 11 +525481.0033527453 + 21 +180732.6574874768 + 31 +0.0 + 0 +LINE + 5 +1C8E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525672.9801281504 + 20 +180807.5030366347 + 30 +0.0 + 11 +525624.7842768374 + 21 +180764.9259815658 + 31 +0.0 + 0 +LINE + 5 +1C8F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525655.7810001165 + 20 +180859.0923283836 + 30 +0.0 + 11 +525670.4020766922 + 21 +180791.8355098239 + 31 +0.0 + 0 +LINE + 5 +1C90 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525658.8481325714 + 20 +180808.7047167351 + 30 +0.0 + 11 +525977.3180809332 + 21 +180561.3709549034 + 31 +0.0 + 0 +LINE + 5 +1C91 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525846.1559071286 + 20 +180896.8836984073 + 30 +0.0 + 11 +525618.2732661557 + 21 +180559.2726852762 + 31 +0.0 + 0 +LINE + 5 +1C92 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525609.3636271522 + 20 +180569.167902708 + 30 +0.0 + 11 +525799.0786610461 + 21 +180424.1024774419 + 31 +0.0 + 0 +LINE + 5 +1C93 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525434.5503005449 + 20 +180493.3648578872 + 30 +0.0 + 11 +525627.4698235871 + 21 +180568.7899169216 + 31 +0.0 + 0 +LINE + 5 +1C94 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525444.2327572913 + 20 +180580.0149269779 + 30 +0.0 + 11 +525493.4427067547 + 21 +180510.2316866175 + 31 +0.0 + 0 +LINE + 5 +1C95 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525961.6524090845 + 20 +180835.2787713809 + 30 +0.0 + 11 +525907.3690808953 + 21 +180763.3384399991 + 31 +0.0 + 0 +LINE + 5 +1C96 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526089.1824986345 + 20 +180793.7252705167 + 30 +0.0 + 11 +525796.0193364219 + 21 +180423.5854187961 + 31 +0.0 + 0 +LINE + 5 +1C97 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525530.6096630857 + 20 +180745.8380174036 + 30 +0.0 + 11 +525854.2915781323 + 21 +180471.8576454403 + 31 +0.0 + 0 +LINE + 5 +1C98 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525389.9409016577 + 20 +180200.0512254642 + 30 +0.0 + 11 +525856.9751624424 + 21 +180478.295941082 + 31 +0.0 + 0 +LINE + 5 +1C99 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525377.2907592685 + 20 +180295.2857780945 + 30 +0.0 + 11 +525478.6515993782 + 21 +180235.9940601101 + 31 +0.0 + 0 +LINE + 5 +1C9A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525430.3557548465 + 20 +180327.521098482 + 30 +0.0 + 11 +525449.4925994674 + 21 +180219.3574166934 + 31 +0.0 + 0 +LINE + 5 +1C9B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525585.8146731471 + 20 +180436.772201818 + 30 +0.0 + 11 +525431.626921985 + 21 +180306.260253121 + 31 +0.0 + 0 +LINE + 5 +1C9C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525373.3902129744 + 20 +180568.0525292673 + 30 +0.0 + 11 +525604.2882998661 + 21 +180325.2027695491 + 31 +0.0 + 0 +LINE + 5 +1C9D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525437.6852535538 + 20 +180636.0433505364 + 30 +0.0 + 11 +525359.7271228865 + 21 +180542.9305405187 + 31 +0.0 + 0 +LINE + 5 +1C9E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525295.8949768945 + 20 +180622.6140249824 + 30 +0.0 + 11 +525405.282512096 + 21 +180673.8204514221 + 31 +0.0 + 0 +LINE + 5 +1C9F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525398.5703166641 + 20 +180673.2538395604 + 30 +0.0 + 11 +525438.2152087374 + 21 +180633.9358611555 + 31 +0.0 + 0 +LINE + 5 +1CA0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525130.5614349412 + 20 +180879.2458920159 + 30 +0.0 + 11 +525485.7019481972 + 21 +180442.9056757742 + 31 +0.0 + 0 +LINE + 5 +1CA1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525498.678701995 + 20 +180441.282830755 + 30 +0.0 + 11 +525479.7250578333 + 21 +180426.1001450563 + 31 +0.0 + 0 +LINE + 5 +1CA2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525687.8825223587 + 20 +180422.4358408612 + 30 +0.0 + 11 +525712.7249873302 + 21 +180384.528201692 + 31 +0.0 + 0 +LINE + 5 +1CA3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525687.79902507 + 20 +180437.9702772509 + 30 +0.0 + 11 +525689.8362126233 + 21 +180413.9911967952 + 31 +0.0 + 0 +LINE + 5 +1CA4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525734.5133923259 + 20 +180481.8592027276 + 30 +0.0 + 11 +525683.5957432436 + 21 +180431.1713798979 + 31 +0.0 + 0 +LINE + 5 +1CA5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525479.962317523 + 20 +180515.6984381563 + 30 +0.0 + 11 +525223.7445992931 + 21 +180269.921447433 + 31 +0.0 + 0 +LINE + 5 +1CA6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525114.4984688314 + 20 +180575.9437046102 + 30 +0.0 + 11 +525148.0515304179 + 21 +180374.6954986379 + 31 +0.0 + 0 +LINE + 5 +1CA7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525117.2592444702 + 20 +180379.0745464745 + 30 +0.0 + 11 +525437.7671699316 + 21 +180506.769297582 + 31 +0.0 + 0 +LINE + 5 +1CA8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525356.4457310868 + 20 +180606.2917409695 + 30 +0.0 + 11 +525329.0914276513 + 21 +180583.626000004 + 31 +0.0 + 0 +LINE + 5 +1CA9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525338.7143704697 + 20 +180397.6906123634 + 30 +0.0 + 11 +525391.6579758414 + 21 +180320.8217965096 + 31 +0.0 + 0 +LINE + 5 +1CAA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525368.4486104316 + 20 +180347.2199300862 + 30 +0.0 + 11 +525445.7945459263 + 21 +180316.0720809731 + 31 +0.0 + 0 +LINE + 5 +1CAB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525377.1091984003 + 20 +180357.0822435868 + 30 +0.0 + 11 +525388.9044896276 + 21 +180277.8041336032 + 31 +0.0 + 0 +LINE + 5 +1CAC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525290.4199535019 + 20 +180218.7723081885 + 30 +0.0 + 11 +525395.1753802871 + 21 +180288.7605865493 + 31 +0.0 + 0 +LINE + 5 +1CAD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525014.2560689964 + 20 +180746.2368038634 + 30 +0.0 + 11 +525138.5689501177 + 21 +180507.0811555747 + 31 +0.0 + 0 +LINE + 5 +1CAE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525622.5061380987 + 20 +180674.6436547186 + 30 +0.0 + 11 +525596.9843036692 + 21 +180635.1626984828 + 31 +0.0 + 0 +LINE + 5 +1CAF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525550.7849538118 + 20 +180679.1848596368 + 30 +0.0 + 11 +525598.8824062162 + 21 +180635.0551335983 + 31 +0.0 + 0 +LINE + 5 +1CB0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525561.9487755611 + 20 +180727.4646134757 + 30 +0.0 + 11 +525483.1889151137 + 21 +180659.0553493637 + 31 +0.0 + 0 +LINE + 5 +1CB1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525400.1152848961 + 20 +180785.1963541049 + 30 +0.0 + 11 +525569.1773391347 + 21 +180539.072903049 + 31 +0.0 + 0 +LINE + 5 +1CB2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525667.1879851137 + 20 +180528.8909585764 + 30 +0.0 + 11 +525622.0929967695 + 21 +180476.8716758188 + 31 +0.0 + 0 +LINE + 5 +1CB3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525598.6842932832 + 20 +180498.4582577588 + 30 +0.0 + 11 +525643.9816726412 + 21 +180458.9523166879 + 31 +0.0 + 0 +LINE + 5 +1CB4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525607.1447210872 + 20 +180500.0348111686 + 30 +0.0 + 11 +525559.6630485436 + 21 +180446.7997974125 + 31 +0.0 + 0 +LINE + 5 +1CB5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525559.1697185455 + 20 +180450.484354677 + 30 +0.0 + 11 +525600.537683186 + 21 +180412.5333165327 + 31 +0.0 + 0 +LINE + 5 +1CB6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525645.082231335 + 20 +180467.9205169104 + 30 +0.0 + 11 +525594.1423550066 + 21 +180409.5148939096 + 31 +0.0 + 0 +LINE + 5 +1CB7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525158.1862402328 + 20 +180735.5486798217 + 30 +0.0 + 11 +525228.9053381709 + 21 +180647.7797802598 + 31 +0.0 + 0 +LINE + 5 +1CB8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525775.1882701215 + 20 +180796.2999456968 + 30 +0.0 + 11 +525993.0046463569 + 21 +180646.0675390643 + 31 +0.0 + 0 +LINE + 5 +1CB9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525418.1832166672 + 20 +180231.9287973527 + 30 +0.0 + 11 +525223.1231718565 + 21 +179691.1013030836 + 31 +0.0 + 0 +LINE + 5 +1CBA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525223.754888888 + 20 +180352.4700418386 + 30 +0.0 + 11 +525106.2860575173 + 21 +180229.8569459029 + 31 +0.0 + 0 +LINE + 5 +1CBB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524881.8800376533 + 20 +180654.3909091102 + 30 +0.0 + 11 +525421.6381162864 + 21 +180125.682277721 + 31 +0.0 + 0 +LINE + 5 +1CBC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525212.2662827289 + 20 +180234.9251137939 + 30 +0.0 + 11 +524986.8238694697 + 21 +179857.9887050464 + 31 +0.0 + 0 +LINE + 5 +1CBD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525264.71496686 + 20 +180189.3316651403 + 30 +0.0 + 11 +525113.7772041884 + 21 +180311.099107059 + 31 +0.0 + 0 +LINE + 5 +1CBE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525218.275614624 + 20 +180133.512450071 + 30 +0.0 + 11 +525168.5585218523 + 21 +180174.3028458577 + 31 +0.0 + 0 +LINE + 5 +1CBF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525266.4625094876 + 20 +180158.7173740281 + 30 +0.0 + 11 +525202.3974678277 + 21 +180133.5593542309 + 31 +0.0 + 0 +LINE + 5 +1CC0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525217.2085946082 + 20 +180147.655250444 + 30 +0.0 + 11 +525023.8187307353 + 21 +179793.8227218339 + 31 +0.0 + 0 +LINE + 5 +1CC1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525334.1253874497 + 20 +179976.8038566251 + 30 +0.0 + 11 +524964.4981331313 + 21 +180147.9394376977 + 31 +0.0 + 0 +LINE + 5 +1CC2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524972.8461245731 + 20 +180158.3128669318 + 30 +0.0 + 11 +524859.8864172327 + 21 +179947.8945307285 + 31 +0.0 + 0 +LINE + 5 +1CC3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524870.1391553542 + 20 +180318.8029888629 + 30 +0.0 + 11 +524975.3599812941 + 21 +180140.3780475297 + 31 +0.0 + 0 +LINE + 5 +1CC4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524957.2244979571 + 20 +180323.0606344381 + 30 +0.0 + 11 +524896.180502328 + 21 +180263.353429186 + 31 +0.0 + 0 +LINE + 5 +1CC5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525270.1249543759 + 20 +179800.8353309385 + 30 +0.0 + 11 +525190.4496126549 + 21 +179842.9533902513 + 31 +0.0 + 0 +LINE + 5 +1CC6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525134.6987595177 + 20 +180264.2290642028 + 30 +0.0 + 11 +524915.8342363212 + 21 +179901.0024863818 + 31 +0.0 + 0 +LINE + 5 +1CC7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524610.868708002 + 20 +180268.9667676791 + 30 +0.0 + 11 +524899.8257795197 + 21 +179931.447802198 + 31 +0.0 + 0 +LINE + 5 +1CC8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524458.7969630624 + 20 +180421.892763538 + 30 +0.0 + 11 +524798.9324632437 + 21 +180053.0762331568 + 31 +0.0 + 0 +LINE + 5 +1CC9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524665.464301145 + 20 +180343.7465446084 + 30 +0.0 + 11 +524623.0929854331 + 21 +180234.228512604 + 31 +0.0 + 0 +LINE + 5 +1CCA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524705.7483468587 + 20 +180296.5003246841 + 30 +0.0 + 11 +524602.0198271621 + 21 +180260.3617707335 + 31 +0.0 + 0 +LINE + 5 +1CCB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524838.3894159758 + 20 +180160.4502396316 + 30 +0.0 + 11 +524684.9621933807 + 21 +180291.8554097274 + 31 +0.0 + 0 +LINE + 5 +1CCC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524912.8934556925 + 20 +180364.2409513169 + 30 +0.0 + 11 +524731.1929690219 + 21 +180124.4233765795 + 31 +0.0 + 0 +LINE + 5 +1CCD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524885.0114208989 + 20 +180451.0797803243 + 30 +0.0 + 11 +524958.7659591307 + 21 +180354.6031841114 + 31 +0.0 + 0 +LINE + 5 +1CCE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525026.0671377887 + 20 +180431.3791693508 + 30 +0.0 + 11 +524919.0566906104 + 21 +180487.3835902562 + 31 +0.0 + 0 +LINE + 5 +1CCF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524925.7371762494 + 20 +180486.5200347311 + 30 +0.0 + 11 +524884.3885775652 + 21 +180448.9978508899 + 31 +0.0 + 0 +LINE + 5 +1CD0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525202.6127386466 + 20 +180680.4308629602 + 30 +0.0 + 11 +525202.6044691076 + 21 +180680.4215757932 + 31 +0.0 + 0 +LINE + 5 +1CD1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525105.2808209763 + 20 +180571.121535247 + 30 +0.0 + 11 +524828.4815915741 + 21 +180260.2601199806 + 31 +0.0 + 0 +LINE + 5 +1CD2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524828.9486333343 + 20 +180247.1906273707 + 30 +0.0 + 11 +524810.9380603054 + 21 +180263.4809260549 + 31 +0.0 + 0 +LINE + 5 +1CD3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524840.5110408532 + 20 +180057.4023100257 + 30 +0.0 + 11 +524807.0494777431 + 21 +180026.8333557182 + 31 +0.0 + 0 +LINE + 5 +1CD4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524855.8334198841 + 20 +180059.9616823253 + 30 +0.0 + 11 +524832.4859485963 + 21 +180054.1271286077 + 31 +0.0 + 0 +LINE + 5 +1CD5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524906.6093788347 + 20 +180020.8429926709 + 30 +0.0 + 11 +524848.451298822 + 21 +180063.0271140968 + 31 +0.0 + 0 +LINE + 5 +1CD6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524899.427885137 + 20 +180277.5330191347 + 30 +0.0 + 11 +524625.9545763003 + 21 +180497.9917991143 + 31 +0.0 + 0 +LINE + 5 +1CD7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524709.6465865055 + 20 +180552.8312479539 + 30 +0.0 + 11 +524883.8850270141 + 21 +180317.7645937127 + 31 +0.0 + 0 +LINE + 5 +1CD8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524969.1676192615 + 20 +180413.9143342909 + 30 +0.0 + 11 +524942.4302544877 + 21 +180437.3046539747 + 31 +0.0 + 0 +LINE + 5 +1CD9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524760.4080436268 + 20 +180398.1576980424 + 30 +0.0 + 11 +524692.9644496469 + 21 +180333.6348196841 + 31 +0.0 + 0 +LINE + 5 +1CDA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524715.3241523529 + 20 +180360.7563940109 + 30 +0.0 + 11 +524696.9074980718 + 21 +180279.4335246133 + 31 +0.0 + 0 +LINE + 5 +1CDB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524726.4412079268 + 20 +180353.7791390408 + 30 +0.0 + 11 +524650.0581049922 + 21 +180329.4939747678 + 31 +0.0 + 0 +LINE + 5 +1CDC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524537.4723958892 + 20 +180453.0920036419 + 30 +0.0 + 11 +524661.8742680996 + 21 +180325.0503028359 + 31 +0.0 + 0 +LINE + 5 +1CDD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525079.0679994453 + 20 +180162.1564531274 + 30 +0.0 + 11 +525036.0227337291 + 21 +180181.0565863907 + 31 +0.0 + 0 +LINE + 5 +1CDE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525072.1152669157 + 20 +180233.6841423673 + 30 +0.0 + 11 +525036.2191946904 + 21 +180179.1656166461 + 31 +0.0 + 0 +LINE + 5 +1CDF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525121.5573963299 + 20 +180230.3612842898 + 30 +0.0 + 11 +525041.4651988386 + 21 +180297.2057525356 + 31 +0.0 + 0 +LINE + 5 +1CE0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525152.7464166145 + 20 +180399.3295582072 + 30 +0.0 + 11 +524936.7285080018 + 21 +180193.1864174004 + 31 +0.0 + 0 +LINE + 5 +1CE1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524942.3044836137 + 20 +180094.8061998036 + 30 +0.0 + 11 +524883.7603928235 + 21 +180131.029854864 + 31 +0.0 + 0 +LINE + 5 +1CE2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524901.33831756 + 20 +180157.581022084 + 30 +0.0 + 11 +524869.560407142 + 21 +180106.5640017272 + 31 +0.0 + 0 +LINE + 5 +1CE3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524904.243703815 + 20 +180149.4802140999 + 30 +0.0 + 11 +524844.1188824767 + 21 +180187.8661721603 + 31 +0.0 + 0 +LINE + 5 +1CE4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524847.6776396538 + 20 +180188.9406879022 + 30 +0.0 + 11 +524816.8081996556 + 21 +180142.0507372842 + 31 +0.0 + 0 +LINE + 5 +1CE5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524878.5893528519 + 20 +180106.9074897788 + 30 +0.0 + 11 +524812.8086682417 + 21 +180147.8829620847 + 31 +0.0 + 0 +LINE + 5 +1CE6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525223.5127926947 + 20 +180030.8256179181 + 30 +0.0 + 11 +525109.9329272069 + 21 +179791.8415935258 + 31 +0.0 + 0 +LINE + 5 +1CE7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524672.8650839235 + 20 +181333.8745039805 + 30 +0.0 + 11 +524859.5012256396 + 21 +182053.1810553086 + 31 +0.0 + 0 +LINE + 5 +1CE8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524716.8211785645 + 20 +181530.7940420282 + 30 +0.0 + 11 +525208.540654474 + 21 +181263.8590629573 + 31 +0.0 + 0 +LINE + 5 +1CE9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524835.4109704701 + 20 +181460.5088428871 + 30 +0.0 + 11 +524886.2527054516 + 21 +181599.335399024 + 31 +0.0 + 0 +LINE + 5 +1CEA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524737.2758838151 + 20 +181592.6887182873 + 30 +0.0 + 11 +525600.752012998 + 21 +181111.7085048984 + 31 +0.0 + 0 +LINE + 5 +1CEB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524866.8151658661 + 20 +181573.106554149 + 30 +0.0 + 11 +524931.5378577799 + 21 +181623.4262461793 + 31 +0.0 + 0 +LINE + 5 +1CEC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524823.9027735845 + 20 +181640.2916879391 + 30 +0.0 + 11 +524878.7593920745 + 21 +181571.6755099045 + 31 +0.0 + 0 +LINE + 5 +1CED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524827.7064194305 + 20 +181621.6569840489 + 30 +0.0 + 11 +524879.2308113621 + 21 +181813.7493832228 + 31 +0.0 + 0 +LINE + 5 +1CEE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524717.6514214086 + 20 +181675.682364936 + 30 +0.0 + 11 +525148.1439612566 + 21 +181629.4720364983 + 31 +0.0 + 0 +LINE + 5 +1CEF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524934.7650866334 + 20 +181805.9952657354 + 30 +0.0 + 11 +524929.9422093081 + 21 +181619.4032546132 + 31 +0.0 + 0 +LINE + 5 +1CF0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524874.3793247449 + 20 +181811.2080950981 + 30 +0.0 + 11 +524935.3073960814 + 21 +181805.343727744 + 31 +0.0 + 0 +LINE + 5 +1CF1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524937.5832628485 + 20 +182101.8236752705 + 30 +0.0 + 11 +524914.4064158528 + 21 +181805.4981787039 + 31 +0.0 + 0 +LINE + 5 +1CF2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524928.6053765027 + 20 +182033.9925239486 + 30 +0.0 + 11 +525040.5229816188 + 21 +182017.4924942015 + 31 +0.0 + 0 +LINE + 5 +1CF3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525046.3391693385 + 20 +182098.7511986293 + 30 +0.0 + 11 +524968.8315460129 + 21 +181292.6000975962 + 31 +0.0 + 0 +LINE + 5 +1CF4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525063.8136333624 + 20 +181565.0834485425 + 30 +0.0 + 11 +525482.2168983525 + 21 +181431.582604177 + 31 +0.0 + 0 +LINE + 5 +1CF5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525053.0631203627 + 20 +181496.4244833779 + 30 +0.0 + 11 +525090.0831673517 + 21 +181686.7900113307 + 31 +0.0 + 0 +LINE + 5 +1CF6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525124.5401973068 + 20 +181483.640678055 + 30 +0.0 + 11 +525136.2950800057 + 21 +181546.8662143109 + 31 +0.0 + 0 +LINE + 5 +1CF7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525071.4460584255 + 20 +181471.8815350281 + 30 +0.0 + 11 +525136.6554013828 + 21 +181493.9041850524 + 31 +0.0 + 0 +LINE + 5 +1CF8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525116.2465394077 + 20 +181495.1460060711 + 30 +0.0 + 11 +525492.088159179 + 21 +181349.0632398076 + 31 +0.0 + 0 +LINE + 5 +1CF9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525136.866173508 + 20 +181289.1494869064 + 30 +0.0 + 11 +525309.3652517367 + 21 +181658.142389622 + 31 +0.0 + 0 +LINE + 5 +1CFA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525296.2978940966 + 20 +181660.6999586831 + 30 +0.0 + 11 +525518.2396293072 + 21 +181572.5090415504 + 31 +0.0 + 0 +LINE + 5 +1CFB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525271.4829984441 + 20 +181849.6179877786 + 30 +0.0 + 11 +525305.9274088119 + 21 +181645.3621078251 + 31 +0.0 + 0 +LINE + 5 +1CFC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525202.1277142461 + 20 +181796.7802266995 + 30 +0.0 + 11 +525287.2804677732 + 21 +181790.4297678073 + 31 +0.0 + 0 +LINE + 5 +1CFD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525371.3681014678 + 20 +181183.7777599395 + 30 +0.0 + 11 +525517.1109097619 + 21 +181575.3991642102 + 31 +0.0 + 0 +LINE + 5 +1CFE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525104.2704918624 + 20 +181637.4622076297 + 30 +0.0 + 11 +525505.6490466426 + 21 +181500.602856059 + 31 +0.0 + 0 +LINE + 5 +1CFF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525501.9037164204 + 20 +181978.5020695708 + 30 +0.0 + 11 +525501.5052255752 + 21 +181494.9919717723 + 31 +0.0 + 0 +LINE + 5 +1D00 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525521.4196865071 + 20 +182231.0925601788 + 30 +0.0 + 11 +525497.1132152171 + 21 +181692.2264156459 + 31 +0.0 + 0 +LINE + 5 +1D01 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525411.9747038597 + 20 +182000.5353745444 + 30 +0.0 + 11 +525514.9292324447 + 21 +181944.0562388116 + 31 +0.0 + 0 +LINE + 5 +1D02 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525411.5936965098 + 20 +181938.4478196756 + 30 +0.0 + 11 +525514.2151067717 + 21 +181977.6198382092 + 31 +0.0 + 0 +LINE + 5 +1D03 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525397.7689600213 + 20 +181748.9427919842 + 30 +0.0 + 11 +525430.4852564121 + 21 +181948.2838948999 + 31 +0.0 + 0 +LINE + 5 +1D04 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525175.9815577455 + 20 +181863.6991593308 + 30 +0.0 + 11 +525502.9710926166 + 21 +181790.4340488745 + 31 +0.0 + 0 +LINE + 5 +1D05 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524784.2330615084 + 20 +181912.0751880627 + 30 +0.0 + 11 +525341.0568122784 + 21 +181831.6707165202 + 31 +0.0 + 0 +LINE + 5 +1D06 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525349.1180495949 + 20 +181821.3728420787 + 30 +0.0 + 11 +525352.4014790639 + 21 +181845.4347136385 + 31 +0.0 + 0 +LINE + 5 +1D07 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525462.5226132335 + 20 +181668.7533819362 + 30 +0.0 + 11 +525507.8082858266 + 21 +181666.9244393336 + 31 +0.0 + 0 +LINE + 5 +1D08 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525449.1537364944 + 20 +181660.8414402994 + 30 +0.0 + 11 +525470.770769125 + 21 +181671.4173720726 + 31 +0.0 + 0 +LINE + 5 +1D09 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525435.5121121047 + 20 +181598.2125653963 + 30 +0.0 + 11 +525452.8258801166 + 21 +181667.9412955474 + 31 +0.0 + 0 +LINE + 5 +1D0A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525275.6629654501 + 20 +181799.1841898901 + 30 +0.0 + 11 +525364.6241005938 + 21 +182224.3232275521 + 31 +0.0 + 0 +LINE + 5 +1D0B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525036.1607473376 + 20 +182081.7297691328 + 30 +0.0 + 11 +525376.5846581334 + 21 +182207.013949368 + 31 +0.0 + 0 +LINE + 5 +1D0C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525239.7094067614 + 20 +182235.172089817 + 30 +0.0 + 11 +525261.6374529488 + 21 +181839.9695430297 + 31 +0.0 + 0 +LINE + 5 +1D0D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525304.3029185713 + 20 +181980.9988828615 + 30 +0.0 + 11 +525397.4527456271 + 21 +181975.0870371206 + 31 +0.0 + 0 +LINE + 5 +1D0E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525362.8796105945 + 20 +181981.4300989267 + 30 +0.0 + 11 +525429.3494648776 + 21 +181931.0878630456 + 31 +0.0 + 0 +LINE + 5 +1D0F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525358.8702955248 + 20 +181968.9322429417 + 30 +0.0 + 11 +525432.939661286 + 21 +181999.5570151602 + 31 +0.0 + 0 +LINE + 5 +1D10 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525447.6529162399 + 20 +182281.8852571326 + 30 +0.0 + 11 +525426.7636260753 + 21 +181988.54681444 + 31 +0.0 + 0 +LINE + 5 +1D11 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524853.8675979557 + 20 +182211.3322892552 + 30 +0.0 + 11 +524856.4895709922 + 21 +182034.7267694308 + 31 +0.0 + 0 +LINE + 5 +1D12 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524844.2820292215 + 20 +182097.1365796394 + 30 +0.0 + 11 +525107.6038457547 + 21 +182096.4716284987 + 31 +0.0 + 0 +LINE + 5 +1D13 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525212.5715177859 + 20 +181595.2190166764 + 30 +0.0 + 11 +525233.3232547421 + 21 +181637.4028447537 + 31 +0.0 + 0 +LINE + 5 +1D14 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525171.8164555471 + 20 +181654.4100271384 + 30 +0.0 + 11 +525234.3910139501 + 21 +181635.8298686707 + 31 +0.0 + 0 +LINE + 5 +1D15 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525136.1378398911 + 20 +181620.021047339 + 30 +0.0 + 11 +525154.3447919175 + 21 +181722.7412981756 + 31 +0.0 + 0 +LINE + 5 +1D16 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525003.4429764331 + 20 +181729.1773837962 + 30 +0.0 + 11 +525301.4615792174 + 21 +181710.639753487 + 31 +0.0 + 0 +LINE + 5 +1D17 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525360.566326539 + 20 +181631.7956822925 + 30 +0.0 + 11 +525382.0146893034 + 21 +181697.2138104154 + 31 +0.0 + 0 +LINE + 5 +1D18 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525351.4666208391 + 20 +181706.2006581319 + 30 +0.0 + 11 +525408.6357065016 + 21 +181687.6462085011 + 31 +0.0 + 0 +LINE + 5 +1D19 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525354.4622434232 + 20 +181698.1327832805 + 30 +0.0 + 11 +525375.7269195981 + 21 +181766.2230870276 + 31 +0.0 + 0 +LINE + 5 +1D1A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525372.3126460178 + 20 +181764.7526882235 + 30 +0.0 + 11 +525426.1284504718 + 21 +181748.7699166965 + 31 +0.0 + 0 +LINE + 5 +1D1B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525401.5080878492 + 20 +181682.0931105359 + 30 +0.0 + 11 +525425.4310228318 + 21 +181755.807294926 + 31 +0.0 + 0 +LINE + 5 +1D1C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525550.4821613834 + 20 +181139.8508269699 + 30 +0.0 + 11 +525791.2774661715 + 21 +181120.4520406538 + 31 +0.0 + 0 +LINE + 5 +1D1D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525580.7167677637 + 20 +181592.8036794261 + 30 +0.0 + 11 +525540.1266019988 + 21 +181073.841759013 + 31 +0.0 + 0 +LINE + 5 +1D1E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525689.4726742537 + 20 +181589.7312027846 + 30 +0.0 + 11 +525617.1625483183 + 21 +180837.6388906033 + 31 +0.0 + 0 +LINE + 5 +1D1F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525706.9471382775 + 20 +181056.0634526979 + 30 +0.0 + 11 +526125.3504032675 + 21 +180922.5626083323 + 31 +0.0 + 0 +LINE + 5 +1D20 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525696.1966252777 + 20 +180987.4044875335 + 30 +0.0 + 11 +525733.2166722667 + 21 +181177.7700154862 + 31 +0.0 + 0 +LINE + 5 +1D21 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525767.673702222 + 20 +180974.6206822104 + 30 +0.0 + 11 +525779.4285849208 + 21 +181037.8462184663 + 31 +0.0 + 0 +LINE + 5 +1D22 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525714.5795633408 + 20 +180962.8615391838 + 30 +0.0 + 11 +525779.7889062979 + 21 +180984.8841892078 + 31 +0.0 + 0 +LINE + 5 +1D23 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525759.3800443228 + 20 +180986.1260102264 + 30 +0.0 + 11 +526135.2216640942 + 21 +180840.0432439632 + 31 +0.0 + 0 +LINE + 5 +1D24 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525826.4972455265 + 20 +180879.8564422131 + 30 +0.0 + 11 +525952.4987566518 + 21 +181149.1223937773 + 31 +0.0 + 0 +LINE + 5 +1D25 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525939.4313990119 + 20 +181151.6799628386 + 30 +0.0 + 11 +526161.3731342222 + 21 +181063.4890457058 + 31 +0.0 + 0 +LINE + 5 +1D26 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525914.6165033592 + 20 +181340.597991934 + 30 +0.0 + 11 +525949.060913727 + 21 +181136.3421119805 + 31 +0.0 + 0 +LINE + 5 +1D27 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525845.2612191611 + 20 +181287.7602308549 + 30 +0.0 + 11 +525930.4139726882 + 21 +181281.4097719626 + 31 +0.0 + 0 +LINE + 5 +1D28 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526039.6595348584 + 20 +180749.1254239648 + 30 +0.0 + 11 +526160.244414677 + 21 +181066.3791683655 + 31 +0.0 + 0 +LINE + 5 +1D29 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525747.4039967776 + 20 +181128.442211785 + 30 +0.0 + 11 +526148.7825515574 + 21 +180991.5828602147 + 31 +0.0 + 0 +LINE + 5 +1D2A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526143.3048822115 + 20 +181529.6072795687 + 30 +0.0 + 11 +526144.6387304903 + 21 +180985.9719759277 + 31 +0.0 + 0 +LINE + 5 +1D2B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526055.1082087747 + 20 +181491.5153786999 + 30 +0.0 + 11 +526158.0627373598 + 21 +181435.0362429673 + 31 +0.0 + 0 +LINE + 5 +1D2C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526054.727201425 + 20 +181429.4278238311 + 30 +0.0 + 11 +526157.3486116869 + 21 +181468.5998423646 + 31 +0.0 + 0 +LINE + 5 +1D2D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526040.9024649364 + 20 +181239.9227961396 + 30 +0.0 + 11 +526073.6187613272 + 21 +181439.2638990554 + 31 +0.0 + 0 +LINE + 5 +1D2E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525819.1150626604 + 20 +181354.6791634863 + 30 +0.0 + 11 +526146.1045975316 + 21 +181281.41405303 + 31 +0.0 + 0 +LINE + 5 +1D2F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525793.8332015857 + 20 +181264.5823737513 + 30 +0.0 + 11 +525833.643721944 + 21 +181379.3106963023 + 31 +0.0 + 0 +LINE + 5 +1D30 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525741.8105573311 + 20 +181279.0130101218 + 30 +0.0 + 11 +525795.9134356442 + 21 +181265.2108562477 + 31 +0.0 + 0 +LINE + 5 +1D31 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525427.3665664235 + 20 +181403.0551922181 + 30 +0.0 + 11 +525984.1903171935 + 21 +181322.6507206756 + 31 +0.0 + 0 +LINE + 5 +1D32 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525992.25155451 + 20 +181312.3528462341 + 30 +0.0 + 11 +525995.5349839787 + 21 +181336.4147177941 + 31 +0.0 + 0 +LINE + 5 +1D33 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526105.6561181488 + 20 +181159.7333860918 + 30 +0.0 + 11 +526150.9417907415 + 21 +181157.904443489 + 31 +0.0 + 0 +LINE + 5 +1D34 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526092.2872414094 + 20 +181151.8214444548 + 30 +0.0 + 11 +526113.90427404 + 21 +181162.397376228 + 31 +0.0 + 0 +LINE + 5 +1D35 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526078.6456170197 + 20 +181089.1925695517 + 30 +0.0 + 11 +526095.9593850317 + 21 +181158.9212997027 + 31 +0.0 + 0 +LINE + 5 +1D36 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525918.7964703651 + 20 +181290.1641940455 + 30 +0.0 + 11 +525997.955051366 + 21 +181636.2678885616 + 31 +0.0 + 0 +LINE + 5 +1D37 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525679.2942522527 + 20 +181572.7097732883 + 30 +0.0 + 11 +525869.1756024465 + 21 +181647.3537361884 + 31 +0.0 + 0 +LINE + 5 +1D38 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525849.5941156315 + 20 +181671.517889556 + 30 +0.0 + 11 +525904.7709578639 + 21 +181330.9495471852 + 31 +0.0 + 0 +LINE + 5 +1D39 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525777.6039437721 + 20 +181349.5625448107 + 30 +0.0 + 11 +525782.9892644946 + 21 +181384.6765313503 + 31 +0.0 + 0 +LINE + 5 +1D3A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525947.4364234862 + 20 +181471.9788870168 + 30 +0.0 + 11 +526040.5862505421 + 21 +181466.0670412759 + 31 +0.0 + 0 +LINE + 5 +1D3B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526006.0131155095 + 20 +181472.4101030822 + 30 +0.0 + 11 +526072.4829697926 + 21 +181422.0678672007 + 31 +0.0 + 0 +LINE + 5 +1D3C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526002.0038004398 + 20 +181459.9122470971 + 30 +0.0 + 11 +526076.073166201 + 21 +181490.5370193159 + 31 +0.0 + 0 +LINE + 5 +1D3D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526076.09878786 + 20 +181605.3584441946 + 30 +0.0 + 11 +526069.8971309905 + 21 +181479.5268185956 + 31 +0.0 + 0 +LINE + 5 +1D3E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525481.6937793638 + 20 +181571.182850897 + 30 +0.0 + 11 +525750.7373506701 + 21 +181587.451632654 + 31 +0.0 + 0 +LINE + 5 +1D3F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525855.7050227011 + 20 +181086.1990208319 + 30 +0.0 + 11 +525876.4567596575 + 21 +181128.3828489091 + 31 +0.0 + 0 +LINE + 5 +1D40 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525814.9499604622 + 20 +181145.390031294 + 30 +0.0 + 11 +525877.5245188651 + 21 +181126.8098728261 + 31 +0.0 + 0 +LINE + 5 +1D41 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525779.2713448061 + 20 +181111.0010514946 + 30 +0.0 + 11 +525797.4782968325 + 21 +181213.721302331 + 31 +0.0 + 0 +LINE + 5 +1D42 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525646.5764813483 + 20 +181220.1573879517 + 30 +0.0 + 11 +525944.5950841326 + 21 +181201.6197576427 + 31 +0.0 + 0 +LINE + 5 +1D43 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526003.6998314539 + 20 +181122.7756864479 + 30 +0.0 + 11 +526025.1481942186 + 21 +181188.1938145709 + 31 +0.0 + 0 +LINE + 5 +1D44 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525994.6001257541 + 20 +181197.1806622872 + 30 +0.0 + 11 +526051.769211417 + 21 +181178.6262126565 + 31 +0.0 + 0 +LINE + 5 +1D45 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525997.5957483383 + 20 +181189.112787436 + 30 +0.0 + 11 +526018.8604245131 + 21 +181257.2030911829 + 31 +0.0 + 0 +LINE + 5 +1D46 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526015.4461509327 + 20 +181255.7326923791 + 30 +0.0 + 11 +526069.261955387 + 21 +181239.7499208522 + 31 +0.0 + 0 +LINE + 5 +1D47 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526044.6415927642 + 20 +181173.0731146914 + 30 +0.0 + 11 +526068.5645277468 + 21 +181246.7872990814 + 31 +0.0 + 0 +LINE + 5 +1D48 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525564.8320348503 + 20 +181453.2075964477 + 30 +0.0 + 11 +525676.4676305909 + 21 +181437.6491804908 + 31 +0.0 + 0 +LINE + 5 +1D49 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526130.473714444 + 20 +181488.9973167478 + 30 +0.0 + 11 +526494.1671899047 + 21 +181934.2723503464 + 31 +0.0 + 0 +LINE + 5 +1D4A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526109.8328697965 + 20 +181554.5942094994 + 30 +0.0 + 11 +526251.9934859582 + 21 +181731.9634965217 + 31 +0.0 + 0 +LINE + 5 +1D4B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525927.1473617616 + 20 +181593.8350989162 + 30 +0.0 + 11 +525971.9586043235 + 21 +181757.6180350803 + 31 +0.0 + 0 +LINE + 5 +1D4C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525492.4506609762 + 20 +181731.9415880005 + 30 +0.0 + 11 +526223.3911410159 + 21 +181540.6365567163 + 31 +0.0 + 0 +LINE + 5 +1D4D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526022.0770722465 + 20 +181664.0999425277 + 30 +0.0 + 11 +526215.550577524 + 21 +182147.2371812123 + 31 +0.0 + 0 +LINE + 5 +1D4E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526088.1434775098 + 20 +181642.5393970146 + 30 +0.0 + 11 +525906.1162328381 + 21 +181709.4393245857 + 31 +0.0 + 0 +LINE + 5 +1D4F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526112.1606457125 + 20 +181711.0636543148 + 30 +0.0 + 11 +526051.6183006626 + 21 +181732.749367538 + 31 +0.0 + 0 +LINE + 5 +1D50 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526115.3035619875 + 20 +181656.7738108306 + 30 +0.0 + 11 +526103.9601991942 + 21 +181724.6603606289 + 31 +0.0 + 0 +LINE + 5 +1D51 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526099.4801024202 + 20 +181704.710611271 + 30 +0.0 + 11 +526304.7553206837 + 21 +181949.7835141037 + 31 +0.0 + 0 +LINE + 5 +1D52 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525857.313670571 + 20 +181761.9825238141 + 30 +0.0 + 11 +526087.2040436257 + 21 +182113.8961217255 + 31 +0.0 + 0 +LINE + 5 +1D53 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525668.4671300806 + 20 +181833.7424880624 + 30 +0.0 + 11 +525789.1324778181 + 21 +181820.0552903225 + 31 +0.0 + 0 +LINE + 5 +1D54 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525757.8593417412 + 20 +181722.8647994392 + 30 +0.0 + 11 +525654.8212814394 + 21 +181785.8797904769 + 31 +0.0 + 0 +LINE + 5 +1D55 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525658.9953514573 + 20 +181780.5928484492 + 30 +0.0 + 11 +525669.9329835094 + 21 +181835.3467441867 + 31 +0.0 + 0 +LINE + 5 +1D56 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525634.9459465169 + 20 +181443.4235846078 + 30 +0.0 + 11 +525634.9496634225 + 21 +181443.4354514254 + 31 +0.0 + 0 +LINE + 5 +1D57 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525678.693672931 + 20 +181583.0952272422 + 30 +0.0 + 11 +525919.2417741847 + 21 +182168.4730579651 + 31 +0.0 + 0 +LINE + 5 +1D58 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525976.3153867182 + 20 +181897.5490736705 + 30 +0.0 + 11 +525495.0880701026 + 21 +182031.8608562202 + 31 +0.0 + 0 +LINE + 5 +1D59 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525491.0565304261 + 20 +181931.8835367471 + 30 +0.0 + 11 +525809.6864879597 + 21 +181871.5776837387 + 31 +0.0 + 0 +LINE + 5 +1D5A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525743.5990615419 + 20 +181780.6507845993 + 30 +0.0 + 11 +525709.7929964333 + 21 +181791.5660808326 + 31 +0.0 + 0 +LINE + 5 +1D5B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526157.4518696392 + 20 +181859.1409376143 + 30 +0.0 + 11 +525977.7109751933 + 21 +181842.9721210265 + 31 +0.0 + 0 +LINE + 5 +1D5C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525951.114209062 + 20 +181784.9639954642 + 30 +0.0 + 11 +525979.4340796496 + 21 +181843.775410835 + 31 +0.0 + 0 +LINE + 5 +1D5D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525850.4565019642 + 20 +181630.6661921994 + 30 +0.0 + 11 +525902.2043944721 + 21 +181859.6510289999 + 31 +0.0 + 0 +LINE + 5 +1D5E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525093.3682658213 + 20 +181879.2959285518 + 30 +0.0 + 11 +525080.1517503274 + 21 +181713.4750750022 + 31 +0.0 + 0 +LINE + 5 +1D5F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525075.2920115007 + 20 +181977.1120209499 + 30 +0.0 + 11 +524897.6469292312 + 21 +181927.1785198064 + 31 +0.0 + 0 +LINE + 5 +1D60 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525559.1342218785 + 20 +181754.3305998252 + 30 +0.0 + 11 +525635.1712887211 + 21 +181559.4054345479 + 31 +0.0 + 0 +LINE + 5 +1D61 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525968.0301132713 + 20 +181790.5144936306 + 30 +0.0 + 11 +525860.2933285217 + 21 +181836.5902880851 + 31 +0.0 + 0 +LINE + 5 +1D62 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525138.5976201284 + 20 +181292.8532256214 + 30 +0.0 + 11 +525174.8263971197 + 21 +181098.0413473536 + 31 +0.0 + 0 +LINE + 5 +1D63 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527943.7217281111 + 20 +183084.8932846896 + 30 +0.0 + 11 +526886.0691300294 + 21 +180903.8038450779 + 31 +0.0 + 0 +LINE + 5 +1D64 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527579.4189956524 + 20 +183075.1156235687 + 30 +0.0 + 11 +527883.4646186981 + 21 +182875.7659136232 + 31 +0.0 + 0 +LINE + 5 +1D65 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527616.3711753756 + 20 +182837.7830018993 + 30 +0.0 + 11 +527887.6384030865 + 21 +182669.8299575536 + 31 +0.0 + 0 +LINE + 5 +1D66 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527511.1304576061 + 20 +182404.0055193513 + 30 +0.0 + 11 +527703.9479938831 + 21 +182285.0018235103 + 31 +0.0 + 0 +LINE + 5 +1D67 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527759.9654076744 + 20 +182990.4690615484 + 30 +0.0 + 11 +527606.7760979401 + 21 +182800.9552573995 + 31 +0.0 + 0 +LINE + 5 +1D68 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527938.6573479137 + 20 +182899.213051281 + 30 +0.0 + 11 +527799.4197403971 + 21 +182644.7157533081 + 31 +0.0 + 0 +LINE + 5 +1D69 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526976.0672279639 + 20 +181073.1283888675 + 30 +0.0 + 11 +525228.9175514841 + 21 +178041.3051799581 + 31 +0.0 + 0 +LINE + 5 +1D6A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526349.4510224499 + 20 +181723.5957364893 + 30 +0.0 + 11 +526137.0436574432 + 21 +181866.8871380226 + 31 +0.0 + 0 +LINE + 5 +1D6B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527011.5634163477 + 20 +181549.3135720685 + 30 +0.0 + 11 +526853.7736129552 + 21 +181139.4524424818 + 31 +0.0 + 0 +LINE + 5 +1D6C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527223.0841845988 + 20 +181435.1536054864 + 30 +0.0 + 11 +526900.2058964616 + 21 +181605.0098790062 + 31 +0.0 + 0 +LINE + 5 +1D6D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527037.0652009413 + 20 +181450.9758915195 + 30 +0.0 + 11 +526980.4001620355 + 21 +181481.3850853253 + 31 +0.0 + 0 +LINE + 5 +1D6E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527181.0254201383 + 20 +181319.6206159791 + 30 +0.0 + 11 +526785.2862686458 + 21 +181416.0686238382 + 31 +0.0 + 0 +LINE + 5 +1D6F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526791.4713041271 + 20 +181427.8602450707 + 30 +0.0 + 11 +526721.3222355628 + 21 +181199.5734082347 + 31 +0.0 + 0 +LINE + 5 +1D70 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526659.6748687927 + 20 +181565.4665690411 + 30 +0.0 + 11 +526797.4050230715 + 21 +181410.7497745311 + 31 +0.0 + 0 +LINE + 5 +1D71 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526744.2941710323 + 20 +181586.4798536614 + 30 +0.0 + 11 +526695.9448348761 + 21 +181516.0976012488 + 31 +0.0 + 0 +LINE + 5 +1D72 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527175.4863038696 + 20 +181208.5202604197 + 30 +0.0 + 11 +527089.1715245067 + 21 +181234.440327206 + 31 +0.0 + 0 +LINE + 5 +1D73 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527168.689694969 + 20 +181055.8945927876 + 30 +0.0 + 11 +526719.774874828 + 21 +181202.2627374366 + 31 +0.0 + 0 +LINE + 5 +1D74 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526929.7940054563 + 20 +181563.0687750525 + 30 +0.0 + 11 +526785.2800684787 + 21 +181164.3822460992 + 31 +0.0 + 0 +LINE + 5 +1D75 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526414.9304229288 + 20 +181466.4465204097 + 30 +0.0 + 11 +526792.2496135724 + 21 +181164.1016811281 + 31 +0.0 + 0 +LINE + 5 +1D76 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526205.7293076139 + 20 +181609.3371162689 + 30 +0.0 + 11 +526641.1837374633 + 21 +181290.9867341505 + 31 +0.0 + 0 +LINE + 5 +1D77 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526454.0390723845 + 20 +181550.3703392336 + 30 +0.0 + 11 +526433.6399297231 + 21 +181434.7269100732 + 31 +0.0 + 0 +LINE + 5 +1D78 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526502.6971109922 + 20 +181511.8034503905 + 30 +0.0 + 11 +526407.9120616558 + 21 +181456.2931333099 + 31 +0.0 + 0 +LINE + 5 +1D79 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526659.1379968794 + 20 +181403.9631606926 + 30 +0.0 + 11 +526483.2010900999 + 21 +181503.2276366846 + 31 +0.0 + 0 +LINE + 5 +1D7A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526792.3949678253 + 20 +181815.5482342014 + 30 +0.0 + 11 +526560.9288521117 + 21 +181347.8919828472 + 31 +0.0 + 0 +LINE + 5 +1D7B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526633.1060476017 + 20 +181487.2419746779 + 30 +0.0 + 11 +526612.2858985422 + 21 +181499.7430132419 + 31 +0.0 + 0 +LINE + 5 +1D7C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526681.1415599006 + 20 +181303.2694652466 + 30 +0.0 + 11 +526654.2210802562 + 21 +181266.8081851133 + 31 +0.0 + 0 +LINE + 5 +1D7D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526695.680076064 + 20 +181308.7427854004 + 30 +0.0 + 11 +526673.901047781 + 21 +181298.5046039371 + 31 +0.0 + 0 +LINE + 5 +1D7E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526753.0608187414 + 20 +181280.1784674954 + 30 +0.0 + 11 +526687.8445923023 + 21 +181310.3232212721 + 31 +0.0 + 0 +LINE + 5 +1D7F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526696.3896537784 + 20 +181530.6374912887 + 30 +0.0 + 11 +526309.1554281505 + 21 +181727.3782837355 + 31 +0.0 + 0 +LINE + 5 +1D80 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526340.3883101176 + 20 +181733.1381633065 + 30 +0.0 + 11 +526282.3497671501 + 21 +181540.4056030153 + 31 +0.0 + 0 +LINE + 5 +1D81 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526378.8858323255 + 20 +181831.5850459025 + 30 +0.0 + 11 +526673.3621656025 + 21 +181567.1052142773 + 31 +0.0 + 0 +LINE + 5 +1D82 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526536.6724852248 + 20 +181622.110195219 + 30 +0.0 + 11 +526482.9752837407 + 21 +181545.7659043168 + 31 +0.0 + 0 +LINE + 5 +1D83 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526499.6698190174 + 20 +181576.6985503557 + 30 +0.0 + 11 +526497.3225266423 + 21 +181493.3494504177 + 31 +0.0 + 0 +LINE + 5 +1D84 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526511.9260369985 + 20 +181572.0021546795 + 30 +0.0 + 11 +526441.678933082 + 21 +181533.4082172145 + 31 +0.0 + 0 +LINE + 5 +1D85 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526307.3223704611 + 20 +181632.9086127737 + 30 +0.0 + 11 +526454.1312590536 + 21 +181531.3327633558 + 31 +0.0 + 0 +LINE + 5 +1D86 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526894.9461643925 + 20 +181452.1668933229 + 30 +0.0 + 11 +526849.0590665425 + 21 +181462.3886440957 + 31 +0.0 + 0 +LINE + 5 +1D87 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526874.2963543948 + 20 +181521.0010139657 + 30 +0.0 + 11 +526849.6173969573 + 21 +181460.5713299699 + 31 +0.0 + 0 +LINE + 5 +1D88 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526923.4481245006 + 20 +181527.2993504338 + 30 +0.0 + 11 +526831.9440671101 + 21 +181577.3987567687 + 31 +0.0 + 0 +LINE + 5 +1D89 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526921.3825863701 + 20 +181699.1096124356 + 30 +0.0 + 11 +526749.2930653531 + 21 +181455.0933668714 + 31 +0.0 + 0 +LINE + 5 +1D8A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526773.7834150032 + 20 +181359.6471438321 + 30 +0.0 + 11 +526709.34078019 + 21 +181383.8692529624 + 31 +0.0 + 0 +LINE + 5 +1D8B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526721.454024047 + 20 +181413.3178054233 + 30 +0.0 + 11 +526700.1386005055 + 21 +181357.1197211509 + 31 +0.0 + 0 +LINE + 5 +1D8C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526725.8707045275 + 20 +181405.9315145532 + 30 +0.0 + 11 +526659.4591287731 + 21 +181431.9695352724 + 31 +0.0 + 0 +LINE + 5 +1D8D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526662.7430145923 + 20 +181433.7117840057 + 30 +0.0 + 11 +526641.5210478957 + 21 +181381.7385416184 + 31 +0.0 + 0 +LINE + 5 +1D8E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526708.9308036916 + 20 +181359.2022695438 + 30 +0.0 + 11 +526636.4694427717 + 21 +181386.6875196267 + 31 +0.0 + 0 +LINE + 5 +1D8F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527324.4023127908 + 20 +181542.1238641195 + 30 +0.0 + 11 +527121.7425878764 + 21 +180197.6711064802 + 31 +0.0 + 0 +LINE + 5 +1D90 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527230.4778736888 + 20 +180841.7992848049 + 30 +0.0 + 11 +527090.3880768281 + 21 +180889.0490839605 + 31 +0.0 + 0 +LINE + 5 +1D91 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527188.824350887 + 20 +181001.0694914723 + 30 +0.0 + 11 +527109.6409313045 + 21 +180512.9971680853 + 31 +0.0 + 0 +LINE + 5 +1D92 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527123.0099071885 + 20 +180887.7895473195 + 30 +0.0 + 11 +527043.2541387421 + 21 +180868.8128338491 + 31 +0.0 + 0 +LINE + 5 +1D93 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527097.4761990254 + 20 +180963.3100436179 + 30 +0.0 + 11 +527116.6493709036 + 21 +180877.5789643039 + 31 +0.0 + 0 +LINE + 5 +1D94 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527182.2719981973 + 20 +181140.0052827173 + 30 +0.0 + 11 +526902.953581457 + 21 +180703.6749845552 + 31 +0.0 + 0 +LINE + 5 +1D95 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526724.9058894234 + 20 +181128.0958067637 + 30 +0.0 + 11 +526667.7181934928 + 21 +181030.4875655608 + 31 +0.0 + 0 +LINE + 5 +1D96 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526600.7071804941 + 20 +181076.8160581087 + 30 +0.0 + 11 +527232.4961109984 + 21 +180662.4317586386 + 31 +0.0 + 0 +LINE + 5 +1D97 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527005.9546060342 + 20 +180729.1363945265 + 30 +0.0 + 11 +526852.309829773 + 21 +180252.8250246601 + 31 +0.0 + 0 +LINE + 5 +1D98 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527066.2282636347 + 20 +180694.542851391 + 30 +0.0 + 11 +526894.597086148 + 21 +180784.8327014642 + 31 +0.0 + 0 +LINE + 5 +1D99 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527031.4563906275 + 20 +180630.7987139774 + 30 +0.0 + 11 +526974.7913517218 + 21 +180661.2079077832 + 31 +0.0 + 0 +LINE + 5 +1D9A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527073.8614118073 + 20 +180664.8439663194 + 30 +0.0 + 11 +527015.8687275841 + 21 +180627.7750561708 + 31 +0.0 + 0 +LINE + 5 +1D9B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527027.6753131541 + 20 +180644.4684172386 + 30 +0.0 + 11 +526985.3752550181 + 21 +180510.4087323127 + 31 +0.0 + 0 +LINE + 5 +1D9C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527175.4166098245 + 20 +180499.4434384371 + 30 +0.0 + 11 +526402.0073828482 + 21 +180690.8630085347 + 31 +0.0 + 0 +LINE + 5 +1D9D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526785.8624938135 + 20 +180607.6830675286 + 30 +0.0 + 11 +526728.7625141292 + 21 +180418.1739236337 + 31 +0.0 + 0 +LINE + 5 +1D9E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527163.4583574716 + 20 +180374.7574255732 + 30 +0.0 + 11 +527077.143578109 + 21 +180400.6774923597 + 31 +0.0 + 0 +LINE + 5 +1D9F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526924.1851951425 + 20 +180742.8915975102 + 30 +0.0 + 11 +526779.21622005 + 21 +180342.9497047469 + 31 +0.0 + 0 +LINE + 5 +1DA0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526702.8643413537 + 20 +180828.581240778 + 30 +0.0 + 11 +526506.2079120824 + 21 +180448.1401350717 + 31 +0.0 + 0 +LINE + 5 +1DA1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526910.3548193506 + 20 +181164.3710947051 + 30 +0.0 + 11 +526624.5123186351 + 21 +180679.7974333797 + 31 +0.0 + 0 +LINE + 5 +1DA2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526690.7808434647 + 20 +180710.4603137467 + 30 +0.0 + 11 +526215.2065931234 + 21 +180941.0748792045 + 31 +0.0 + 0 +LINE + 5 +1DA3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526620.3527323503 + 20 +181074.0991428002 + 30 +0.0 + 11 +526443.2837607318 + 21 +180972.7422109263 + 31 +0.0 + 0 +LINE + 5 +1DA4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526436.6962569662 + 20 +181003.1386865113 + 30 +0.0 + 11 +526667.7533552889 + 21 +180746.9280367352 + 31 +0.0 + 0 +LINE + 5 +1DA5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526531.0636749112 + 20 +180801.933017677 + 30 +0.0 + 11 +526408.4835079856 + 21 +180625.7016248967 + 31 +0.0 + 0 +LINE + 5 +1DA6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526346.5095508479 + 20 +180785.0841135451 + 30 +0.0 + 11 +526459.7865481565 + 21 +180663.571212232 + 31 +0.0 + 0 +LINE + 5 +1DA7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526745.2325381531 + 20 +181227.243886362 + 30 +0.0 + 11 +526564.135988081 + 21 +181027.6113337231 + 31 +0.0 + 0 +LINE + 5 +1DA8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526889.3373540787 + 20 +180631.9897157808 + 30 +0.0 + 11 +526843.4502562289 + 21 +180642.2114665537 + 31 +0.0 + 0 +LINE + 5 +1DA9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526868.6875440812 + 20 +180700.8238364236 + 30 +0.0 + 11 +526844.0085866436 + 21 +180640.3941524279 + 31 +0.0 + 0 +LINE + 5 +1DAA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526917.8393141868 + 20 +180707.1221728916 + 30 +0.0 + 11 +526826.3352567963 + 21 +180757.2215792266 + 31 +0.0 + 0 +LINE + 5 +1DAB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526785.1958007188 + 20 +181088.5605498259 + 30 +0.0 + 11 +526727.4503039016 + 21 +180991.761644146 + 31 +0.0 + 0 +LINE + 5 +1DAC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527056.4469199513 + 20 +180531.0616247083 + 30 +0.0 + 11 +526941.7075286161 + 21 +180189.3892904521 + 31 +0.0 + 0 +LINE + 5 +1DAD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526364.9824813638 + 20 +180727.0001515036 + 30 +0.0 + 11 +526014.8921859642 + 21 +180764.5781846883 + 31 +0.0 + 0 +LINE + 5 +1DAE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526613.1300481536 + 20 +181319.4827837597 + 30 +0.0 + 11 +526290.2675920513 + 21 +180597.2276236572 + 31 +0.0 + 0 +LINE + 5 +1DAF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526294.3528492354 + 20 +181213.945122317 + 30 +0.0 + 11 +526135.5486117216 + 21 +181037.9738909294 + 31 +0.0 + 0 +LINE + 5 +1DB0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526328.5897194393 + 20 +181133.7589566729 + 30 +0.0 + 11 +526251.3986893869 + 21 +181170.2673754394 + 31 +0.0 + 0 +LINE + 5 +1DB1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526246.6614287466 + 20 +181414.5429920229 + 30 +0.0 + 11 +526129.2449001803 + 21 +181416.2419766329 + 31 +0.0 + 0 +LINE + 5 +1DB2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526216.3464087707 + 20 +181360.3580383912 + 30 +0.0 + 11 +526146.4329392632 + 21 +181445.0793914347 + 31 +0.0 + 0 +LINE + 5 +1DB3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526342.9116307196 + 20 +181175.2131736575 + 30 +0.0 + 11 +526123.3088360611 + 21 +181290.8186824505 + 31 +0.0 + 0 +LINE + 5 +1DB4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526423.5612846294 + 20 +181245.937528677 + 30 +0.0 + 11 +526358.7042820345 + 21 +181143.2679872298 + 31 +0.0 + 0 +LINE + 5 +1DB5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526454.0747501559 + 20 +181106.8197449054 + 30 +0.0 + 11 +526469.4291336368 + 21 +181226.6194689207 + 31 +0.0 + 0 +LINE + 5 +1DB6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526470.93942316 + 20 +181220.0548941384 + 30 +0.0 + 11 +526421.3926324677 + 21 +181245.7985618147 + 31 +0.0 + 0 +LINE + 5 +1DB7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526748.9377916851 + 20 +181027.7572252637 + 30 +0.0 + 11 +526748.9262106236 + 21 +181027.7617546961 + 31 +0.0 + 0 +LINE + 5 +1DB8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526612.6294771829 + 20 +181081.0683378015 + 30 +0.0 + 11 +526224.986478683 + 21 +181232.678161405 + 31 +0.0 + 0 +LINE + 5 +1DB9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526265.8234853017 + 20 +181172.1466117311 + 30 +0.0 + 11 +526377.5843756956 + 21 +181505.1619682758 + 31 +0.0 + 0 +LINE + 5 +1DBA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526458.0761615913 + 20 +181445.7246893631 + 30 +0.0 + 11 +526298.1529495785 + 21 +181200.6942170815 + 31 +0.0 + 0 +LINE + 5 +1DBB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526417.9361183032 + 20 +181154.1121857402 + 30 +0.0 + 11 +526430.5848035984 + 21 +181187.3086387173 + 31 +0.0 + 0 +LINE + 5 +1DBC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526330.6592396082 + 20 +181344.4055867037 + 30 +0.0 + 11 +526246.7297386135 + 21 +181385.2428131443 + 31 +0.0 + 0 +LINE + 5 +1DBD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526279.9285591622 + 20 +181373.6940290857 + 30 +0.0 + 11 +526197.2715351827 + 21 +181362.7213981878 + 31 +0.0 + 0 +LINE + 5 +1DBE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526277.2464841459 + 20 +181360.8457807552 + 30 +0.0 + 11 +526227.9455098227 + 21 +181424.0404130312 + 31 +0.0 + 0 +LINE + 5 +1DBF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526304.749963081 + 20 +181572.5432432923 + 30 +0.0 + 11 +526227.8821140592 + 21 +181411.4164710242 + 31 +0.0 + 0 +LINE + 5 +1DC0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526468.0150100879 + 20 +180976.8948188468 + 30 +0.0 + 11 +526199.6812261328 + 21 +181107.8746330602 + 31 +0.0 + 0 +LINE + 5 +1DC1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527177.7303266084 + 20 +181751.4685846251 + 30 +0.0 + 11 +527701.5928006742 + 21 +181808.0544919456 + 31 +0.0 + 0 +LINE + 5 +1DC2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527450.2036285262 + 20 +181826.5587563648 + 30 +0.0 + 11 +527363.6210441879 + 21 +181292.8793153189 + 31 +0.0 + 0 +LINE + 5 +1DC3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527369.3614103036 + 20 +181546.873448078 + 30 +0.0 + 11 +527720.1122960226 + 21 +181749.5979243848 + 31 +0.0 + 0 +LINE + 5 +1DC4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +528024.703594832 + 20 +181666.8781985996 + 30 +0.0 + 11 +527183.1410703766 + 21 +181445.7012363482 + 31 +0.0 + 0 +LINE + 5 +1DC5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527614.5857858546 + 20 +180887.3170383316 + 30 +0.0 + 11 +527614.5982048961 + 21 +180887.3176740574 + 31 +0.0 + 0 +LINE + 5 +1DC6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527301.0085882168 + 20 +181300.4785506191 + 30 +0.0 + 11 +527130.9045834213 + 21 +181198.8477494359 + 31 +0.0 + 0 +LINE + 5 +1DC7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524905.0467234861 + 20 +179966.2211383896 + 30 +0.0 + 11 +524511.244865442 + 21 +179567.0832419587 + 31 +0.0 + 0 +LINE + 5 +1DC8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524886.0389746226 + 20 +179957.9478773517 + 30 +0.0 + 11 +525573.550575652 + 21 +179566.6698251386 + 31 +0.0 + 0 +LINE + 5 +1DC9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525007.2785092507 + 20 +179892.3390120542 + 30 +0.0 + 11 +524914.3173388969 + 21 +179777.3785166172 + 31 +0.0 + 0 +LINE + 5 +1DCA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524926.827850516 + 20 +179807.5324110196 + 30 +0.0 + 11 +524916.9246637157 + 21 +179726.1504403762 + 31 +0.0 + 0 +LINE + 5 +1DCB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524847.1403262642 + 20 +179809.8158497277 + 30 +0.0 + 11 +524934.1939106882 + 21 +179798.0217020612 + 31 +0.0 + 0 +LINE + 5 +1DCC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524865.0806026798 + 20 +179816.1298336475 + 30 +0.0 + 11 +524726.7770255972 + 21 +179673.2089697036 + 31 +0.0 + 0 +LINE + 5 +1DCD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524762.1755525736 + 20 +179882.7736257986 + 30 +0.0 + 11 +525023.0581350619 + 21 +179537.2312991965 + 31 +0.0 + 0 +LINE + 5 +1DCE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524761.9693411359 + 20 +179629.5548405179 + 30 +0.0 + 11 +524919.5556749655 + 21 +179729.5867661742 + 31 +0.0 + 0 +LINE + 5 +1DCF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524726.4637179141 + 20 +179678.6767760302 + 30 +0.0 + 11 +524762.8069600158 + 21 +179629.4244721773 + 31 +0.0 + 0 +LINE + 5 +1DD0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524509.6460579089 + 20 +179475.1030656924 + 30 +0.0 + 11 +524751.9328858016 + 21 +179647.2746637618 + 31 +0.0 + 0 +LINE + 5 +1DD1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524563.219935467 + 20 +179517.664869887 + 30 +0.0 + 11 +524634.8917138494 + 21 +179430.1379740204 + 31 +0.0 + 0 +LINE + 5 +1DD2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524568.1743441253 + 20 +179383.3875979579 + 30 +0.0 + 11 +525137.7149643251 + 21 +179837.1898916572 + 31 +0.0 + 0 +LINE + 5 +1DD3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525034.9532006296 + 20 +179642.663750922 + 30 +0.0 + 11 +525364.5035351414 + 21 +179352.3529784319 + 31 +0.0 + 0 +LINE + 5 +1DD4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525088.3262039714 + 20 +179687.1716102447 + 30 +0.0 + 11 +524944.0498189723 + 21 +179557.5805502009 + 31 +0.0 + 0 +LINE + 5 +1DD5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525136.0265943775 + 20 +179632.4260993589 + 30 +0.0 + 11 +525087.8307430644 + 21 +179589.8490442901 + 31 +0.0 + 0 +LINE + 5 +1DD6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525118.8274663434 + 20 +179684.0153911079 + 30 +0.0 + 11 +525133.4485429193 + 21 +179616.7585725482 + 31 +0.0 + 0 +LINE + 5 +1DD7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525121.8945987984 + 20 +179633.6277794594 + 30 +0.0 + 11 +525440.3645471604 + 21 +179386.2940176274 + 31 +0.0 + 0 +LINE + 5 +1DD8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525309.2023733555 + 20 +179721.8067611314 + 30 +0.0 + 11 +525081.3197323827 + 21 +179384.1957480005 + 31 +0.0 + 0 +LINE + 5 +1DD9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525072.4100933793 + 20 +179394.0909654322 + 30 +0.0 + 11 +525262.1251272731 + 21 +179249.0255401661 + 31 +0.0 + 0 +LINE + 5 +1DDA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524897.5967667719 + 20 +179318.2879206117 + 30 +0.0 + 11 +525090.5162898143 + 21 +179393.7129796461 + 31 +0.0 + 0 +LINE + 5 +1DDB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524907.2792235184 + 20 +179404.9379897022 + 30 +0.0 + 11 +524956.4891729818 + 21 +179335.1547493418 + 31 +0.0 + 0 +LINE + 5 +1DDC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525411.4637193101 + 20 +179678.027908497 + 30 +0.0 + 11 +525357.1803911208 + 21 +179606.0875771149 + 31 +0.0 + 0 +LINE + 5 +1DDD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525552.2289648615 + 20 +179618.6483332411 + 30 +0.0 + 11 +525259.0658026489 + 21 +179248.5084815205 + 31 +0.0 + 0 +LINE + 5 +1DDE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524993.6561293127 + 20 +179570.7610801281 + 30 +0.0 + 11 +525317.3380443595 + 21 +179296.7807081647 + 31 +0.0 + 0 +LINE + 5 +1DDF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524905.4551001676 + 20 +179054.3882040365 + 30 +0.0 + 11 +525320.0216286696 + 21 +179303.2190038064 + 31 +0.0 + 0 +LINE + 5 +1DE0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524698.8042163758 + 20 +178907.8336365132 + 30 +0.0 + 11 +525148.5700750326 + 21 +179205.6224856277 + 31 +0.0 + 0 +LINE + 5 +1DE1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524840.3372254955 + 20 +179120.2088408187 + 30 +0.0 + 11 +524941.6980656054 + 21 +179060.9171228345 + 31 +0.0 + 0 +LINE + 5 +1DE2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524893.4022210735 + 20 +179152.4441612063 + 30 +0.0 + 11 +524912.5390656945 + 21 +179044.2804794176 + 31 +0.0 + 0 +LINE + 5 +1DE3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525048.8611393741 + 20 +179261.6952645422 + 30 +0.0 + 11 +524894.6733882119 + 21 +179131.1833158452 + 31 +0.0 + 0 +LINE + 5 +1DE4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524836.4366792015 + 20 +179392.9755919916 + 30 +0.0 + 11 +525067.3347660931 + 21 +179150.1258322735 + 31 +0.0 + 0 +LINE + 5 +1DE5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524900.7317197808 + 20 +179460.9664132607 + 30 +0.0 + 11 +524822.7735891135 + 21 +179367.8536032429 + 31 +0.0 + 0 +LINE + 5 +1DE6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524758.9414431214 + 20 +179447.5370877066 + 30 +0.0 + 11 +524868.3289783231 + 21 +179498.7435141465 + 31 +0.0 + 0 +LINE + 5 +1DE7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524861.6167828911 + 20 +179498.1769022848 + 30 +0.0 + 11 +524901.2616749643 + 21 +179458.8589238799 + 31 +0.0 + 0 +LINE + 5 +1DE8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524593.6079011682 + 20 +179704.1689547404 + 30 +0.0 + 11 +524948.7484144244 + 21 +179267.8287384986 + 31 +0.0 + 0 +LINE + 5 +1DE9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524961.7251682221 + 20 +179266.2058934793 + 30 +0.0 + 11 +524942.7715240602 + 21 +179251.0232077804 + 31 +0.0 + 0 +LINE + 5 +1DEA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525150.9289885858 + 20 +179247.3589035855 + 30 +0.0 + 11 +525175.7714535572 + 21 +179209.4512644161 + 31 +0.0 + 0 +LINE + 5 +1DEB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525150.8454912971 + 20 +179262.8933399751 + 30 +0.0 + 11 +525152.8826788504 + 21 +179238.9142595195 + 31 +0.0 + 0 +LINE + 5 +1DEC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525197.5598585529 + 20 +179306.7822654515 + 30 +0.0 + 11 +525146.6422094706 + 21 +179256.0944426223 + 31 +0.0 + 0 +LINE + 5 +1DED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524943.0087837501 + 20 +179340.6215008807 + 30 +0.0 + 11 +524624.0296722295 + 21 +179045.8171397802 + 31 +0.0 + 0 +LINE + 5 +1DEE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524577.5449350585 + 20 +179400.8667673345 + 30 +0.0 + 11 +524645.025011905 + 21 +179044.4526765811 + 31 +0.0 + 0 +LINE + 5 +1DEF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524550.5260999387 + 20 +179147.397666498 + 30 +0.0 + 11 +524900.8136361586 + 21 +179331.692360306 + 31 +0.0 + 0 +LINE + 5 +1DF0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524819.4921973141 + 20 +179431.214803694 + 30 +0.0 + 11 +524792.1378938785 + 21 +179408.5490627281 + 31 +0.0 + 0 +LINE + 5 +1DF1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524801.7608366968 + 20 +179222.613675088 + 30 +0.0 + 11 +524854.7044420686 + 21 +179145.7448592339 + 31 +0.0 + 0 +LINE + 5 +1DF2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524831.4950766586 + 20 +179172.1429928104 + 30 +0.0 + 11 +524908.8410121534 + 21 +179140.9951436974 + 31 +0.0 + 0 +LINE + 5 +1DF3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524840.1556646274 + 20 +179182.0053063112 + 30 +0.0 + 11 +524851.9509558546 + 21 +179102.7271963276 + 31 +0.0 + 0 +LINE + 5 +1DF4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524303.5770037772 + 20 +179361.6882295428 + 30 +0.0 + 11 +524525.5278053027 + 21 +179579.1508995571 + 31 +0.0 + 0 +LINE + 5 +1DF5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524465.7167711658 + 20 +179557.5488468338 + 30 +0.0 + 11 +524601.6154163449 + 21 +179332.0042182991 + 31 +0.0 + 0 +LINE + 5 +1DF6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525085.5526043257 + 20 +179499.5667174429 + 30 +0.0 + 11 +525060.0307698961 + 21 +179460.0857612072 + 31 +0.0 + 0 +LINE + 5 +1DF7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525013.8314200389 + 20 +179504.1079223612 + 30 +0.0 + 11 +525061.9288724432 + 21 +179459.9781963227 + 31 +0.0 + 0 +LINE + 5 +1DF8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525024.9952417884 + 20 +179552.3876762001 + 30 +0.0 + 11 +524946.2353813408 + 21 +179483.9784120883 + 31 +0.0 + 0 +LINE + 5 +1DF9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524863.1617511231 + 20 +179610.1194168292 + 30 +0.0 + 11 +525032.2238053618 + 21 +179363.9959657733 + 31 +0.0 + 0 +LINE + 5 +1DFA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525130.2344513407 + 20 +179353.8140213007 + 30 +0.0 + 11 +525085.1394629966 + 21 +179301.794738543 + 31 +0.0 + 0 +LINE + 5 +1DFB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525061.7307595102 + 20 +179323.3813204832 + 30 +0.0 + 11 +525107.0281388681 + 21 +179283.8753794123 + 31 +0.0 + 0 +LINE + 5 +1DFC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525070.1911873143 + 20 +179324.9578738929 + 30 +0.0 + 11 +525022.7095147707 + 21 +179271.7228601367 + 31 +0.0 + 0 +LINE + 5 +1DFD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525022.2161847724 + 20 +179275.4074174014 + 30 +0.0 + 11 +525063.5841494132 + 21 +179237.4563792571 + 31 +0.0 + 0 +LINE + 5 +1DFE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525108.1286975622 + 20 +179292.8435796346 + 30 +0.0 + 11 +525057.1888212336 + 21 +179234.4379566338 + 31 +0.0 + 0 +LINE + 5 +1DFF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524621.23270646 + 20 +179560.471742546 + 30 +0.0 + 11 +524691.951804398 + 21 +179472.702842984 + 31 +0.0 + 0 +LINE + 5 +1E00 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525238.2347363486 + 20 +179621.2230084213 + 30 +0.0 + 11 +525456.0511125839 + 21 +179470.9906017885 + 31 +0.0 + 0 +LINE + 5 +1E01 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525211.4080794374 + 20 +179919.2887862473 + 30 +0.0 + 11 +526340.7289148488 + 21 +179276.5673308692 + 31 +0.0 + 0 +LINE + 5 +1E02 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525774.4568484473 + 20 +179602.2365177847 + 30 +0.0 + 11 +525681.4956780933 + 21 +179487.2760223476 + 31 +0.0 + 0 +LINE + 5 +1E03 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525610.6341941539 + 20 +179618.4892908976 + 30 +0.0 + 11 +526040.8271050026 + 21 +179374.7298474935 + 31 +0.0 + 0 +LINE + 5 +1E04 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525694.0061897128 + 20 +179517.42991675 + 30 +0.0 + 11 +525684.1030029122 + 21 +179436.0479461065 + 31 +0.0 + 0 +LINE + 5 +1E05 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525614.3186654611 + 20 +179519.713355458 + 30 +0.0 + 11 +525701.3722498848 + 21 +179507.9192077916 + 31 +0.0 + 0 +LINE + 5 +1E06 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525631.1275244898 + 20 +179524.5988424941 + 30 +0.0 + 11 +525492.8239474074 + 21 +179381.67797855 + 31 +0.0 + 0 +LINE + 5 +1E07 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525478.070698009 + 20 +179660.5963794274 + 30 +0.0 + 11 +525790.2364742585 + 21 +179247.1288049273 + 31 +0.0 + 0 +LINE + 5 +1E08 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525529.1476803325 + 20 +179339.4523462485 + 30 +0.0 + 11 +525686.7340141623 + 21 +179439.4842719045 + 31 +0.0 + 0 +LINE + 5 +1E09 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525493.6420571108 + 20 +179388.5742817606 + 30 +0.0 + 11 +525529.9852992123 + 21 +179339.3219779076 + 31 +0.0 + 0 +LINE + 5 +1E0A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525276.8243971054 + 20 +179185.0005714228 + 30 +0.0 + 11 +525519.1112249984 + 21 +179357.172169492 + 31 +0.0 + 0 +LINE + 5 +1E0B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525330.3982746635 + 20 +179227.5623756174 + 30 +0.0 + 11 +525402.0700530462 + 21 +179140.0354797507 + 31 +0.0 + 0 +LINE + 5 +1E0C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525335.3526833219 + 20 +179093.2851036883 + 30 +0.0 + 11 +525943.3607832583 + 21 +179541.8358263128 + 31 +0.0 + 0 +LINE + 5 +1E0D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525802.1315398264 + 20 +179352.5612566525 + 30 +0.0 + 11 +526131.681874338 + 21 +179062.2504841623 + 31 +0.0 + 0 +LINE + 5 +1E0E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525855.5045431681 + 20 +179397.0691159753 + 30 +0.0 + 11 +525711.228158169 + 21 +179267.4780559315 + 31 +0.0 + 0 +LINE + 5 +1E0F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525903.204933574 + 20 +179342.3236050893 + 30 +0.0 + 11 +525855.0090822612 + 21 +179299.7465500204 + 31 +0.0 + 0 +LINE + 5 +1E10 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525886.00580554 + 20 +179393.9128968382 + 30 +0.0 + 11 +525900.626882116 + 21 +179326.6560782785 + 31 +0.0 + 0 +LINE + 5 +1E11 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525889.072937995 + 20 +179343.5252851897 + 30 +0.0 + 11 +526207.5428863568 + 21 +179096.191523358 + 31 +0.0 + 0 +LINE + 5 +1E12 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526267.3138975824 + 20 +179615.3908302213 + 30 +0.0 + 11 +525890.2062519648 + 21 +179035.9957485947 + 31 +0.0 + 0 +LINE + 5 +1E13 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525839.588432576 + 20 +179103.9884711629 + 30 +0.0 + 11 +526029.3034664696 + 21 +178958.9230458965 + 31 +0.0 + 0 +LINE + 5 +1E14 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525664.7751059686 + 20 +179028.1854263421 + 30 +0.0 + 11 +525857.6946290109 + 21 +179103.6104853765 + 31 +0.0 + 0 +LINE + 5 +1E15 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525674.4575627151 + 20 +179114.8354954328 + 30 +0.0 + 11 +525723.6675121784 + 21 +179045.0522550722 + 31 +0.0 + 0 +LINE + 5 +1E16 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526239.8931634749 + 20 +179340.4647148076 + 30 +0.0 + 11 +526185.6098352858 + 21 +179268.5243834258 + 31 +0.0 + 0 +LINE + 5 +1E17 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526319.4073040581 + 20 +179328.5458389713 + 30 +0.0 + 11 +526026.2441418455 + 21 +178958.4059872507 + 31 +0.0 + 0 +LINE + 5 +1E18 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525760.8344685093 + 20 +179280.6585858584 + 30 +0.0 + 11 +526084.5163835561 + 21 +179006.678213895 + 31 +0.0 + 0 +LINE + 5 +1E19 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525782.854755432 + 20 +178831.7969486525 + 30 +0.0 + 11 +526087.1999678662 + 21 +179013.1165095366 + 31 +0.0 + 0 +LINE + 5 +1E1A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525603.615018398 + 20 +179102.8730977221 + 30 +0.0 + 11 +525834.5131052899 + 21 +178860.023338004 + 31 +0.0 + 0 +LINE + 5 +1E1B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525667.9100589774 + 20 +179170.8639189911 + 30 +0.0 + 11 +525589.9519283101 + 21 +179077.7511089732 + 31 +0.0 + 0 +LINE + 5 +1E1C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525526.1197823183 + 20 +179157.4345934369 + 30 +0.0 + 11 +525635.5073175197 + 21 +179208.641019877 + 31 +0.0 + 0 +LINE + 5 +1E1D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525628.7951220878 + 20 +179208.0744080153 + 30 +0.0 + 11 +525668.4400141611 + 21 +179168.7564296102 + 31 +0.0 + 0 +LINE + 5 +1E1E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525360.7862403647 + 20 +179414.0664604705 + 30 +0.0 + 11 +525715.9267536209 + 21 +178977.7262442288 + 31 +0.0 + 0 +LINE + 5 +1E1F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525728.9035074186 + 20 +178976.1033992095 + 30 +0.0 + 11 +525709.949863257 + 21 +178960.9207135108 + 31 +0.0 + 0 +LINE + 5 +1E20 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525918.1073277824 + 20 +178957.2564093159 + 30 +0.0 + 11 +525942.9497927538 + 21 +178919.3487701466 + 31 +0.0 + 0 +LINE + 5 +1E21 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525918.0238304939 + 20 +178972.7908457055 + 30 +0.0 + 11 +525920.0610180469 + 21 +178948.8117652499 + 31 +0.0 + 0 +LINE + 5 +1E22 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525964.7381977496 + 20 +179016.6797711822 + 30 +0.0 + 11 +525913.8205486673 + 21 +178965.9919483526 + 31 +0.0 + 0 +LINE + 5 +1E23 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525710.1871229467 + 20 +179050.5190066111 + 30 +0.0 + 11 +525453.9694047169 + 21 +178804.7420158878 + 31 +0.0 + 0 +LINE + 5 +1E24 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525344.7232742551 + 20 +179110.7642730649 + 30 +0.0 + 11 +525378.2763358416 + 21 +178909.5160670926 + 31 +0.0 + 0 +LINE + 5 +1E25 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525347.4840498939 + 20 +178913.895114929 + 30 +0.0 + 11 +525667.9919753553 + 21 +179041.5898660366 + 31 +0.0 + 0 +LINE + 5 +1E26 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525586.6705365106 + 20 +179141.1123094243 + 30 +0.0 + 11 +525559.3162330751 + 21 +179118.4465684587 + 31 +0.0 + 0 +LINE + 5 +1E27 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525244.4808744201 + 20 +179281.0573723183 + 30 +0.0 + 11 +525368.7937555415 + 21 +179041.9017240295 + 31 +0.0 + 0 +LINE + 5 +1E28 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525852.7309435223 + 20 +179209.4642231735 + 30 +0.0 + 11 +525827.2091090929 + 21 +179169.9832669377 + 31 +0.0 + 0 +LINE + 5 +1E29 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525781.0097592355 + 20 +179214.0054280916 + 30 +0.0 + 11 +525829.1072116399 + 21 +179169.8757020531 + 31 +0.0 + 0 +LINE + 5 +1E2A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525792.1735809848 + 20 +179262.2851819305 + 30 +0.0 + 11 +525713.4137205373 + 21 +179193.8759178186 + 31 +0.0 + 0 +LINE + 5 +1E2B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525630.3400903196 + 20 +179320.0169225595 + 30 +0.0 + 11 +525799.4021445584 + 21 +179073.8934715036 + 31 +0.0 + 0 +LINE + 5 +1E2C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525388.4110456565 + 20 +179270.3692482764 + 30 +0.0 + 11 +525459.1301435945 + 21 +179182.6003487144 + 31 +0.0 + 0 +LINE + 5 +1E2D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526037.8628631727 + 20 +179311.0930584983 + 30 +0.0 + 11 +526223.2294517805 + 21 +179180.8881075191 + 31 +0.0 + 0 +LINE + 5 +1E2E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525453.9796943118 + 20 +178887.2906102932 + 30 +0.0 + 11 +525336.510862941 + 21 +178764.6775143576 + 31 +0.0 + 0 +LINE + 5 +1E2F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525112.104843077 + 20 +179189.2114775647 + 30 +0.0 + 11 +525651.8629217101 + 21 +178660.5028461757 + 31 +0.0 + 0 +LINE + 5 +1E30 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525442.4910881526 + 20 +178769.7456822486 + 30 +0.0 + 11 +525208.4408025759 + 21 +178398.1219055309 + 31 +0.0 + 0 +LINE + 5 +1E31 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525494.9397722838 + 20 +178724.1522335949 + 30 +0.0 + 11 +525344.0020096121 + 21 +178845.9196755137 + 31 +0.0 + 0 +LINE + 5 +1E32 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525448.5004200477 + 20 +178668.3330185256 + 30 +0.0 + 11 +525398.783327276 + 21 +178709.1234143126 + 31 +0.0 + 0 +LINE + 5 +1E33 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525496.6873149113 + 20 +178693.5379424829 + 30 +0.0 + 11 +525432.6222732513 + 21 +178668.3799226858 + 31 +0.0 + 0 +LINE + 5 +1E34 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525447.4334000319 + 20 +178682.4758188987 + 30 +0.0 + 11 +525254.0435361588 + 21 +178328.6432902885 + 31 +0.0 + 0 +LINE + 5 +1E35 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525564.3501928733 + 20 +178511.6244250797 + 30 +0.0 + 11 +525194.722938555 + 21 +178682.7600061523 + 31 +0.0 + 0 +LINE + 5 +1E36 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525203.0709299968 + 20 +178693.1334353863 + 30 +0.0 + 11 +525099.213844755 + 21 +178499.6712213452 + 31 +0.0 + 0 +LINE + 5 +1E37 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525100.363960778 + 20 +178853.6235573177 + 30 +0.0 + 11 +525205.5847867179 + 21 +178675.1986159843 + 31 +0.0 + 0 +LINE + 5 +1E38 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525187.4493033807 + 20 +178857.8812028928 + 30 +0.0 + 11 +525126.4053077517 + 21 +178798.1739976407 + 31 +0.0 + 0 +LINE + 5 +1E39 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525501.2617850861 + 20 +178255.2585961814 + 30 +0.0 + 11 +525127.8717471582 + 21 +178461.7315855154 + 31 +0.0 + 0 +LINE + 5 +1E3A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525364.9235649414 + 20 +178799.0496326572 + 30 +0.0 + 11 +525146.0590417449 + 21 +178435.8230548363 + 31 +0.0 + 0 +LINE + 5 +1E3B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524315.2950718407 + 20 +179499.9302652056 + 30 +0.0 + 11 +525161.4225941317 + 21 +178440.5096480434 + 31 +0.0 + 0 +LINE + 5 +1E3C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525068.6142213994 + 20 +178695.2708080864 + 30 +0.0 + 11 +524915.1869988046 + 21 +178826.6759781821 + 31 +0.0 + 0 +LINE + 5 +1E3D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525143.1182611162 + 20 +178899.0615197718 + 30 +0.0 + 11 +524961.4177744454 + 21 +178659.2439450341 + 31 +0.0 + 0 +LINE + 5 +1E3E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525115.2362263225 + 20 +178985.9003487789 + 30 +0.0 + 11 +525188.9907645544 + 21 +178889.423752566 + 31 +0.0 + 0 +LINE + 5 +1E3F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525256.2919432123 + 20 +178966.1997378055 + 30 +0.0 + 11 +525149.2814960341 + 21 +179022.2041587109 + 31 +0.0 + 0 +LINE + 5 +1E40 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525155.9619816731 + 20 +179021.3406031857 + 30 +0.0 + 11 +525114.613382989 + 21 +178983.8184193446 + 31 +0.0 + 0 +LINE + 5 +1E41 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525432.8375440702 + 20 +179215.2514314149 + 30 +0.0 + 11 +525432.8292745313 + 21 +179215.2421442479 + 31 +0.0 + 0 +LINE + 5 +1E42 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525335.5056263998 + 20 +179105.9421037015 + 30 +0.0 + 11 +525058.7063969978 + 21 +178795.0806884354 + 31 +0.0 + 0 +LINE + 5 +1E43 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525059.173438758 + 20 +178782.0111958253 + 30 +0.0 + 11 +525041.1628657293 + 21 +178798.3014945095 + 31 +0.0 + 0 +LINE + 5 +1E44 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525129.6526905607 + 20 +178812.3535875894 + 30 +0.0 + 11 +524856.1793817239 + 21 +179032.8123675689 + 31 +0.0 + 0 +LINE + 5 +1E45 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524939.8713919292 + 20 +179087.6518164087 + 30 +0.0 + 11 +525114.1098324377 + 21 +178852.5851621675 + 31 +0.0 + 0 +LINE + 5 +1E46 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525199.3924246851 + 20 +178948.7349027456 + 30 +0.0 + 11 +525172.6550599113 + 21 +178972.1252224294 + 31 +0.0 + 0 +LINE + 5 +1E47 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524990.6328490503 + 20 +178932.978266497 + 30 +0.0 + 11 +524923.1892550706 + 21 +178868.4553881387 + 31 +0.0 + 0 +LINE + 5 +1E48 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524945.5489577764 + 20 +178895.5769624656 + 30 +0.0 + 11 +524927.1323034953 + 21 +178814.2540930681 + 31 +0.0 + 0 +LINE + 5 +1E49 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524956.6660133504 + 20 +178888.5997074953 + 30 +0.0 + 11 +524880.2829104158 + 21 +178864.3145432224 + 31 +0.0 + 0 +LINE + 5 +1E4A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524767.6972013128 + 20 +178987.9125720965 + 30 +0.0 + 11 +524892.0990735233 + 21 +178859.8708712906 + 31 +0.0 + 0 +LINE + 5 +1E4B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525309.292804869 + 20 +178696.9770215821 + 30 +0.0 + 11 +525266.2475391527 + 21 +178715.8771548452 + 31 +0.0 + 0 +LINE + 5 +1E4C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525302.3400723392 + 20 +178768.5047108219 + 30 +0.0 + 11 +525266.444000114 + 21 +178713.9861851008 + 31 +0.0 + 0 +LINE + 5 +1E4D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525351.7822017535 + 20 +178765.1818527446 + 30 +0.0 + 11 +525271.6900042621 + 21 +178832.0263209903 + 31 +0.0 + 0 +LINE + 5 +1E4E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525382.9712220381 + 20 +178934.1501266619 + 30 +0.0 + 11 +525166.9533134254 + 21 +178728.0069858551 + 31 +0.0 + 0 +LINE + 5 +1E4F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525172.5292890373 + 20 +178629.6267682583 + 30 +0.0 + 11 +525113.9851982472 + 21 +178665.8504233187 + 31 +0.0 + 0 +LINE + 5 +1E50 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525131.5631229839 + 20 +178692.4015905385 + 30 +0.0 + 11 +525099.7852125658 + 21 +178641.384570182 + 31 +0.0 + 0 +LINE + 5 +1E51 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525134.4685092385 + 20 +178684.3007825545 + 30 +0.0 + 11 +525074.3436879002 + 21 +178722.686740615 + 31 +0.0 + 0 +LINE + 5 +1E52 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525077.9024450775 + 20 +178723.7612563569 + 30 +0.0 + 11 +525047.0330050794 + 21 +178676.8713057391 + 31 +0.0 + 0 +LINE + 5 +1E53 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525108.8141582754 + 20 +178641.7280582332 + 30 +0.0 + 11 +525043.0334736655 + 21 +178682.7035305395 + 31 +0.0 + 0 +LINE + 5 +1E54 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525277.2864968406 + 20 +179951.9759059466 + 30 +0.0 + 11 +525397.6936000875 + 21 +179883.749843338 + 31 +0.0 + 0 +LINE + 5 +1E55 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525294.0384387862 + 20 +180099.9040169973 + 30 +0.0 + 11 +525712.441703776 + 21 +179966.4031726317 + 31 +0.0 + 0 +LINE + 5 +1E56 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525346.4713448314 + 20 +180029.9665745256 + 30 +0.0 + 11 +525722.3129646027 + 21 +179883.8838082623 + 31 +0.0 + 0 +LINE + 5 +1E57 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525367.0909789318 + 20 +179823.9700553612 + 30 +0.0 + 11 +525515.7739640111 + 21 +180142.0179360354 + 31 +0.0 + 0 +LINE + 5 +1E58 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525529.3928401671 + 20 +179730.5940236112 + 30 +0.0 + 11 +525563.208015364 + 21 +179814.1321880935 + 31 +0.0 + 0 +LINE + 5 +1E59 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525580.4817299055 + 20 +179668.5095368278 + 30 +0.0 + 11 +525747.3357151855 + 21 +180110.2197326648 + 31 +0.0 + 0 +LINE + 5 +1E5A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525334.4952972862 + 20 +180172.2827760843 + 30 +0.0 + 11 +525735.8738520661 + 21 +180035.4234245136 + 31 +0.0 + 0 +LINE + 5 +1E5B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525732.0503643001 + 20 +180418.4899406992 + 30 +0.0 + 11 +525731.7300309989 + 21 +180029.8125402269 + 31 +0.0 + 0 +LINE + 5 +1E5C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525442.7963232096 + 20 +180130.0395851312 + 30 +0.0 + 11 +525463.5480601659 + 21 +180172.2234132085 + 31 +0.0 + 0 +LINE + 5 +1E5D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525402.0412609708 + 20 +180189.2305955932 + 30 +0.0 + 11 +525464.6158193738 + 21 +180170.6504371254 + 31 +0.0 + 0 +LINE + 5 +1E5E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525506.3853305195 + 20 +179710.566768304 + 30 +0.0 + 11 +526021.5022715954 + 21 +179655.2726091083 + 31 +0.0 + 0 +LINE + 5 +1E5F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525810.9415731873 + 20 +180127.6242478806 + 30 +0.0 + 11 +525780.88439704 + 21 +179743.3309206274 + 31 +0.0 + 0 +LINE + 5 +1E60 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525919.6974796773 + 20 +180124.5517712393 + 30 +0.0 + 11 +525847.3873537419 + 21 +179372.4594590579 + 31 +0.0 + 0 +LINE + 5 +1E61 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525937.1719437012 + 20 +179590.8840211527 + 30 +0.0 + 11 +526355.5752086912 + 21 +179457.3831767871 + 31 +0.0 + 0 +LINE + 5 +1E62 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525926.4214307014 + 20 +179522.2250559882 + 30 +0.0 + 11 +525963.4414776904 + 21 +179712.5905839408 + 31 +0.0 + 0 +LINE + 5 +1E63 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525997.8985076456 + 20 +179509.4412506651 + 30 +0.0 + 11 +526009.6533903446 + 21 +179572.666786921 + 31 +0.0 + 0 +LINE + 5 +1E64 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525944.8043687644 + 20 +179497.6821076383 + 30 +0.0 + 11 +526010.0137117215 + 21 +179519.7047576626 + 31 +0.0 + 0 +LINE + 5 +1E65 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526143.2653595122 + 20 +179461.2215478405 + 30 +0.0 + 11 +526365.4464695179 + 21 +179374.8638124178 + 31 +0.0 + 0 +LINE + 5 +1E66 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526075.4860245848 + 20 +179822.5807993095 + 30 +0.0 + 11 +526160.6387781117 + 21 +179816.2303404174 + 31 +0.0 + 0 +LINE + 5 +1E67 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526269.8843402822 + 20 +179283.9459924196 + 30 +0.0 + 11 +526324.2307933421 + 21 +179493.875925033 + 31 +0.0 + 0 +LINE + 5 +1E68 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525977.6288022012 + 20 +179663.2627802396 + 30 +0.0 + 11 +526379.0073569811 + 21 +179526.4034286693 + 31 +0.0 + 0 +LINE + 5 +1E69 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526049.3398680841 + 20 +179889.4997319409 + 30 +0.0 + 11 +526376.3294029554 + 21 +179816.2346214849 + 31 +0.0 + 0 +LINE + 5 +1E6A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526024.0580070095 + 20 +179799.402942206 + 30 +0.0 + 11 +526063.8685273676 + 21 +179914.1312647571 + 31 +0.0 + 0 +LINE + 5 +1E6B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525972.0353627549 + 20 +179813.8335785763 + 30 +0.0 + 11 +526026.138241068 + 21 +179800.0314247022 + 31 +0.0 + 0 +LINE + 5 +1E6C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525657.5913718472 + 20 +179937.8757606729 + 30 +0.0 + 11 +526214.4151226173 + 21 +179857.4712891304 + 31 +0.0 + 0 +LINE + 5 +1E6D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526222.4763599335 + 20 +179847.1734146887 + 30 +0.0 + 11 +526225.7597894024 + 21 +179871.2352862486 + 31 +0.0 + 0 +LINE + 5 +1E6E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526149.0212757887 + 20 +179824.9847625001 + 30 +0.0 + 11 +526228.1798567896 + 21 +180171.0884570164 + 31 +0.0 + 0 +LINE + 5 +1E6F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525909.5190576763 + 20 +180107.530341743 + 30 +0.0 + 11 +526099.4004078702 + 21 +180182.1743046431 + 31 +0.0 + 0 +LINE + 5 +1E70 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526079.818921055 + 20 +180206.3384580108 + 30 +0.0 + 11 +526134.9957632876 + 21 +179865.7701156398 + 31 +0.0 + 0 +LINE + 5 +1E71 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525711.9185847874 + 20 +180106.0034193516 + 30 +0.0 + 11 +525980.9621560936 + 21 +180122.2722011088 + 31 +0.0 + 0 +LINE + 5 +1E72 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526085.9298281247 + 20 +179621.0195892866 + 30 +0.0 + 11 +526106.6815650811 + 21 +179663.2034173638 + 31 +0.0 + 0 +LINE + 5 +1E73 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526045.1747658859 + 20 +179680.2105997487 + 30 +0.0 + 11 +526107.7493242888 + 21 +179661.6304412809 + 31 +0.0 + 0 +LINE + 5 +1E74 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526009.4961502297 + 20 +179645.8216199492 + 30 +0.0 + 11 +526027.7031022563 + 21 +179748.5418707858 + 31 +0.0 + 0 +LINE + 5 +1E75 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525795.056840274 + 20 +179988.0281649024 + 30 +0.0 + 11 +525906.6924360145 + 21 +179972.4697489455 + 31 +0.0 + 0 +LINE + 5 +1E76 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526157.3721671854 + 20 +180128.6556673708 + 30 +0.0 + 11 +526202.1834097474 + 21 +180292.4386035349 + 31 +0.0 + 0 +LINE + 5 +1E77 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525722.6754663999 + 20 +180266.7621564555 + 30 +0.0 + 11 +526453.6159464396 + 21 +180075.4571251711 + 31 +0.0 + 0 +LINE + 5 +1E78 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526252.3018776702 + 20 +180198.9205109824 + 30 +0.0 + 11 +526445.7753829477 + 21 +180682.057749667 + 31 +0.0 + 0 +LINE + 5 +1E79 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526318.3682829335 + 20 +180177.3599654693 + 30 +0.0 + 11 +526136.3410382619 + 21 +180244.2598930404 + 31 +0.0 + 0 +LINE + 5 +1E7A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526301.4865506871 + 20 +180101.2214370023 + 30 +0.0 + 11 +526334.1850046179 + 21 +180259.4809290837 + 31 +0.0 + 0 +LINE + 5 +1E7B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526329.704907844 + 20 +180239.5311797255 + 30 +0.0 + 11 +526534.9801261073 + 21 +180484.6040825584 + 31 +0.0 + 0 +LINE + 5 +1E7C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526087.5384759946 + 20 +180296.8030922689 + 30 +0.0 + 11 +526317.4288490493 + 21 +180648.7166901801 + 31 +0.0 + 0 +LINE + 5 +1E7D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525898.6919355042 + 20 +180368.563056517 + 30 +0.0 + 11 +526019.3572832418 + 21 +180354.8758587771 + 31 +0.0 + 0 +LINE + 5 +1E7E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525988.0841471649 + 20 +180257.6853678938 + 30 +0.0 + 11 +525885.0460868631 + 21 +180320.7003589317 + 31 +0.0 + 0 +LINE + 5 +1E7F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525889.220156881 + 20 +180315.4134169037 + 30 +0.0 + 11 +525900.1577889329 + 21 +180370.1673126414 + 31 +0.0 + 0 +LINE + 5 +1E80 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525865.1707519406 + 20 +179978.2441530627 + 30 +0.0 + 11 +525865.1744688462 + 21 +179978.2560198802 + 31 +0.0 + 0 +LINE + 5 +1E81 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525908.9184783546 + 20 +180117.9157956967 + 30 +0.0 + 11 +526306.8625173747 + 21 +181086.3192754854 + 31 +0.0 + 0 +LINE + 5 +1E82 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526206.5401921418 + 20 +180432.3696421253 + 30 +0.0 + 11 +525861.4479683868 + 21 +180549.1055735451 + 31 +0.0 + 0 +LINE + 5 +1E83 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525770.026693169 + 20 +180436.6193017752 + 30 +0.0 + 11 +526039.9112933834 + 21 +180406.3982521934 + 31 +0.0 + 0 +LINE + 5 +1E84 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525973.8238669656 + 20 +180315.4713530542 + 30 +0.0 + 11 +525940.0178018569 + 21 +180326.3866492873 + 31 +0.0 + 0 +LINE + 5 +1E85 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526387.676675063 + 20 +180393.9615060689 + 30 +0.0 + 11 +526207.9357806169 + 21 +180377.7926894812 + 31 +0.0 + 0 +LINE + 5 +1E86 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526181.3390144858 + 20 +180319.7845639188 + 30 +0.0 + 11 +526209.6588850731 + 21 +180378.5959792896 + 31 +0.0 + 0 +LINE + 5 +1E87 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526080.6813073879 + 20 +180165.4867606541 + 30 +0.0 + 11 +526132.4291998959 + 21 +180394.4715974546 + 31 +0.0 + 0 +LINE + 5 +1E88 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525789.3590273023 + 20 +180289.1511682799 + 30 +0.0 + 11 +525865.3960941447 + 21 +180094.2260030026 + 31 +0.0 + 0 +LINE + 5 +1E89 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526198.2549186949 + 20 +180325.3350620853 + 30 +0.0 + 11 +526090.5181339454 + 21 +180371.4108565399 + 31 +0.0 + 0 +LINE + 5 +1E8A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525368.8224255521 + 20 +179827.6737940761 + 30 +0.0 + 11 +525405.0512025434 + 21 +179632.8619158082 + 31 +0.0 + 0 +LINE + 5 +1E8B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526340.1321654935 + 20 +180444.2921744968 + 30 +0.0 + 11 +525959.6088533624 + 21 +180667.0275531655 + 31 +0.0 + 0 +LINE + 5 +1E8C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525943.4109402349 + 20 +180796.5443965836 + 30 +0.0 + 11 +526008.5505737855 + 21 +181146.5684762149 + 31 +0.0 + 0 +LINE + 5 +1E8D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525600.2574380592 + 20 +180032.4074553064 + 30 +0.0 + 11 +525594.054054251 + 21 +180351.3841439652 + 31 +0.0 + 0 +LINE + 5 +1E8E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526288.1311668085 + 20 +179495.7837681826 + 30 +0.0 + 11 +526168.5844052437 + 21 +179281.6470285089 + 31 +0.0 + 0 +LINE + 5 +1E8F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526267.7956939577 + 20 +179469.0424015861 + 30 +0.0 + 11 +526508.5909987458 + 21 +179449.6436152699 + 31 +0.0 + 0 +LINE + 5 +1E90 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526406.7862068278 + 20 +179918.9227774008 + 30 +0.0 + 11 +526334.4760808925 + 21 +179166.8304652195 + 31 +0.0 + 0 +LINE + 5 +1E91 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526424.2606708517 + 20 +179385.2550273141 + 30 +0.0 + 11 +526842.6639358418 + 21 +179251.7541829487 + 31 +0.0 + 0 +LINE + 5 +1E92 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526413.5101578521 + 20 +179316.5960621496 + 30 +0.0 + 11 +526450.530204841 + 21 +179506.9615901023 + 31 +0.0 + 0 +LINE + 5 +1E93 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526484.9872347962 + 20 +179303.8122568266 + 30 +0.0 + 11 +526496.7421174952 + 21 +179367.0377930824 + 31 +0.0 + 0 +LINE + 5 +1E94 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526476.6935768971 + 20 +179315.3175848426 + 30 +0.0 + 11 +526852.5351966685 + 21 +179169.2348185793 + 31 +0.0 + 0 +LINE + 5 +1E95 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526543.8107781008 + 20 +179209.0480168294 + 30 +0.0 + 11 +526669.8122892258 + 21 +179478.3139683937 + 31 +0.0 + 0 +LINE + 5 +1E96 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526656.744931586 + 20 +179480.8715374547 + 30 +0.0 + 11 +526878.6866667965 + 21 +179392.680620322 + 31 +0.0 + 0 +LINE + 5 +1E97 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526631.9300359334 + 20 +179669.7895665503 + 30 +0.0 + 11 +526666.3744463014 + 21 +179465.5336865968 + 31 +0.0 + 0 +LINE + 5 +1E98 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526562.5747517353 + 20 +179616.9518054711 + 30 +0.0 + 11 +526647.7275052624 + 21 +179610.601346579 + 31 +0.0 + 0 +LINE + 5 +1E99 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526756.9730674327 + 20 +179078.316998581 + 30 +0.0 + 11 +526877.5579472513 + 21 +179395.5707429818 + 31 +0.0 + 0 +LINE + 5 +1E9A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526464.7175293518 + 20 +179457.6337864013 + 30 +0.0 + 11 +526866.0960841318 + 21 +179320.7744348308 + 31 +0.0 + 0 +LINE + 5 +1E9B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526860.6184147858 + 20 +179858.7988541849 + 30 +0.0 + 11 +526861.9522630644 + 21 +179315.163550544 + 31 +0.0 + 0 +LINE + 5 +1E9C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526772.4217413488 + 20 +179820.7069533161 + 30 +0.0 + 11 +526875.3762699339 + 21 +179764.2278175836 + 31 +0.0 + 0 +LINE + 5 +1E9D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526772.0407339991 + 20 +179758.6193984473 + 30 +0.0 + 11 +526874.6621442611 + 21 +179797.7914169808 + 31 +0.0 + 0 +LINE + 5 +1E9E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526758.2159975106 + 20 +179569.1143707557 + 30 +0.0 + 11 +526790.9322939016 + 21 +179768.4554736715 + 31 +0.0 + 0 +LINE + 5 +1E9F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526536.4285952347 + 20 +179683.8707381025 + 30 +0.0 + 11 +526963.5064845303 + 21 +179587.5356502704 + 31 +0.0 + 0 +LINE + 5 +1EA0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526511.14673416 + 20 +179593.7739483675 + 30 +0.0 + 11 +526550.9572545182 + 21 +179708.5022709184 + 31 +0.0 + 0 +LINE + 5 +1EA1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526459.1240899054 + 20 +179608.204584738 + 30 +0.0 + 11 +526513.2269682183 + 21 +179594.4024308638 + 31 +0.0 + 0 +LINE + 5 +1EA2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525753.434535395 + 20 +179785.4801100221 + 30 +0.0 + 11 +526701.5038497678 + 21 +179651.842295292 + 31 +0.0 + 0 +LINE + 5 +1EA3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526709.5650870841 + 20 +179641.5444208502 + 30 +0.0 + 11 +526712.8485165531 + 21 +179665.6062924103 + 31 +0.0 + 0 +LINE + 5 +1EA4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526822.969650723 + 20 +179488.9249607078 + 30 +0.0 + 11 +526868.2553233158 + 21 +179487.0960181053 + 31 +0.0 + 0 +LINE + 5 +1EA5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526809.6007739837 + 20 +179481.013019071 + 30 +0.0 + 11 +526831.2178066143 + 21 +179491.5889508443 + 31 +0.0 + 0 +LINE + 5 +1EA6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526795.9591495938 + 20 +179418.3841441678 + 30 +0.0 + 11 +526813.2729176061 + 21 +179488.112874319 + 31 +0.0 + 0 +LINE + 5 +1EA7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526636.1100029395 + 20 +179619.3557686616 + 30 +0.0 + 11 +526715.2685839402 + 21 +179965.4594631777 + 31 +0.0 + 0 +LINE + 5 +1EA8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526396.6077848269 + 20 +179901.9013479045 + 30 +0.0 + 11 +526586.4891350208 + 21 +179976.5453108047 + 31 +0.0 + 0 +LINE + 5 +1EA9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526566.9076482057 + 20 +180000.7094641722 + 30 +0.0 + 11 +526622.0844904381 + 21 +179660.1411218014 + 31 +0.0 + 0 +LINE + 5 +1EAA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526494.9174763462 + 20 +179678.7541194271 + 30 +0.0 + 11 +526500.3027970688 + 21 +179713.8681059663 + 31 +0.0 + 0 +LINE + 5 +1EAB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526664.7499560606 + 20 +179801.1704616331 + 30 +0.0 + 11 +526757.8997831164 + 21 +179795.258615892 + 31 +0.0 + 0 +LINE + 5 +1EAC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526723.3266480838 + 20 +179801.6016776982 + 30 +0.0 + 11 +526789.7965023669 + 21 +179751.2594418172 + 31 +0.0 + 0 +LINE + 5 +1EAD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526719.3173330142 + 20 +179789.1038217133 + 30 +0.0 + 11 +526793.3866987752 + 21 +179819.7285939321 + 31 +0.0 + 0 +LINE + 5 +1EAE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526793.4123204343 + 20 +179934.5500188108 + 30 +0.0 + 11 +526787.2106635646 + 21 +179808.7183932118 + 31 +0.0 + 0 +LINE + 5 +1EAF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526163.6968290265 + 20 +179991.1895204469 + 30 +0.0 + 11 +526468.0508832441 + 21 +179916.6432072703 + 31 +0.0 + 0 +LINE + 5 +1EB0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526573.0185552753 + 20 +179415.3905954482 + 30 +0.0 + 11 +526593.7702922315 + 21 +179457.5744235253 + 31 +0.0 + 0 +LINE + 5 +1EB1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526532.2634930363 + 20 +179474.5816059103 + 30 +0.0 + 11 +526594.8380514394 + 21 +179456.0014474424 + 31 +0.0 + 0 +LINE + 5 +1EB2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526496.5848773803 + 20 +179440.1926261107 + 30 +0.0 + 11 +526514.7918294069 + 21 +179542.9128769474 + 31 +0.0 + 0 +LINE + 5 +1EB3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526363.8900139225 + 20 +179549.3489625679 + 30 +0.0 + 11 +526661.9086167068 + 21 +179530.8113322588 + 31 +0.0 + 0 +LINE + 5 +1EB4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526721.0133640281 + 20 +179451.967261064 + 30 +0.0 + 11 +526742.4617267929 + 21 +179517.3853891871 + 31 +0.0 + 0 +LINE + 5 +1EB5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526711.9136583285 + 20 +179526.3722369036 + 30 +0.0 + 11 +526769.0827439912 + 21 +179507.8177872728 + 31 +0.0 + 0 +LINE + 5 +1EB6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526714.9092809126 + 20 +179518.3043620523 + 30 +0.0 + 11 +526736.1739570874 + 21 +179586.3946657991 + 31 +0.0 + 0 +LINE + 5 +1EB7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526732.759683507 + 20 +179584.9242669951 + 30 +0.0 + 11 +526786.5754879611 + 21 +179568.9414954683 + 31 +0.0 + 0 +LINE + 5 +1EB8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526761.9551253384 + 20 +179502.2646893075 + 30 +0.0 + 11 +526785.878060321 + 21 +179575.9788736977 + 31 +0.0 + 0 +LINE + 5 +1EB9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526282.1455674244 + 20 +179782.3991710638 + 30 +0.0 + 11 +526393.7811631652 + 21 +179766.8407551071 + 31 +0.0 + 0 +LINE + 5 +1EBA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526847.7872470182 + 20 +179818.1888913642 + 30 +0.0 + 11 +527137.9529271293 + 21 +180223.3699557505 + 31 +0.0 + 0 +LINE + 5 +1EBB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526827.1464023706 + 20 +179883.7857841154 + 30 +0.0 + 11 +526969.3070185326 + 21 +180061.1550711378 + 31 +0.0 + 0 +LINE + 5 +1EBC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526644.4608943359 + 20 +179923.0266735323 + 30 +0.0 + 11 +526616.8198055494 + 21 +180035.3862282373 + 31 +0.0 + 0 +LINE + 5 +1EBD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526307.4165122343 + 20 +180027.1168364971 + 30 +0.0 + 11 +527138.5741937184 + 21 +179816.0033204743 + 31 +0.0 + 0 +LINE + 5 +1EBE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526829.4741782867 + 20 +180040.2552289311 + 30 +0.0 + 11 +526768.9318332369 + 21 +180061.9409421541 + 31 +0.0 + 0 +LINE + 5 +1EBF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526832.6170945618 + 20 +179985.9653854469 + 30 +0.0 + 11 +526821.2737317685 + 21 +180053.8519352452 + 31 +0.0 + 0 +LINE + 5 +1EC0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526816.7936349946 + 20 +180033.9021858869 + 30 +0.0 + 11 +526957.2168035019 + 21 +180224.7761332145 + 31 +0.0 + 0 +LINE + 5 +1EC1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526352.2594790912 + 20 +179772.6151592242 + 30 +0.0 + 11 +526352.2631959968 + 21 +179772.6270260417 + 31 +0.0 + 0 +LINE + 5 +1EC2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526314.9106074973 + 20 +180249.9782180647 + 30 +0.0 + 11 +526507.1714302967 + 21 +180187.2289110584 + 31 +0.0 + 0 +LINE + 5 +1EC3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527073.8171808937 + 20 +179977.5827294601 + 30 +0.0 + 11 +526861.4098158871 + 21 +180120.8741309933 + 31 +0.0 + 0 +LINE + 5 +1EC4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527049.1786023032 + 20 +180034.3736699857 + 30 +0.0 + 11 +526985.7328634694 + 21 +179826.2728416301 + 31 +0.0 + 0 +LINE + 5 +1EC5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +527002.591502373 + 20 +179513.810835256 + 30 +0.0 + 11 +526852.862144296 + 21 +179367.1654655456 + 31 +0.0 + 0 +LINE + 5 +1EC6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526660.724472809 + 20 +179125.7359711999 + 30 +0.0 + 11 +526725.8641063598 + 21 +179475.760050831 + 31 +0.0 + 0 +LINE + 5 +1EC7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525746.0995262102 + 20 +182025.6174555021 + 30 +0.0 + 11 +525056.4892183749 + 21 +182481.9606767529 + 31 +0.0 + 0 +LINE + 5 +1EC8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526255.1770219457 + 20 +176496.5269798067 + 30 +0.0 + 11 +526588.3769258359 + 21 +177160.7654823236 + 31 +0.0 + 0 +LINE + 5 +1EC9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526351.7667754745 + 20 +176673.6706001668 + 30 +0.0 + 11 +525577.3034436981 + 21 +176834.8452365946 + 31 +0.0 + 0 +LINE + 5 +1ECA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526216.2354019187 + 20 +176698.8657335175 + 30 +0.0 + 11 +526269.3892037421 + 21 +176836.823582357 + 31 +0.0 + 0 +LINE + 5 +1ECB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526377.1301782186 + 20 +176733.7209433581 + 30 +0.0 + 11 +525892.8589853867 + 21 +176833.5508917015 + 31 +0.0 + 0 +LINE + 5 +1ECC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526266.7460571489 + 20 +176804.2846207156 + 30 +0.0 + 11 +526251.1719546794 + 21 +176884.7740336025 + 31 +0.0 + 0 +LINE + 5 +1ECD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526343.2823493881 + 20 +176826.5895884126 + 30 +0.0 + 11 +526256.8146720737 + 21 +176811.0728471291 + 31 +0.0 + 0 +LINE + 5 +1ECE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526328.1489277797 + 20 +176815.0700631957 + 30 +0.0 + 11 +526415.8642461339 + 21 +176993.564532887 + 31 +0.0 + 0 +LINE + 5 +1ECF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526446.5501364223 + 20 +176783.258144649 + 30 +0.0 + 11 +526092.1384880852 + 21 +177031.9579734428 + 31 +0.0 + 0 +LINE + 5 +1ED0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526368.9639172092 + 20 +177024.2979221347 + 30 +0.0 + 11 +526249.7236978589 + 21 +176880.6956629269 + 31 +0.0 + 0 +LINE + 5 +1ED1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526417.8419793417 + 20 +176988.4573184709 + 30 +0.0 + 11 +526368.1267487453 + 21 +177024.1646920515 + 31 +0.0 + 0 +LINE + 5 +1ED2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526561.6444323391 + 20 +177248.7898130673 + 30 +0.0 + 11 +526383.958226091 + 21 +177010.5177453355 + 31 +0.0 + 0 +LINE + 5 +1ED3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526523.7346062075 + 20 +177191.8291896897 + 30 +0.0 + 11 +526428.6418707171 + 21 +177253.1086558552 + 31 +0.0 + 0 +LINE + 5 +1ED4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526477.7731172824 + 20 +177318.0926977102 + 30 +0.0 + 11 +526002.9071639054 + 21 +176654.219553631 + 31 +0.0 + 0 +LINE + 5 +1ED5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526113.2047176925 + 20 +176927.9689911812 + 30 +0.0 + 11 +525710.4109407036 + 21 +177103.0145304551 + 31 +0.0 + 0 +LINE + 5 +1ED6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526076.0838334604 + 20 +176869.2181019876 + 30 +0.0 + 11 +526173.577774299 + 21 +177036.861919683 + 31 +0.0 + 0 +LINE + 5 +1ED7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526013.8731623593 + 20 +176906.6644717475 + 30 +0.0 + 11 +526046.6602886157 + 21 +176961.9876138668 + 31 +0.0 + 0 +LINE + 5 +1ED8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526046.0877021004 + 20 +176862.852504689 + 30 +0.0 + 11 +526011.5139015976 + 21 +176922.3664345021 + 31 +0.0 + 0 +LINE + 5 +1ED9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526027.6910453359 + 20 +176909.8618838492 + 30 +0.0 + 11 +525648.6434118033 + 21 +177047.4118357381 + 31 +0.0 + 0 +LINE + 5 +1EDA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525876.5253984999 + 20 +176768.4098338997 + 30 +0.0 + 11 +525989.6849763969 + 21 +177159.6982239322 + 31 +0.0 + 0 +LINE + 5 +1EDB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526001.2034243672 + 20 +177153.0182275587 + 30 +0.0 + 11 +525776.1000689673 + 21 +177232.7944839307 + 31 +0.0 + 0 +LINE + 5 +1EDC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526144.2802689023 + 20 +177278.8546981125 + 30 +0.0 + 11 +525983.856499181 + 21 +177147.8161693907 + 31 +0.0 + 0 +LINE + 5 +1EDD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526161.6826575419 + 20 +177193.4196859003 + 30 +0.0 + 11 +526093.4161965302 + 21 +177244.7130583994 + 31 +0.0 + 0 +LINE + 5 +1EDE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525765.760308933 + 20 +176778.6599923234 + 30 +0.0 + 11 +525795.3209390993 + 21 +176863.7967067469 + 31 +0.0 + 0 +LINE + 5 +1EDF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525613.560714316 + 20 +176791.9291939231 + 30 +0.0 + 11 +525778.8526571896 + 21 +177234.2262921855 + 31 +0.0 + 0 +LINE + 5 +1EE0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526130.4185050208 + 20 +177009.0808133312 + 30 +0.0 + 11 +525738.2257169645 + 21 +177170.3881081017 + 31 +0.0 + 0 +LINE + 5 +1EE1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526055.738486585 + 20 +177527.5817907187 + 30 +0.0 + 11 +525737.6495586863 + 21 +177163.4367544813 + 31 +0.0 + 0 +LINE + 5 +1EE2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526207.3805466062 + 20 +177730.5288642783 + 30 +0.0 + 11 +525870.8327531437 + 21 +177308.9803985171 + 31 +0.0 + 0 +LINE + 5 +1EE3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526137.9265610156 + 20 +177484.9459577887 + 30 +0.0 + 11 +526023.2532773761 + 21 +177510.2355949675 + 31 +0.0 + 0 +LINE + 5 +1EE4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526097.3289771107 + 20 +177437.968880216 + 30 +0.0 + 11 +526045.8921695055 + 21 +177535.0248213197 + 31 +0.0 + 0 +LINE + 5 +1EE5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525982.9452194781 + 20 +177286.2466509642 + 30 +0.0 + 11 +526089.5884684561 + 21 +177457.8113583155 + 31 +0.0 + 0 +LINE + 5 +1EE6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526225.4256337584 + 20 +177226.5647915325 + 30 +0.0 + 11 +525931.0934040827 + 21 +177386.7474088776 + 31 +0.0 + 0 +LINE + 5 +1EE7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526185.12413629 + 20 +177142.1112935483 + 30 +0.0 + 11 +526230.7113104238 + 21 +177254.669167911 + 31 +0.0 + 0 +LINE + 5 +1EE8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526315.9341363822 + 20 +177198.4457698113 + 30 +0.0 + 11 +526227.5644827577 + 21 +177116.1139091223 + 31 +0.0 + 0 +LINE + 5 +1EE9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526233.7781151948 + 20 +177118.7149451577 + 30 +0.0 + 11 +526183.9724349232 + 21 +177143.9541033457 + 31 +0.0 + 0 +LINE + 5 +1EEA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526552.1051833143 + 20 +177005.0075836561 + 30 +0.0 + 11 +526080.1018509581 + 21 +177311.1618302548 + 31 +0.0 + 0 +LINE + 5 +1EEB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526067.253986068 + 20 +177308.720082347 + 30 +0.0 + 11 +526080.6275394143 + 21 +177328.9908160026 + 31 +0.0 + 0 +LINE + 5 +1EEC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525881.4082668052 + 20 +177268.5372091289 + 30 +0.0 + 11 +525846.1225825818 + 21 +177296.9811480634 + 31 +0.0 + 0 +LINE + 5 +1EED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525886.2595165639 + 20 +177253.7794633145 + 30 +0.0 + 11 +525876.9550485725 + 21 +177275.9734559256 + 31 +0.0 + 0 +LINE + 5 +1EEE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525855.2852228508 + 20 +177197.6629504452 + 30 +0.0 + 11 +525888.1711318466 + 21 +177261.5407976287 + 31 +0.0 + 0 +LINE + 5 +1EEF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526107.9240993181 + 20 +177243.6514450411 + 30 +0.0 + 11 +526320.9250431739 + 21 +177622.1853045925 + 31 +0.0 + 0 +LINE + 5 +1EF0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526325.353944576 + 20 +177590.736076287 + 30 +0.0 + 11 +526135.2587465105 + 21 +177656.903499832 + 31 +0.0 + 0 +LINE + 5 +1EF1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526474.2247281625 + 20 +177298.5801819529 + 30 +0.0 + 11 +526300.5256348284 + 21 +177617.0345583299 + 31 +0.0 + 0 +LINE + 5 +1EF2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526422.077933941 + 20 +177548.0943386304 + 30 +0.0 + 11 +526145.3364330091 + 21 +177265.1101803126 + 31 +0.0 + 0 +LINE + 5 +1EF3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526253.2970288973 + 20 +177195.3792482302 + 30 +0.0 + 11 +526272.3664885074 + 21 +177225.3517262752 + 31 +0.0 + 0 +LINE + 5 +1EF4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526206.0940969802 + 20 +177399.3417821021 + 30 +0.0 + 11 +526132.0979797496 + 21 +177456.2312788077 + 31 +0.0 + 0 +LINE + 5 +1EF5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526162.294088263 + 20 +177438.2387489769 + 30 +0.0 + 11 +526079.1197531001 + 21 +177444.1219634151 + 31 +0.0 + 0 +LINE + 5 +1EF6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526157.0816685246 + 20 +177426.1929326067 + 30 +0.0 + 11 +526121.5043960536 + 21 +177498.0149717119 + 31 +0.0 + 0 +LINE + 5 +1EF7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526226.6183319566 + 20 +177628.0267985385 + 30 +0.0 + 11 +526118.902231297 + 21 +177485.6619692671 + 31 +0.0 + 0 +LINE + 5 +1EF8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526696.7584575979 + 20 +177276.0780754461 + 30 +0.0 + 11 +526578.4914040608 + 21 +177144.8938979601 + 31 +0.0 + 0 +LINE + 5 +1EF9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526628.7751494532 + 20 +177183.8240075886 + 30 +0.0 + 11 +526430.1651325173 + 21 +177356.7195899359 + 31 +0.0 + 0 +LINE + 5 +1EFA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526021.0958195116 + 20 +177048.6048545089 + 30 +0.0 + 11 +526033.2561919037 + 21 +177094.0166952692 + 31 +0.0 + 0 +LINE + 5 +1EFB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526090.744449026 + 20 +177066.3141521915 + 30 +0.0 + 11 +526031.4168155517 + 21 +177093.5360102175 + 31 +0.0 + 0 +LINE + 5 +1EFC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526094.9506934654 + 20 +177016.939330121 + 30 +0.0 + 11 +526148.8891460266 + 21 +177106.2342704555 + 31 +0.0 + 0 +LINE + 5 +1EFD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526266.6937747585 + 20 +177011.7099319813 + 30 +0.0 + 11 +526030.2023995345 + 21 +177194.0024463306 + 31 +0.0 + 0 +LINE + 5 +1EFE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525933.8026293408 + 20 +177173.5857123843 + 30 +0.0 + 11 +525960.7383942654 + 21 +177236.9420721305 + 31 +0.0 + 0 +LINE + 5 +1EFF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525989.6462154662 + 20 +177223.5897018464 + 30 +0.0 + 11 +525934.4035908969 + 21 +177247.2714329343 + 31 +0.0 + 0 +LINE + 5 +1F00 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525982.0791010418 + 20 +177219.4905386911 + 30 +0.0 + 11 +526010.9127192368 + 21 +177284.7369821109 + 31 +0.0 + 0 +LINE + 5 +1F01 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526012.5140018397 + 20 +177281.3821004813 + 30 +0.0 + 11 +525961.4884440385 + 21 +177304.7911210896 + 31 +0.0 + 0 +LINE + 5 +1F02 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525936.1110470527 + 20 +177238.398753624 + 30 +0.0 + 11 +525966.6473939993 + 21 +177309.6280966901 + 31 +0.0 + 0 +LINE + 5 +1F03 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526481.6757723958 + 20 +177133.2718294049 + 30 +0.0 + 11 +526387.4153207091 + 21 +177195.0742386724 + 31 +0.0 + 0 +LINE + 5 +1F04 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525913.1651616291 + 20 +176885.9301494603 + 30 +0.0 + 11 +525659.7319104015 + 21 +176961.9915518347 + 31 +0.0 + 0 +LINE + 5 +1F05 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525397.0355684111 + 20 +176739.2847153854 + 30 +0.0 + 11 +525450.1893702347 + 21 +176877.2425642249 + 31 +0.0 + 0 +LINE + 5 +1F06 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525557.930344711 + 20 +176774.139925226 + 30 +0.0 + 11 +525073.6591518792 + 21 +176873.9698735696 + 31 +0.0 + 0 +LINE + 5 +1F07 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525447.5462236413 + 20 +176844.7036025835 + 30 +0.0 + 11 +525431.9721211719 + 21 +176925.1930154706 + 31 +0.0 + 0 +LINE + 5 +1F08 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525524.0825158807 + 20 +176867.0085702805 + 30 +0.0 + 11 +525437.6148385663 + 21 +176851.4918289969 + 31 +0.0 + 0 +LINE + 5 +1F09 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525509.5870126812 + 20 +176857.1960215582 + 30 +0.0 + 11 +525597.3023310353 + 21 +177035.6904912493 + 31 +0.0 + 0 +LINE + 5 +1F0A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525697.0190445365 + 20 +176774.7887669079 + 30 +0.0 + 11 +525272.9386545777 + 21 +177072.376955311 + 31 +0.0 + 0 +LINE + 5 +1F0B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525549.7640837018 + 20 +177064.7169040027 + 30 +0.0 + 11 +525430.5238643515 + 21 +176921.1146447949 + 31 +0.0 + 0 +LINE + 5 +1F0C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525598.6421458342 + 20 +177028.8763003388 + 30 +0.0 + 11 +525548.9269152378 + 21 +177064.5836739195 + 31 +0.0 + 0 +LINE + 5 +1F0D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525742.4445988317 + 20 +177289.2087949354 + 30 +0.0 + 11 +525564.7583925835 + 21 +177050.9367272036 + 31 +0.0 + 0 +LINE + 5 +1F0E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525704.5347726999 + 20 +177232.2481715577 + 30 +0.0 + 11 +525609.4420372094 + 21 +177293.5276377232 + 31 +0.0 + 0 +LINE + 5 +1F0F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525658.5732837748 + 20 +177358.5116795782 + 30 +0.0 + 11 +525217.744042467 + 21 +176744.8821656507 + 31 +0.0 + 0 +LINE + 5 +1F10 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525294.004884185 + 20 +176968.3879730492 + 30 +0.0 + 11 +524709.4042916746 + 21 +177247.8133178601 + 31 +0.0 + 0 +LINE + 5 +1F11 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525256.8839999527 + 20 +176909.6370838556 + 30 +0.0 + 11 +525354.3779407914 + 21 +177077.280901551 + 31 +0.0 + 0 +LINE + 5 +1F12 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525194.6733288519 + 20 +176947.0834536155 + 30 +0.0 + 11 +525227.4604551082 + 21 +177002.4065957346 + 31 +0.0 + 0 +LINE + 5 +1F13 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525226.887868593 + 20 +176903.2714865569 + 30 +0.0 + 11 +525192.3140680902 + 21 +176962.78541637 + 31 +0.0 + 0 +LINE + 5 +1F14 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525208.4912118285 + 20 +176950.2808657172 + 30 +0.0 + 11 +525076.3479310441 + 21 +176998.2334191865 + 31 +0.0 + 0 +LINE + 5 +1F15 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525057.3255649925 + 20 +176808.8288157677 + 30 +0.0 + 11 +525170.4851428896 + 21 +177200.1172058003 + 31 +0.0 + 0 +LINE + 5 +1F16 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525182.0035908596 + 20 +177193.4372094267 + 30 +0.0 + 11 +524956.9002354598 + 21 +177273.2134657988 + 31 +0.0 + 0 +LINE + 5 +1F17 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525325.0804353948 + 20 +177319.2736799805 + 30 +0.0 + 11 +525164.6566656736 + 21 +177188.2351512587 + 31 +0.0 + 0 +LINE + 5 +1F18 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525342.4828240345 + 20 +177233.8386677683 + 30 +0.0 + 11 +525274.2163630228 + 21 +177285.1320402674 + 31 +0.0 + 0 +LINE + 5 +1F19 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524933.259545622 + 20 +176826.0690141637 + 30 +0.0 + 11 +524962.8201757881 + 21 +176911.205728587 + 31 +0.0 + 0 +LINE + 5 +1F1A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525311.2186715134 + 20 +177049.4997951991 + 30 +0.0 + 11 +524919.025883457 + 21 +177210.8070899695 + 31 +0.0 + 0 +LINE + 5 +1F1B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525318.7267275081 + 20 +177525.3649396567 + 30 +0.0 + 11 +525204.0534438687 + 21 +177550.6545768355 + 31 +0.0 + 0 +LINE + 5 +1F1C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525278.1291436034 + 20 +177478.3878620838 + 30 +0.0 + 11 +525226.6923359981 + 21 +177575.4438031876 + 31 +0.0 + 0 +LINE + 5 +1F1D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525163.7453859706 + 20 +177326.6656328321 + 30 +0.0 + 11 +525270.3886349485 + 21 +177498.2303401834 + 31 +0.0 + 0 +LINE + 5 +1F1E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525406.2258002512 + 20 +177266.9837734004 + 30 +0.0 + 11 +525034.4753566237 + 21 +177479.6120728989 + 31 +0.0 + 0 +LINE + 5 +1F1F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525365.9243027826 + 20 +177182.5302754163 + 30 +0.0 + 11 +525411.5114769163 + 21 +177295.0881497791 + 31 +0.0 + 0 +LINE + 5 +1F20 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525496.7343028748 + 20 +177238.8647516793 + 30 +0.0 + 11 +525408.3646492504 + 21 +177156.5328909903 + 31 +0.0 + 0 +LINE + 5 +1F21 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525414.5782816872 + 20 +177159.1339270254 + 30 +0.0 + 11 +525364.7726014158 + 21 +177184.3730852137 + 31 +0.0 + 0 +LINE + 5 +1F22 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525732.9053498066 + 20 +177045.4265655241 + 30 +0.0 + 11 +525260.9020174507 + 21 +177351.580812123 + 31 +0.0 + 0 +LINE + 5 +1F23 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525248.0541525605 + 20 +177349.139064215 + 30 +0.0 + 11 +525261.427705907 + 21 +177369.4097978704 + 31 +0.0 + 0 +LINE + 5 +1F24 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525062.2084332978 + 20 +177308.9561909968 + 30 +0.0 + 11 +525000.2989745414 + 21 +177355.4359634337 + 31 +0.0 + 0 +LINE + 5 +1F25 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525067.0596830563 + 20 +177294.1984451826 + 30 +0.0 + 11 +525057.755215065 + 21 +177316.3924377936 + 31 +0.0 + 0 +LINE + 5 +1F26 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525036.0853893436 + 20 +177238.0819323134 + 30 +0.0 + 11 +525068.971298339 + 21 +177301.9597794967 + 31 +0.0 + 0 +LINE + 5 +1F27 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525288.7242658106 + 20 +177284.0704269092 + 30 +0.0 + 11 +525457.0581157747 + 21 +177596.6685127321 + 31 +0.0 + 0 +LINE + 5 +1F28 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525655.024894655 + 20 +177338.9991638207 + 30 +0.0 + 11 +525561.2756183285 + 21 +177520.2109778318 + 31 +0.0 + 0 +LINE + 5 +1F29 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525591.9243254799 + 20 +177525.5022615888 + 30 +0.0 + 11 +525326.1365995015 + 21 +177305.5291621807 + 31 +0.0 + 0 +LINE + 5 +1F2A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525434.0971953899 + 20 +177235.7982300982 + 30 +0.0 + 11 +525453.1666549999 + 21 +177265.7707081433 + 31 +0.0 + 0 +LINE + 5 +1F2B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525386.8942634725 + 20 +177439.76076397 + 30 +0.0 + 11 +525312.8981462424 + 21 +177496.6502606758 + 31 +0.0 + 0 +LINE + 5 +1F2C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525343.0942547557 + 20 +177478.6577308449 + 30 +0.0 + 11 +525259.9199195926 + 21 +177484.540945283 + 31 +0.0 + 0 +LINE + 5 +1F2D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525337.8818350173 + 20 +177466.6119144748 + 30 +0.0 + 11 +525302.304562546 + 21 +177538.43395358 + 31 +0.0 + 0 +LINE + 5 +1F2E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525377.8945772925 + 20 +177624.8637513252 + 30 +0.0 + 11 +525299.7023977896 + 21 +177526.0809511351 + 31 +0.0 + 0 +LINE + 5 +1F2F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525802.7306519567 + 20 +177207.7311645296 + 30 +0.0 + 11 +525610.9652990102 + 21 +177397.138571804 + 31 +0.0 + 0 +LINE + 5 +1F30 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525201.8959860041 + 20 +177089.0238363769 + 30 +0.0 + 11 +525214.0563583964 + 21 +177134.4356771372 + 31 +0.0 + 0 +LINE + 5 +1F31 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525271.5446155183 + 20 +177106.7331340595 + 30 +0.0 + 11 +525212.2169820442 + 21 +177133.9549920855 + 31 +0.0 + 0 +LINE + 5 +1F32 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525275.750859958 + 20 +177057.3583119888 + 30 +0.0 + 11 +525329.6893125192 + 21 +177146.6532523234 + 31 +0.0 + 0 +LINE + 5 +1F33 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525447.4939412511 + 20 +177052.1289138494 + 30 +0.0 + 11 +525211.0025660272 + 21 +177234.4214281987 + 31 +0.0 + 0 +LINE + 5 +1F34 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525114.6027958332 + 20 +177214.0046942522 + 30 +0.0 + 11 +525141.5385607578 + 21 +177277.3610539983 + 31 +0.0 + 0 +LINE + 5 +1F35 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525170.4463819585 + 20 +177264.0086837144 + 30 +0.0 + 11 +525115.2037573895 + 21 +177287.6904148024 + 31 +0.0 + 0 +LINE + 5 +1F36 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525162.8792675344 + 20 +177259.909520559 + 30 +0.0 + 11 +525191.7128857292 + 21 +177325.1559639791 + 31 +0.0 + 0 +LINE + 5 +1F37 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525193.314168332 + 20 +177321.8010823494 + 30 +0.0 + 11 +525142.2886105311 + 21 +177345.2101029576 + 31 +0.0 + 0 +LINE + 5 +1F38 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525116.9112135452 + 20 +177278.8177354919 + 30 +0.0 + 11 +525147.4475604918 + 21 +177350.047078558 + 31 +0.0 + 0 +LINE + 5 +1F39 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525662.4759388884 + 20 +177173.6908112729 + 30 +0.0 + 11 +525568.2154872015 + 21 +177235.4932205403 + 31 +0.0 + 0 +LINE + 5 +1F3A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525093.9653281217 + 20 +176926.3491313284 + 30 +0.0 + 11 +524840.532076894 + 21 +177002.4105337027 + 31 +0.0 + 0 +LINE + 5 +1F3B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524637.4032810166 + 20 +176359.3587226847 + 30 +0.0 + 11 +525300.6708435408 + 21 +178206.4147988111 + 31 +0.0 + 0 +LINE + 5 +1F3C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525319.0788219256 + 20 +177608.8730437454 + 30 +0.0 + 11 +525328.8875517543 + 21 +177835.970585752 + 31 +0.0 + 0 +LINE + 5 +1F3D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525482.4051818097 + 20 +177518.1077287009 + 30 +0.0 + 11 +525556.5310875172 + 21 +177670.8763371959 + 31 +0.0 + 0 +LINE + 5 +1F3E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525900.4939529543 + 20 +177335.7991895602 + 30 +0.0 + 11 +525192.5947924674 + 21 +177689.029228539 + 31 +0.0 + 0 +LINE + 5 +1F3F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525457.2314948729 + 20 +177633.4987321044 + 30 +0.0 + 11 +525565.8126626467 + 21 +178059.0500187968 + 31 +0.0 + 0 +LINE + 5 +1F40 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525393.3133794839 + 20 +177660.7769569792 + 30 +0.0 + 11 +525574.3576694129 + 21 +177591.260892679 + 31 +0.0 + 0 +LINE + 5 +1F41 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525420.3612685173 + 20 +177728.1624888528 + 30 +0.0 + 11 +525480.204479206 + 21 +177704.6160276196 + 31 +0.0 + 0 +LINE + 5 +1F42 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525382.2463826507 + 20 +177689.3743398424 + 30 +0.0 + 11 +525435.4861634504 + 21 +177732.9952208904 + 31 +0.0 + 0 +LINE + 5 +1F43 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525425.7210150123 + 20 +177715.0312112448 + 30 +0.0 + 11 +525501.0725929005 + 21 +178111.1615401282 + 31 +0.0 + 0 +LINE + 5 +1F44 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525258.1774284148 + 20 +177841.2839282224 + 30 +0.0 + 11 +525666.3009968047 + 21 +177792.387080208 + 31 +0.0 + 0 +LINE + 5 +1F45 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525661.543062447 + 20 +177779.9508807949 + 30 +0.0 + 11 +525704.4062784762 + 21 +178014.8945259626 + 31 +0.0 + 0 +LINE + 5 +1F46 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525808.5830059624 + 20 +177658.7689688832 + 30 +0.0 + 11 +525653.6416162046 + 21 +177796.2464130009 + 31 +0.0 + 0 +LINE + 5 +1F47 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525727.0158142383 + 20 +177627.9667339593 + 30 +0.0 + 11 +525766.767963913 + 21 +177703.5384638431 + 31 +0.0 + 0 +LINE + 5 +1F48 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524991.8246753834 + 20 +178155.4541019633 + 30 +0.0 + 11 +525706.2586647039 + 21 +178012.4054534317 + 31 +0.0 + 0 +LINE + 5 +1F49 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525540.0503052236 + 20 +177629.4383357195 + 30 +0.0 + 11 +525636.7593045289 + 21 +178042.3337169034 + 31 +0.0 + 0 +LINE + 5 +1F4A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526040.0100858348 + 20 +177785.8371415856 + 30 +0.0 + 11 +525629.8050172541 + 21 +178041.7941207417 + 31 +0.0 + 0 +LINE + 5 +1F4B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526231.7046598897 + 20 +177687.0172746743 + 30 +0.0 + 11 +525794.7224773271 + 21 +177933.5215620383 + 31 +0.0 + 0 +LINE + 5 +1F4C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526011.024494235 + 20 +177697.9023401254 + 30 +0.0 + 11 +526017.7060938436 + 21 +177815.1409172062 + 31 +0.0 + 0 +LINE + 5 +1F4D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525958.1752044581 + 20 +177730.490101728 + 30 +0.0 + 11 +526045.7879111788 + 21 +177796.7442676439 + 31 +0.0 + 0 +LINE + 5 +1F4E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525790.155749319 + 20 +177819.2185726607 + 30 +0.0 + 11 +525976.5296098422 + 21 +177741.2954344097 + 31 +0.0 + 0 +LINE + 5 +1F4F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525781.8531474059 + 20 +177602.3947434703 + 30 +0.0 + 11 +525881.1030283052 + 21 +177886.4317078795 + 31 +0.0 + 0 +LINE + 5 +1F50 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525835.0618820717 + 20 +177528.3189671136 + 30 +0.0 + 11 +525735.2379582577 + 21 +177597.4756714956 + 31 +0.0 + 0 +LINE + 5 +1F51 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525694.774242326 + 20 +177503.738335011 + 30 +0.0 + 11 +525813.8142166504 + 21 +177483.3124818092 + 31 +0.0 + 0 +LINE + 5 +1F52 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525807.1914493779 + 20 +177482.082209412 + 30 +0.0 + 11 +525835.0150963279 + 21 +177530.4915635056 + 31 +0.0 + 0 +LINE + 5 +1F53 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525603.2665140946 + 20 +177212.4971446795 + 30 +0.0 + 11 +525603.2715310418 + 21 +177212.5085230352 + 31 +0.0 + 0 +LINE + 5 +1F54 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525662.315648034 + 20 +177346.4196263749 + 30 +0.0 + 11 +525830.2436531786 + 21 +177727.2776287684 + 31 +0.0 + 0 +LINE + 5 +1F55 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525825.7845710629 + 20 +177739.5717880226 + 30 +0.0 + 11 +525847.9283594355 + 21 +177729.6014716514 + 31 +0.0 + 0 +LINE + 5 +1F56 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525756.4829586113 + 20 +177916.6327413126 + 30 +0.0 + 11 +525778.9367416901 + 21 +177956.0023336231 + 31 +0.0 + 0 +LINE + 5 +1F57 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525742.68754455 + 20 +177909.4904562009 + 30 +0.0 + 11 +525763.1140086971 + 21 +177922.214684864 + 31 +0.0 + 0 +LINE + 5 +1F58 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525682.3501668144 + 20 +177931.1207760227 + 30 +0.0 + 11 +525750.6543864948 + 21 +177908.8408311148 + 31 +0.0 + 0 +LINE + 5 +1F59 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525768.0331965474 + 20 +177689.0468989655 + 30 +0.0 + 11 +526096.0043194264 + 21 +177563.2507667763 + 31 +0.0 + 0 +LINE + 5 +1F5A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526033.2038644383 + 20 +177485.3545500873 + 30 +0.0 + 11 +525795.1827360411 + 21 +177655.5347737426 + 31 +0.0 + 0 +LINE + 5 +1F5B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525743.5580844673 + 20 +177537.8369041633 + 30 +0.0 + 11 +525776.1876994059 + 21 +177523.7904825929 + 31 +0.0 + 0 +LINE + 5 +1F5C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525937.38473207 + 20 +177616.9574620742 + 30 +0.0 + 11 +525981.7478251474 + 21 +177699.0778381885 + 31 +0.0 + 0 +LINE + 5 +1F5D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525968.8002129287 + 20 +177666.3991687407 + 30 +0.0 + 11 +525961.3461323477 + 21 +177749.4474614664 + 31 +0.0 + 0 +LINE + 5 +1F5E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525956.0773950968 + 20 +177669.6242141621 + 30 +0.0 + 11 +526021.3078160592 + 21 +177716.1982390985 + 31 +0.0 + 0 +LINE + 5 +1F5F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526166.4165668602 + 20 +177633.1593019857 + 30 +0.0 + 11 +526008.6979435723 + 21 +177716.7974441392 + 31 +0.0 + 0 +LINE + 5 +1F60 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525561.6373423731 + 20 +177743.6644239177 + 30 +0.0 + 11 +525608.4071486459 + 21 +177738.9004802636 + 31 +0.0 + 0 +LINE + 5 +1F61 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525590.2254440928 + 20 +177677.7305839139 + 30 +0.0 + 11 +525607.6393274828 + 21 +177740.6396795464 + 31 +0.0 + 0 +LINE + 5 +1F62 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525542.1529911521 + 20 +177665.7054096925 + 30 +0.0 + 11 +525638.9059212225 + 21 +177626.6949808709 + 31 +0.0 + 0 +LINE + 5 +1F63 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525564.3746808246 + 20 +177495.325748098 + 30 +0.0 + 11 +525706.6267833462 + 21 +177757.8577855168 + 31 +0.0 + 0 +LINE + 5 +1F64 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525671.1004532344 + 20 +177849.7688217813 + 30 +0.0 + 11 +525737.9411154572 + 21 +177833.2797458222 + 31 +0.0 + 0 +LINE + 5 +1F65 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525729.3688821658 + 20 +177802.6127483302 + 30 +0.0 + 11 +525743.9392788691 + 21 +177860.9246295939 + 31 +0.0 + 0 +LINE + 5 +1F66 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525724.1155973437 + 20 +177809.4294453208 + 30 +0.0 + 11 +525793.1247719047 + 21 +177791.3681678577 + 31 +0.0 + 0 +LINE + 5 +1F67 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525790.068134001 + 20 +177789.2524406895 + 30 +0.0 + 11 +525805.0417143705 + 21 +177843.3577240329 + 31 +0.0 + 0 +LINE + 5 +1F68 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525735.4523658776 + 20 +177857.8242824288 + 30 +0.0 + 11 +525810.6393939268 + 21 +177839.0360251497 + 31 +0.0 + 0 +LINE + 5 +1F69 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525383.8344721295 + 20 +177824.2759981915 + 30 +0.0 + 11 +525418.5132004842 + 21 +178086.5947652645 + 31 +0.0 + 0 +LINE + 5 +1F6A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526308.1239966137 + 20 +176753.3706925865 + 30 +0.0 + 11 +526351.46407407 + 21 +176011.5104619067 + 31 +0.0 + 0 +LINE + 5 +1F6B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526940.0214358629 + 20 +176429.6370203297 + 30 +0.0 + 11 +524680.4828571335 + 21 +176882.2243582025 + 31 +0.0 + 0 +LINE + 5 +1F6C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526192.3355979434 + 20 +176582.9287149022 + 30 +0.0 + 11 +526186.5959414836 + 21 +176435.1966904509 + 31 +0.0 + 0 +LINE + 5 +1F6D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526326.328497571 + 20 +176487.2839683498 + 30 +0.0 + 11 +525842.057304739 + 21 +176587.1139166937 + 31 +0.0 + 0 +LINE + 5 +1F6E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526197.0368922976 + 20 +176466.1281759423 + 30 +0.0 + 11 +526150.9002913538 + 21 +176398.3600985904 + 31 +0.0 + 0 +LINE + 5 +1F6F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526258.5121904945 + 20 +176415.3728478937 + 30 +0.0 + 11 +526185.2305518461 + 21 +176463.8210668214 + 31 +0.0 + 0 +LINE + 5 +1F70 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526249.168325507 + 20 +176431.9382364462 + 30 +0.0 + 11 +526259.1409477169 + 21 +176233.3059138232 + 31 +0.0 + 0 +LINE + 5 +1F71 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526370.497744524 + 20 +176414.3309524263 + 30 +0.0 + 11 +525946.6235430839 + 21 +176326.0706404363 + 31 +0.0 + 0 +LINE + 5 +1F72 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526203.9097136959 + 20 +176223.6264067887 + 30 +0.0 + 11 +526151.1830329954 + 21 +176402.6787340636 + 31 +0.0 + 0 +LINE + 5 +1F73 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526262.9772598672 + 20 +176237.2145935001 + 30 +0.0 + 11 +526203.1934871118 + 21 +176224.0798610557 + 31 +0.0 + 0 +LINE + 5 +1F74 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526292.0988566732 + 20 +175941.234719471 + 30 +0.0 + 11 +526223.1314125833 + 21 +176230.353134325 + 31 +0.0 + 0 +LINE + 5 +1F75 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526279.8066610718 + 20 +176008.5442244475 + 30 +0.0 + 11 +526168.2315331545 + 21 +175989.8682466451 + 31 +0.0 + 0 +LINE + 5 +1F76 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526187.6571765576 + 20 +175910.7515640599 + 30 +0.0 + 11 +526013.7881416039 + 21 +176701.736132844 + 31 +0.0 + 0 +LINE + 5 +1F77 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526007.0981989844 + 20 +176413.2503998727 + 30 +0.0 + 11 +525567.9153355425 + 21 +176411.7738974628 + 31 +0.0 + 0 +LINE + 5 +1F78 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525996.2386453274 + 20 +176481.8922028909 + 30 +0.0 + 11 +526019.4839204014 + 21 +176289.358633614 + 31 +0.0 + 0 +LINE + 5 +1F79 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525924.2904011676 + 20 +176472.1019848462 + 30 +0.0 + 11 +525932.5251302081 + 21 +176408.3224039468 + 31 +0.0 + 0 +LINE + 5 +1F7A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525971.2054875981 + 20 +176499.6017974548 + 30 +0.0 + 11 +525915.9136219851 + 21 +176458.6132000153 + 31 +0.0 + 0 +LINE + 5 +1F7B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525935.717234424 + 20 +176463.7005078429 + 30 +0.0 + 11 +525533.1734404422 + 21 +176487.2715001471 + 31 +0.0 + 0 +LINE + 5 +1F7C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525852.8175313351 + 20 +176653.4038932794 + 30 +0.0 + 11 +525802.0036205032 + 21 +176249.2632733093 + 31 +0.0 + 0 +LINE + 5 +1F7D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525815.2248326041 + 20 +176250.843319441 + 30 +0.0 + 11 +525576.923260623 + 21 +176266.5955410115 + 31 +0.0 + 0 +LINE + 5 +1F7E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525896.8708853521 + 20 +176078.6814106625 + 30 +0.0 + 11 +525801.3494721967 + 21 +176262.481686859 + 31 +0.0 + 0 +LINE + 5 +1F7F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525946.6426193002 + 20 +176150.2688323363 + 30 +0.0 + 11 +525863.6560382271 + 21 +176130.1554755012 + 31 +0.0 + 0 +LINE + 5 +1F80 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525669.6796913576 + 20 +176692.4104188136 + 30 +0.0 + 11 +525663.1602053267 + 21 +176602.5238942365 + 31 +0.0 + 0 +LINE + 5 +1F81 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525601.9899951039 + 20 +176735.8000854975 + 30 +0.0 + 11 +525578.8851832505 + 21 +176264.1918612483 + 31 +0.0 + 0 +LINE + 5 +1F82 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525990.8302451481 + 20 +176331.9435991444 + 30 +0.0 + 11 +525566.8173502574 + 21 +176338.8927944822 + 31 +0.0 + 0 +LINE + 5 +1F83 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525653.4333764499 + 20 +176004.2532276039 + 30 +0.0 + 11 +525569.0373073484 + 21 +176345.5052876603 + 31 +0.0 + 0 +LINE + 5 +1F84 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525776.1972912831 + 20 +175638.8756795467 + 30 +0.0 + 11 +525712.6787874618 + 21 +175870.9585620065 + 31 +0.0 + 0 +LINE + 5 +1F85 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526379.7490696148 + 20 +176168.9147862752 + 30 +0.0 + 11 +525825.147800122 + 21 +176074.3896555292 + 31 +0.0 + 0 +LINE + 5 +1F86 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525814.3130500861 + 20 +176081.7134494056 + 30 +0.0 + 11 +525818.5795679024 + 21 +176057.8063082598 + 31 +0.0 + 0 +LINE + 5 +1F87 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525659.5103779263 + 20 +176192.1191891137 + 30 +0.0 + 11 +525599.027879986 + 21 +176176.7137827821 + 31 +0.0 + 0 +LINE + 5 +1F88 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525669.8025604574 + 20 +176203.7551963534 + 30 +0.0 + 11 +525652.4793060129 + 21 +176187.050368067 + 31 +0.0 + 0 +LINE + 5 +1F89 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525663.5466343454 + 20 +176267.5465223788 + 30 +0.0 + 11 +525668.4888511959 + 21 +176195.8706068711 + 31 +0.0 + 0 +LINE + 5 +1F8A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526163.1087802012 + 20 +175749.3538325748 + 30 +0.0 + 11 +525979.5087794271 + 21 +175614.8763002626 + 31 +0.0 + 0 +LINE + 5 +1F8B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526192.1149468061 + 20 +175930.0766157012 + 30 +0.0 + 11 +526158.0071352461 + 21 +175717.5680579371 + 31 +0.0 + 0 +LINE + 5 +1F8C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526405.4054263194 + 20 +175862.7358636809 + 30 +0.0 + 11 +526348.661430612 + 21 +176029.9976445105 + 31 +0.0 + 0 +LINE + 5 +1F8D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526379.4495038881 + 20 +175974.3550077079 + 30 +0.0 + 11 +526128.6542323571 + 21 +175894.1019516912 + 31 +0.0 + 0 +LINE + 5 +1F8E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525874.789192354 + 20 +176338.8771021823 + 30 +0.0 + 11 +525867.9985523191 + 21 +176292.3583194611 + 31 +0.0 + 0 +LINE + 5 +1F8F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525931.7558665713 + 20 +176295.0667284537 + 30 +0.0 + 11 +525866.4992371829 + 21 +176293.5272581273 + 31 +0.0 + 0 +LINE + 5 +1F90 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525955.1460984748 + 20 +176338.7526826987 + 30 +0.0 + 11 +525969.3724818535 + 21 +176235.4059215012 + 31 +0.0 + 0 +LINE + 5 +1F91 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526114.955662 + 20 +176275.6342544645 + 30 +0.0 + 11 +525825.6510484453 + 21 +176201.7318057975 + 31 +0.0 + 0 +LINE + 5 +1F92 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525745.1849126536 + 20 +176258.6085120067 + 30 +0.0 + 11 +525744.8683208652 + 21 +176189.7647503285 + 31 +0.0 + 0 +LINE + 5 +1F93 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525776.7000182735 + 20 +176190.5959896947 + 30 +0.0 + 11 +525716.5954207258 + 21 +176190.6924791494 + 31 +0.0 + 0 +LINE + 5 +1F94 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525771.3709760044 + 20 +176197.3536274314 + 30 +0.0 + 11 +525772.0500154658 + 21 +176126.0233055297 + 31 +0.0 + 0 +LINE + 5 +1F95 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525774.8475497621 + 20 +176128.4713942915 + 30 +0.0 + 11 +525718.7240675965 + 21 +176127.1505822807 + 31 +0.0 + 0 +LINE + 5 +1F96 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525721.6726684595 + 20 +176198.1665275917 + 30 +0.0 + 11 +525721.5494828701 + 21 +176120.6676719627 + 31 +0.0 + 0 +LINE + 5 +1F97 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525479.1614602226 + 20 +176747.2399923062 + 30 +0.0 + 11 +525490.653625448 + 21 +176518.3417724971 + 31 +0.0 + 0 +LINE + 5 +1F98 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525499.4599018504 + 20 +176682.7764694169 + 30 +0.0 + 11 +525178.2253902241 + 21 +176612.9265973124 + 31 +0.0 + 0 +LINE + 5 +1F99 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525435.5115608358 + 20 +176510.4823636649 + 30 +0.0 + 11 +525382.7848801356 + 21 +176689.5346909398 + 31 +0.0 + 0 +LINE + 5 +1F9A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525494.5791070076 + 20 +176524.0705503761 + 30 +0.0 + 11 +525434.795334252 + 21 +176510.9358179317 + 31 +0.0 + 0 +LINE + 5 +1F9B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525523.7007038133 + 20 +176228.090676347 + 30 +0.0 + 11 +525454.7332597232 + 21 +176517.2090912012 + 31 +0.0 + 0 +LINE + 5 +1F9C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525399.3618533586 + 20 +176301.078169511 + 30 +0.0 + 11 +525257.049278716 + 21 +176935.550336463 + 31 +0.0 + 0 +LINE + 5 +1F9D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525238.7000461245 + 20 +176700.1063567486 + 30 +0.0 + 11 +524973.2827348328 + 21 +176699.2140421064 + 31 +0.0 + 0 +LINE + 5 +1F9E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525227.8404924674 + 20 +176768.7481597669 + 30 +0.0 + 11 +525251.0857675414 + 21 +176576.2145904901 + 31 +0.0 + 0 +LINE + 5 +1F9F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525155.8922483074 + 20 +176758.9579417224 + 30 +0.0 + 11 +525164.1269773482 + 21 +176695.1783608227 + 31 +0.0 + 0 +LINE + 5 +1FA0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525202.8073347379 + 20 +176786.4577543309 + 30 +0.0 + 11 +525147.5154691249 + 21 +176745.4691568915 + 31 +0.0 + 0 +LINE + 5 +1FA1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525167.3190815642 + 20 +176750.5564647189 + 30 +0.0 + 11 +524764.7752875822 + 21 +176774.127457023 + 31 +0.0 + 0 +LINE + 5 +1FA2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525070.8034445501 + 20 +176831.0715042767 + 30 +0.0 + 11 +525033.6054676431 + 21 +176536.1192301853 + 31 +0.0 + 0 +LINE + 5 +1FA3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525046.8266797438 + 20 +176537.6992763171 + 30 +0.0 + 11 +524808.5251077629 + 21 +176553.4514978876 + 31 +0.0 + 0 +LINE + 5 +1FA4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525112.755593354 + 20 +176395.779953145 + 30 +0.0 + 11 +525032.9513193365 + 21 +176549.3376437352 + 31 +0.0 + 0 +LINE + 5 +1FA5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525379.5573529772 + 20 +176498.9294258487 + 30 +0.0 + 11 +525095.257885367 + 21 +176417.0114323773 + 31 +0.0 + 0 +LINE + 5 +1FA6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525222.4320922882 + 20 +176618.7995560205 + 30 +0.0 + 11 +524798.4191973975 + 21 +176625.7487513584 + 31 +0.0 + 0 +LINE + 5 +1FA7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524956.8013278007 + 20 +176113.092283917 + 30 +0.0 + 11 +524976.4701680052 + 21 +176476.6207072047 + 31 +0.0 + 0 +LINE + 5 +1FA8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525041.1314063764 + 20 +176178.7608441982 + 30 +0.0 + 11 +524925.8054389438 + 21 +176200.8843377061 + 31 +0.0 + 0 +LINE + 5 +1FA9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525022.4222532825 + 20 +176237.9636923282 + 30 +0.0 + 11 +524936.7949349053 + 21 +176169.1627967839 + 31 +0.0 + 0 +LINE + 5 +1FAA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525611.3509167548 + 20 +176455.7707431512 + 30 +0.0 + 11 +525296.3009969729 + 21 +176407.3107920077 + 31 +0.0 + 0 +LINE + 5 +1FAB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525320.8538129465 + 20 +176417.4479063852 + 30 +0.0 + 11 +525139.9857252317 + 21 +176058.562690482 + 31 +0.0 + 0 +LINE + 5 +1FAC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525209.4191285801 + 20 +176148.0617544851 + 30 +0.0 + 11 +525059.6401223514 + 21 +176221.5272619363 + 31 +0.0 + 0 +LINE + 5 +1FAD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525081.9842410516 + 20 +176212.0232199121 + 30 +0.0 + 11 +525003.2641276836 + 21 +176239.513690866 + 31 +0.0 + 0 +LINE + 5 +1FAE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525081.9606900939 + 20 +176225.1484039835 + 30 +0.0 + 11 +525020.8795128013 + 21 +176173.2519937195 + 31 +0.0 + 0 +LINE + 5 +1FAF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525056.1253922576 + 20 +176063.9739618511 + 30 +0.0 + 11 +525023.3748981102 + 21 +176185.6270081834 + 31 +0.0 + 0 +LINE + 5 +1FB0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525611.2948584211 + 20 +176279.0835830742 + 30 +0.0 + 11 +525472.2889781802 + 21 +176224.7491658278 + 31 +0.0 + 0 +LINE + 5 +1FB1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525106.3910394939 + 20 +176625.7330590585 + 30 +0.0 + 11 +525099.6003994591 + 21 +176579.2142763372 + 31 +0.0 + 0 +LINE + 5 +1FB2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525163.3577137114 + 20 +176581.9226853298 + 30 +0.0 + 11 +525098.1010843228 + 21 +176580.3832150034 + 31 +0.0 + 0 +LINE + 5 +1FB3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525186.747945615 + 20 +176625.6086395747 + 30 +0.0 + 11 +525200.9743289936 + 21 +176522.2618783774 + 31 +0.0 + 0 +LINE + 5 +1FB4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525346.55750914 + 20 +176562.4902113408 + 30 +0.0 + 11 +525057.2528955853 + 21 +176488.5877626738 + 31 +0.0 + 0 +LINE + 5 +1FB5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524976.7867597936 + 20 +176545.4644688829 + 30 +0.0 + 11 +524976.4701680052 + 21 +176476.6207072047 + 31 +0.0 + 0 +LINE + 5 +1FB6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525124.8475752318 + 20 +176409.0964892458 + 30 +0.0 + 11 +524948.1972678658 + 21 +176477.5484360255 + 31 +0.0 + 0 +LINE + 5 +1FB7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525495.9370425737 + 20 +176365.8171089485 + 30 +0.0 + 11 +525384.9195298884 + 21 +176346.3316676994 + 31 +0.0 + 0 +LINE + 5 +1FB8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524968.6361060145 + 20 +176158.0067721589 + 30 +0.0 + 11 +524759.3034177146 + 21 +175622.5419037983 + 31 +0.0 + 0 +LINE + 5 +1FB9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525008.428749703 + 20 +176101.9216376339 + 30 +0.0 + 11 +524927.6245599849 + 21 +175889.4594346649 + 31 +0.0 + 0 +LINE + 5 +1FBA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525194.3357915465 + 20 +176120.6943316627 + 30 +0.0 + 11 +525202.001045836 + 21 +175951.0649075782 + 31 +0.0 + 0 +LINE + 5 +1FBB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525333.8731606127 + 20 +176105.4721252761 + 30 +0.0 + 11 +524371.1220574266 + 21 +176050.7676381506 + 31 +0.0 + 0 +LINE + 5 +1FBC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525125.5792390395 + 20 +176024.6665509538 + 30 +0.0 + 11 +525057.0097835689 + 21 +175590.8670611235 + 31 +0.0 + 0 +LINE + 5 +1FBD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525056.084082703 + 20 +176024.8907673184 + 30 +0.0 + 11 +525249.860849121 + 21 +176017.1394507645 + 31 +0.0 + 0 +LINE + 5 +1FBE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525054.2770043241 + 20 +175952.3019756577 + 30 +0.0 + 11 +525118.5536201788 + 21 +175950.261790285 + 31 +0.0 + 0 +LINE + 5 +1FBF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525034.6095598894 + 20 +176003.0016468368 + 30 +0.0 + 11 +525066.257551652 + 21 +175941.8815998767 + 31 +0.0 + 0 +LINE + 5 +1FC0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525064.3929867726 + 20 +175962.2430134911 + 30 +0.0 + 11 +524976.9385344599 + 21 +175568.6076282395 + 31 +0.0 + 0 +LINE + 5 +1FC1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524863.8983838503 + 20 +175910.6518377226 + 30 +0.0 + 11 +525254.7663220056 + 21 +175796.0483946414 + 31 +0.0 + 0 +LINE + 5 +1FC2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525255.3145936151 + 20 +175809.3523937935 + 30 +0.0 + 11 +525201.7670636297 + 21 +175576.6112635104 + 31 +0.0 + 0 +LINE + 5 +1FC3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525438.2922485863 + 20 +175862.5029210243 + 30 +0.0 + 11 +525241.6127186602 + 21 +175797.5102721375 + 31 +0.0 + 0 +LINE + 5 +1FC4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525375.5567296231 + 20 +175923.0523975084 + 30 +0.0 + 11 +525382.1806715409 + 21 +175837.9204813144 + 31 +0.0 + 0 +LINE + 5 +1FC5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524742.5622633709 + 20 +175676.171281405 + 30 +0.0 + 11 +525204.4528169983 + 21 +175578.1648225352 + 31 +0.0 + 0 +LINE + 5 +1FC6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525203.2519185999 + 20 +175995.6424744553 + 30 +0.0 + 11 +525128.7833911182 + 21 +175578.1623374859 + 31 +0.0 + 0 +LINE + 5 +1FC7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525600.5985110734 + 20 +175654.2686996066 + 30 +0.0 + 11 +525122.6094655095 + 21 +175581.4082453863 + 31 +0.0 + 0 +LINE + 5 +1FC8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525801.8496525614 + 20 +175652.8800890392 + 30 +0.0 + 11 +525316.9017097373 + 21 +175615.6316209963 + 31 +0.0 + 0 +LINE + 5 +1FC9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525608.7527508469 + 20 +175746.4977742084 + 30 +0.0 + 11 +525568.5237424624 + 21 +175636.1748182397 + 31 +0.0 + 0 +LINE + 5 +1FCA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525547.3241824866 + 20 +175737.4677894125 + 30 +0.0 + 11 +525601.5917047545 + 21 +175641.9657637425 + 31 +0.0 + 0 +LINE + 5 +1FCB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525357.9121957003 + 20 +175722.4219221779 + 30 +0.0 + 11 +525559.9088859833 + 21 +175720.2845228642 + 31 +0.0 + 0 +LINE + 5 +1FCC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525436.036643558 + 20 +175924.8523466458 + 30 +0.0 + 11 +525414.8631771929 + 21 +175624.7203418022 + 31 +0.0 + 0 +LINE + 5 +1FCD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525539.1274344841 + 20 +175929.9645081115 + 30 +0.0 + 11 +525735.4989487451 + 21 +176140.9866987503 + 31 +0.0 + 0 +LINE + 5 +1FCE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525426.207520169 + 20 +176353.5908584147 + 30 +0.0 + 11 +525426.2076281533 + 21 +176353.5784235813 + 31 +0.0 + 0 +LINE + 5 +1FCF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525440.321241981 + 20 +176047.8798081949 + 30 +0.0 + 11 +525431.0929545699 + 21 +175791.013129566 + 31 +0.0 + 0 +LINE + 5 +1FD0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525422.1352744367 + 20 +175781.4847649781 + 30 +0.0 + 11 +525446.4168434282 + 21 +175781.8847391607 + 31 +0.0 + 0 +LINE + 5 +1FD1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525288.4589785783 + 20 +175646.266635299 + 30 +0.0 + 11 +525293.5121681359 + 21 +175601.2266258793 + 31 +0.0 + 0 +LINE + 5 +1FD2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525278.6129131255 + 20 +175658.2824865316 + 30 +0.0 + 11 +525292.341856174 + 21 +175638.5173010937 + 31 +0.0 + 0 +LINE + 5 +1FD3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525214.6402196538 + 20 +175662.2780312479 + 30 +0.0 + 11 +525286.1871600408 + 21 +175655.7283982416 + 31 +0.0 + 0 +LINE + 5 +1FD4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525389.0739232269 + 20 +175850.7302177447 + 30 +0.0 + 11 +525740.0568714903 + 21 +175836.5635545971 + 31 +0.0 + 0 +LINE + 5 +1FD5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525619.2862598824 + 20 +175914.8895411783 + 30 +0.0 + 11 +525427.2635288181 + 21 +175870.7730233485 + 31 +0.0 + 0 +LINE + 5 +1FD6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525154.18579619 + 20 +176177.1716581862 + 30 +0.0 + 11 +525755.0764899278 + 21 +175817.2858196714 + 31 +0.0 + 0 +LINE + 5 +1FD7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525573.128933022 + 20 +175849.9667621131 + 30 +0.0 + 11 +525581.3980240038 + 21 +175756.9965392731 + 31 +0.0 + 0 +LINE + 5 +1FD8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525582.429850939 + 20 +175792.1315849146 + 30 +0.0 + 11 +525542.7392790357 + 21 +175718.8019132671 + 31 +0.0 + 0 +LINE + 5 +1FD9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525569.4688321452 + 20 +175794.2011267442 + 30 +0.0 + 11 +525610.9619874878 + 21 +175725.626600297 + 31 +0.0 + 0 +LINE + 5 +1FDA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525777.0809907501 + 20 +175744.5075799035 + 30 +0.0 + 11 +525599.1431815309 + 21 +175730.0632382783 + 31 +0.0 + 0 +LINE + 5 +1FDB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525177.9045442866 + 20 +175882.1915599004 + 30 +0.0 + 11 +525222.7454192442 + 21 +175868.0704455326 + 31 +0.0 + 0 +LINE + 5 +1FDC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525230.2376718728 + 20 +175931.443915932 + 30 +0.0 + 11 +525221.352372083 + 21 +175866.7766978408 + 31 +0.0 + 0 +LINE + 5 +1FDD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525278.6324720035 + 20 +176109.2014176325 + 30 +0.0 + 11 +525305.4602313113 + 21 +175811.8144598258 + 31 +0.0 + 0 +LINE + 5 +1FDE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525236.4809838362 + 20 +175741.4466963524 + 30 +0.0 + 11 +525401.5150701644 + 21 +175717.8045106914 + 31 +0.0 + 0 +LINE + 5 +1FDF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524982.7168481601 + 20 +175878.4700206413 + 30 +0.0 + 11 +524910.8256864786 + 21 +175623.8224001321 + 31 +0.0 + 0 +LINE + 5 +1FE0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526075.4906367242 + 20 +176105.1506865437 + 30 +0.0 + 11 +526037.1321662943 + 21 +176267.0143930995 + 31 +0.0 + 0 +LINE + 5 +1FE1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526122.7396103357 + 20 +176017.616273911 + 30 +0.0 + 11 +526276.4577789378 + 21 +176119.7037581224 + 31 +0.0 + 0 +LINE + 5 +1FE2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525215.8445735419 + 20 +175920.96562573 + 30 +0.0 + 11 +525332.5259441775 + 21 +175910.2114930633 + 31 +0.0 + 0 +LINE + 5 +1FE3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525852.3074904985 + 20 +176649.3473619765 + 30 +0.0 + 11 +525757.9889398609 + 21 +176823.6121122912 + 31 +0.0 + 0 +LINE + 5 +1FE4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524542.8023875946 + 20 +179000.7833106453 + 30 +0.0 + 11 +524431.8915657004 + 21 +179098.5405829653 + 31 +0.0 + 0 +LINE + 5 +1FE5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524565.994524599 + 20 +179163.7684003769 + 30 +0.0 + 11 +524304.1937811976 + 21 +178744.3104435472 + 31 +0.0 + 0 +LINE + 5 +1FE6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524461.4872296996 + 20 +179084.7613623397 + 30 +0.0 + 11 +524380.5989865734 + 21 +179098.1101592356 + 31 +0.0 + 0 +LINE + 5 +1FE7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524467.151219915 + 20 +179164.2801326305 + 30 +0.0 + 11 +524451.672415497 + 21 +179077.8056560839 + 31 +0.0 + 0 +LINE + 5 +1FE8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524472.6979763602 + 20 +179146.0880078581 + 30 +0.0 + 11 +524335.776701389 + 21 +179290.3336914834 + 31 +0.0 + 0 +LINE + 5 +1FE9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524543.6498567635 + 20 +179246.07138166 + 30 +0.0 + 11 +524187.3449274755 + 21 +179000.0916697241 + 31 +0.0 + 0 +LINE + 5 +1FEA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524290.6680611737 + 20 +179257.0261451039 + 30 +0.0 + 11 +524383.920532796 + 21 +179095.3356528147 + 31 +0.0 + 0 +LINE + 5 +1FEB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524341.2528787772 + 20 +179290.414617019 + 30 +0.0 + 11 +524290.5022547393 + 21 +179256.1948151342 + 31 +0.0 + 0 +LINE + 5 +1FEC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524147.066225208 + 20 +179515.6782332696 + 30 +0.0 + 11 +524308.7979445157 + 21 +179266.3013756385 + 31 +0.0 + 0 +LINE + 5 +1FED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524187.3155401592 + 20 +179460.3459625875 + 30 +0.0 + 11 +524096.8251819277 + 21 +179392.4541634975 + 31 +0.0 + 0 +LINE + 5 +1FEE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524052.9489909405 + 20 +179461.095877851 + 30 +0.0 + 11 +524510.5819551447 + 21 +178785.2280688973 + 31 +0.0 + 0 +LINE + 5 +1FEF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524292.1774219008 + 20 +178983.7318844501 + 30 +0.0 + 11 +523988.1394265688 + 21 +178666.8018211947 + 31 +0.0 + 0 +LINE + 5 +1FF0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524334.3795647158 + 20 +178928.5176999585 + 30 +0.0 + 11 +524211.0296152242 + 21 +179078.1649788252 + 31 +0.0 + 0 +LINE + 5 +1FF1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524277.6585918697 + 20 +178883.1841643977 + 30 +0.0 + 11 +524237.1657510626 + 21 +178933.1439036428 + 31 +0.0 + 0 +LINE + 5 +1FF2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524329.9314599481 + 20 +178898.1779061311 + 30 +0.0 + 11 +524262.1146210516 + 21 +178886.4249539442 + 31 +0.0 + 0 +LINE + 5 +1FF3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524279.4590697602 + 20 +178897.252412813 + 30 +0.0 + 11 +524018.8296930751 + 21 +178589.5684422194 + 31 +0.0 + 0 +LINE + 5 +1FF4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524359.6076526764 + 20 +178706.370407703 + 30 +0.0 + 11 +524031.9742005421 + 21 +178948.3787036076 + 31 +0.0 + 0 +LINE + 5 +1FF5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524042.2386991308 + 20 +178956.8602756267 + 30 +0.0 + 11 +523889.2509233729 + 21 +178773.4740379708 + 31 +0.0 + 0 +LINE + 5 +1FF6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523973.9245285336 + 20 +179134.7337555477 + 30 +0.0 + 11 +524041.0924745702 + 21 +178938.7864439398 + 31 +0.0 + 0 +LINE + 5 +1FF7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524060.085491399 + 20 +179121.3818672867 + 30 +0.0 + 11 +523988.2762647926 + 21 +179075.1784611826 + 31 +0.0 + 0 +LINE + 5 +1FF8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524411.2137166957 + 20 +178359.7278200375 + 30 +0.0 + 11 +524241.9561798962 + 21 +178663.3477312312 + 31 +0.0 + 0 +LINE + 5 +1FF9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524246.2261103226 + 20 +178467.9417783873 + 30 +0.0 + 11 +523888.8641942761 + 21 +178776.5525534257 + 31 +0.0 + 0 +LINE + 5 +1FFA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524222.0925554075 + 20 +179028.0438879628 + 30 +0.0 + 11 +523934.6193464978 + 21 +178716.2837549942 + 31 +0.0 + 0 +LINE + 5 +1FFB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523709.9291016019 + 20 +179138.0846317387 + 30 +0.0 + 11 +523940.9379251233 + 21 +178713.3292940167 + 31 +0.0 + 0 +LINE + 5 +1FFC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523572.2786335773 + 20 +179350.7702628629 + 30 +0.0 + 11 +523850.7072225497 + 21 +178888.7691296246 + 31 +0.0 + 0 +LINE + 5 +1FFD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523778.4545626078 + 20 +179200.3498308638 + 30 +0.0 + 11 +523714.913678927 + 21 +179101.5971912518 + 31 +0.0 + 0 +LINE + 5 +1FFE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523808.4083026672 + 20 +179145.9643264288 + 30 +0.0 + 11 +523699.5297843255 + 21 +179131.4361082373 + 31 +0.0 + 0 +LINE + 5 +1FFF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523910.9619477837 + 20 +178986.0079925976 + 30 +0.0 + 11 +523787.1126615274 + 21 +179145.596794382 + 31 +0.0 + 0 +LINE + 5 +2000 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524051.1410301031 + 20 +179192.6683432578 + 30 +0.0 + 11 +523798.708901256 + 21 +178972.2869632569 + 31 +0.0 + 0 +LINE + 5 +2001 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524116.3413454738 + 20 +179125.5451513231 + 30 +0.0 + 11 +524026.6216614344 + 21 +179207.3855070313 + 31 +0.0 + 0 +LINE + 5 +2002 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524108.9428978228 + 20 +179267.7776803463 + 30 +0.0 + 11 +524155.4598415749 + 21 +179156.3151085556 + 31 +0.0 + 0 +LINE + 5 +2003 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524155.178662528 + 20 +179163.0453057934 + 30 +0.0 + 11 +524114.213259897 + 21 +179125.1051334082 + 31 +0.0 + 0 +LINE + 5 +2004 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524372.3616001382 + 20 +179422.0685826785 + 30 +0.0 + 11 +523921.3395205944 + 21 +179085.7701256054 + 31 +0.0 + 0 +LINE + 5 +2005 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523919.1672955888 + 20 +179072.8739554913 + 30 +0.0 + 11 +523904.8028469463 + 21 +179092.4549970173 + 31 +0.0 + 0 +LINE + 5 +2006 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523892.3058896266 + 20 +178884.6406971708 + 30 +0.0 + 11 +523853.3778947085 + 21 +178861.4297431853 + 31 +0.0 + 0 +LINE + 5 +2007 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523907.8298685278 + 20 +178884.0647068877 + 30 +0.0 + 11 +523883.7859259912 + 21 +178883.0472296616 + 31 +0.0 + 0 +LINE + 5 +2008 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523949.6962839617 + 20 +178835.529429549 + 30 +0.0 + 11 +523901.2155219774 + 21 +178888.5528025903 + 31 +0.0 + 0 +LINE + 5 +2009 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523994.310310179 + 20 +179088.4146450171 + 30 +0.0 + 11 +523713.3118281377 + 21 +179419.6202277009 + 31 +0.0 + 0 +LINE + 5 +200A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523744.3416693581 + 20 +179412.851322139 + 30 +0.0 + 11 +523616.2737920614 + 21 +179257.5679325866 + 31 +0.0 + 0 +LINE + 5 +200B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524070.0146388352 + 20 +179450.9917698515 + 30 +0.0 + 11 +523711.0573757446 + 21 +179398.7017312847 + 31 +0.0 + 0 +LINE + 5 +200C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523817.9209068757 + 20 +179488.7456151748 + 30 +0.0 + 11 +523987.1803352345 + 21 +179130.9507883419 + 31 +0.0 + 0 +LINE + 5 +200D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524090.0650417751 + 20 +179207.9743582003 + 30 +0.0 + 11 +524068.5808773766 + 21 +179236.2661310338 + 31 +0.0 + 0 +LINE + 5 +200E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523882.4046020887 + 20 +179234.5445255751 + 30 +0.0 + 11 +523803.3576987031 + 21 +179184.9116003569 + 31 +0.0 + 0 +LINE + 5 +200F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523830.7172395122 + 20 +179206.9794871106 + 30 +0.0 + 11 +523796.3142523012 + 21 +179131.0254436837 + 31 +0.0 + 0 +LINE + 5 +2010 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523840.2030354173 + 20 +179197.9080656343 + 30 +0.0 + 11 +523760.4956905026 + 21 +179189.4886366538 + 31 +0.0 + 0 +LINE + 5 +2011 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523675.0817546599 + 20 +179333.2122401419 + 30 +0.0 + 11 +523771.1760785405 + 21 +179182.7583140627 + 31 +0.0 + 0 +LINE + 5 +2012 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524168.4008082703 + 20 +179651.8593062971 + 30 +0.0 + 11 +524250.3461214321 + 21 +179495.3941343705 + 31 +0.0 + 0 +LINE + 5 +2013 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524231.3024235346 + 20 +179556.068231453 + 30 +0.0 + 11 +524000.1924044534 + 21 +179429.8660908105 + 31 +0.0 + 0 +LINE + 5 +2014 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524147.0615027255 + 20 +178939.2523313183 + 30 +0.0 + 11 +524108.6994938733 + 21 +178966.4270661795 + 31 +0.0 + 0 +LINE + 5 +2015 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524154.6430655738 + 20 +179010.7161034157 + 30 +0.0 + 11 +524108.5114544834 + 21 +178964.5352404283 + 31 +0.0 + 0 +LINE + 5 +2016 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524202.4054162988 + 20 +178997.5129447023 + 30 +0.0 + 11 +524137.4010440239 + 21 +179079.1056810162 + 31 +0.0 + 0 +LINE + 5 +2017 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524266.9546972896 + 20 +179156.7499469993 + 30 +0.0 + 11 +524013.8766698282 + 21 +178998.287827364 + 31 +0.0 + 0 +LINE + 5 +2018 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523999.5435054869 + 20 +178900.7977298236 + 30 +0.0 + 11 +523949.4853209126 + 21 +178948.0602086997 + 31 +0.0 + 0 +LINE + 5 +2019 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523972.0461085181 + 20 +178970.5314966329 + 30 +0.0 + 11 +523930.6529734734 + 21 +178926.9519104971 + 31 +0.0 + 0 +LINE + 5 +201A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523973.2621091063 + 20 +178962.0117723504 + 30 +0.0 + 11 +523922.0906002993 + 21 +179011.7103900734 + 31 +0.0 + 0 +LINE + 5 +201B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523925.7927776032 + 20 +179012.0468717714 + 30 +0.0 + 11 +523886.1199414426 + 21 +178972.3271554368 + 31 +0.0 + 0 +LINE + 5 +201C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523939.5663733144 + 20 +178925.4716578331 + 30 +0.0 + 11 +523883.3757110357 + 21 +178978.8448465255 + 31 +0.0 + 0 +LINE + 5 +201D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524227.6212786628 + 20 +179400.568396655 + 30 +0.0 + 11 +524136.9295746451 + 21 +179333.6386919953 + 31 +0.0 + 0 +LINE + 5 +201E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524262.1270243825 + 20 +178781.5437002942 + 30 +0.0 + 11 +524102.784066827 + 21 +178570.3007793799 + 31 +0.0 + 0 +LINE + 5 +201F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524188.0053421091 + 20 +178194.2972296616 + 30 +0.0 + 11 +523870.9828607271 + 21 +177694.6733340894 + 31 +0.0 + 0 +LINE + 5 +2020 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524318.3542007789 + 20 +178215.8393498417 + 30 +0.0 + 11 +524109.4850426079 + 21 +178344.368125777 + 31 +0.0 + 0 +LINE + 5 +2021 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524662.8767133136 + 20 +179120.3209471774 + 30 +0.0 + 11 +523981.7872581052 + 21 +177990.1379863591 + 31 +0.0 + 0 +LINE + 5 +2022 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524139.0807066072 + 20 +178330.5889051513 + 30 +0.0 + 11 +524058.192463481 + 21 +178343.9377020474 + 31 +0.0 + 0 +LINE + 5 +2023 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524144.7446968224 + 20 +178410.1076754422 + 30 +0.0 + 11 +524129.2658924044 + 21 +178323.6331988957 + 31 +0.0 + 0 +LINE + 5 +2024 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524148.9122708286 + 20 +178393.1065857026 + 30 +0.0 + 11 +524011.9909958576 + 21 +178537.3522693281 + 31 +0.0 + 0 +LINE + 5 +2025 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524291.2842484481 + 20 +178540.2525750229 + 30 +0.0 + 11 +523864.9384043831 + 21 +178245.9192125361 + 31 +0.0 + 0 +LINE + 5 +2026 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523968.2615380813 + 20 +178502.8536879156 + 30 +0.0 + 11 +524061.5140097036 + 21 +178341.1631956266 + 31 +0.0 + 0 +LINE + 5 +2027 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524018.8463556848 + 20 +178536.2421598306 + 30 +0.0 + 11 +523968.095731647 + 21 +178502.0223579458 + 31 +0.0 + 0 +LINE + 5 +2028 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523824.6597021152 + 20 +178761.5057760814 + 30 +0.0 + 11 +523986.3914214229 + 21 +178512.1289184503 + 31 +0.0 + 0 +LINE + 5 +2029 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523864.9090170671 + 20 +178706.1735053991 + 30 +0.0 + 11 +523774.4186588351 + 21 +178638.2817063094 + 31 +0.0 + 0 +LINE + 5 +202A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523730.542467848 + 20 +178706.9234206626 + 30 +0.0 + 11 +524152.8799091047 + 21 +178080.4230726436 + 31 +0.0 + 0 +LINE + 5 +202B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523969.7708988082 + 20 +178229.5594272618 + 30 +0.0 + 11 +523665.732903476 + 21 +177912.6293640066 + 31 +0.0 + 0 +LINE + 5 +202C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524011.9730416233 + 20 +178174.3452427703 + 30 +0.0 + 11 +523888.6230921318 + 21 +178323.992521637 + 31 +0.0 + 0 +LINE + 5 +202D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523955.2520687775 + 20 +178129.0117072094 + 30 +0.0 + 11 +523914.75922797 + 21 +178178.9714464547 + 31 +0.0 + 0 +LINE + 5 +202E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524007.5249368556 + 20 +178144.0054489427 + 30 +0.0 + 11 +523939.7080979591 + 21 +178132.2524967561 + 31 +0.0 + 0 +LINE + 5 +202F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523957.052546668 + 20 +178143.0799556247 + 30 +0.0 + 11 +523696.423169983 + 21 +177835.3959850311 + 31 +0.0 + 0 +LINE + 5 +2030 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524037.201129584 + 20 +177952.1979505146 + 30 +0.0 + 11 +523709.5676774497 + 21 +178194.2062464195 + 31 +0.0 + 0 +LINE + 5 +2031 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523719.8321760384 + 20 +178202.6878184385 + 30 +0.0 + 11 +523566.8444002805 + 21 +178019.3015807826 + 31 +0.0 + 0 +LINE + 5 +2032 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523651.518005441 + 20 +178380.5612983597 + 30 +0.0 + 11 +523718.6859514777 + 21 +178184.6139867516 + 31 +0.0 + 0 +LINE + 5 +2033 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523737.6789683065 + 20 +178367.2094100985 + 30 +0.0 + 11 +523665.8697417005 + 21 +178321.0060039942 + 31 +0.0 + 0 +LINE + 5 +2034 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523970.7490853096 + 20 +177839.4205821743 + 30 +0.0 + 11 +523901.1778382863 + 21 +177896.7087361529 + 31 +0.0 + 0 +LINE + 5 +2035 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523923.8195872301 + 20 +177713.769321199 + 30 +0.0 + 11 +523566.4576711837 + 21 +178022.3800962373 + 31 +0.0 + 0 +LINE + 5 +2036 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523899.6860323151 + 20 +178273.8714307745 + 30 +0.0 + 11 +523612.212823405 + 21 +177962.111297806 + 31 +0.0 + 0 +LINE + 5 +2037 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523360.362347059 + 20 +178437.5811898571 + 30 +0.0 + 11 +523618.5314020309 + 21 +177959.1568368285 + 31 +0.0 + 0 +LINE + 5 +2038 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523456.0480395155 + 20 +178446.1773736755 + 30 +0.0 + 11 +523392.5071558344 + 21 +178347.4247340636 + 31 +0.0 + 0 +LINE + 5 +2039 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523486.0017795747 + 20 +178391.7918692405 + 30 +0.0 + 11 +523377.123261233 + 21 +178377.263651049 + 31 +0.0 + 0 +LINE + 5 +203A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523588.5554246914 + 20 +178231.8355354097 + 30 +0.0 + 11 +523464.706138435 + 21 +178391.4243371938 + 31 +0.0 + 0 +LINE + 5 +203B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523728.7345070106 + 20 +178438.4958860697 + 30 +0.0 + 11 +523476.3023781635 + 21 +178218.1145060688 + 31 +0.0 + 0 +LINE + 5 +203C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523793.9348223813 + 20 +178371.3726941348 + 30 +0.0 + 11 +523704.215138342 + 21 +178453.213049843 + 31 +0.0 + 0 +LINE + 5 +203D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523786.5363747306 + 20 +178513.6052231579 + 30 +0.0 + 11 +523833.0533184824 + 21 +178402.1426513674 + 31 +0.0 + 0 +LINE + 5 +203E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523832.7721394355 + 20 +178408.8728486055 + 30 +0.0 + 11 +523791.8067368046 + 21 +178370.93267622 + 31 +0.0 + 0 +LINE + 5 +203F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524049.9550770458 + 20 +178667.8961254901 + 30 +0.0 + 11 +523598.932997502 + 21 +178331.5976684171 + 31 +0.0 + 0 +LINE + 5 +2040 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523596.7607724965 + 20 +178318.7014983031 + 30 +0.0 + 11 +523582.396323854 + 21 +178338.2825398289 + 31 +0.0 + 0 +LINE + 5 +2041 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523569.8993665342 + 20 +178130.4682399823 + 30 +0.0 + 11 +523530.971371616 + 21 +178107.2572859973 + 31 +0.0 + 0 +LINE + 5 +2042 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523585.4233454357 + 20 +178129.8922496992 + 30 +0.0 + 11 +523561.3794028986 + 21 +178128.8747724734 + 31 +0.0 + 0 +LINE + 5 +2043 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523627.2897608695 + 20 +178081.3569723606 + 30 +0.0 + 11 +523578.8089988852 + 21 +178134.3803454021 + 31 +0.0 + 0 +LINE + 5 +2044 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523671.9037870865 + 20 +178334.242187829 + 30 +0.0 + 11 +523437.2243629574 + 21 +178600.6618120954 + 31 +0.0 + 0 +LINE + 5 +2045 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523747.6081157428 + 20 +178696.8193126631 + 30 +0.0 + 11 +523545.1170284044 + 21 +178671.8391625966 + 31 +0.0 + 0 +LINE + 5 +2046 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523550.7992131782 + 20 +178702.4178105399 + 30 +0.0 + 11 +523664.7738121421 + 21 +178376.7783311538 + 31 +0.0 + 0 +LINE + 5 +2047 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523767.6585186823 + 20 +178453.801901012 + 30 +0.0 + 11 +523746.1743542842 + 21 +178482.0936738456 + 31 +0.0 + 0 +LINE + 5 +2048 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523559.9980789962 + 20 +178480.3720683869 + 30 +0.0 + 11 +523480.9511756107 + 21 +178430.7391431687 + 31 +0.0 + 0 +LINE + 5 +2049 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523508.3107164198 + 20 +178452.8070299222 + 30 +0.0 + 11 +523473.9077292088 + 21 +178376.8529864954 + 31 +0.0 + 0 +LINE + 5 +204A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523517.7965123248 + 20 +178443.7356084459 + 30 +0.0 + 11 +523438.0891674102 + 21 +178435.3161794655 + 31 +0.0 + 0 +LINE + 5 +204B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523383.2910629254 + 20 +178536.217755333 + 30 +0.0 + 11 +523448.7695554481 + 21 +178428.5858568744 + 31 +0.0 + 0 +LINE + 5 +204C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523922.0028546302 + 20 +178789.7426866138 + 30 +0.0 + 11 +523677.7858813611 + 21 +178675.6936336222 + 31 +0.0 + 0 +LINE + 5 +204D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523824.6549796329 + 20 +178185.0798741302 + 30 +0.0 + 11 +523786.2929707809 + 21 +178212.2546089911 + 31 +0.0 + 0 +LINE + 5 +204E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523832.2365424811 + 20 +178256.5436462275 + 30 +0.0 + 11 +523786.1049313909 + 21 +178210.3627832404 + 31 +0.0 + 0 +LINE + 5 +204F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523879.9988932064 + 20 +178243.3404875143 + 30 +0.0 + 11 +523814.9945209313 + 21 +178324.933223828 + 31 +0.0 + 0 +LINE + 5 +2050 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523944.5481741972 + 20 +178402.577489811 + 30 +0.0 + 11 +523691.4701467358 + 21 +178244.1153701758 + 31 +0.0 + 0 +LINE + 5 +2051 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523677.1369823944 + 20 +178146.6252726353 + 30 +0.0 + 11 +523627.0787978201 + 21 +178193.8877515116 + 31 +0.0 + 0 +LINE + 5 +2052 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523649.6395854257 + 20 +178216.3590394448 + 30 +0.0 + 11 +523608.246450381 + 21 +178172.779453309 + 31 +0.0 + 0 +LINE + 5 +2053 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523650.8555860139 + 20 +178207.8393151623 + 30 +0.0 + 11 +523599.6840772069 + 21 +178257.5379328851 + 31 +0.0 + 0 +LINE + 5 +2054 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523603.3862545109 + 20 +178257.8744145832 + 30 +0.0 + 11 +523563.7134183502 + 21 +178218.1546982485 + 31 +0.0 + 0 +LINE + 5 +2055 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523617.1598502217 + 20 +178171.2992006449 + 30 +0.0 + 11 +523560.9691879433 + 21 +178224.6723893374 + 31 +0.0 + 0 +LINE + 5 +2056 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523905.2147555707 + 20 +178646.3959394668 + 30 +0.0 + 11 +523814.5230515527 + 21 +178579.466234807 + 31 +0.0 + 0 +LINE + 5 +2057 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523939.7205012899 + 20 +178027.3712431062 + 30 +0.0 + 11 +523780.3775437346 + 21 +177816.1283221916 + 31 +0.0 + 0 +LINE + 5 +2058 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523391.0123446939 + 20 +178408.0111781633 + 30 +0.0 + 11 +522858.9523112461 + 21 +178625.8526812025 + 31 +0.0 + 0 +LINE + 5 +2059 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523519.6981161965 + 20 +178597.1474741987 + 30 +0.0 + 11 +523402.1819029408 + 21 +178719.7151586041 + 31 +0.0 + 0 +LINE + 5 +205A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523835.8588979495 + 20 +178925.8981153875 + 30 +0.0 + 11 +523284.7149343134 + 21 +178409.0693896933 + 31 +0.0 + 0 +LINE + 5 +205B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523402.7468093565 + 20 +178613.6153219293 + 30 +0.0 + 11 +523035.7198233606 + 21 +178854.8548905876 + 31 +0.0 + 0 +LINE + 5 +205C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523354.9680920425 + 20 +178563.1492818721 + 30 +0.0 + 11 +523483.0328498929 + 21 +178708.7821624604 + 31 +0.0 + 0 +LINE + 5 +205D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523301.1704663153 + 20 +178611.9162140408 + 30 +0.0 + 11 +523344.0345082054 + 21 +178659.857006848 + 31 +0.0 + 0 +LINE + 5 +205E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523324.3072144031 + 20 +178562.7028427259 + 30 +0.0 + 11 +523301.8913304754 + 21 +178627.7780582134 + 31 +0.0 + 0 +LINE + 5 +205F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523315.3458125261 + 20 +178612.3819327488 + 30 +0.0 + 11 +522970.0413020606 + 21 +178820.6171190256 + 31 +0.0 + 0 +LINE + 5 +2060 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523139.6854806142 + 20 +178502.8228938208 + 30 +0.0 + 11 +523326.3569039595 + 21 +178864.852552758 + 31 +0.0 + 0 +LINE + 5 +2061 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523336.366624138 + 20 +178856.0717499962 + 30 +0.0 + 11 +523130.9329078317 + 21 +178977.8615685262 + 31 +0.0 + 0 +LINE + 5 +2062 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523501.0718386049 + 20 +178951.8735928333 + 30 +0.0 + 11 +523318.3412608636 + 21 +178854.3214638997 + 31 +0.0 + 0 +LINE + 5 +2063 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523501.6290112135 + 20 +178864.6860134383 + 30 +0.0 + 11 +523444.5668437729 + 21 +178928.2094642923 + 31 +0.0 + 0 +LINE + 5 +2064 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522966.5922798777 + 20 +178574.2352269626 + 30 +0.0 + 11 +523012.0544690127 + 21 +178652.050908915 + 31 +0.0 + 0 +LINE + 5 +2065 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523435.3169658926 + 20 +178689.8690239371 + 30 +0.0 + 11 +523081.708232544 + 21 +178923.9546707615 + 31 +0.0 + 0 +LINE + 5 +2066 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523462.2861582033 + 20 +179213.0258181883 + 30 +0.0 + 11 +523112.8056404958 + 21 +178938.6563428773 + 31 +0.0 + 0 +LINE + 5 +2067 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523621.5295212859 + 20 +179358.469027492 + 30 +0.0 + 11 +523238.6072048998 + 21 +179034.295784951 + 31 +0.0 + 0 +LINE + 5 +2068 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523534.681036312 + 20 +179155.3051507301 + 30 +0.0 + 11 +523427.0603128358 + 21 +179202.2871431067 + 31 +0.0 + 0 +LINE + 5 +2069 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523485.7674071429 + 20 +179117.0629421416 + 30 +0.0 + 11 +523454.0645383182 + 21 +179222.2319917162 + 31 +0.0 + 0 +LINE + 5 +206A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523344.2095454536 + 20 +178990.3165392215 + 30 +0.0 + 11 +523482.0090182521 + 21 +179138.0275295288 + 31 +0.0 + 0 +LINE + 5 +206B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523544.6539933986 + 20 +178907.2290588684 + 30 +0.0 + 11 +523312.7654748956 + 21 +179098.9456491675 + 31 +0.0 + 0 +LINE + 5 +206C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523632.5980994354 + 20 +178931.3997911901 + 30 +0.0 + 11 +523533.0776977153 + 21 +178861.8070101844 + 31 +0.0 + 0 +LINE + 5 +206D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523606.9276528144 + 20 +178791.3074733768 + 30 +0.0 + 11 +523667.4240192958 + 21 +178895.8441684115 + 31 +0.0 + 0 +LINE + 5 +206E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523666.2776660543 + 20 +178889.2063607339 + 30 +0.0 + 11 +523630.544485245 + 21 +178932.1104477491 + 31 +0.0 + 0 +LINE + 5 +206F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523848.2607838725 + 20 +178604.3491488078 + 30 +0.0 + 11 +523848.2518561053 + 21 +178604.3578051187 + 31 +0.0 + 0 +LINE + 5 +2070 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523743.1815674026 + 20 +178706.2333457597 + 30 +0.0 + 11 +523444.3500346296 + 21 +178995.9786613726 + 31 +0.0 + 0 +LINE + 5 +2071 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523431.2724968967 + 20 +178996.0668199145 + 30 +0.0 + 11 +523448.3126328807 + 21 +179013.3696618109 + 31 +0.0 + 0 +LINE + 5 +2072 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523241.1644374892 + 20 +178992.5710486596 + 30 +0.0 + 11 +523212.0434267714 + 21 +179027.3000553831 + 31 +0.0 + 0 +LINE + 5 +2073 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523243.0710921107 + 20 +178977.1538389934 + 30 +0.0 + 11 +523238.2328606282 + 21 +179000.7279338593 + 31 +0.0 + 0 +LINE + 5 +2074 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523201.8323023783 + 20 +178928.0841731191 + 30 +0.0 + 11 +523246.4471202749 + 21 +178984.3991835094 + 31 +0.0 + 0 +LINE + 5 +2075 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523458.5958068072 + 20 +178924.3631072621 + 30 +0.0 + 11 +523690.464388803 + 21 +179188.2317961954 + 31 +0.0 + 0 +LINE + 5 +2076 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523741.7018148549 + 20 +179102.2873729164 + 30 +0.0 + 11 +523499.4508888406 + 21 +178938.1841891197 + 31 +0.0 + 0 +LINE + 5 +2077 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523591.893854295 + 20 +178848.8970607549 + 30 +0.0 + 11 +523616.3980502818 + 21 +178874.6174438973 + 31 +0.0 + 0 +LINE + 5 +2078 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523585.0129347177 + 20 +179058.1373172804 + 30 +0.0 + 11 +523523.4110875841 + 21 +179128.2590159926 + 31 +0.0 + 0 +LINE + 5 +2079 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523549.5590820407 + 20 +179104.7681989575 + 30 +0.0 + 11 +523469.0912701507 + 21 +179126.6202810466 + 31 +0.0 + 0 +LINE + 5 +207A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523542.1162144856 + 20 +179093.9573370996 + 30 +0.0 + 11 +523521.0952816062 + 21 +179171.3024597549 + 31 +0.0 + 0 +LINE + 5 +207B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523649.360992273 + 20 +179278.540149505 + 30 +0.0 + 11 +523516.1540374569 + 21 +179159.6855738952 + 31 +0.0 + 0 +LINE + 5 +207C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523335.6977949764 + 20 +178749.7824630303 + 30 +0.0 + 11 +523356.4080963917 + 21 +178791.9866494723 + 31 +0.0 + 0 +LINE + 5 +207D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523407.4561459401 + 20 +178753.6926912383 + 30 +0.0 + 11 +523354.5104915972 + 21 +178791.870634271 + 31 +0.0 + 0 +LINE + 5 +207E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523402.0375425117 + 20 +178704.4361760988 + 30 +0.0 + 11 +523472.2215485359 + 21 +178781.6187410497 + 31 +0.0 + 0 +LINE + 5 +207F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523569.5295937877 + 20 +178666.1028311331 + 30 +0.0 + 11 +523372.7418774964 + 21 +178890.6764851088 + 31 +0.0 + 0 +LINE + 5 +2080 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523274.2136426055 + 20 +178889.281620349 + 30 +0.0 + 11 +523312.8897520948 + 21 +178946.2353059817 + 31 +0.0 + 0 +LINE + 5 +2081 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523338.6708325046 + 20 +178927.5461697877 + 30 +0.0 + 11 +523289.0487180073 + 21 +178961.4610295014 + 31 +0.0 + 0 +LINE + 5 +2082 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523330.453997045 + 20 +178924.9872687913 + 30 +0.0 + 11 +523371.3575600804 + 21 +178983.4284738455 + 31 +0.0 + 0 +LINE + 5 +2083 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523372.2800436911 + 20 +178979.8273128224 + 30 +0.0 + 11 +523326.7427159016 + 21 +179012.6593333595 + 31 +0.0 + 0 +LINE + 5 +2084 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523289.0086319607 + 20 +178952.42564142 + 30 +0.0 + 11 +523332.7394576793 + 21 +179016.4076910938 + 31 +0.0 + 0 +LINE + 5 +2085 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523198.3538800154 + 20 +178611.042650443 + 30 +0.0 + 11 +522964.4065476657 + 21 +178734.6646365355 + 31 +0.0 + 0 +LINE + 5 +2086 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524738.0077992766 + 20 +178705.4710425049 + 30 +0.0 + 11 +524586.8667262392 + 21 +178293.1118015007 + 31 +0.0 + 0 +LINE + 5 +2087 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524758.5993848548 + 20 +178957.9025597381 + 30 +0.0 + 11 +524445.747518893 + 21 +178322.7063720054 + 31 +0.0 + 0 +LINE + 5 +2088 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524459.2215830315 + 20 +178644.1973088366 + 30 +0.0 + 11 +525002.3886547115 + 21 +178361.5835693572 + 31 +0.0 + 0 +LINE + 5 +2089 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524823.6695363629 + 20 +178469.1375592657 + 30 +0.0 + 11 +524726.1370328227 + 21 +178251.1394343973 + 31 +0.0 + 0 +LINE + 5 +208A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524864.5810622931 + 20 +178645.0206934348 + 30 +0.0 + 11 +525061.4539381199 + 21 +178431.2255060558 + 31 +0.0 + 0 +LINE + 5 +208B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524343.9905950533 + 20 +178414.3796104963 + 30 +0.0 + 11 +524729.0724628618 + 21 +178252.1444554355 + 31 +0.0 + 0 +LINE + 5 +208C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524808.6039906535 + 20 +178661.9782852946 + 30 +0.0 + 11 +524654.8301096539 + 21 +178266.7709727712 + 31 +0.0 + 0 +LINE + 5 +208D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525390.9100109588 + 20 +178239.0326645809 + 30 +0.0 + 11 +524649.4001813499 + 21 +178271.1492320292 + 31 +0.0 + 0 +LINE + 5 +208E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525116.8958157751 + 20 +178519.6602617097 + 30 +0.0 + 11 +524857.3147946125 + 21 +178236.5020363899 + 31 +0.0 + 0 +LINE + 5 +208F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524824.6597237038 + 20 +178302.720810087 + 30 +0.0 + 11 +524820.9101242572 + 21 +178257.5535910312 + 31 +0.0 + 0 +LINE + 5 +2090 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524817.3224011424 + 20 +178316.4134863543 + 30 +0.0 + 11 +524826.9711914755 + 21 +178294.3670064145 + 31 +0.0 + 0 +LINE + 5 +2091 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524755.3290416091 + 20 +178332.7013119114 + 30 +0.0 + 11 +524824.2599803013 + 21 +178312.4432749316 + 31 +0.0 + 0 +LINE + 5 +2092 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524761.8016675394 + 20 +178555.5680322682 + 30 +0.0 + 11 +524803.0665951361 + 21 +178533.0443627539 + 31 +0.0 + 0 +LINE + 5 +2093 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524822.6693148313 + 20 +178593.7737953252 + 30 +0.0 + 11 +524801.4497121466 + 21 +178532.0443363133 + 31 +0.0 + 0 +LINE + 5 +2094 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524441.6662571833 + 20 +178845.7581638587 + 30 +0.0 + 11 +524891.6806406799 + 21 +178608.329156404 + 31 +0.0 + 0 +LINE + 5 +2095 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524904.5164691505 + 20 +178758.8217562954 + 30 +0.0 + 11 +524867.3512457227 + 21 +178404.7561514077 + 31 +0.0 + 0 +LINE + 5 +2096 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524292.5001459931 + 20 +178237.2916223235 + 30 +0.0 + 11 +524262.8974638588 + 21 +177997.536803959 + 31 +0.0 + 0 +LINE + 5 +2097 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524743.7613223771 + 20 +178187.8571337603 + 30 +0.0 + 11 +524226.9901518362 + 21 +178250.4398286003 + 31 +0.0 + 0 +LINE + 5 +2098 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524736.0750984626 + 20 +178079.329675156 + 30 +0.0 + 11 +523987.7301282686 + 21 +178183.4997569488 + 31 +0.0 + 0 +LINE + 5 +2099 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524202.146601295 + 20 +178084.5243154731 + 30 +0.0 + 11 +524051.0055282573 + 21 +177672.1650744688 + 31 +0.0 + 0 +LINE + 5 +209A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524134.0058635479 + 20 +178098.1796033321 + 30 +0.0 + 11 +524322.6283647658 + 21 +178053.1122077325 + 31 +0.0 + 0 +LINE + 5 +209B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524118.1994916559 + 20 +178027.3096039344 + 30 +0.0 + 11 +524180.8690639548 + 21 +178012.8814921389 + 31 +0.0 + 0 +LINE + 5 +209C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524108.7047100372 + 20 +178080.8550439858 + 30 +0.0 + 11 +524127.939476443 + 21 +178014.7696501053 + 31 +0.0 + 0 +LINE + 5 +209D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524130.046502145 + 20 +178035.1074034045 + 30 +0.0 + 11 +523968.1415224852 + 21 +177665.8055278164 + 31 +0.0 + 0 +LINE + 5 +209E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524021.02369991 + 20 +177972.5616731266 + 30 +0.0 + 11 +524284.6983858481 + 21 +177835.2438175031 + 31 +0.0 + 0 +LINE + 5 +209F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524287.8083383811 + 20 +177848.1908322338 + 30 +0.0 + 11 +524190.2758348411 + 21 +177630.1927073653 + 31 +0.0 + 0 +LINE + 5 +20A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524477.6094411748 + 20 +177864.9640889815 + 30 +0.0 + 11 +524272.075554444 + 21 +177839.2210645568 + 31 +0.0 + 0 +LINE + 5 +20A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524427.7633272846 + 20 +177936.4997400382 + 30 +0.0 + 11 +524417.803992296 + 21 +177851.6933050936 + 31 +0.0 + 0 +LINE + 5 +20A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523881.3621119936 + 20 +177765.1408410339 + 30 +0.0 + 11 +524193.21126488 + 21 +177631.1977284036 + 31 +0.0 + 0 +LINE + 5 +20A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524272.7427926718 + 20 +178041.0315582626 + 30 +0.0 + 11 +524118.9689116724 + 21 +177645.8242457393 + 31 +0.0 + 0 +LINE + 5 +20A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524656.740906261 + 20 +177628.458690205 + 30 +0.0 + 11 +524113.5389833685 + 21 +177650.2025049972 + 31 +0.0 + 0 +LINE + 5 +20A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524622.4271487831 + 20 +177718.1928094959 + 30 +0.0 + 11 +524561.6286626985 + 21 +177617.7285281862 + 31 +0.0 + 0 +LINE + 5 +20A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524560.4117291013 + 20 +177721.2089921625 + 30 +0.0 + 11 +524595.1923233731 + 21 +177617.0172883553 + 31 +0.0 + 0 +LINE + 5 +20A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524371.664348211 + 20 +177743.0654572557 + 30 +0.0 + 11 +524569.4370217646 + 21 +177701.916934115 + 31 +0.0 + 0 +LINE + 5 +20A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524495.7318062599 + 20 +177959.7817268529 + 30 +0.0 + 11 +524408.6525428254 + 21 +177636.196909216 + 31 +0.0 + 0 +LINE + 5 +20A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524406.7893995179 + 20 +177988.8652669207 + 30 +0.0 + 11 +524519.7244190173 + 21 +177944.220593137 + 31 +0.0 + 0 +LINE + 5 +20AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524423.4153081321 + 20 +178040.2284633169 + 30 +0.0 + 11 +524407.3290128842 + 21 +177986.760229771 + 31 +0.0 + 0 +LINE + 5 +20AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524560.6933372315 + 20 +178349.1236382285 + 30 +0.0 + 11 +524456.725047904 + 21 +177796.2148181869 + 31 +0.0 + 0 +LINE + 5 +20AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524446.0942685496 + 20 +177788.5979753106 + 30 +0.0 + 11 +524469.9950757708 + 21 +177784.2961168499 + 31 +0.0 + 0 +LINE + 5 +20AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524288.7985257223 + 20 +177681.7740830548 + 30 +0.0 + 11 +524285.0489262757 + 21 +177636.6068639992 + 31 +0.0 + 0 +LINE + 5 +20AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524281.4612031608 + 20 +177695.4667593225 + 30 +0.0 + 11 +524291.1099934939 + 21 +177673.4202793828 + 31 +0.0 + 0 +LINE + 5 +20AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524219.4678436274 + 20 +177711.7545848795 + 30 +0.0 + 11 +524288.3987823195 + 21 +177691.4965478998 + 31 +0.0 + 0 +LINE + 5 +20B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524427.0436683059 + 20 +177862.9287246882 + 30 +0.0 + 11 +524769.475248697 + 21 +177769.1499368164 + 31 +0.0 + 0 +LINE + 5 +20B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524719.5010690223 + 20 +178090.2214557565 + 30 +0.0 + 11 +524786.0175886017 + 21 +177897.3427348676 + 31 +0.0 + 0 +LINE + 5 +20B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524810.9911650572 + 20 +177915.8808419147 + 30 +0.0 + 11 +524468.3876208303 + 21 +177875.2103215432 + 31 +0.0 + 0 +LINE + 5 +20B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524492.3818808952 + 20 +178001.4726224788 + 30 +0.0 + 11 +524527.2356194102 + 21 +177994.6016224428 + 31 +0.0 + 0 +LINE + 5 +20B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524607.4787635174 + 20 +177826.5968390907 + 30 +0.0 + 11 +524597.618183188 + 21 +177733.7819202675 + 31 +0.0 + 0 +LINE + 5 +20B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524605.4231027638 + 20 +177768.0546401694 + 30 +0.0 + 11 +524552.304701948 + 21 +177703.7816463328 + 31 +0.0 + 0 +LINE + 5 +20B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524593.1067007006 + 20 +177772.5908557468 + 30 +0.0 + 11 +524620.5597418726 + 21 +177697.2882784462 + 31 +0.0 + 0 +LINE + 5 +20B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524735.2765859546 + 20 +177692.3886915756 + 30 +0.0 + 11 +524609.8216280412 + 21 +177703.9261125934 + 31 +0.0 + 0 +LINE + 5 +20B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524726.363351182 + 20 +178287.7086387874 + 30 +0.0 + 11 +524731.1969941583 + 21 +178018.2169832271 + 31 +0.0 + 0 +LINE + 5 +20B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524225.9404695578 + 20 +177934.6213052363 + 30 +0.0 + 11 +524267.2053971543 + 21 +177912.0976357217 + 31 +0.0 + 0 +LINE + 5 +20BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524286.8081168498 + 20 +177972.8270682933 + 30 +0.0 + 11 +524265.5885141649 + 21 +177911.0976092813 + 31 +0.0 + 0 +LINE + 5 +20BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524253.9646341658 + 20 +178009.9332832979 + 30 +0.0 + 11 +524355.8194426984 + 21 +177987.3824293719 + 31 +0.0 + 0 +LINE + 5 +20BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524368.6552711687 + 20 +178137.8750292635 + 30 +0.0 + 11 +524337.4839301416 + 21 +177840.9119358636 + 31 +0.0 + 0 +LINE + 5 +20BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524256.2020210389 + 20 +177785.207268455 + 30 +0.0 + 11 +524320.6507359999 + 21 +177761.0013416544 + 31 +0.0 + 0 +LINE + 5 +20BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524330.9262008103 + 20 +177791.1403984032 + 30 +0.0 + 11 +524309.9617375784 + 21 +177734.8104486604 + 31 +0.0 + 0 +LINE + 5 +20BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524322.7384384093 + 20 +177788.4899444518 + 30 +0.0 + 11 +524389.8647176601 + 21 +177764.3541090383 + 31 +0.0 + 0 +LINE + 5 +20C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524388.540574712 + 20 +177767.8277213047 + 30 +0.0 + 11 +524370.2878131228 + 21 +177714.7388666447 + 31 +0.0 + 0 +LINE + 5 +20C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524304.7162010103 + 20 +177742.1673631482 + 30 +0.0 + 11 +524377.3484529812 + 21 +177715.1369400639 + 31 +0.0 + 0 +LINE + 5 +20C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524604.9653448457 + 20 +178209.65318257 + 30 +0.0 + 11 +524584.6821974333 + 21 +178098.7786387176 + 31 +0.0 + 0 +LINE + 5 +20C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524616.7122096681 + 20 +177643.0021215638 + 30 +0.0 + 11 +525046.1476847069 + 21 +177260.7352351909 + 31 +0.0 + 0 +LINE + 5 +20C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524683.1261485707 + 20 +177660.8398771929 + 30 +0.0 + 11 +524854.3010716392 + 21 +177511.278349791 + 31 +0.0 + 0 +LINE + 5 +20C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524730.0863801362 + 20 +177841.6950095487 + 30 +0.0 + 11 +524891.8195255732 + 21 +177789.9718299717 + 31 +0.0 + 0 +LINE + 5 +20C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524886.5205772781 + 20 +178270.1374980642 + 30 +0.0 + 11 +524664.3607069593 + 21 +177547.9764409759 + 31 +0.0 + 0 +LINE + 5 +20C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524796.2582747829 + 20 +177743.868231316 + 30 +0.0 + 11 +525270.7473973083 + 21 +177530.0606981159 + 31 +0.0 + 0 +LINE + 5 +20C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524771.912748007 + 20 +177678.7765855139 + 30 +0.0 + 11 +524846.4791452751 + 21 +177857.7999653004 + 31 +0.0 + 0 +LINE + 5 +20C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524839.355750728 + 20 +177651.8723183613 + 30 +0.0 + 11 +524863.5918447558 + 21 +177711.4395698372 + 31 +0.0 + 0 +LINE + 5 +20CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524784.9814290404 + 20 +177651.036753114 + 30 +0.0 + 11 +524853.2882977952 + 21 +177659.4882147568 + 31 +0.0 + 0 +LINE + 5 +20CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524833.5467029925 + 20 +177664.8111088192 + 30 +0.0 + 11 +525069.6851025939 + 21 +177449.3179554017 + 31 +0.0 + 0 +LINE + 5 +20CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524901.0465769525 + 20 +177904.3281639453 + 30 +0.0 + 11 +525242.8844973097 + 21 +177659.7068234534 + 31 +0.0 + 0 +LINE + 5 +20CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524980.7580986971 + 20 +178089.9583921551 + 30 +0.0 + 11 +524961.961184173 + 21 +177969.9828049263 + 31 +0.0 + 0 +LINE + 5 +20CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524866.1857902924 + 20 +178005.3533362377 + 30 +0.0 + 11 +524933.5177864408 + 21 +178105.6236372292 + 31 +0.0 + 0 +LINE + 5 +20CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524928.058427062 + 20 +178101.6777518159 + 30 +0.0 + 11 +524982.2986856754 + 21 +178088.4257618186 + 31 +0.0 + 0 +LINE + 5 +20D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524592.2139268167 + 20 +178140.017783274 + 30 +0.0 + 11 +524592.2256251614 + 21 +178140.013565991 + 31 +0.0 + 0 +LINE + 5 +20D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524729.9026557909 + 20 +178090.3806476191 + 30 +0.0 + 11 +525304.5419744521 + 21 +177825.2009968782 + 31 +0.0 + 0 +LINE + 5 +20D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525031.4395001166 + 20 +177779.6791227352 + 30 +0.0 + 11 +525186.0575622661 + 21 +178254.7713664581 + 31 +0.0 + 0 +LINE + 5 +20D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525159.7267250844 + 20 +178479.6984389388 + 30 +0.0 + 11 +525012.5646530729 + 21 +177947.2602766442 + 31 +0.0 + 0 +LINE + 5 +20D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524924.525016998 + 20 +178017.1478391817 + 30 +0.0 + 11 +524936.8654889531 + 21 +178050.4600964139 + 31 +0.0 + 0 +LINE + 5 +20D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524985.3770249892 + 20 +177600.3362702277 + 30 +0.0 + 11 +524976.8524993605 + 21 +177780.6014976812 + 31 +0.0 + 0 +LINE + 5 +20D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524920.025649624 + 20 +177809.6366444678 + 30 +0.0 + 11 +524977.5819220661 + 21 +177778.845847944 + 31 +0.0 + 0 +LINE + 5 +20D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524770.1396820498 + 20 +177916.7533229772 + 30 +0.0 + 11 +524996.7215091665 + 21 +177855.3320279399 + 31 +0.0 + 0 +LINE + 5 +20D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524906.0587970422 + 20 +178202.5636635308 + 30 +0.0 + 11 +524708.0816721999 + 21 +178134.8693976615 + 31 +0.0 + 0 +LINE + 5 +20D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524924.8530914603 + 20 +177792.5003773588 + 30 +0.0 + 11 +524975.4606124475 + 21 +177898.1842098137 + 31 +0.0 + 0 +LINE + 5 +20DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524462.8484862399 + 20 +178642.3102049752 + 30 +0.0 + 11 +524266.6743453862 + 21 +178614.3835392793 + 31 +0.0 + 0 +LINE + 5 +20DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526557.2525553547 + 20 +175535.8312332927 + 30 +0.0 + 11 +523999.9723634475 + 21 +176912.9282941857 + 31 +0.0 + 0 +LINE + 5 +20DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525747.934562985 + 20 +175742.1415793237 + 30 +0.0 + 11 +526031.2914894814 + 21 +175652.8044649422 + 31 +0.0 + 0 +LINE + 5 +20DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526139.8954430117 + 20 +176128.0346140474 + 30 +0.0 + 11 +525830.2490952948 + 21 +175696.8619054419 + 31 +0.0 + 0 +LINE + 5 +20DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526215.600250218 + 20 +175902.2688151789 + 30 +0.0 + 11 +525996.0746696981 + 21 +175977.801639612 + 31 +0.0 + 0 +LINE + 5 +20DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525901.2081771194 + 20 +176101.1901361145 + 30 +0.0 + 11 +525721.8916498757 + 21 +175837.2967542493 + 31 +0.0 + 0 +LINE + 5 +20E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525472.2889781802 + 20 +176224.7491658278 + 30 +0.0 + 11 +525345.2077450251 + 21 +176037.1569429094 + 31 +0.0 + 0 +LINE + 5 +20E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526047.6612660637 + 20 +175951.2440488057 + 30 +0.0 + 11 +525864.820922853 + 21 +176112.3398447609 + 31 +0.0 + 0 +LINE + 5 +20E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525948.9023176328 + 20 +175776.5868444847 + 30 +0.0 + 11 +525700.5448251069 + 21 +175926.5019602293 + 31 +0.0 + 0 +LINE + 5 +20E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524165.3240109262 + 20 +176815.8237554785 + 30 +0.0 + 11 +521210.3972538704 + 21 +178690.0947664428 + 31 +0.0 + 0 +LINE + 5 +20E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524841.8039351653 + 20 +177414.2638539312 + 30 +0.0 + 11 +524993.9825398388 + 21 +177620.3972736916 + 31 +0.0 + 0 +LINE + 5 +20E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524639.5732319613 + 20 +176760.1462516073 + 30 +0.0 + 11 +524236.7794549726 + 21 +176935.191790881 + 31 +0.0 + 0 +LINE + 5 +20E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524516.5374395311 + 20 +176553.6620460306 + 30 +0.0 + 11 +524699.9462885679 + 21 +176869.0391801092 + 31 +0.0 + 0 +LINE + 5 +20E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524540.2416766282 + 20 +176738.8417321735 + 30 +0.0 + 11 +524573.0288028847 + 21 +176794.1648742926 + 31 +0.0 + 0 +LINE + 5 +20E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524402.8939127689 + 20 +176600.5870943258 + 30 +0.0 + 11 +524516.0534906659 + 21 +176991.8754843581 + 31 +0.0 + 0 +LINE + 5 +20E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524527.5719386363 + 20 +176985.1954879848 + 30 +0.0 + 11 +524302.4685832363 + 21 +177064.9717443567 + 31 +0.0 + 0 +LINE + 5 +20EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524670.6487831715 + 20 +177111.0319585387 + 30 +0.0 + 11 +524510.2250134501 + 21 +176979.9934298166 + 31 +0.0 + 0 +LINE + 5 +20EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524688.051171811 + 20 +177025.5969463264 + 30 +0.0 + 11 +524619.7847107993 + 21 +177076.8903188255 + 31 +0.0 + 0 +LINE + 5 +20EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524292.1288232022 + 20 +176610.8372527493 + 30 +0.0 + 11 +524321.6894533681 + 21 +176695.9739671731 + 31 +0.0 + 0 +LINE + 5 +20ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524139.9292285851 + 20 +176624.1064543491 + 30 +0.0 + 11 +524305.2211714586 + 21 +177066.4035526116 + 31 +0.0 + 0 +LINE + 5 +20EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524656.7870192897 + 20 +176841.2580737571 + 30 +0.0 + 11 +524264.5942312336 + 21 +177002.5653685276 + 31 +0.0 + 0 +LINE + 5 +20EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524582.1070008542 + 20 +177359.7590511446 + 30 +0.0 + 11 +524264.0180729551 + 21 +176995.6140149074 + 31 +0.0 + 0 +LINE + 5 +20F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524733.7490608754 + 20 +177562.7061247043 + 30 +0.0 + 11 +524397.2012674127 + 21 +177141.1576589432 + 31 +0.0 + 0 +LINE + 5 +20F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524664.2950752848 + 20 +177317.1232182147 + 30 +0.0 + 11 +524549.6217916453 + 21 +177342.4128553935 + 31 +0.0 + 0 +LINE + 5 +20F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524623.6974913797 + 20 +177270.1461406419 + 30 +0.0 + 11 +524572.2606837746 + 21 +177367.2020817456 + 31 +0.0 + 0 +LINE + 5 +20F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524509.3137337471 + 20 +177118.4239113903 + 30 +0.0 + 11 +524615.9569827252 + 21 +177289.9886187415 + 31 +0.0 + 0 +LINE + 5 +20F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524914.8712808239 + 20 +176967.8159134291 + 30 +0.0 + 11 +524457.4619183516 + 21 +177218.9246693036 + 31 +0.0 + 0 +LINE + 5 +20F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524593.6225003369 + 20 +177140.8973427732 + 30 +0.0 + 11 +524606.9960536835 + 21 +177161.1680764284 + 31 +0.0 + 0 +LINE + 5 +20F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524407.7767810743 + 20 +177100.7144695549 + 30 +0.0 + 11 +524372.4910968508 + 21 +177129.1584084896 + 31 +0.0 + 0 +LINE + 5 +20F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524412.6280308329 + 20 +177085.9567237407 + 30 +0.0 + 11 +524403.3235628415 + 21 +177108.1507163518 + 31 +0.0 + 0 +LINE + 5 +20F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524381.65373712 + 20 +177029.8402108713 + 30 +0.0 + 11 +524414.5396461155 + 21 +177093.7180580547 + 31 +0.0 + 0 +LINE + 5 +20F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524634.2926135871 + 20 +177075.8287054672 + 30 +0.0 + 11 +524847.2935574429 + 21 +177454.3625650186 + 31 +0.0 + 0 +LINE + 5 +20FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524851.722458845 + 20 +177422.913336713 + 30 +0.0 + 11 +524661.6272607795 + 21 +177489.0807602579 + 31 +0.0 + 0 +LINE + 5 +20FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524948.4464482099 + 20 +177380.2715990563 + 30 +0.0 + 11 +524671.7049472782 + 21 +177097.2874407387 + 31 +0.0 + 0 +LINE + 5 +20FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524732.4626112492 + 20 +177231.5190425282 + 30 +0.0 + 11 +524658.4664940188 + 21 +177288.4085392337 + 31 +0.0 + 0 +LINE + 5 +20FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524688.6626025321 + 20 +177270.4160094029 + 30 +0.0 + 11 +524605.488267369 + 21 +177276.2992238412 + 31 +0.0 + 0 +LINE + 5 +20FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524683.4501827937 + 20 +177258.3701930328 + 30 +0.0 + 11 +524647.8729103227 + 21 +177330.192232138 + 31 +0.0 + 0 +LINE + 5 +20FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524752.9868462255 + 20 +177460.2040589644 + 30 +0.0 + 11 +524645.2707455659 + 21 +177317.8392296933 + 31 +0.0 + 0 +LINE + 5 +2100 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524547.4643337807 + 20 +176880.782114935 + 30 +0.0 + 11 +524559.6247061727 + 21 +176926.1939556954 + 31 +0.0 + 0 +LINE + 5 +2101 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524617.112963295 + 20 +176898.4914126176 + 30 +0.0 + 11 +524557.7853298208 + 21 +176925.7132706436 + 31 +0.0 + 0 +LINE + 5 +2102 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524621.3192077346 + 20 +176849.1165905469 + 30 +0.0 + 11 +524675.2576602958 + 21 +176938.4115308814 + 31 +0.0 + 0 +LINE + 5 +2103 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524793.0622890275 + 20 +176843.8871924073 + 30 +0.0 + 11 +524556.5709138037 + 21 +177026.1797067567 + 31 +0.0 + 0 +LINE + 5 +2104 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524460.1711436096 + 20 +177005.7629728102 + 30 +0.0 + 11 +524487.1069085343 + 21 +177069.1193325565 + 31 +0.0 + 0 +LINE + 5 +2105 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524516.0147297351 + 20 +177055.7669622723 + 30 +0.0 + 11 +524460.7721051657 + 21 +177079.4486933603 + 31 +0.0 + 0 +LINE + 5 +2106 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524508.447615311 + 20 +177051.6677991172 + 30 +0.0 + 11 +524537.2812335059 + 21 +177116.9142425369 + 31 +0.0 + 0 +LINE + 5 +2107 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524538.8825161087 + 20 +177113.5593609073 + 30 +0.0 + 11 +524487.8569583077 + 21 +177136.9683815156 + 31 +0.0 + 0 +LINE + 5 +2108 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524462.4795613218 + 20 +177070.5760140498 + 30 +0.0 + 11 +524493.0159082682 + 21 +177141.8053571161 + 31 +0.0 + 0 +LINE + 5 +2109 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524058.9354562361 + 20 +176546.2668424607 + 30 +0.0 + 11 +523284.4721244596 + 21 +176707.4414788887 + 31 +0.0 + 0 +LINE + 5 +210A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523923.4040826801 + 20 +176571.4619758116 + 30 +0.0 + 11 +523976.5578845037 + 21 +176709.4198246509 + 31 +0.0 + 0 +LINE + 5 +210B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524084.29885898 + 20 +176606.317185652 + 30 +0.0 + 11 +523600.0276661482 + 21 +176706.1471339956 + 31 +0.0 + 0 +LINE + 5 +210C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523973.9147379101 + 20 +176676.8808630096 + 30 +0.0 + 11 +523958.3406354409 + 21 +176757.3702758966 + 31 +0.0 + 0 +LINE + 5 +210D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524050.4510301497 + 20 +176699.1858307063 + 30 +0.0 + 11 +523963.9833528352 + 21 +176683.6690894231 + 31 +0.0 + 0 +LINE + 5 +210E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524223.3875588055 + 20 +176606.9660273341 + 30 +0.0 + 11 +523799.3071688467 + 21 +176904.554215737 + 31 +0.0 + 0 +LINE + 5 +210F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524230.9032869689 + 20 +177064.4254319837 + 30 +0.0 + 11 +524135.8105514784 + 21 +177125.7048981491 + 31 +0.0 + 0 +LINE + 5 +2110 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524184.9417980438 + 20 +177190.6889400043 + 30 +0.0 + 11 +523744.1125567359 + 21 +176577.0594260767 + 31 +0.0 + 0 +LINE + 5 +2111 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523820.3733984538 + 20 +176800.5652334753 + 30 +0.0 + 11 +523351.0133256151 + 21 +176974.2901895443 + 31 +0.0 + 0 +LINE + 5 +2112 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523783.2525142218 + 20 +176741.8143442817 + 30 +0.0 + 11 +523880.7464550603 + 21 +176909.458161977 + 31 +0.0 + 0 +LINE + 5 +2113 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523721.0418431207 + 20 +176779.2607140414 + 30 +0.0 + 11 +523753.8289693772 + 21 +176834.5838561607 + 31 +0.0 + 0 +LINE + 5 +2114 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523753.256382862 + 20 +176735.448746983 + 30 +0.0 + 11 +523718.6825823592 + 21 +176794.9626767961 + 31 +0.0 + 0 +LINE + 5 +2115 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523734.8597260975 + 20 +176782.4581261431 + 30 +0.0 + 11 +523602.716445313 + 21 +176830.4106796125 + 31 +0.0 + 0 +LINE + 5 +2116 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523583.6940792614 + 20 +176641.0060761937 + 30 +0.0 + 11 +523807.7711164501 + 21 +177405.5927394266 + 31 +0.0 + 0 +LINE + 5 +2117 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523708.3721051288 + 20 +177025.6144698526 + 30 +0.0 + 11 +523414.0942205851 + 21 +177128.0965747663 + 31 +0.0 + 0 +LINE + 5 +2118 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523459.628059891 + 20 +176658.2462745898 + 30 +0.0 + 11 +523489.188690057 + 21 +176743.3829890131 + 31 +0.0 + 0 +LINE + 5 +2119 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523837.5871857822 + 20 +176881.6770556252 + 30 +0.0 + 11 +523401.4561761059 + 21 +177061.0559618133 + 31 +0.0 + 0 +LINE + 5 +211A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523932.59431452 + 20 +177099.1610338265 + 30 +0.0 + 11 +523560.8438708927 + 21 +177311.7893333251 + 31 +0.0 + 0 +LINE + 5 +211B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524259.2738640755 + 20 +176877.6038259502 + 30 +0.0 + 11 +523787.2705317197 + 21 +177183.7580725489 + 31 +0.0 + 0 +LINE + 5 +211C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523815.0927800796 + 20 +177116.2476873352 + 30 +0.0 + 11 +524065.686859798 + 21 +177581.6040589463 + 31 +0.0 + 0 +LINE + 5 +211D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524181.393408924 + 20 +177171.1764242468 + 30 +0.0 + 11 +524087.6441325976 + 21 +177352.3882382578 + 31 +0.0 + 0 +LINE + 5 +211E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524118.2928397489 + 20 +177357.6795220147 + 30 +0.0 + 11 +523852.5051137707 + 21 +177137.7064226066 + 31 +0.0 + 0 +LINE + 5 +211F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523913.2627777417 + 20 +177271.938024396 + 30 +0.0 + 11 +523742.3935641112 + 21 +177401.888449398 + 31 +0.0 + 0 +LINE + 5 +2120 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523904.2630915616 + 20 +177457.0410117514 + 30 +0.0 + 11 +523778.0512849523 + 21 +177349.0241465069 + 31 +0.0 + 0 +LINE + 5 +2121 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524329.0991662258 + 20 +177039.9084249556 + 30 +0.0 + 11 +524137.3338132791 + 21 +177229.3158322298 + 31 +0.0 + 0 +LINE + 5 +2122 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523728.264500273 + 20 +176921.2010968029 + 30 +0.0 + 11 +523740.4248726654 + 21 +176966.6129375633 + 31 +0.0 + 0 +LINE + 5 +2123 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523797.9131297873 + 20 +176938.9103944856 + 30 +0.0 + 11 +523738.5854963134 + 21 +176966.1322525115 + 31 +0.0 + 0 +LINE + 5 +2124 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523802.119374227 + 20 +176889.5355724147 + 30 +0.0 + 11 +523856.0578267882 + 21 +176978.8305127494 + 31 +0.0 + 0 +LINE + 5 +2125 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524188.8444531574 + 20 +177005.8680716988 + 30 +0.0 + 11 +524094.5840014705 + 21 +177067.6704809664 + 31 +0.0 + 0 +LINE + 5 +2126 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523620.3338423907 + 20 +176758.5263917544 + 30 +0.0 + 11 +523286.1844197433 + 21 +176841.7763756921 + 31 +0.0 + 0 +LINE + 5 +2127 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523845.4473361947 + 20 +177441.0503041714 + 30 +0.0 + 11 +523897.8522793977 + 21 +177789.229920805 + 31 +0.0 + 0 +LINE + 5 +2128 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524426.8624672233 + 20 +177167.9764499862 + 30 +0.0 + 11 +523718.9633067363 + 21 +177521.2064889649 + 31 +0.0 + 0 +LINE + 5 +2129 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524334.9515202315 + 20 +177490.9462293093 + 30 +0.0 + 11 +524165.8798881372 + 21 +177657.0770312377 + 31 +0.0 + 0 +LINE + 5 +212A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524253.3843285075 + 20 +177460.1439943853 + 30 +0.0 + 11 +524293.136478182 + 21 +177535.7157242692 + 31 +0.0 + 0 +LINE + 5 +212B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524537.393008504 + 20 +177530.0796005514 + 30 +0.0 + 11 +524544.0746081126 + 21 +177647.3181776323 + 31 +0.0 + 0 +LINE + 5 +212C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524484.5437187272 + 20 +177562.6673621539 + 30 +0.0 + 11 +524572.1564254478 + 21 +177628.9215280699 + 31 +0.0 + 0 +LINE + 5 +212D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524294.1932385935 + 20 +177444.0753259245 + 30 +0.0 + 11 +524419.0163395771 + 21 +177658.572912265 + 31 +0.0 + 0 +LINE + 5 +212E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524361.4303963406 + 20 +177360.4962275396 + 30 +0.0 + 11 +524261.6064725267 + 21 +177429.6529319217 + 31 +0.0 + 0 +LINE + 5 +212F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524221.1427565949 + 20 +177335.9155954373 + 30 +0.0 + 11 +524340.1827309195 + 21 +177315.4897422352 + 31 +0.0 + 0 +LINE + 5 +2130 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524333.559963647 + 20 +177314.2594698381 + 30 +0.0 + 11 +524361.383610597 + 21 +177362.6688239315 + 31 +0.0 + 0 +LINE + 5 +2131 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524129.6350283636 + 20 +177044.6744051055 + 30 +0.0 + 11 +524129.6400453109 + 21 +177044.6857834614 + 31 +0.0 + 0 +LINE + 5 +2132 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524188.6841623029 + 20 +177178.5968868009 + 30 +0.0 + 11 +524356.6121674477 + 21 +177559.4548891945 + 31 +0.0 + 0 +LINE + 5 +2133 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524294.4017108166 + 20 +177521.2241593916 + 30 +0.0 + 11 +524622.3728336955 + 21 +177395.4280272024 + 31 +0.0 + 0 +LINE + 5 +2134 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524559.5723787072 + 20 +177317.5318105132 + 30 +0.0 + 11 +524321.55125031 + 21 +177487.7120341687 + 31 +0.0 + 0 +LINE + 5 +2135 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524269.9265987363 + 20 +177370.0141645893 + 30 +0.0 + 11 +524302.556213675 + 21 +177355.9677430189 + 31 +0.0 + 0 +LINE + 5 +2136 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524463.7532463389 + 20 +177449.1347225002 + 30 +0.0 + 11 +524508.1163394164 + 21 +177531.2550986146 + 31 +0.0 + 0 +LINE + 5 +2137 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524495.1687271976 + 20 +177498.5764291668 + 30 +0.0 + 11 +524487.7146466169 + 21 +177581.6247218925 + 31 +0.0 + 0 +LINE + 5 +2138 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524482.4459093658 + 20 +177501.8014745882 + 30 +0.0 + 11 +524547.6763303283 + 21 +177548.3754995245 + 31 +0.0 + 0 +LINE + 5 +2139 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524692.7850811292 + 20 +177465.3365624116 + 30 +0.0 + 11 +524535.0664578412 + 21 +177548.9747045653 + 31 +0.0 + 0 +LINE + 5 +213A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524090.7431950936 + 20 +177327.5030085241 + 30 +0.0 + 11 +524232.9952976152 + 21 +177590.0350459429 + 31 +0.0 + 0 +LINE + 5 +213B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524834.4925108826 + 20 +176585.5479530126 + 30 +0.0 + 11 +524868.7902796302 + 21 +176059.7556749212 + 31 +0.0 + 0 +LINE + 5 +213C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524853.1503024604 + 20 +176384.6466599991 + 30 +0.0 + 11 +524078.0846057808 + 21 +176542.899247733 + 31 +0.0 + 0 +LINE + 5 +213D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524718.7041122123 + 20 +176415.1059753282 + 30 +0.0 + 11 +524712.9644557525 + 21 +176267.373950877 + 31 +0.0 + 0 +LINE + 5 +213E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524852.6970118399 + 20 +176319.461228776 + 30 +0.0 + 11 +524368.4258190082 + 21 +176419.2911771196 + 31 +0.0 + 0 +LINE + 5 +213F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524723.4054065664 + 20 +176298.3054363685 + 30 +0.0 + 11 +524677.2688056228 + 21 +176230.5373590165 + 31 +0.0 + 0 +LINE + 5 +2140 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524784.8807047635 + 20 +176247.5501083199 + 30 +0.0 + 11 +524711.5990661153 + 21 +176295.9983272473 + 31 +0.0 + 0 +LINE + 5 +2141 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524775.536839776 + 20 +176264.1154968722 + 30 +0.0 + 11 +524785.5094619859 + 21 +176065.4831742494 + 31 +0.0 + 0 +LINE + 5 +2142 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524896.866258793 + 20 +176246.5082128524 + 30 +0.0 + 11 +524472.992057353 + 21 +176158.2479008623 + 31 +0.0 + 0 +LINE + 5 +2143 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524730.2782279649 + 20 +176055.8036672147 + 30 +0.0 + 11 +524677.5515472646 + 21 +176234.8559944898 + 31 +0.0 + 0 +LINE + 5 +2144 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524789.3457741364 + 20 +176069.3918539262 + 30 +0.0 + 11 +524729.562001381 + 21 +176056.2571214818 + 31 +0.0 + 0 +LINE + 5 +2145 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524818.4673709424 + 20 +175773.411979897 + 30 +0.0 + 11 +524749.4999268523 + 21 +176062.5303947511 + 31 +0.0 + 0 +LINE + 5 +2146 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524806.1751753408 + 20 +175840.7214848734 + 30 +0.0 + 11 +524694.6000474236 + 21 +175822.0455070709 + 31 +0.0 + 0 +LINE + 5 +2147 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524714.0256908267 + 20 +175742.9288244858 + 30 +0.0 + 11 +524528.7710855574 + 21 +176593.1214276208 + 31 +0.0 + 0 +LINE + 5 +2148 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524533.4667132535 + 20 +176245.4276602987 + 30 +0.0 + 11 +524094.2838498115 + 21 +176243.951157889 + 31 +0.0 + 0 +LINE + 5 +2149 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524522.6071595965 + 20 +176314.069463317 + 30 +0.0 + 11 +524545.8524346704 + 21 +176121.53589404 + 31 +0.0 + 0 +LINE + 5 +214A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524450.6589154366 + 20 +176304.2792452722 + 30 +0.0 + 11 +524458.8936444774 + 21 +176240.4996643729 + 31 +0.0 + 0 +LINE + 5 +214B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524497.5740018673 + 20 +176331.7790578808 + 30 +0.0 + 11 +524442.2821362541 + 21 +176290.7904604414 + 31 +0.0 + 0 +LINE + 5 +214C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524462.085748693 + 20 +176295.877768269 + 30 +0.0 + 11 +524059.5419547112 + 21 +176319.4487605732 + 31 +0.0 + 0 +LINE + 5 +214D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524379.1860456042 + 20 +176485.5811537055 + 30 +0.0 + 11 +524328.3721347721 + 21 +176081.4405337352 + 31 +0.0 + 0 +LINE + 5 +214E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524341.5933468728 + 20 +176083.0205798669 + 30 +0.0 + 11 +524103.2917748921 + 21 +176098.7728014375 + 31 +0.0 + 0 +LINE + 5 +214F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524423.2393996213 + 20 +175910.8586710884 + 30 +0.0 + 11 +524327.7179864655 + 21 +176094.6589472851 + 31 +0.0 + 0 +LINE + 5 +2150 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524473.0111335692 + 20 +175982.4460927623 + 30 +0.0 + 11 +524390.0245524959 + 21 +175962.3327359273 + 31 +0.0 + 0 +LINE + 5 +2151 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524196.0482056268 + 20 +176524.5876792396 + 30 +0.0 + 11 +524189.5287195957 + 21 +176434.7011546625 + 31 +0.0 + 0 +LINE + 5 +2152 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524128.358509373 + 20 +176567.9773459235 + 30 +0.0 + 11 +524105.2536975196 + 21 +176096.3691216743 + 31 +0.0 + 0 +LINE + 5 +2153 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524517.1987594172 + 20 +176164.1208595706 + 30 +0.0 + 11 +524093.1858645262 + 21 +176171.0700549083 + 31 +0.0 + 0 +LINE + 5 +2154 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524179.8018907191 + 20 +175836.4304880299 + 30 +0.0 + 11 +524110.3161840115 + 21 +176113.4995720353 + 31 +0.0 + 0 +LINE + 5 +2155 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524401.0527004668 + 20 +175571.5431528407 + 30 +0.0 + 11 +524337.5341966459 + 21 +175803.6260353005 + 31 +0.0 + 0 +LINE + 5 +2156 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524906.1175838838 + 20 +176001.0920467013 + 30 +0.0 + 11 +524351.516314391 + 21 +175906.5669159554 + 31 +0.0 + 0 +LINE + 5 +2157 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524185.8788921953 + 20 +176024.2964495397 + 30 +0.0 + 11 +524125.3963942551 + 21 +176008.8910432083 + 31 +0.0 + 0 +LINE + 5 +2158 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524196.1710747265 + 20 +176035.9324567793 + 30 +0.0 + 11 +524178.8478202819 + 21 +176019.2276284931 + 31 +0.0 + 0 +LINE + 5 +2159 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524189.9151486143 + 20 +176099.7237828048 + 30 +0.0 + 11 +524194.857365465 + 21 +176028.0478672973 + 31 +0.0 + 0 +LINE + 5 +215A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524689.4772944703 + 20 +175581.5310930009 + 30 +0.0 + 11 +524505.877293696 + 21 +175447.0535606886 + 31 +0.0 + 0 +LINE + 5 +215B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524718.4834610751 + 20 +175762.2538761273 + 30 +0.0 + 11 +524684.3756495151 + 21 +175549.7453183631 + 31 +0.0 + 0 +LINE + 5 +215C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524401.1577066231 + 20 +176171.0543626083 + 30 +0.0 + 11 +524394.3670665881 + 21 +176124.5355798873 + 31 +0.0 + 0 +LINE + 5 +215D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524458.1243808401 + 20 +176127.2439888799 + 30 +0.0 + 11 +524392.8677514518 + 21 +176125.7045185535 + 31 +0.0 + 0 +LINE + 5 +215E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524481.5146127438 + 20 +176170.9299431248 + 30 +0.0 + 11 +524495.7409961227 + 21 +176067.5831819273 + 31 +0.0 + 0 +LINE + 5 +215F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524641.3241762692 + 20 +176107.8115148906 + 30 +0.0 + 11 +524352.0195627142 + 21 +176033.9090662238 + 31 +0.0 + 0 +LINE + 5 +2160 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524271.5534269223 + 20 +176090.7857724328 + 30 +0.0 + 11 +524271.2368351342 + 21 +176021.9420107544 + 31 +0.0 + 0 +LINE + 5 +2161 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524303.0685325427 + 20 +176022.7732501209 + 30 +0.0 + 11 +524242.9639349946 + 21 +176022.8697395756 + 31 +0.0 + 0 +LINE + 5 +2162 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524297.7394902733 + 20 +176029.5308878573 + 30 +0.0 + 11 +524298.4185297348 + 21 +175958.2005659559 + 31 +0.0 + 0 +LINE + 5 +2163 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524301.2160640311 + 20 +175960.6486547176 + 30 +0.0 + 11 +524245.0925818655 + 21 +175959.3278427067 + 31 +0.0 + 0 +LINE + 5 +2164 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524248.0411827285 + 20 +176030.3437880178 + 30 +0.0 + 11 +524247.917997139 + 21 +175952.8449323889 + 31 +0.0 + 0 +LINE + 5 +2165 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523955.0072537066 + 20 +176585.1613932447 + 30 +0.0 + 11 +523908.8706527628 + 21 +176517.3933158926 + 31 +0.0 + 0 +LINE + 5 +2166 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524016.4825519034 + 20 +176534.4060651959 + 30 +0.0 + 11 +523943.2009132551 + 21 +176582.8542841236 + 31 +0.0 + 0 +LINE + 5 +2167 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524007.0495175071 + 20 +176549.1513555462 + 30 +0.0 + 11 +524017.0221397171 + 21 +176350.5190329231 + 31 +0.0 + 0 +LINE + 5 +2168 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524211.791502212 + 20 +176550.7140082577 + 30 +0.0 + 11 +523704.593904493 + 21 +176445.1038577385 + 31 +0.0 + 0 +LINE + 5 +2169 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523961.8800751049 + 20 +176342.6596240908 + 30 +0.0 + 11 +523909.1533944044 + 21 +176521.7119513658 + 31 +0.0 + 0 +LINE + 5 +216A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524020.9476212765 + 20 +176356.2478108022 + 30 +0.0 + 11 +523961.163848521 + 21 +176343.1130783577 + 31 +0.0 + 0 +LINE + 5 +216B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524050.0692180822 + 20 +176060.2679367731 + 30 +0.0 + 11 +523981.1017739921 + 21 +176349.3863516272 + 31 +0.0 + 0 +LINE + 5 +216C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523925.7303676276 + 20 +176133.255429937 + 30 +0.0 + 11 +523783.4177929851 + 21 +176767.7275968893 + 31 +0.0 + 0 +LINE + 5 +216D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523765.0685603935 + 20 +176532.2836171748 + 30 +0.0 + 11 +523499.6512491019 + 21 +176531.3913025323 + 31 +0.0 + 0 +LINE + 5 +216E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523754.2090067364 + 20 +176600.925420193 + 30 +0.0 + 11 +523777.4542818105 + 21 +176408.3918509162 + 31 +0.0 + 0 +LINE + 5 +216F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523682.2607625766 + 20 +176591.1352021484 + 30 +0.0 + 11 +523690.4954916173 + 21 +176527.3556212487 + 31 +0.0 + 0 +LINE + 5 +2170 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523729.1758490071 + 20 +176618.635014757 + 30 +0.0 + 11 +523673.883983394 + 21 +176577.6464173176 + 31 +0.0 + 0 +LINE + 5 +2171 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523693.6875958331 + 20 +176582.7337251451 + 30 +0.0 + 11 +523291.1438018511 + 21 +176606.3047174492 + 31 +0.0 + 0 +LINE + 5 +2172 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523597.1719588192 + 20 +176663.2487647028 + 30 +0.0 + 11 +523559.9739819122 + 21 +176368.2964906114 + 31 +0.0 + 0 +LINE + 5 +2173 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523573.1951940131 + 20 +176369.8765367431 + 30 +0.0 + 11 +523334.893622032 + 21 +176385.6287583135 + 31 +0.0 + 0 +LINE + 5 +2174 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523654.8412467612 + 20 +176197.7146279646 + 30 +0.0 + 11 +523559.3198336054 + 21 +176381.5149041611 + 31 +0.0 + 0 +LINE + 5 +2175 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523905.9258672462 + 20 +176331.1066862747 + 30 +0.0 + 11 +523621.6263996359 + 21 +176249.1886928035 + 31 +0.0 + 0 +LINE + 5 +2176 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523748.8006065571 + 20 +176450.9768164465 + 30 +0.0 + 11 +523287.6327858075 + 21 +176455.5451722603 + 31 +0.0 + 0 +LINE + 5 +2177 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523581.6567369846 + 20 +176045.7597572108 + 30 +0.0 + 11 +523601.3255771891 + 21 +176409.2881804986 + 31 +0.0 + 0 +LINE + 5 +2178 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523665.9868155602 + 20 +176111.4283174921 + 30 +0.0 + 11 +523550.6608481276 + 21 +176133.5518110002 + 31 +0.0 + 0 +LINE + 5 +2179 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523647.2776624665 + 20 +176170.6311656222 + 30 +0.0 + 11 +523561.6503440895 + 21 +176101.8302700779 + 31 +0.0 + 0 +LINE + 5 +217A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524137.7194310238 + 20 +176287.9480035772 + 30 +0.0 + 11 +523822.669511242 + 21 +176239.4880524337 + 31 +0.0 + 0 +LINE + 5 +217B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523912.551407782 + 20 +176284.3224058519 + 30 +0.0 + 11 +523764.8411344153 + 21 +175991.2301637763 + 31 +0.0 + 0 +LINE + 5 +217C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523834.274537764 + 20 +176080.7292277792 + 30 +0.0 + 11 +523684.4955315352 + 21 +176154.1947352304 + 31 +0.0 + 0 +LINE + 5 +217D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523706.8396502355 + 20 +176144.6906932061 + 30 +0.0 + 11 +523628.1195368675 + 21 +176172.1811641599 + 31 +0.0 + 0 +LINE + 5 +217E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523706.8160992776 + 20 +176157.8158772775 + 30 +0.0 + 11 +523645.7349219852 + 21 +176105.9194670136 + 31 +0.0 + 0 +LINE + 5 +217F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523680.9808014415 + 20 +175996.6414351451 + 30 +0.0 + 11 +523648.2303072941 + 21 +176118.2944814773 + 31 +0.0 + 0 +LINE + 5 +2180 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524137.66337269 + 20 +176111.2608435002 + 30 +0.0 + 11 +523998.6574924492 + 21 +176056.9264262539 + 31 +0.0 + 0 +LINE + 5 +2181 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523632.759553763 + 20 +176457.9103194846 + 30 +0.0 + 11 +523625.9689137283 + 21 +176411.3915367633 + 31 +0.0 + 0 +LINE + 5 +2182 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523689.7262279803 + 20 +176414.0999457557 + 30 +0.0 + 11 +523624.4695985917 + 21 +176412.5604754293 + 31 +0.0 + 0 +LINE + 5 +2183 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523713.1164598839 + 20 +176457.7859000009 + 30 +0.0 + 11 +523727.3428432626 + 21 +176354.4391388034 + 31 +0.0 + 0 +LINE + 5 +2184 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523872.9260234091 + 20 +176394.6674717667 + 30 +0.0 + 11 +523583.6214098542 + 21 +176320.7650230998 + 31 +0.0 + 0 +LINE + 5 +2185 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523503.1552740625 + 20 +176377.641729309 + 30 +0.0 + 11 +523502.8386822742 + 21 +176308.7979676306 + 31 +0.0 + 0 +LINE + 5 +2186 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523534.6703796825 + 20 +176309.629206997 + 30 +0.0 + 11 +523474.5657821348 + 21 +176309.7256964516 + 31 +0.0 + 0 +LINE + 5 +2187 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524022.3055568426 + 20 +176197.9943693747 + 30 +0.0 + 11 +523911.2880441574 + 21 +176178.5089281253 + 31 +0.0 + 0 +LINE + 5 +2188 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523593.4915151983 + 20 +176090.6742454528 + 30 +0.0 + 11 +523384.1588268988 + 21 +175555.2093770923 + 31 +0.0 + 0 +LINE + 5 +2189 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523633.2841588868 + 20 +176034.5891109277 + 30 +0.0 + 11 +523552.479969169 + 21 +175822.1269079588 + 31 +0.0 + 0 +LINE + 5 +218A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523819.1912007304 + 20 +176053.3618049566 + 30 +0.0 + 11 +523826.85645502 + 21 +175883.7323808723 + 31 +0.0 + 0 +LINE + 5 +218B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523958.7285697965 + 20 +176038.1395985702 + 30 +0.0 + 11 +522674.7588793094 + 21 +175965.1831478631 + 31 +0.0 + 0 +LINE + 5 +218C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523750.4346482233 + 20 +175957.3340242478 + 30 +0.0 + 11 +523681.8651927528 + 21 +175523.5345344176 + 31 +0.0 + 0 +LINE + 5 +218D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523680.9394918868 + 20 +175957.5582406125 + 30 +0.0 + 11 +523874.7162583049 + 21 +175949.8069240586 + 31 +0.0 + 0 +LINE + 5 +218E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523679.132413508 + 20 +175884.9694489518 + 30 +0.0 + 11 +523743.4090293628 + 21 +175882.9292635791 + 31 +0.0 + 0 +LINE + 5 +218F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523659.4649690731 + 20 +175935.669120131 + 30 +0.0 + 11 +523691.1129608358 + 21 +175874.5490731707 + 31 +0.0 + 0 +LINE + 5 +2190 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523689.2483959566 + 20 +175894.910486785 + 30 +0.0 + 11 +523601.7939436437 + 21 +175501.2751015337 + 31 +0.0 + 0 +LINE + 5 +2191 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523488.7537930343 + 20 +175843.3193110165 + 30 +0.0 + 11 +523879.6217311897 + 21 +175728.7158679355 + 31 +0.0 + 0 +LINE + 5 +2192 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523880.170002799 + 20 +175742.0198670875 + 30 +0.0 + 11 +523826.6224728135 + 21 +175509.2787368043 + 31 +0.0 + 0 +LINE + 5 +2193 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524063.14765777 + 20 +175795.1703943184 + 30 +0.0 + 11 +523866.4681278443 + 21 +175730.1777454313 + 31 +0.0 + 0 +LINE + 5 +2194 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524000.4121388068 + 20 +175855.7198708024 + 30 +0.0 + 11 +524007.0360807248 + 21 +175770.5879546085 + 31 +0.0 + 0 +LINE + 5 +2195 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523421.0452457656 + 20 +175668.7440261316 + 30 +0.0 + 11 +523508.7422612466 + 21 +175647.9756734188 + 31 +0.0 + 0 +LINE + 5 +2196 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523367.4176725549 + 20 +175608.8387546992 + 30 +0.0 + 11 +523829.3082261822 + 21 +175510.8322958291 + 31 +0.0 + 0 +LINE + 5 +2197 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523828.1073277839 + 20 +175928.3099477495 + 30 +0.0 + 11 +523753.6388003021 + 21 +175510.8298107797 + 31 +0.0 + 0 +LINE + 5 +2198 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524225.4539202574 + 20 +175586.9361729005 + 30 +0.0 + 11 +523747.4648746935 + 21 +175514.0757186803 + 31 +0.0 + 0 +LINE + 5 +2199 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524426.7050617454 + 20 +175585.5475623332 + 30 +0.0 + 11 +523941.7571189213 + 21 +175548.2990942904 + 31 +0.0 + 0 +LINE + 5 +219A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524233.6081600306 + 20 +175679.1652475025 + 30 +0.0 + 11 +524193.379151646 + 21 +175568.8422915338 + 31 +0.0 + 0 +LINE + 5 +219B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524172.1795916705 + 20 +175670.1352627065 + 30 +0.0 + 11 +524226.4471139384 + 21 +175574.6332370366 + 31 +0.0 + 0 +LINE + 5 +219C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523982.767604884 + 20 +175655.0893954719 + 30 +0.0 + 11 +524184.7642951671 + 21 +175652.9519961581 + 31 +0.0 + 0 +LINE + 5 +219D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524060.8920527418 + 20 +175857.5198199396 + 30 +0.0 + 11 +524039.718586377 + 21 +175557.3878150962 + 31 +0.0 + 0 +LINE + 5 +219E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524163.9828436678 + 20 +175862.6319814055 + 30 +0.0 + 11 +524262.2482765593 + 21 +175978.5874908516 + 31 +0.0 + 0 +LINE + 5 +219F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523952.5760344381 + 20 +176185.7681188406 + 30 +0.0 + 11 +523952.5761424223 + 21 +176185.7556840073 + 31 +0.0 + 0 +LINE + 5 +21A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524065.176651165 + 20 +175980.5472814888 + 30 +0.0 + 11 +524055.9483637536 + 21 +175723.6806028601 + 31 +0.0 + 0 +LINE + 5 +21A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524046.9906836203 + 20 +175714.1522382722 + 30 +0.0 + 11 +524071.272252612 + 21 +175714.5522124547 + 31 +0.0 + 0 +LINE + 5 +21A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523913.3143877621 + 20 +175578.9341085931 + 30 +0.0 + 11 +523918.3675773197 + 21 +175533.8940991734 + 31 +0.0 + 0 +LINE + 5 +21A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523903.4683223095 + 20 +175590.9499598256 + 30 +0.0 + 11 +523917.1972653579 + 21 +175571.1847743874 + 31 +0.0 + 0 +LINE + 5 +21A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523839.4956288376 + 20 +175594.9455045419 + 30 +0.0 + 11 +523911.0425692246 + 21 +175588.3958715355 + 31 +0.0 + 0 +LINE + 5 +21A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524013.929332411 + 20 +175783.3976910387 + 30 +0.0 + 11 +524364.9122806743 + 21 +175769.2310278912 + 31 +0.0 + 0 +LINE + 5 +21A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524244.1416690661 + 20 +175847.5570144723 + 30 +0.0 + 11 +524052.1189380022 + 21 +175803.4404966425 + 31 +0.0 + 0 +LINE + 5 +21A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523779.0412053739 + 20 +176109.8391314804 + 30 +0.0 + 11 +524379.9318991116 + 21 +175749.9532929654 + 31 +0.0 + 0 +LINE + 5 +21A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524197.9843422059 + 20 +175782.6342354071 + 30 +0.0 + 11 +524206.2534331876 + 21 +175689.6640125672 + 31 +0.0 + 0 +LINE + 5 +21A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524207.2852601229 + 20 +175724.7990582087 + 30 +0.0 + 11 +524167.5946882196 + 21 +175651.4693865612 + 31 +0.0 + 0 +LINE + 5 +21AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524194.3242413292 + 20 +175726.8686000381 + 30 +0.0 + 11 +524235.8173966716 + 21 +175658.294073591 + 31 +0.0 + 0 +LINE + 5 +21AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524401.936399934 + 20 +175677.1750531974 + 30 +0.0 + 11 +524223.9985907147 + 21 +175662.7307115722 + 31 +0.0 + 0 +LINE + 5 +21AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523802.7599534706 + 20 +175814.8590331944 + 30 +0.0 + 11 +523847.6008284282 + 21 +175800.7379188267 + 31 +0.0 + 0 +LINE + 5 +21AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523855.0930810568 + 20 +175864.1113892261 + 30 +0.0 + 11 +523846.207781267 + 21 +175799.4441711348 + 31 +0.0 + 0 +LINE + 5 +21AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523903.4878811873 + 20 +176041.8688909265 + 30 +0.0 + 11 +523930.3156404951 + 21 +175744.4819331198 + 31 +0.0 + 0 +LINE + 5 +21AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523861.3363930202 + 20 +175674.1141696465 + 30 +0.0 + 11 +524026.3704793484 + 21 +175650.4719839854 + 31 +0.0 + 0 +LINE + 5 +21B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523607.5722573438 + 20 +175811.1374939353 + 30 +0.0 + 11 +523535.6810956624 + 21 +175556.489873426 + 31 +0.0 + 0 +LINE + 5 +21B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524601.8591509933 + 20 +175937.3279469695 + 30 +0.0 + 11 +524563.5006805631 + 21 +176099.1916535255 + 31 +0.0 + 0 +LINE + 5 +21B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524649.1081246048 + 20 +175849.7935343369 + 30 +0.0 + 11 +524802.8262932069 + 21 +175951.8810185483 + 31 +0.0 + 0 +LINE + 5 +21B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523840.6999827257 + 20 +175853.6330990243 + 30 +0.0 + 11 +523957.3813533612 + 21 +175842.8789663575 + 31 +0.0 + 0 +LINE + 5 +21B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524378.6760047676 + 20 +176481.5246224025 + 30 +0.0 + 11 +524284.3574541301 + 21 +176655.7893727172 + 31 +0.0 + 0 +LINE + 5 +21B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523147.326013239 + 20 +178931.9640315077 + 30 +0.0 + 11 +522765.2641434303 + 21 +179342.3537138884 + 31 +0.0 + 0 +LINE + 5 +21B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523139.8670581723 + 20 +178951.3058347943 + 30 +0.0 + 11 +522719.7578980884 + 21 +178281.0230517039 + 31 +0.0 + 0 +LINE + 5 +21B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523069.1709018637 + 20 +178832.9605710714 + 30 +0.0 + 11 +522958.2600799692 + 21 +178930.7178433913 + 31 +0.0 + 0 +LINE + 5 +21B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522987.8557439687 + 20 +178916.9386227657 + 30 +0.0 + 11 +522906.9675008426 + 21 +178930.2874196615 + 31 +0.0 + 0 +LINE + 5 +21B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522993.5197341839 + 20 +178996.4573930566 + 30 +0.0 + 11 +522978.0409297662 + 21 +178909.9829165099 + 31 +0.0 + 0 +LINE + 5 +21BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522999.0664906292 + 20 +178978.2652682841 + 30 +0.0 + 11 +522862.1452156581 + 21 +179122.5109519096 + 31 +0.0 + 0 +LINE + 5 +21BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523070.0183710327 + 20 +179078.2486420859 + 30 +0.0 + 11 +522713.7134417443 + 21 +178832.2689301503 + 31 +0.0 + 0 +LINE + 5 +21BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522817.0365754428 + 20 +179089.20340553 + 30 +0.0 + 11 +522910.289047065 + 21 +178927.5129132409 + 31 +0.0 + 0 +LINE + 5 +21BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522867.6213930463 + 20 +179122.5918774449 + 30 +0.0 + 11 +522816.8707690084 + 21 +179088.3720755601 + 31 +0.0 + 0 +LINE + 5 +21BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522673.4347394771 + 20 +179347.8554936956 + 30 +0.0 + 11 +522835.1664587846 + 21 +179098.4786360647 + 31 +0.0 + 0 +LINE + 5 +21BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522713.6840544283 + 20 +179292.5232230136 + 30 +0.0 + 11 +522623.1936961966 + 21 +179224.6314239237 + 31 +0.0 + 0 +LINE + 5 +21C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522579.3175052096 + 20 +179293.273138277 + 30 +0.0 + 11 +523008.5346679032 + 21 +178704.9826767926 + 31 +0.0 + 0 +LINE + 5 +21C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522818.5459361698 + 20 +178815.9091448761 + 30 +0.0 + 11 +522514.5079408377 + 21 +178498.9790816208 + 31 +0.0 + 0 +LINE + 5 +21C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522860.7480789847 + 20 +178760.6949603847 + 30 +0.0 + 11 +522737.3981294931 + 21 +178910.3422392513 + 31 +0.0 + 0 +LINE + 5 +21C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522804.027106139 + 20 +178715.3614248236 + 30 +0.0 + 11 +522763.5342653316 + 21 +178765.321164069 + 31 +0.0 + 0 +LINE + 5 +21C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522856.299974217 + 20 +178730.3551665571 + 30 +0.0 + 11 +522788.4831353206 + 21 +178718.6022143702 + 31 +0.0 + 0 +LINE + 5 +21C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522805.8275840294 + 20 +178729.429673239 + 30 +0.0 + 11 +522545.1982073443 + 21 +178421.7457026453 + 31 +0.0 + 0 +LINE + 5 +21C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522885.9761669452 + 20 +178538.5476681291 + 30 +0.0 + 11 +522558.3427148113 + 21 +178780.5559640336 + 31 +0.0 + 0 +LINE + 5 +21C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522568.6072133998 + 20 +178789.0375360528 + 30 +0.0 + 11 +522415.6194376418 + 21 +178605.6512983969 + 31 +0.0 + 0 +LINE + 5 +21C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522500.2930428026 + 20 +178966.9110159738 + 30 +0.0 + 11 +522567.4609888394 + 21 +178770.9637043657 + 31 +0.0 + 0 +LINE + 5 +21C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522586.4540056679 + 20 +178953.5591277127 + 30 +0.0 + 11 +522514.6447790618 + 21 +178907.3557216087 + 31 +0.0 + 0 +LINE + 5 +21CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522837.8959411886 + 20 +178438.2368376785 + 30 +0.0 + 11 +522768.3246941651 + 21 +178495.5249916571 + 31 +0.0 + 0 +LINE + 5 +21CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522772.5946245916 + 20 +178300.1190388134 + 30 +0.0 + 11 +522415.2327085451 + 21 +178608.7298138516 + 31 +0.0 + 0 +LINE + 5 +21CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522748.4610696767 + 20 +178860.2211483888 + 30 +0.0 + 11 +522460.9878607667 + 21 +178548.4610154204 + 31 +0.0 + 0 +LINE + 5 +21CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522236.2976158708 + 20 +178970.2618921646 + 30 +0.0 + 11 +522467.3064393924 + 21 +178545.5065544425 + 31 +0.0 + 0 +LINE + 5 +21CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522098.6471478465 + 20 +179182.9475232887 + 30 +0.0 + 11 +522377.0757368185 + 21 +178720.9463900508 + 31 +0.0 + 0 +LINE + 5 +21CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522304.8230768771 + 20 +179032.5270912898 + 30 +0.0 + 11 +522241.2821931961 + 21 +178933.7744516778 + 31 +0.0 + 0 +LINE + 5 +21D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522334.7768169362 + 20 +178978.1415868549 + 30 +0.0 + 11 +522225.8982985945 + 21 +178963.6133686634 + 31 +0.0 + 0 +LINE + 5 +21D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522437.3304620526 + 20 +178818.1852530238 + 30 +0.0 + 11 +522313.4811757963 + 21 +178977.7740548083 + 31 +0.0 + 0 +LINE + 5 +21D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522577.5095443722 + 20 +179024.845603684 + 30 +0.0 + 11 +522325.0774155249 + 21 +178804.4642236829 + 31 +0.0 + 0 +LINE + 5 +21D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522642.7098597427 + 20 +178957.7224117491 + 30 +0.0 + 11 +522552.9901757035 + 21 +179039.5627674574 + 31 +0.0 + 0 +LINE + 5 +21D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522635.311412092 + 20 +179099.9549407722 + 30 +0.0 + 11 +522681.828355844 + 21 +178988.4923689815 + 31 +0.0 + 0 +LINE + 5 +21D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522681.547176797 + 20 +178995.2225662195 + 30 +0.0 + 11 +522640.581774166 + 21 +178957.2823938343 + 31 +0.0 + 0 +LINE + 5 +21D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522898.7301144073 + 20 +179254.2458431046 + 30 +0.0 + 11 +522447.7080348636 + 21 +178917.9473860314 + 31 +0.0 + 0 +LINE + 5 +21D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522445.5358098579 + 20 +178905.0512159173 + 30 +0.0 + 11 +522431.1713612153 + 21 +178924.6322574431 + 31 +0.0 + 0 +LINE + 5 +21D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522418.6744038956 + 20 +178716.8179575967 + 30 +0.0 + 11 +522379.7464089774 + 21 +178693.6070036115 + 31 +0.0 + 0 +LINE + 5 +21D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522434.198382797 + 20 +178716.2419673135 + 30 +0.0 + 11 +522410.1544402602 + 21 +178715.2244900878 + 31 +0.0 + 0 +LINE + 5 +21DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522476.0647982307 + 20 +178667.7066899749 + 30 +0.0 + 11 +522427.5840362466 + 21 +178720.7300630164 + 31 +0.0 + 0 +LINE + 5 +21DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522520.6788244482 + 20 +178920.5919054432 + 30 +0.0 + 11 +522239.6803424068 + 21 +179251.7974881269 + 31 +0.0 + 0 +LINE + 5 +21DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522270.7101836271 + 20 +179245.0285825652 + 30 +0.0 + 11 +522142.6423063304 + 21 +179089.7451930127 + 31 +0.0 + 0 +LINE + 5 +21DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522596.3831531044 + 20 +179283.1690302777 + 30 +0.0 + 11 +522237.4258900137 + 21 +179230.8789917106 + 31 +0.0 + 0 +LINE + 5 +21DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522344.2894211447 + 20 +179320.9228756008 + 30 +0.0 + 11 +522513.5488495037 + 21 +178963.1280487681 + 31 +0.0 + 0 +LINE + 5 +21DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522616.433556044 + 20 +179040.1516186263 + 30 +0.0 + 11 +522594.9493916457 + 21 +179068.44339146 + 31 +0.0 + 0 +LINE + 5 +21E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522408.7731163578 + 20 +179066.7217860012 + 30 +0.0 + 11 +522329.726212972 + 21 +179017.088860783 + 31 +0.0 + 0 +LINE + 5 +21E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522357.0857537812 + 20 +179039.1567475365 + 30 +0.0 + 11 +522322.6827665701 + 21 +178963.2027041097 + 31 +0.0 + 0 +LINE + 5 +21E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522366.5715496863 + 20 +179030.0853260603 + 30 +0.0 + 11 +522286.8642047714 + 21 +179021.6658970797 + 31 +0.0 + 0 +LINE + 5 +21E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522201.450268929 + 20 +179165.3895005678 + 30 +0.0 + 11 +522297.5445928094 + 21 +179014.9355744889 + 31 +0.0 + 0 +LINE + 5 +21E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522694.7693225394 + 20 +179484.036566723 + 30 +0.0 + 11 +522776.714635701 + 21 +179327.5713947966 + 31 +0.0 + 0 +LINE + 5 +21E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522757.6709378034 + 20 +179388.2454918792 + 30 +0.0 + 11 +522526.5609187225 + 21 +179262.0433512364 + 31 +0.0 + 0 +LINE + 5 +21E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522673.4300169945 + 20 +178771.4295917444 + 30 +0.0 + 11 +522635.0680081422 + 21 +178798.6043266053 + 31 +0.0 + 0 +LINE + 5 +21E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522681.0115798427 + 20 +178842.8933638417 + 30 +0.0 + 11 +522634.8799687523 + 21 +178796.7125008545 + 31 +0.0 + 0 +LINE + 5 +21E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522728.7739305676 + 20 +178829.6902051285 + 30 +0.0 + 11 +522663.7695582929 + 21 +178911.2829414423 + 31 +0.0 + 0 +LINE + 5 +21E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522793.3232115586 + 20 +178988.9272074254 + 30 +0.0 + 11 +522540.2451840974 + 21 +178830.46508779 + 31 +0.0 + 0 +LINE + 5 +21EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522525.9120197558 + 20 +178732.9749902497 + 30 +0.0 + 11 +522475.8538351816 + 21 +178780.2374691257 + 31 +0.0 + 0 +LINE + 5 +21EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522498.4146227873 + 20 +178802.708757059 + 30 +0.0 + 11 +522457.0214877424 + 21 +178759.1291709232 + 31 +0.0 + 0 +LINE + 5 +21EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522499.6306233752 + 20 +178794.1890327764 + 30 +0.0 + 11 +522448.4591145681 + 21 +178843.8876504995 + 31 +0.0 + 0 +LINE + 5 +21ED +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522452.1612918723 + 20 +178844.2241321974 + 30 +0.0 + 11 +522412.4884557117 + 21 +178804.5044158627 + 31 +0.0 + 0 +LINE + 5 +21EE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522465.9348875831 + 20 +178757.6489182592 + 30 +0.0 + 11 +522409.7442253048 + 21 +178811.0221069516 + 31 +0.0 + 0 +LINE + 5 +21EF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522753.9897929319 + 20 +179232.745657081 + 30 +0.0 + 11 +522663.2980889141 + 21 +179165.8159524214 + 31 +0.0 + 0 +LINE + 5 +21F0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522788.4955386514 + 20 +178613.7209607204 + 30 +0.0 + 11 +522629.152581096 + 21 +178402.478039806 + 31 +0.0 + 0 +LINE + 5 +21F1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523087.4314069828 + 20 +178627.8710157389 + 30 +0.0 + 11 +522397.3513749961 + 21 +177526.8505945155 + 31 +0.0 + 0 +LINE + 5 +21F2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522746.7643787713 + 20 +178078.788113883 + 30 +0.0 + 11 +522635.8535568769 + 21 +178176.5453862029 + 31 +0.0 + 0 +LINE + 5 +21F3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522769.9565157756 + 20 +178241.7732036145 + 30 +0.0 + 11 +522508.1557723742 + 21 +177822.3152467851 + 31 +0.0 + 0 +LINE + 5 +21F4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522665.4492208762 + 20 +178162.7661655775 + 30 +0.0 + 11 +522584.5609777499 + 21 +178176.1149624734 + 31 +0.0 + 0 +LINE + 5 +21F5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522671.1132110915 + 20 +178242.2849358682 + 30 +0.0 + 11 +522655.6344066736 + 21 +178155.8104593216 + 31 +0.0 + 0 +LINE + 5 +21F6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522675.2807850979 + 20 +178225.2838461286 + 30 +0.0 + 11 +522538.3595101266 + 21 +178369.5295297541 + 31 +0.0 + 0 +LINE + 5 +21F7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522817.6527627173 + 20 +178372.429835449 + 30 +0.0 + 11 +522391.3069186522 + 21 +178078.096472962 + 31 +0.0 + 0 +LINE + 5 +21F8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522494.6300523502 + 20 +178335.0309483416 + 30 +0.0 + 11 +522587.8825239725 + 21 +178173.3404560525 + 31 +0.0 + 0 +LINE + 5 +21F9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522545.2148699541 + 20 +178368.4194202566 + 30 +0.0 + 11 +522494.4642459159 + 21 +178334.199618372 + 31 +0.0 + 0 +LINE + 5 +21FA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522351.0282163845 + 20 +178593.6830365074 + 30 +0.0 + 11 +522512.7599356921 + 21 +178344.3061788763 + 31 +0.0 + 0 +LINE + 5 +21FB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522391.2775313359 + 20 +178538.3507658254 + 30 +0.0 + 11 +522300.7871731041 + 21 +178470.4589667354 + 31 +0.0 + 0 +LINE + 5 +21FC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522256.9109821169 + 20 +178539.1006810888 + 30 +0.0 + 11 +522679.2484233736 + 21 +177912.6003330697 + 31 +0.0 + 0 +LINE + 5 +21FD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522496.1394130775 + 20 +178061.7366876876 + 30 +0.0 + 11 +522192.1014177453 + 21 +177744.8066244325 + 31 +0.0 + 0 +LINE + 5 +21FE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522538.3415558925 + 20 +178006.5225031963 + 30 +0.0 + 11 +522414.991606401 + 21 +178156.1697820629 + 31 +0.0 + 0 +LINE + 5 +21FF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522481.6205830464 + 20 +177961.1889676354 + 30 +0.0 + 11 +522441.1277422392 + 21 +178011.1487068806 + 31 +0.0 + 0 +LINE + 5 +2200 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522533.8934511245 + 20 +177976.1827093689 + 30 +0.0 + 11 +522466.0766122282 + 21 +177964.429757182 + 31 +0.0 + 0 +LINE + 5 +2201 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522483.4210609369 + 20 +177975.2572160508 + 30 +0.0 + 11 +522222.7916842517 + 21 +177667.5732454571 + 31 +0.0 + 0 +LINE + 5 +2202 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522738.9858306533 + 20 +177585.8169169486 + 30 +0.0 + 11 +522176.1206057709 + 21 +177987.17906715 + 31 +0.0 + 0 +LINE + 5 +2203 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522246.2006903077 + 20 +178034.8650788645 + 30 +0.0 + 11 +522093.2129145495 + 21 +177851.4788412087 + 31 +0.0 + 0 +LINE + 5 +2204 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522177.8865197101 + 20 +178212.7385587857 + 30 +0.0 + 11 +522245.0544657469 + 21 +178016.7912471776 + 31 +0.0 + 0 +LINE + 5 +2205 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522264.0474825756 + 20 +178199.3866705242 + 30 +0.0 + 11 +522192.2382559694 + 21 +178153.1832644204 + 31 +0.0 + 0 +LINE + 5 +2206 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522465.4714841699 + 20 +177624.8831154229 + 30 +0.0 + 11 +522395.9002371468 + 21 +177682.1712694014 + 31 +0.0 + 0 +LINE + 5 +2207 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522450.1881014992 + 20 +177545.9465816251 + 30 +0.0 + 11 +522092.8261854525 + 21 +177854.5573566635 + 31 +0.0 + 0 +LINE + 5 +2208 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522426.0545465842 + 20 +178106.0486912007 + 30 +0.0 + 11 +522138.5813376741 + 21 +177794.2885582321 + 31 +0.0 + 0 +LINE + 5 +2209 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521976.6627601065 + 20 +178103.1017202797 + 30 +0.0 + 11 +522144.8999162999 + 21 +177791.3340972542 + 31 +0.0 + 0 +LINE + 5 +220A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522255.1030212797 + 20 +178270.6731464957 + 30 +0.0 + 11 +522002.6708924326 + 21 +178050.2917664946 + 31 +0.0 + 0 +LINE + 5 +220B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522320.3033366504 + 20 +178203.5499545608 + 30 +0.0 + 11 +522230.5836526111 + 21 +178285.390310269 + 31 +0.0 + 0 +LINE + 5 +220C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522312.9048889996 + 20 +178345.782483584 + 30 +0.0 + 11 +522359.4218327516 + 21 +178234.3199117933 + 31 +0.0 + 0 +LINE + 5 +220D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522359.1406537046 + 20 +178241.0501090313 + 30 +0.0 + 11 +522318.1752510736 + 21 +178203.1099366461 + 31 +0.0 + 0 +LINE + 5 +220E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522576.3235913146 + 20 +178500.0733859163 + 30 +0.0 + 11 +522125.301511771 + 21 +178163.7749288433 + 31 +0.0 + 0 +LINE + 5 +220F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522123.1292867654 + 20 +178150.8787587293 + 30 +0.0 + 11 +522108.7648381229 + 21 +178170.4598002547 + 31 +0.0 + 0 +LINE + 5 +2210 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522096.2678808032 + 20 +177962.6455004086 + 30 +0.0 + 11 +522057.339885885 + 21 +177939.4345464232 + 31 +0.0 + 0 +LINE + 5 +2211 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522111.7918597045 + 20 +177962.0695101251 + 30 +0.0 + 11 +522087.7479171678 + 21 +177961.0520328995 + 31 +0.0 + 0 +LINE + 5 +2212 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522153.6582751383 + 20 +177913.5342327866 + 30 +0.0 + 11 +522105.1775131542 + 21 +177966.5576058281 + 31 +0.0 + 0 +LINE + 5 +2213 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522198.2723013558 + 20 +178166.4194482549 + 30 +0.0 + 11 +521963.5928772264 + 21 +178432.8390725215 + 31 +0.0 + 0 +LINE + 5 +2214 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522273.9766300119 + 20 +178528.9965730892 + 30 +0.0 + 11 +522071.4855426733 + 21 +178504.0164230226 + 31 +0.0 + 0 +LINE + 5 +2215 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522077.167727447 + 20 +178534.5950709659 + 30 +0.0 + 11 +522191.142326411 + 21 +178208.9555915796 + 31 +0.0 + 0 +LINE + 5 +2216 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522294.0270329515 + 20 +178285.979161438 + 30 +0.0 + 11 +522272.5428685532 + 21 +178314.2709342715 + 31 +0.0 + 0 +LINE + 5 +2217 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522448.3713688994 + 20 +178621.9199470397 + 30 +0.0 + 11 +522204.1543956301 + 21 +178507.8708940481 + 31 +0.0 + 0 +LINE + 5 +2218 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522351.0234939022 + 20 +178017.2571345561 + 30 +0.0 + 11 +522312.66148505 + 21 +178044.4318694172 + 31 +0.0 + 0 +LINE + 5 +2219 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522358.6050567503 + 20 +178088.7209066533 + 30 +0.0 + 11 +522312.47344566 + 21 +178042.5400436663 + 31 +0.0 + 0 +LINE + 5 +221A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522406.3674074755 + 20 +178075.5177479402 + 30 +0.0 + 11 +522341.3630352003 + 21 +178157.1104842541 + 31 +0.0 + 0 +LINE + 5 +221B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522470.9166884662 + 20 +178234.7547502371 + 30 +0.0 + 11 +522217.8386610046 + 21 +178076.2926306018 + 31 +0.0 + 0 +LINE + 5 +221C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522431.5832698395 + 20 +178478.573199893 + 30 +0.0 + 11 +522340.8915658216 + 21 +178411.6434952332 + 31 +0.0 + 0 +LINE + 5 +221D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522444.7021691809 + 20 +177827.9780981021 + 30 +0.0 + 11 +522306.7460580036 + 21 +177648.3055826175 + 31 +0.0 + 0 +LINE + 5 +221E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522046.0666304656 + 20 +178429.3247346246 + 30 +0.0 + 11 +521928.5504172098 + 21 +178551.8924190301 + 31 +0.0 + 0 +LINE + 5 +221F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522362.2274122185 + 20 +178758.0753758135 + 30 +0.0 + 11 +521811.0834485826 + 21 +178241.2466501194 + 31 +0.0 + 0 +LINE + 5 +2220 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521929.1153236254 + 20 +178445.7925823553 + 30 +0.0 + 11 +521567.7615717663 + 21 +178695.4067518605 + 31 +0.0 + 0 +LINE + 5 +2221 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521881.3366063116 + 20 +178395.3265422981 + 30 +0.0 + 11 +522009.4013641621 + 21 +178540.9594228863 + 31 +0.0 + 0 +LINE + 5 +2222 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521827.5389805842 + 20 +178444.093474467 + 30 +0.0 + 11 +521870.4030224746 + 21 +178492.034267274 + 31 +0.0 + 0 +LINE + 5 +2223 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521850.6757286721 + 20 +178394.8801031518 + 30 +0.0 + 11 +521828.2598447447 + 21 +178459.9553186394 + 31 +0.0 + 0 +LINE + 5 +2224 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521841.714326795 + 20 +178444.559193175 + 30 +0.0 + 11 +521496.4098163296 + 21 +178652.7943794518 + 31 +0.0 + 0 +LINE + 5 +2225 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521666.0539948833 + 20 +178335.0001542468 + 30 +0.0 + 11 +521852.7254182287 + 21 +178697.029813184 + 31 +0.0 + 0 +LINE + 5 +2226 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521862.7351384069 + 20 +178688.2490104224 + 30 +0.0 + 11 +521657.3014221008 + 21 +178810.0388289521 + 31 +0.0 + 0 +LINE + 5 +2227 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522027.4403528741 + 20 +178784.0508532594 + 30 +0.0 + 11 +521844.7097751325 + 21 +178686.4987243258 + 31 +0.0 + 0 +LINE + 5 +2228 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522027.9975254821 + 20 +178696.8632738643 + 30 +0.0 + 11 +521970.9353580419 + 21 +178760.3867247183 + 31 +0.0 + 0 +LINE + 5 +2229 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521412.5972422444 + 20 +178408.9140228072 + 30 +0.0 + 11 +521660.2788883792 + 21 +178810.9114751353 + 31 +0.0 + 0 +LINE + 5 +222A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521961.6854801614 + 20 +178522.0462843632 + 30 +0.0 + 11 +521608.076746813 + 21 +178756.1319311876 + 31 +0.0 + 0 +LINE + 5 +222B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521988.6546724721 + 20 +179045.2030786144 + 30 +0.0 + 11 +521606.1675726558 + 21 +178749.4231064354 + 31 +0.0 + 0 +LINE + 5 +222C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522147.8980355549 + 20 +179190.6462879181 + 30 +0.0 + 11 +521764.9757191689 + 21 +178866.4730453769 + 31 +0.0 + 0 +LINE + 5 +222D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522061.0495505812 + 20 +178987.4824111563 + 30 +0.0 + 11 +521953.4288271045 + 21 +179034.4644035328 + 31 +0.0 + 0 +LINE + 5 +222E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522012.1359214122 + 20 +178949.2402025678 + 30 +0.0 + 11 +521980.4330525875 + 21 +179054.4092521422 + 31 +0.0 + 0 +LINE + 5 +222F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521870.5780597225 + 20 +178822.4937996476 + 30 +0.0 + 11 +522008.3775325211 + 21 +178970.2047899548 + 31 +0.0 + 0 +LINE + 5 +2230 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522071.0225076675 + 20 +178739.4063192945 + 30 +0.0 + 11 +521839.1339891647 + 21 +178931.1229095936 + 31 +0.0 + 0 +LINE + 5 +2231 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522158.9666137042 + 20 +178763.5770516162 + 30 +0.0 + 11 +522059.4462119843 + 21 +178693.9842706105 + 31 +0.0 + 0 +LINE + 5 +2232 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522133.2961670834 + 20 +178623.4847338028 + 30 +0.0 + 11 +522193.7925335648 + 21 +178728.0214288374 + 31 +0.0 + 0 +LINE + 5 +2233 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522192.6461803232 + 20 +178721.3836211599 + 30 +0.0 + 11 +522156.9129995139 + 21 +178764.2877081752 + 31 +0.0 + 0 +LINE + 5 +2234 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522374.6292981416 + 20 +178436.5264092339 + 30 +0.0 + 11 +522374.6203703744 + 21 +178436.5350655447 + 31 +0.0 + 0 +LINE + 5 +2235 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522269.5500816715 + 20 +178538.4106061858 + 30 +0.0 + 11 +521970.7185488986 + 21 +178828.1559217988 + 31 +0.0 + 0 +LINE + 5 +2236 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521957.6410111656 + 20 +178828.2440803406 + 30 +0.0 + 11 +521974.6811471498 + 21 +178845.5469222367 + 31 +0.0 + 0 +LINE + 5 +2237 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521767.5329517585 + 20 +178824.7483090856 + 30 +0.0 + 11 +521738.4119410404 + 21 +178859.4773158093 + 31 +0.0 + 0 +LINE + 5 +2238 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521769.4396063798 + 20 +178809.3310994195 + 30 +0.0 + 11 +521764.6013748971 + 21 +178832.9051942855 + 31 +0.0 + 0 +LINE + 5 +2239 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521728.2008166475 + 20 +178760.2614335449 + 30 +0.0 + 11 +521772.8156345441 + 21 +178816.5764439355 + 31 +0.0 + 0 +LINE + 5 +223A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521984.9643210763 + 20 +178756.5403676881 + 30 +0.0 + 11 +522216.8329030719 + 21 +179020.4090566216 + 31 +0.0 + 0 +LINE + 5 +223B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522268.0703291239 + 20 +178934.4646333423 + 30 +0.0 + 11 +522025.8194031096 + 21 +178770.3614495457 + 31 +0.0 + 0 +LINE + 5 +223C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522118.262368564 + 20 +178681.074321181 + 30 +0.0 + 11 +522142.766564551 + 21 +178706.7947043234 + 31 +0.0 + 0 +LINE + 5 +223D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522111.3814489866 + 20 +178890.3145777064 + 30 +0.0 + 11 +522049.7796018531 + 21 +178960.4362764188 + 31 +0.0 + 0 +LINE + 5 +223E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522075.9275963096 + 20 +178936.9454593836 + 30 +0.0 + 11 +521995.4597844196 + 21 +178958.7975414727 + 31 +0.0 + 0 +LINE + 5 +223F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522068.4847287545 + 20 +178926.1345975258 + 30 +0.0 + 11 +522047.4637958751 + 21 +179003.4797201811 + 31 +0.0 + 0 +LINE + 5 +2240 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522175.729506542 + 20 +179110.717409931 + 30 +0.0 + 11 +522042.522551726 + 21 +178991.8628343214 + 31 +0.0 + 0 +LINE + 5 +2241 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521862.0663092455 + 20 +178581.9597234564 + 30 +0.0 + 11 +521882.7766106609 + 21 +178624.1639098984 + 31 +0.0 + 0 +LINE + 5 +2242 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521933.824660209 + 20 +178585.8699516644 + 30 +0.0 + 11 +521880.879005866 + 21 +178624.0478946972 + 31 +0.0 + 0 +LINE + 5 +2243 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521928.4060567806 + 20 +178536.6134365247 + 30 +0.0 + 11 +521998.5900628049 + 21 +178613.7960014759 + 31 +0.0 + 0 +LINE + 5 +2244 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522095.8981080569 + 20 +178498.2800915594 + 30 +0.0 + 11 +521899.1103917653 + 21 +178722.8537455348 + 31 +0.0 + 0 +LINE + 5 +2245 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521800.5821568744 + 20 +178721.4588807749 + 30 +0.0 + 11 +521839.2582663639 + 21 +178778.4125664076 + 31 +0.0 + 0 +LINE + 5 +2246 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521865.0393467737 + 20 +178759.7234302135 + 30 +0.0 + 11 +521815.4172322763 + 21 +178793.6382899275 + 31 +0.0 + 0 +LINE + 5 +2247 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521856.8225113138 + 20 +178757.1645292175 + 30 +0.0 + 11 +521897.7260743494 + 21 +178815.6057342713 + 31 +0.0 + 0 +LINE + 5 +2248 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521898.6485579601 + 20 +178812.0045732485 + 30 +0.0 + 11 +521853.1112301707 + 21 +178844.8365937855 + 31 +0.0 + 0 +LINE + 5 +2249 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521815.3771462296 + 20 +178784.6029018461 + 30 +0.0 + 11 +521859.1079719484 + 21 +178848.5849515198 + 31 +0.0 + 0 +LINE + 5 +224A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +521724.7223942844 + 20 +178443.219910869 + 30 +0.0 + 11 +521490.7750619347 + 21 +178566.8418969614 + 31 +0.0 + 0 +LINE + 5 +224B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523117.2926295911 + 20 +178560.6644605667 + 30 +0.0 + 11 +523044.0169703556 + 21 +178443.2619738169 + 31 +0.0 + 0 +LINE + 5 +224C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523264.3763135458 + 20 +178537.648302931 + 30 +0.0 + 11 +523113.2352405079 + 21 +178125.2890619266 + 31 +0.0 + 0 +LINE + 5 +224D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523192.2762143955 + 20 +178488.2313908624 + 30 +0.0 + 11 +523030.3712347359 + 21 +178118.9295152746 + 31 +0.0 + 0 +LINE + 5 +224E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522985.5900973007 + 20 +178476.3745692628 + 30 +0.0 + 11 +523297.0399504419 + 21 +178314.3249674994 + 31 +0.0 + 0 +LINE + 5 +224F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522885.4087712395 + 20 +178318.1826624708 + 30 +0.0 + 11 +522967.4362385638 + 21 +178280.8519029954 + 31 +0.0 + 0 +LINE + 5 +2250 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522821.2116009624 + 20 +178269.7752097155 + 30 +0.0 + 11 +523255.4409771307 + 21 +178084.3217158616 + 31 +0.0 + 0 +LINE + 5 +2251 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523334.9725049224 + 20 +178494.1555457205 + 30 +0.0 + 11 +523181.1986239229 + 21 +178098.9482331972 + 31 +0.0 + 0 +LINE + 5 +2252 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523564.082167775 + 20 +178086.5077055402 + 30 +0.0 + 11 +523175.7686956189 + 21 +178103.3264924552 + 31 +0.0 + 0 +LINE + 5 +2253 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523288.1701818084 + 20 +178387.7452926942 + 30 +0.0 + 11 +523329.4351094049 + 21 +178365.2216231799 + 31 +0.0 + 0 +LINE + 5 +2254 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523349.0378291003 + 20 +178425.9510557512 + 30 +0.0 + 11 +523327.8182264157 + 21 +178364.2215967394 + 31 +0.0 + 0 +LINE + 5 +2255 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522866.3761997883 + 20 +178342.019559905 + 30 +0.0 + 11 +522789.2659781276 + 21 +177829.7140643849 + 31 +0.0 + 0 +LINE + 5 +2256 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523270.1298366463 + 20 +178020.0343941863 + 30 +0.0 + 11 +522887.4587682224 + 21 +178066.3771239369 + 31 +0.0 + 0 +LINE + 5 +2257 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523262.4436127314 + 20 +177911.5069355821 + 30 +0.0 + 11 +522514.0986425375 + 21 +178015.677017375 + 31 +0.0 + 0 +LINE + 5 +2258 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522728.5151155639 + 20 +177916.7015758992 + 30 +0.0 + 11 +522577.3740425265 + 21 +177504.3423348947 + 31 +0.0 + 0 +LINE + 5 +2259 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522660.374377817 + 20 +177930.3568637583 + 30 +0.0 + 11 +522848.9968790347 + 21 +177885.2894681586 + 31 +0.0 + 0 +LINE + 5 +225A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522644.5680059249 + 20 +177859.4868643608 + 30 +0.0 + 11 +522707.2375782236 + 21 +177845.0587525647 + 31 +0.0 + 0 +LINE + 5 +225B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522635.0732243063 + 20 +177913.0323044117 + 30 +0.0 + 11 +522654.3079907121 + 21 +177846.9469105315 + 31 +0.0 + 0 +LINE + 5 +225C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522590.2211719876 + 20 +177716.2978878188 + 30 +0.0 + 11 +522494.5100367545 + 21 +177497.9827882424 + 31 +0.0 + 0 +LINE + 5 +225D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522954.1318415535 + 20 +177768.6770004641 + 30 +0.0 + 11 +522944.1725065651 + 21 +177683.8705655197 + 31 +0.0 + 0 +LINE + 5 +225E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522407.7306262626 + 20 +177597.3181014599 + 30 +0.0 + 11 +522615.1644193533 + 21 +177534.1094386737 + 31 +0.0 + 0 +LINE + 5 +225F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522799.1113069407 + 20 +177873.2088186888 + 30 +0.0 + 11 +522645.3374259413 + 21 +177478.0015061654 + 31 +0.0 + 0 +LINE + 5 +2260 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523022.100320529 + 20 +177791.958987279 + 30 +0.0 + 11 +522935.0210570945 + 21 +177468.3741696419 + 31 +0.0 + 0 +LINE + 5 +2261 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522933.1579137868 + 20 +177821.0425273467 + 30 +0.0 + 11 +523046.0929332863 + 21 +177776.3978535631 + 31 +0.0 + 0 +LINE + 5 +2262 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522949.7838224009 + 20 +177872.405723743 + 30 +0.0 + 11 +522933.6975271531 + 21 +177818.9374901971 + 31 +0.0 + 0 +LINE + 5 +2263 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523087.0618515006 + 20 +178181.3008986546 + 30 +0.0 + 11 +522983.093562173 + 21 +177628.3920786128 + 31 +0.0 + 0 +LINE + 5 +2264 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522972.4627828186 + 20 +177620.7752357368 + 30 +0.0 + 11 +522996.3635900396 + 21 +177616.473377276 + 31 +0.0 + 0 +LINE + 5 +2265 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522953.4121825747 + 20 +177695.1059851142 + 30 +0.0 + 11 +523295.8437629662 + 21 +177601.3271972424 + 31 +0.0 + 0 +LINE + 5 +2266 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523245.8695832916 + 20 +177922.3987161826 + 30 +0.0 + 11 +523312.3861028709 + 21 +177729.5199952934 + 31 +0.0 + 0 +LINE + 5 +2267 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523337.3596793261 + 20 +177748.0581023406 + 30 +0.0 + 11 +522994.7561350993 + 21 +177707.3875819691 + 31 +0.0 + 0 +LINE + 5 +2268 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523252.7318654509 + 20 +178119.8858992136 + 30 +0.0 + 11 +523257.5655084273 + 21 +177850.3942436533 + 31 +0.0 + 0 +LINE + 5 +2269 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522752.3089838269 + 20 +177766.7985656624 + 30 +0.0 + 11 +522793.5739114233 + 21 +177744.2748961479 + 31 +0.0 + 0 +LINE + 5 +226A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522813.1766311186 + 20 +177805.0043287195 + 30 +0.0 + 11 +522791.957028434 + 21 +177743.2748697074 + 31 +0.0 + 0 +LINE + 5 +226B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522780.3331484347 + 20 +177842.1105437243 + 30 +0.0 + 11 +522882.1879569673 + 21 +177819.5596897982 + 31 +0.0 + 0 +LINE + 5 +226C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523131.3338591148 + 20 +178041.830442996 + 30 +0.0 + 11 +523111.0507117023 + 21 +177930.9558991438 + 31 +0.0 + 0 +LINE + 5 +226D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523256.4548944052 + 20 +177673.8722699746 + 30 +0.0 + 11 +523418.1880398422 + 21 +177622.1490903978 + 31 +0.0 + 0 +LINE + 5 +226E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523412.8890915473 + 20 +178102.3147584902 + 30 +0.0 + 11 +523190.7292212283 + 21 +177380.1537014019 + 31 +0.0 + 0 +LINE + 5 +226F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523322.6267890519 + 20 +177576.0454917421 + 30 +0.0 + 11 +523797.1159115772 + 21 +177362.2379585418 + 31 +0.0 + 0 +LINE + 5 +2270 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523298.2812622759 + 20 +177510.9538459399 + 30 +0.0 + 11 +523372.8476595442 + 21 +177689.9772257265 + 31 +0.0 + 0 +LINE + 5 +2271 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523222.927963442 + 20 +177531.0523223896 + 30 +0.0 + 11 +523379.6568120642 + 21 +177491.6654751828 + 31 +0.0 + 0 +LINE + 5 +2272 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523359.9152172615 + 20 +177496.9883692452 + 30 +0.0 + 11 +523596.0536168629 + 21 +177281.4952158278 + 31 +0.0 + 0 +LINE + 5 +2273 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523427.4150912213 + 20 +177736.5054243714 + 30 +0.0 + 11 +523769.2530115786 + 21 +177491.8840838794 + 31 +0.0 + 0 +LINE + 5 +2274 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523507.126612966 + 20 +177922.1356525813 + 30 +0.0 + 11 +523488.329698442 + 21 +177802.1600653523 + 31 +0.0 + 0 +LINE + 5 +2275 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523392.5543045613 + 20 +177837.5305966636 + 30 +0.0 + 11 +523459.8863007098 + 21 +177937.800897655 + 31 +0.0 + 0 +LINE + 5 +2276 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523454.426941331 + 20 +177933.855012242 + 30 +0.0 + 11 +523508.6671999444 + 21 +177920.6030222447 + 31 +0.0 + 0 +LINE + 5 +2277 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523118.5824410856 + 20 +177972.1950437001 + 30 +0.0 + 11 +523118.5941394303 + 21 +177972.1908264169 + 31 +0.0 + 0 +LINE + 5 +2278 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523256.2711700598 + 20 +177922.5579080452 + 30 +0.0 + 11 +524206.9096920682 + 21 +177483.8653524531 + 31 +0.0 + 0 +LINE + 5 +2279 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523557.8080143858 + 20 +177611.8563831612 + 30 +0.0 + 11 +523689.0873473517 + 21 +177951.6823052399 + 31 +0.0 + 0 +LINE + 5 +227A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523580.5831528878 + 20 +178047.796043503 + 30 +0.0 + 11 +523538.933167342 + 21 +177779.4375370703 + 31 +0.0 + 0 +LINE + 5 +227B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523450.8935312671 + 20 +177849.3250996077 + 30 +0.0 + 11 +523463.2340032221 + 21 +177882.6373568399 + 31 +0.0 + 0 +LINE + 5 +227C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523511.7455392582 + 20 +177432.5135306539 + 30 +0.0 + 11 +523503.2210136295 + 21 +177612.7787581072 + 31 +0.0 + 0 +LINE + 5 +227D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523446.394163893 + 20 +177641.8139048939 + 30 +0.0 + 11 +523503.9504363352 + 21 +177611.02310837 + 31 +0.0 + 0 +LINE + 5 +227E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523296.5081963189 + 20 +177748.9305834032 + 30 +0.0 + 11 +523523.0900234353 + 21 +177687.5092883659 + 31 +0.0 + 0 +LINE + 5 +227F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523432.4273113113 + 20 +178034.7409239569 + 30 +0.0 + 11 +523234.4501864689 + 21 +177967.0466580876 + 31 +0.0 + 0 +LINE + 5 +2280 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523451.2216057295 + 20 +177624.6776377849 + 30 +0.0 + 11 +523501.8291267167 + 21 +177730.3614702396 + 31 +0.0 + 0 +LINE + 5 +2281 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522989.217000509 + 20 +178474.4874654012 + 30 +0.0 + 11 +522793.0428596554 + 21 +178446.5607997053 + 31 +0.0 + 0 +LINE + 5 +2282 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524372.789972169 + 20 +175674.8090526176 + 30 +0.0 + 11 +524656.1468986651 + 21 +175585.4719382363 + 31 +0.0 + 0 +LINE + 5 +2283 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524609.9276783371 + 20 +175845.1157330388 + 30 +0.0 + 11 +524455.1045044787 + 21 +175629.5293787359 + 31 +0.0 + 0 +LINE + 5 +2284 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524837.1252858419 + 20 +175691.9315692493 + 30 +0.0 + 11 +524522.4431839671 + 21 +175809.978900038 + 31 +0.0 + 0 +LINE + 5 +2285 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524477.787930299 + 20 +175895.319111842 + 30 +0.0 + 11 +524346.7470590595 + 21 +175769.9642275434 + 31 +0.0 + 0 +LINE + 5 +2286 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524062.1636056715 + 20 +176105.7794112304 + 30 +0.0 + 11 +523970.0631542091 + 21 +175969.8244162033 + 31 +0.0 + 0 +LINE + 5 +2287 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524574.029780333 + 20 +175783.4213092316 + 30 +0.0 + 11 +524391.1894371221 + 21 +175944.5171051869 + 31 +0.0 + 0 +LINE + 5 +2288 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524475.2708319019 + 20 +175608.7641049108 + 30 +0.0 + 11 +524226.9133393759 + 21 +175758.6792206554 + 31 +0.0 + 0 +LINE + 5 +2289 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523564.0490320267 + 20 +177477.8787289761 + 30 +0.0 + 11 +523802.7362644429 + 21 +177848.6042946811 + 31 +0.0 + 0 +LINE + 5 +228A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523932.823944941 + 20 +177859.2898223397 + 30 +0.0 + 11 +524279.7674590437 + 21 +177779.3509319115 + 31 +0.0 + 0 +LINE + 5 +228B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523183.9420759116 + 20 +178234.5704337749 + 30 +0.0 + 11 +523502.8945818244 + 21 +178227.2281691125 + 31 +0.0 + 0 +LINE + 5 +228C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +525106.4182794202 + 20 +176431.403902401 + 30 +0.0 + 11 +525008.4747173305 + 21 +176216.1914333139 + 31 +0.0 + 0 +LINE + 5 +228D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523366.006484977 + 20 +176426.2010255347 + 30 +0.0 + 11 +523009.6530059661 + 21 +176602.0695102401 + 31 +0.0 + 0 +LINE + 5 +228E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522712.3374426255 + 20 +175087.5753245441 + 30 +0.0 + 11 +523600.7708103929 + 21 +177556.09968367 + 31 +0.0 + 0 +LINE + 5 +228F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522618.6029150704 + 20 +177570.0955422215 + 30 +0.0 + 11 +522409.733756899 + 21 +177698.6243181571 + 31 +0.0 + 0 +LINE + 5 +2290 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522592.7488602845 + 20 +177591.5478147034 + 30 +0.0 + 11 +522563.14617815 + 21 +177351.7929963389 + 31 +0.0 + 0 +LINE + 5 +2291 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523036.3238127537 + 20 +177433.5858675359 + 30 +0.0 + 11 +522287.97884256 + 21 +177537.755949329 + 31 +0.0 + 0 +LINE + 5 +2292 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522502.3953155862 + 20 +177438.780507853 + 30 +0.0 + 11 +522351.2542425488 + 21 +177026.4212668487 + 31 +0.0 + 0 +LINE + 5 +2293 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522434.2545778394 + 20 +177452.4357957124 + 30 +0.0 + 11 +522622.8770790572 + 21 +177407.3684001126 + 31 +0.0 + 0 +LINE + 5 +2294 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522418.4482059472 + 20 +177381.5657963146 + 30 +0.0 + 11 +522481.1177782461 + 21 +177367.1376845188 + 31 +0.0 + 0 +LINE + 5 +2295 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522430.2952164364 + 20 +177389.3635957844 + 30 +0.0 + 11 +522268.3902367768 + 21 +177020.0617201964 + 31 +0.0 + 0 +LINE + 5 +2296 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522321.2724142016 + 20 +177326.8178655068 + 30 +0.0 + 11 +522584.9471001396 + 21 +177189.5000098832 + 31 +0.0 + 0 +LINE + 5 +2297 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522588.0570526725 + 20 +177202.4470246138 + 30 +0.0 + 11 +522490.5245491324 + 21 +176984.4488997454 + 31 +0.0 + 0 +LINE + 5 +2298 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522777.8581554662 + 20 +177219.2202813615 + 30 +0.0 + 11 +522572.3242687356 + 21 +177193.4772569366 + 31 +0.0 + 0 +LINE + 5 +2299 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522728.0120415759 + 20 +177290.7559324181 + 30 +0.0 + 11 +522718.0527065875 + 21 +177205.9494974737 + 31 +0.0 + 0 +LINE + 5 +229A +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522181.6108262849 + 20 +177119.3970334139 + 30 +0.0 + 11 +522493.4599791716 + 21 +176985.4539207836 + 31 +0.0 + 0 +LINE + 5 +229B +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522572.9915069632 + 20 +177395.2877506425 + 30 +0.0 + 11 +522419.2176259636 + 21 +177000.0804381194 + 31 +0.0 + 0 +LINE + 5 +229C +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522956.9896205523 + 20 +176982.7148825853 + 30 +0.0 + 11 +522413.7876976597 + 21 +177004.4586973774 + 31 +0.0 + 0 +LINE + 5 +229D +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522922.6758630746 + 20 +177072.4490018759 + 30 +0.0 + 11 +522861.8773769898 + 21 +176971.984720566 + 31 +0.0 + 0 +LINE + 5 +229E +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522860.6604433927 + 20 +177075.4651845424 + 30 +0.0 + 11 +522895.4410376646 + 21 +176971.2734807353 + 31 +0.0 + 0 +LINE + 5 +229F +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522671.9130625024 + 20 +177097.3216496357 + 30 +0.0 + 11 +522869.6857360561 + 21 +177056.1731264949 + 31 +0.0 + 0 +LINE + 5 +22A0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522795.9805205514 + 20 +177314.0379192328 + 30 +0.0 + 11 +522708.9012571168 + 21 +176990.453101596 + 31 +0.0 + 0 +LINE + 5 +22A1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522707.0381138093 + 20 +177343.1214593006 + 30 +0.0 + 11 +522819.9731333086 + 21 +177298.4767855171 + 31 +0.0 + 0 +LINE + 5 +22A2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522723.6640224234 + 20 +177394.484655697 + 30 +0.0 + 11 +522707.5777271754 + 21 +177341.016422151 + 31 +0.0 + 0 +LINE + 5 +22A3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522930.7351701595 + 20 +178092.0130773293 + 30 +0.0 + 11 +522756.9737621957 + 21 +177150.4710105668 + 31 +0.0 + 0 +LINE + 5 +22A4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522746.3429828408 + 20 +177142.8541676907 + 30 +0.0 + 11 +522770.2437900621 + 21 +177138.5523092299 + 31 +0.0 + 0 +LINE + 5 +22A5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522589.0472400136 + 20 +177036.0302754347 + 30 +0.0 + 11 +522585.2976405672 + 21 +176990.8630563793 + 31 +0.0 + 0 +LINE + 5 +22A6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522581.7099174523 + 20 +177049.7229517024 + 30 +0.0 + 11 +522591.3587077851 + 21 +177027.6764717624 + 31 +0.0 + 0 +LINE + 5 +22A7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522519.7165579189 + 20 +177066.0107772594 + 30 +0.0 + 11 +522588.647496611 + 21 +177045.7527402797 + 31 +0.0 + 0 +LINE + 5 +22A8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522727.2923825973 + 20 +177217.1849170681 + 30 +0.0 + 11 +523069.7239629884 + 21 +177123.4061291966 + 31 +0.0 + 0 +LINE + 5 +22A9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523019.7497833138 + 20 +177444.4776481365 + 30 +0.0 + 11 +523086.2663028933 + 21 +177251.5989272474 + 31 +0.0 + 0 +LINE + 5 +22AA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523111.2398793484 + 20 +177270.1370342946 + 30 +0.0 + 11 +522768.6363351217 + 21 +177229.466513923 + 31 +0.0 + 0 +LINE + 5 +22AB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522792.6305951866 + 20 +177355.728814859 + 30 +0.0 + 11 +522827.4843337016 + 21 +177348.8578148228 + 31 +0.0 + 0 +LINE + 5 +22AC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522907.727477809 + 20 +177180.8530314709 + 30 +0.0 + 11 +522897.8668974793 + 21 +177088.0381126475 + 31 +0.0 + 0 +LINE + 5 +22AD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522905.6718170554 + 20 +177122.3108325493 + 30 +0.0 + 11 +522852.5534162397 + 21 +177058.0378387128 + 31 +0.0 + 0 +LINE + 5 +22AE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522893.3554149922 + 20 +177126.8470481271 + 30 +0.0 + 11 +522920.808456164 + 21 +177051.5444708262 + 31 +0.0 + 0 +LINE + 5 +22AF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523035.5253002461 + 20 +177046.6448839554 + 30 +0.0 + 11 +522910.0703423325 + 21 +177058.1823049736 + 31 +0.0 + 0 +LINE + 5 +22B0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523118.8441793682 + 20 +177673.3885298317 + 30 +0.0 + 11 +523031.4457084499 + 21 +177372.4731756072 + 31 +0.0 + 0 +LINE + 5 +22B1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522526.1891838492 + 20 +177288.8774976165 + 30 +0.0 + 11 +522567.4541114458 + 21 +177266.3538281018 + 31 +0.0 + 0 +LINE + 5 +22B2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522587.0568311411 + 20 +177327.0832606734 + 30 +0.0 + 11 +522565.8372284563 + 21 +177265.3538016613 + 31 +0.0 + 0 +LINE + 5 +22B3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522554.2133484569 + 20 +177364.1894756781 + 30 +0.0 + 11 +522656.0681569896 + 21 +177341.6386217522 + 31 +0.0 + 0 +LINE + 5 +22B4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522668.9039854603 + 20 +177492.1312216434 + 30 +0.0 + 11 +522637.7326444329 + 21 +177195.1681282435 + 31 +0.0 + 0 +LINE + 5 +22B5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522556.4507353304 + 20 +177139.4634608348 + 30 +0.0 + 11 +522620.8994502913 + 21 +177115.2575340343 + 31 +0.0 + 0 +LINE + 5 +22B6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522631.1749151017 + 20 +177145.3965907832 + 30 +0.0 + 11 +522610.21045187 + 21 +177089.0666410405 + 31 +0.0 + 0 +LINE + 5 +22B7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522622.9871527007 + 20 +177142.7461368318 + 30 +0.0 + 11 +522690.1134319515 + 21 +177118.6103014182 + 31 +0.0 + 0 +LINE + 5 +22B8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522688.7892890037 + 20 +177122.0839136846 + 30 +0.0 + 11 +522670.5365274142 + 21 +177068.9950590248 + 31 +0.0 + 0 +LINE + 5 +22B9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522604.9649153015 + 20 +177096.4235555283 + 30 +0.0 + 11 +522677.5971672725 + 21 +177069.393132444 + 31 +0.0 + 0 +LINE + 5 +22BA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522905.2140591371 + 20 +177563.9093749503 + 30 +0.0 + 11 +522884.9309117248 + 21 +177453.0348310975 + 31 +0.0 + 0 +LINE + 5 +22BB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522916.9609239598 + 20 +176997.2583139437 + 30 +0.0 + 11 +523309.4597069945 + 21 +176690.1548750701 + 31 +0.0 + 0 +LINE + 5 +22BC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522983.3748628622 + 20 +177015.0960695728 + 30 +0.0 + 11 +523154.5497859308 + 21 +176865.5345421712 + 31 +0.0 + 0 +LINE + 5 +22BD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523030.3350944276 + 20 +177195.9512019287 + 30 +0.0 + 11 +523192.0682398648 + 21 +177144.2280223518 + 31 +0.0 + 0 +LINE + 5 +22BE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523149.8577154443 + 20 +177504.407561558 + 30 +0.0 + 11 +522964.6094212506 + 21 +176902.2326333558 + 31 +0.0 + 0 +LINE + 5 +22BF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523072.1614622984 + 20 +177033.0327778939 + 30 +0.0 + 11 +523146.7278595665 + 21 +177212.0561576804 + 31 +0.0 + 0 +LINE + 5 +22C0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523139.6044650193 + 20 +177006.1285107414 + 30 +0.0 + 11 +523163.8405590469 + 21 +177065.6957622174 + 31 +0.0 + 0 +LINE + 5 +22C1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523085.2301433318 + 20 +177005.292945494 + 30 +0.0 + 11 +523153.5370120867 + 21 +177013.7444071367 + 31 +0.0 + 0 +LINE + 5 +22C2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523133.7954172838 + 20 +177019.0673011991 + 30 +0.0 + 11 +523369.9338168852 + 21 +176803.5741477818 + 31 +0.0 + 0 +LINE + 5 +22C3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523201.2952912438 + 20 +177258.5843563253 + 30 +0.0 + 11 +523469.6868838103 + 21 +177102.9976669321 + 31 +0.0 + 0 +LINE + 5 +22C4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522892.4626411082 + 20 +177494.273975654 + 30 +0.0 + 11 +522892.4743394529 + 21 +177494.2697583709 + 31 +0.0 + 0 +LINE + 5 +22C5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523370.9808339675 + 20 +177511.3258745974 + 30 +0.0 + 11 +523229.2729998291 + 21 +177132.4780320576 + 31 +0.0 + 0 +LINE + 5 +22C6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523285.6257392806 + 20 +176954.5924626077 + 30 +0.0 + 11 +523277.1012136519 + 21 +177134.8576900612 + 31 +0.0 + 0 +LINE + 5 +22C7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523220.2743639153 + 20 +177163.8928368478 + 30 +0.0 + 11 +523277.8306363575 + 21 +177133.1020403241 + 31 +0.0 + 0 +LINE + 5 +22C8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523070.3883963411 + 20 +177271.0095153573 + 30 +0.0 + 11 +523296.9702234576 + 21 +177209.5882203198 + 31 +0.0 + 0 +LINE + 5 +22C9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523142.0526494567 + 20 +176768.5200463112 + 30 +0.0 + 11 +523294.2312541298 + 21 +176974.6534660719 + 31 +0.0 + 0 +LINE + 5 +22CA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522970.8974974627 + 20 +176465.2881509185 + 30 +0.0 + 11 +522810.4737277414 + 21 +176334.2496221969 + 31 +0.0 + 0 +LINE + 5 +22CB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522882.3557151454 + 20 +176714.0152435247 + 30 +0.0 + 11 +522564.2667872466 + 21 +176349.8702072874 + 31 +0.0 + 0 +LINE + 5 +22CC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523033.9977751668 + 20 +176916.9623170844 + 30 +0.0 + 11 +522697.4499817042 + 21 +176495.4138513231 + 31 +0.0 + 0 +LINE + 5 +22CD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522964.5437895761 + 20 +176671.3794105949 + 30 +0.0 + 11 +522849.8705059365 + 21 +176696.6690477735 + 31 +0.0 + 0 +LINE + 5 +22CE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522923.946205671 + 20 +176624.402333022 + 30 +0.0 + 11 +522872.5093980661 + 21 +176721.4582741256 + 31 +0.0 + 0 +LINE + 5 +22CF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522809.5624480385 + 20 +176472.6801037702 + 30 +0.0 + 11 +522916.2056970165 + 21 +176644.2448111216 + 31 +0.0 + 0 +LINE + 5 +22D0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523215.1199951155 + 20 +176322.0721058092 + 30 +0.0 + 11 +522757.7106326434 + 21 +176573.1808616837 + 31 +0.0 + 0 +LINE + 5 +22D1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522893.8712146281 + 20 +176495.1535351531 + 30 +0.0 + 11 +522907.2447679747 + 21 +176515.4242688083 + 31 +0.0 + 0 +LINE + 5 +22D2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522934.5413278785 + 20 +176430.0848978472 + 30 +0.0 + 11 +523147.5422717344 + 21 +176808.6187573986 + 31 +0.0 + 0 +LINE + 5 +22D3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523151.9711731364 + 20 +176777.1695290931 + 30 +0.0 + 11 +522961.8759750708 + 21 +176843.336952638 + 31 +0.0 + 0 +LINE + 5 +22D4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523258.3890803028 + 20 +176748.837564359 + 30 +0.0 + 11 +522971.9536615696 + 21 +176451.5436331187 + 31 +0.0 + 0 +LINE + 5 +22D5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523032.7113255405 + 20 +176585.7752349081 + 30 +0.0 + 11 +522958.7152083104 + 21 +176642.6647316137 + 31 +0.0 + 0 +LINE + 5 +22D6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522988.9113168237 + 20 +176624.6722017828 + 30 +0.0 + 11 +522905.7369816604 + 21 +176630.5554162212 + 31 +0.0 + 0 +LINE + 5 +22D7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522983.6988970849 + 20 +176612.6263854128 + 30 +0.0 + 11 +522948.121624614 + 21 +176684.4484245179 + 31 +0.0 + 0 +LINE + 5 +22D8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +523053.235560517 + 20 +176814.4602513443 + 30 +0.0 + 11 +522945.5194598575 + 21 +176672.0954220733 + 31 +0.0 + 0 +LINE + 5 +22D9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522635.2002345229 + 20 +176845.2024216892 + 30 +0.0 + 11 +522466.1286024288 + 21 +177011.3332236175 + 31 +0.0 + 0 +LINE + 5 +22DA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522553.6330427988 + 20 +176814.4001867653 + 30 +0.0 + 11 +522593.3851924734 + 21 +176889.9719166494 + 31 +0.0 + 0 +LINE + 5 +22DB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522837.6417227955 + 20 +176884.3357929314 + 30 +0.0 + 11 +522844.323322404 + 21 +177001.5743700122 + 31 +0.0 + 0 +LINE + 5 +22DC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522784.7924330184 + 20 +176916.9235545342 + 30 +0.0 + 11 +522872.4051397392 + 21 +176983.1777204499 + 31 +0.0 + 0 +LINE + 5 +22DD +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522594.441952885 + 20 +176798.3315183045 + 30 +0.0 + 11 +522719.2650538682 + 21 +177012.829104645 + 31 +0.0 + 0 +LINE + 5 +22DE +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522661.679110632 + 20 +176714.7524199197 + 30 +0.0 + 11 +522561.8551868182 + 21 +176783.9091243017 + 31 +0.0 + 0 +LINE + 5 +22DF +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522521.3914708863 + 20 +176690.1717878172 + 30 +0.0 + 11 +522640.4314452108 + 21 +176669.7459346153 + 31 +0.0 + 0 +LINE + 5 +22E0 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522633.8086779382 + 20 +176668.5156622181 + 30 +0.0 + 11 +522661.6323248885 + 21 +176716.9250163114 + 31 +0.0 + 0 +LINE + 5 +22E1 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522488.9328765944 + 20 +176532.853079181 + 30 +0.0 + 11 +522656.8608817391 + 21 +176913.7110815744 + 31 +0.0 + 0 +LINE + 5 +22E2 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522594.650425108 + 20 +176875.4803517717 + 30 +0.0 + 11 +522922.6215479869 + 21 +176749.6842195823 + 31 +0.0 + 0 +LINE + 5 +22E3 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522859.8210929988 + 20 +176671.7880028932 + 30 +0.0 + 11 +522621.7999646015 + 21 +176841.9682265487 + 31 +0.0 + 0 +LINE + 5 +22E4 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522570.1753130277 + 20 +176724.2703569694 + 30 +0.0 + 11 +522602.804927966 + 21 +176710.223935399 + 31 +0.0 + 0 +LINE + 5 +22E5 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522764.0019606305 + 20 +176803.3909148802 + 30 +0.0 + 11 +522808.3650537079 + 21 +176885.5112909946 + 31 +0.0 + 0 +LINE + 5 +22E6 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522795.4174414889 + 20 +176852.8326215467 + 30 +0.0 + 11 +522787.9633609084 + 21 +176935.8809142724 + 31 +0.0 + 0 +LINE + 5 +22E7 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522782.6946236574 + 20 +176856.0576669683 + 30 +0.0 + 11 +522847.9250446198 + 21 +176902.6316919044 + 31 +0.0 + 0 +LINE + 5 +22E8 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522993.0337954206 + 20 +176819.5927547916 + 30 +0.0 + 11 +522835.3151721327 + 21 +176903.2308969453 + 31 +0.0 + 0 +LINE + 5 +22E9 +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522390.9919093851 + 20 +176681.7592009042 + 30 +0.0 + 11 +522533.2440119064 + 21 +176944.2912383229 + 31 +0.0 + 0 +LINE + 5 +22EA +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +522233.0726592325 + 20 +177213.5460147199 + 30 +0.0 + 11 +522580.016173335 + 21 +177133.6071242916 + 31 +0.0 + 0 +LINE + 5 +22EB +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +524709.0037862509 + 20 +178824.6619104634 + 30 +0.0 + 11 +524537.941867023 + 21 +178950.6289273412 + 31 +0.0 + 0 +LINE + 5 +22EC +330 +6F +100 +AcDbEntity + 8 +0 +100 +AcDbLine + 10 +526843.0193992567 + 20 +179583.5671331468 + 30 +0.0 + 11 +527269.5564950807 + 21 +179979.6252205521 + 31 +0.0 + 0 +ENDSEC + 0 +SECTION + 2 +OBJECTS + 0 +DICTIONARY + 5 +C +330 +0 +100 +AcDbDictionary +281 + 1 + 3 +ACAD_CIP_PREVIOUS_PRODUCT_INFO +350 +B4 + 3 +ACAD_COLOR +350 +62 + 3 +ACAD_DETAILVIEWSTYLE +350 +69 + 3 +ACAD_GROUP +350 +D + 3 +ACAD_LAYOUT +350 +61 + 3 +ACAD_MATERIAL +350 +10 + 3 +ACAD_MLEADERSTYLE +350 +65 + 3 +ACAD_MLINESTYLE +350 +5E + 3 +ACAD_PLOTSETTINGS +350 +60 + 3 +ACAD_PLOTSTYLENAME +350 +E + 3 +ACAD_SCALELIST +350 +42 + 3 +ACAD_SECTIONVIEWSTYLE +350 +67 + 3 +ACAD_TABLESTYLE +350 +63 + 3 +ACAD_VISUALSTYLE +350 +29 + 3 +ACDB_RECOMPOSE_DATA +350 +22F5 + 3 +AcDbVariableDictionary +350 +34B + 0 +DICTIONARY + 5 +345 +330 +2 +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +ACAD_LAYERSTATES +360 +346 + 0 +DICTIONARY + 5 +340 +330 +54 +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +ADSK_XREC_LAYER_RECONCILED +360 +341 + 0 +DICTIONARY + 5 +135 +330 +6F +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +ACAD_SORTENTS +360 +136 + 0 +XRECORD + 5 +B4 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbXrecord +280 + 1 +300 +ACDMAC +300 +2018 +300 +ACDMAC_F_S + 0 +DICTIONARY + 5 +62 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +DICTIONARY + 5 +69 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Imperial24 +350 +6A + 0 +DICTIONARY + 5 +D +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +DICTIONARY + 5 +61 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Layout1 +350 +6E + 3 +Model +350 +72 + 0 +DICTIONARY + 5 +10 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +ByBlock +350 +19 + 3 +ByLayer +350 +11 + 3 +Global +350 +21 + 0 +DICTIONARY + 5 +65 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Standard +350 +66 + 0 +DICTIONARY + 5 +5E +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Standard +350 +5F + 0 +DICTIONARY + 5 +60 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +ACDBDICTIONARYWDFLT + 5 +E +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Normal +350 +F +100 +AcDbDictionaryWithDefault +340 +F + 0 +DICTIONARY + 5 +42 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +A0 +350 +43 + 3 +A1 +350 +44 + 3 +A2 +350 +45 + 3 +A3 +350 +46 + 3 +A4 +350 +47 + 3 +A5 +350 +48 + 3 +A6 +350 +49 + 3 +A7 +350 +4A + 3 +A8 +350 +4B + 3 +A9 +350 +4C + 3 +B0 +350 +4D + 3 +B1 +350 +4E + 3 +B2 +350 +4F + 3 +B3 +350 +50 + 3 +B4 +350 +51 + 3 +B5 +350 +52 + 3 +B6 +350 +53 + 0 +DICTIONARY + 5 +67 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Imperial24 +350 +68 + 0 +DICTIONARY + 5 +63 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Standard +350 +64 + 0 +DICTIONARY + 5 +29 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +2dWireframe +350 +2F + 3 +Basic +350 +2E + 3 +Brighten +350 +35 + 3 +ColorChange +350 +39 + 3 +Conceptual +350 +32 + 3 +Dim +350 +34 + 3 +EdgeColorOff +350 +41 + 3 +Facepattern +350 +38 + 3 +Flat +350 +2A + 3 +FlatWithEdges +350 +2B + 3 +Gouraud +350 +2C + 3 +GouraudWithEdges +350 +2D + 3 +Hidden +350 +31 + 3 +JitterOff +350 +3F + 3 +Linepattern +350 +37 + 3 +OverhangOff +350 +40 + 3 +Realistic +350 +33 + 3 +Shaded +350 +3E + 3 +Shaded with edges +350 +3D + 3 +Shades of Gray +350 +3A + 3 +Sketchy +350 +3B + 3 +Thicken +350 +36 + 3 +Wireframe +350 +30 + 3 +X-Ray +350 +3C + 0 +XRECORD + 5 +22F5 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbXrecord +280 + 1 + 90 + 1 +330 +64 + 0 +DICTIONARY + 5 +34B +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +CANNOSCALE +350 +351 + 3 +CMLEADERSTYLE +350 +34D + 3 +CTABLESTYLE +350 +34C + 3 +CVIEWDETAILSTYLE +350 +34E + 3 +CVIEWSECTIONSTYLE +350 +34F + 3 +LAYEREVAL +350 +353 + 3 +LAYERNOTIFY +350 +354 + 3 +LIGHTINGUNITS +350 +352 + 3 +MSLTSCALE +350 +350 + 0 +DICTIONARY + 5 +346 +102 +{ACAD_REACTORS +330 +345 +102 +} +330 +345 +100 +AcDbDictionary +281 + 1 + 0 +XRECORD + 5 +341 +102 +{ACAD_REACTORS +330 +340 +102 +} +330 +340 +100 +AcDbXrecord +280 + 1 +290 + 1 + 0 +SORTENTSTABLE + 5 +136 +102 +{ACAD_REACTORS +330 +135 +102 +} +330 +135 +100 +AcDbSortentsTable +330 +6F +331 +324 + 5 +1BF +331 +320 + 5 +321 +331 +31C + 5 +31D +331 +147 + 5 +147 +331 +BD + 5 +BD +331 +318 + 5 +319 +331 +143 + 5 +143 +331 +B9 + 5 +B9 +331 +17C + 5 +17C +331 +13F + 5 +13F +331 +AD + 5 +AD +331 +A9 + 5 +A9 +331 +13B + 5 +13B +331 +1B6 + 5 +1B6 +331 +1F7 + 5 +1F8 +331 +1F3 + 5 +1F4 +331 +1B2 + 5 +1B2 +331 +237 + 5 +238 +331 +233 + 5 +234 +331 +2AE + 5 +2AF +331 +22F + 5 +230 +331 +26C + 5 +26D +331 +268 + 5 +269 +331 +2AA + 5 +2AB +331 +22B + 5 +22C +331 +2E7 + 5 +2E8 +331 +2A6 + 5 +2A7 +331 +2A2 + 5 +2A3 +331 +2E3 + 5 +2E4 +331 +310 + 5 +311 +331 +EE + 5 +EE +331 +12F + 5 +130 +331 +A5 + 5 +A5 +331 +EA + 5 +EA +331 +308 + 5 +309 +331 +170 + 5 +170 +331 +12B + 5 +12C +331 +A1 + 5 +A1 +331 +E6 + 5 +E6 +331 +E2 + 5 +E2 +331 +16C + 5 +16C +331 +127 + 5 +128 +331 +9D + 5 +9D +331 +168 + 5 +168 +331 +99 + 5 +99 +331 +1AE + 5 +1AE +331 +1EF + 5 +1F0 +331 +123 + 5 +124 +331 +1EB + 5 +1EC +331 +1A6 + 5 +1A6 +331 +1E7 + 5 +1E8 +331 +1A2 + 5 +1A2 +331 +227 + 5 +228 +331 +264 + 5 +265 +331 +223 + 5 +224 +331 +260 + 5 +261 +331 +21F + 5 +220 +331 +2DF + 5 +2E0 +331 +25C + 5 +25D +331 +258 + 5 +259 +331 +29A + 5 +29B +331 +21B + 5 +21C +331 +2DB + 5 +2DC +331 +2D7 + 5 +2D8 +331 +296 + 5 +297 +331 +292 + 5 +293 +331 +2D3 + 5 +2D4 +331 +74 + 5 +74 +331 +134 + 5 +11B +331 +130 + 5 +131 +331 +DE + 5 +DE +331 +DA + 5 +DA +331 +2F8 + 5 +2F9 +331 +11F + 5 +120 +331 +160 + 5 +160 +331 +11B + 5 +11C +331 +91 + 5 +91 +331 +D6 + 5 +D6 +331 +D2 + 5 +D2 +331 +15C + 5 +15C +331 +117 + 5 +117 +331 +8D + 5 +8D +331 +89 + 5 +89 +331 +19E + 5 +19E +331 +113 + 5 +113 +331 +1D7 + 5 +1DC +331 +1D3 + 5 +1D4 +331 +217 + 5 +218 +331 +254 + 5 +255 +331 +213 + 5 +214 +331 +250 + 5 +251 +331 +28E + 5 +28F +331 +20F + 5 +210 +331 +2CF + 5 +2D0 +331 +24C + 5 +24D +331 +248 + 5 +249 +331 +28A + 5 +28B +331 +20B + 5 +20C +331 +2CB + 5 +2CC +331 +2C7 + 5 +2C8 +331 +286 + 5 +287 +331 +282 + 5 +283 +331 +F0 + 5 +F0 +331 +2F4 + 5 +2F5 +331 +2F0 + 5 +2F1 +331 +2EC + 5 +2ED +331 +85 + 5 +85 +331 +CA + 5 +CA +331 +2E8 + 5 +2E9 +331 +10F + 5 +10F +331 +150 + 5 +150 +331 +10B + 5 +10B +331 +81 + 5 +81 +331 +C6 + 5 +C6 +331 +C2 + 5 +C2 +331 +14C + 5 +14C +331 +107 + 5 +107 +331 +7D + 5 +7D +331 +148 + 5 +148 +331 +1CF + 5 +1D0 +331 +18E + 5 +18E +331 +79 + 5 +79 +331 +1CB + 5 +1CC +331 +186 + 5 +186 +331 +1C7 + 5 +1C8 +331 +182 + 5 +182 +331 +1C3 + 5 +1C4 +331 +244 + 5 +245 +331 +207 + 5 +208 +331 +203 + 5 +204 +331 +240 + 5 +241 +331 +27E + 5 +27F +331 +1FF + 5 +200 +331 +23C + 5 +23D +331 +27A + 5 +27B +331 +1FB + 5 +1FC +331 +2BB + 5 +2BC +331 +238 + 5 +239 +331 +2B7 + 5 +2B8 +331 +276 + 5 +277 +331 +2B3 + 5 +2B4 +331 +272 + 5 +273 +331 +BE + 5 +BE +331 +31D + 5 +31E +331 +319 + 5 +31A +331 +144 + 5 +144 +331 +BA + 5 +BA +331 +FF + 5 +FF +331 +140 + 5 +140 +331 +AE + 5 +AE +331 +FB + 5 +FB +331 +13C + 5 +13C +331 +17D + 5 +17D +331 +AA + 5 +AA +331 +179 + 5 +179 +331 +1BF + 5 +1C0 +331 +138 + 5 +138 +331 +1BB + 5 +1BB +331 +1B7 + 5 +1B7 +331 +1F4 + 5 +1F5 +331 +1F0 + 5 +1F1 +331 +1B3 + 5 +1B3 +331 +234 + 5 +235 +331 +230 + 5 +231 +331 +22C + 5 +22D +331 +2AF + 5 +2B0 +331 +26D + 5 +26E +331 +269 + 5 +26A +331 +2AB + 5 +2AC +331 +228 + 5 +229 +331 +2E4 + 5 +2E5 +331 +2A7 + 5 +2A8 +331 +2A3 + 5 +2A4 +331 +2E0 + 5 +2E1 +331 +311 + 5 +312 +331 +A6 + 5 +A6 +331 +EF + 5 +EF +331 +A2 + 5 +A2 +331 +12C + 5 +12D +331 +EB + 5 +EB +331 +309 + 5 +30A +331 +9E + 5 +9E +331 +171 + 5 +171 +331 +E7 + 5 +E7 +331 +E3 + 5 +E3 +331 +124 + 5 +125 +331 +16D + 5 +16D +331 +9A + 5 +9A +331 +169 + 5 +169 +331 +1AF + 5 +1AF +331 +1EC + 5 +1ED +331 +1AB + 5 +1AB +331 +1E8 + 5 +1E9 +331 +1A7 + 5 +1A7 +331 +1E4 + 5 +1E5 +331 +1E0 + 5 +1E1 +331 +1A3 + 5 +1A3 +331 +224 + 5 +225 +331 +265 + 5 +266 +331 +220 + 5 +221 +331 +261 + 5 +262 +331 +21C + 5 +21D +331 +29F + 5 +2A0 +331 +2DC + 5 +2DD +331 +25D + 5 +25E +331 +218 + 5 +219 +331 +29B + 5 +29C +331 +2D8 + 5 +2D9 +331 +2D4 + 5 +2D5 +331 +297 + 5 +298 +331 +293 + 5 +294 +331 +2D0 + 5 +2D1 +331 +75 + 5 +75 +331 +131 + 5 +132 +331 +DF + 5 +DF +331 +92 + 5 +92 +331 +11C + 5 +11D +331 +DB + 5 +DB +331 +2F9 + 5 +2FA +331 +8E + 5 +8E +331 +118 + 5 +118 +331 +D7 + 5 +D7 +331 +D3 + 5 +D3 +331 +114 + 5 +114 +331 +15D + 5 +15D +331 +8A + 5 +8A +331 +159 + 5 +159 +331 +19F + 5 +19F +331 +1DC + 5 +1DD +331 +110 + 5 +110 +331 +1D4 + 5 +1D6 +331 +1D0 + 5 +1D1 +331 +214 + 5 +215 +331 +255 + 5 +256 +331 +210 + 5 +211 +331 +251 + 5 +252 +331 +20C + 5 +20D +331 +28F + 5 +290 +331 +2CC + 5 +2CD +331 +24D + 5 +24E +331 +249 + 5 +24A +331 +208 + 5 +209 +331 +28B + 5 +28C +331 +2C8 + 5 +2C9 +331 +287 + 5 +288 +331 +283 + 5 +284 +331 +F1 + 5 +F1 +331 +2F5 + 5 +2F6 +331 +2F1 + 5 +2F2 +331 +86 + 5 +86 +331 +2ED + 5 +2EE +331 +82 + 5 +82 +331 +CB + 5 +CB +331 +2E9 + 5 +2EA +331 +10C + 5 +10C +331 +7E + 5 +7E +331 +108 + 5 +108 +331 +151 + 5 +151 +331 +C7 + 5 +C7 +331 +C3 + 5 +C3 +331 +104 + 5 +104 +331 +14D + 5 +14D +331 +7A + 5 +7A +331 +1CC + 5 +1CD +331 +149 + 5 +149 +331 +18B + 5 +18B +331 +1C8 + 5 +1C9 +331 +187 + 5 +187 +331 +1C0 + 5 +1C1 +331 +183 + 5 +183 +331 +204 + 5 +205 +331 +245 + 5 +246 +331 +200 + 5 +201 +331 +241 + 5 +242 +331 +1FC + 5 +1FD +331 +27F + 5 +280 +331 +2BC + 5 +2BD +331 +23D + 5 +23E +331 +239 + 5 +23A +331 +1F8 + 5 +1F9 +331 +27B + 5 +27C +331 +2B8 + 5 +2B9 +331 +2B4 + 5 +2B5 +331 +277 + 5 +278 +331 +273 + 5 +274 +331 +2B0 + 5 +2B1 +331 +322 + 5 +323 +331 +31E + 5 +31F +331 +BF + 5 +BF +331 +BB + 5 +BB +331 +141 + 5 +141 +331 +AF + 5 +AF +331 +AB + 5 +AB +331 +13D + 5 +13D +331 +17A + 5 +17A +331 +1BC + 5 +1BC +331 +139 + 5 +139 +331 +1B8 + 5 +1B8 +331 +1F5 + 5 +1F6 +331 +1B4 + 5 +1B4 +331 +1F1 + 5 +1F2 +331 +1B0 + 5 +1B0 +331 +235 + 5 +236 +331 +231 + 5 +232 +331 +26E + 5 +26F +331 +26A + 5 +26B +331 +2AC + 5 +2AD +331 +22D + 5 +22E +331 +2A8 + 5 +2A9 +331 +229 + 5 +22A +331 +2A4 + 5 +2A5 +331 +2E5 + 5 +2E6 +331 +2A0 + 5 +2A1 +331 +2E1 + 5 +2E2 +331 +312 + 5 +313 +331 +A7 + 5 +A7 +331 +EC + 5 +EC +331 +30A + 5 +30B +331 +12D + 5 +12E +331 +A3 + 5 +A3 +331 +E8 + 5 +E8 +331 +E4 + 5 +E4 +331 +16E + 5 +16E +331 +129 + 5 +12A +331 +9F + 5 +9F +331 +E0 + 5 +E0 +331 +16A + 5 +16A +331 +125 + 5 +126 +331 +9B + 5 +9B +331 +1ED + 5 +1EE +331 +1E9 + 5 +1EA +331 +1A4 + 5 +1A4 +331 +1E5 + 5 +1E6 +331 +1E1 + 5 +1E2 +331 +1A0 + 5 +1A0 +331 +225 + 5 +226 +331 +262 + 5 +263 +331 +221 + 5 +222 +331 +25E + 5 +25F +331 +29C + 5 +29D +331 +21D + 5 +21E +331 +2DD + 5 +2DE +331 +25A + 5 +25B +331 +2D9 + 5 +2DA +331 +298 + 5 +299 +331 +219 + 5 +21A +331 +2D5 + 5 +2D6 +331 +294 + 5 +295 +331 +290 + 5 +291 +331 +76 + 5 +76 +331 +2D1 + 5 +2D2 +331 +97 + 5 +97 +331 +DC + 5 +DC +331 +11D + 5 +11E +331 +93 + 5 +93 +331 +D8 + 5 +D8 +331 +15E + 5 +15E +331 +119 + 5 +119 +331 +8F + 5 +8F +331 +D4 + 5 +D4 +331 +D0 + 5 +D0 +331 +15A + 5 +15A +331 +115 + 5 +115 +331 +8B + 5 +8B +331 +1DD + 5 +1DE +331 +111 + 5 +111 +331 +194 + 5 +194 +331 +1D1 + 5 +1D2 +331 +256 + 5 +257 +331 +215 + 5 +216 +331 +252 + 5 +253 +331 +211 + 5 +212 +331 +24E + 5 +24F +331 +28C + 5 +28D +331 +20D + 5 +20E +331 +2CD + 5 +2CE +331 +24A + 5 +24B +331 +288 + 5 +289 +331 +209 + 5 +20A +331 +2C9 + 5 +2CA +331 +2C5 + 5 +2C6 +331 +284 + 5 +285 +331 +280 + 5 +281 +331 +2F6 + 5 +2F7 +331 +2F2 + 5 +2F3 +331 +2EE + 5 +2EF +331 +87 + 5 +87 +331 +2EA + 5 +2EB +331 +10D + 5 +10D +331 +83 + 5 +83 +331 +C8 + 5 +C8 +331 +14E + 5 +14E +331 +109 + 5 +109 +331 +7F + 5 +7F +331 +C4 + 5 +C4 +331 +C0 + 5 +C0 +331 +14A + 5 +14A +331 +105 + 5 +105 +331 +7B + 5 +7B +331 +18C + 5 +18C +331 +1CD + 5 +1CE +331 +188 + 5 +188 +331 +1C9 + 5 +1CA +331 +184 + 5 +184 +331 +1C1 + 5 +1C2 +331 +180 + 5 +180 +331 +246 + 5 +247 +331 +205 + 5 +206 +331 +242 + 5 +243 +331 +201 + 5 +202 +331 +23E + 5 +23F +331 +27C + 5 +27D +331 +1FD + 5 +1FE +331 +2BD + 5 +2BE +331 +23A + 5 +23B +331 +278 + 5 +279 +331 +1F9 + 5 +1FA +331 +2B9 + 5 +2BA +331 +2B5 + 5 +2B6 +331 +274 + 5 +275 +331 +270 + 5 +271 +331 +2B1 + 5 +2B2 +331 +323 + 5 +324 +331 +31F + 5 +320 +331 +146 + 5 +146 +331 +BC + 5 +BC +331 +142 + 5 +142 +331 +B8 + 5 +B8 +331 +17F + 5 +17F +331 +AC + 5 +AC +331 +A8 + 5 +A8 +331 +F9 + 5 +F9 +331 +17B + 5 +17B +331 +13A + 5 +13A +331 +1BD + 5 +1BD +331 +1B9 + 5 +1B9 +331 +1F6 + 5 +1F7 +331 +1F2 + 5 +1F3 +331 +1B5 + 5 +1B5 +331 +1B1 + 5 +1B1 +331 +236 + 5 +237 +331 +232 + 5 +233 +331 +22E + 5 +22F +331 +26F + 5 +270 +331 +26B + 5 +26C +331 +22A + 5 +22B +331 +2E6 + 5 +2E7 +331 +2A9 + 5 +2AA +331 +2A5 + 5 +2A6 +331 +2E2 + 5 +2E3 +331 +2A1 + 5 +2A2 +331 +317 + 5 +318 +331 +A4 + 5 +A4 +331 +ED + 5 +ED +331 +30B + 5 +30C +331 +12E + 5 +12F +331 +A0 + 5 +A0 +331 +12A + 5 +12B +331 +E9 + 5 +E9 +331 +126 + 5 +127 +331 +16F + 5 +16F +331 +9C + 5 +9C +331 +98 + 5 +98 +331 +E1 + 5 +E1 +331 +122 + 5 +123 +331 +1EE + 5 +1EF +331 +16B + 5 +16B +331 +1AD + 5 +1AD +331 +1EA + 5 +1EB +331 +1E6 + 5 +1E7 +331 +1E2 + 5 +1E3 +331 +1A5 + 5 +1A5 +331 +1A1 + 5 +1A1 +331 +226 + 5 +227 +331 +267 + 5 +268 +331 +222 + 5 +223 +331 +263 + 5 +264 +331 +21E + 5 +21F +331 +2DE + 5 +2DF +331 +25F + 5 +260 +331 +25B + 5 +25C +331 +21A + 5 +21B +331 +29D + 5 +29E +331 +2DA + 5 +2DB +331 +2D6 + 5 +2D7 +331 +299 + 5 +29A +331 +295 + 5 +296 +331 +2D2 + 5 +2D3 +331 +291 + 5 +292 +331 +77 + 5 +77 +331 +73 + 5 +73 +331 +137 + 5 +137 +331 +133 + 5 +134 +331 +307 + 5 +308 +331 +94 + 5 +94 +331 +2FB + 5 +2FC +331 +167 + 5 +167 +331 +11E + 5 +11F +331 +90 + 5 +90 +331 +11A + 5 +11A +331 +D9 + 5 +D9 +331 +D5 + 5 +D5 +331 +116 + 5 +116 +331 +8C + 5 +8C +331 +D1 + 5 +D1 +331 +112 + 5 +112 +331 +1DE + 5 +1DF +331 +15B + 5 +15B +331 +88 + 5 +88 +331 +19D + 5 +19D +331 +199 + 5 +199 +331 +1D6 + 5 +1D7 +331 +1D2 + 5 +1D3 +331 +257 + 5 +258 +331 +216 + 5 +217 +331 +212 + 5 +213 +331 +253 + 5 +254 +331 +20E + 5 +20F +331 +2CE + 5 +2CF +331 +24F + 5 +250 +331 +20A + 5 +20B +331 +28D + 5 +28E +331 +2CA + 5 +2CB +331 +24B + 5 +24C +331 +2C6 + 5 +2C7 +331 +289 + 5 +28A +331 +2C2 + 5 +2C3 +331 +285 + 5 +286 +331 +281 + 5 +282 +331 +B7 + 5 +B7 +331 +2F7 + 5 +2F8 +331 +2F3 + 5 +2F4 +331 +2EF + 5 +2F0 +331 +84 + 5 +84 +331 +CD + 5 +CD +331 +2EB + 5 +2EC +331 +80 + 5 +80 +331 +10A + 5 +10A +331 +C9 + 5 +C9 +331 +7C + 5 +7C +331 +106 + 5 +106 +331 +14F + 5 +14F +331 +C5 + 5 +C5 +331 +C1 + 5 +C1 +331 +1CE + 5 +1CF +331 +14B + 5 +14B +331 +78 + 5 +78 +331 +18D + 5 +18D +331 +1CA + 5 +1CB +331 +1C6 + 5 +1C7 +331 +185 + 5 +185 +331 +1C2 + 5 +1C3 +331 +181 + 5 +181 +331 +247 + 5 +248 +331 +206 + 5 +207 +331 +202 + 5 +203 +331 +243 + 5 +244 +331 +1FE + 5 +1FF +331 +2BE + 5 +2BF +331 +23F + 5 +240 +331 +1FA + 5 +1FB +331 +27D + 5 +27E +331 +2BA + 5 +2BB +331 +23B + 5 +23C +331 +279 + 5 +27A +331 +2B6 + 5 +2B7 +331 +2B2 + 5 +2B3 +331 +275 + 5 +276 +331 +271 + 5 +272 + 0 +ACDBDETAILVIEWSTYLE + 5 +6A +102 +{ACAD_REACTORS +330 +69 +102 +} +330 +69 +100 +AcDbModelDocViewStyle + 70 + 0 + 3 +Imperial24 +290 + 0 +300 +Imperial24 + 90 + 0 +100 +AcDbDetailViewStyle + 70 + 0 + 71 + 0 + 90 + 3 + 71 + 1 +340 +55 + 62 + 256 + 40 +0.24 +340 +0 + 62 + 256 + 40 +0.24 +300 + + 40 +0.36 +280 + 3 + 71 + 2 +340 +5C + 90 + 25 + 62 + 256 + 71 + 3 +340 +55 + 62 + 256 + 40 +0.24 + 90 + 1 + 40 +0.75 + 90 + 1 +300 +%<\AcVar ViewType \f "%tc1">% %<\AcVar ViewDetailId>%\PSCALE %<\AcVar ViewScale \f "%sn">% + 71 + 4 +340 +5C + 90 + 25 + 62 + 256 +340 +5C + 90 + 25 + 62 + 256 +280 + 0 + 0 +LAYOUT + 5 +6E +102 +{ACAD_REACTORS +330 +61 +102 +} +330 +61 +100 +AcDbPlotSettings + 1 + + 2 + + 4 + + 6 + + 40 +0.0 + 41 +0.0 + 42 +0.0 + 43 +0.0 + 44 +0.0 + 45 +0.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 + 49 +0.0 +140 +0.0 +141 +0.0 +142 +1.0 +143 +1.0 + 70 + 688 + 72 + 0 + 73 + 0 + 74 + 5 + 7 + + 75 + 16 +147 +1.0 + 76 + 0 + 77 + 2 + 78 + 300 +148 +0.0 +149 +0.0 +100 +AcDbLayout + 1 +Layout1 + 70 + 1 + 71 + 1 + 10 +0.0 + 20 +0.0 + 11 +12.0 + 21 +9.0 + 12 +0.0 + 22 +0.0 + 32 +0.0 + 14 +1.000000000000000E+20 + 24 +1.000000000000000E+20 + 34 +1.000000000000000E+20 + 15 +-1.000000000000000E+20 + 25 +-1.000000000000000E+20 + 35 +-1.000000000000000E+20 +146 +0.0 + 13 +0.0 + 23 +0.0 + 33 +0.0 + 16 +1.0 + 26 +0.0 + 36 +0.0 + 17 +0.0 + 27 +1.0 + 37 +0.0 + 76 + 0 +330 +6B + 0 +LAYOUT + 5 +72 +102 +{ACAD_REACTORS +330 +61 +102 +} +330 +61 +100 +AcDbPlotSettings + 1 + + 2 + + 4 + + 6 + + 40 +0.0 + 41 +0.0 + 42 +0.0 + 43 +0.0 + 44 +0.0 + 45 +0.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 + 49 +0.0 +140 +0.0 +141 +0.0 +142 +1.0 +143 +1.0 + 70 + 1712 + 72 + 0 + 73 + 0 + 74 + 0 + 7 + + 75 + 0 +147 +1.0 + 76 + 0 + 77 + 2 + 78 + 300 +148 +0.0 +149 +0.0 +100 +AcDbLayout + 1 +Model + 70 + 1 + 71 + 0 + 10 +0.0 + 20 +0.0 + 11 +12.0 + 21 +9.0 + 12 +0.0 + 22 +0.0 + 32 +0.0 + 14 +0.0 + 24 +0.0 + 34 +0.0 + 15 +0.0 + 25 +0.0 + 35 +0.0 +146 +0.0 + 13 +0.0 + 23 +0.0 + 33 +0.0 + 16 +1.0 + 26 +0.0 + 36 +0.0 + 17 +0.0 + 27 +1.0 + 37 +0.0 + 76 + 0 +330 +6F +331 +B3 + 0 +MATERIAL + 5 +19 +102 +{ACAD_XDICTIONARY +360 +1A +102 +} +102 +{ACAD_REACTORS +330 +10 +102 +} +330 +10 +100 +AcDbMaterial + 1 +ByBlock + 72 + 0 + 43 +0.0208333333333333 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0208333333333333 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +1.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +1.0 + 77 + 0 + 47 +0.0208333333333333 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0208333333333333 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +1.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +1.0 +171 + 0 + 49 +0.0208333333333333 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0208333333333333 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +1.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +1.0 +175 + 0 +142 +0.0208333333333333 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0208333333333333 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +1.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +1.0 +179 + 0 +144 +0.0208333333333333 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0208333333333333 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +1.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +1.0 +147 +0.0208333333333333 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0208333333333333 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +1.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +1.0 + 0 +MATERIAL + 5 +11 +102 +{ACAD_XDICTIONARY +360 +12 +102 +} +102 +{ACAD_REACTORS +330 +10 +102 +} +330 +10 +100 +AcDbMaterial + 1 +ByLayer + 72 + 0 + 43 +0.0208333333333333 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0208333333333333 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +1.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +1.0 + 77 + 0 + 47 +0.0208333333333333 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0208333333333333 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +1.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +1.0 +171 + 0 + 49 +0.0208333333333333 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0208333333333333 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +1.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +1.0 +175 + 0 +142 +0.0208333333333333 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0208333333333333 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +1.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +1.0 +179 + 0 +144 +0.0208333333333333 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0208333333333333 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +1.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +1.0 +147 +0.0208333333333333 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0208333333333333 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +1.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +1.0 + 0 +MATERIAL + 5 +21 +102 +{ACAD_XDICTIONARY +360 +22 +102 +} +102 +{ACAD_REACTORS +330 +10 +102 +} +330 +10 +100 +AcDbMaterial + 1 +Global + 72 + 0 + 43 +0.0208333333333333 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0208333333333333 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +1.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +1.0 + 77 + 0 + 47 +0.0208333333333333 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0208333333333333 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +1.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +0.0 + 47 +1.0 +171 + 0 + 49 +0.0208333333333333 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0208333333333333 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +1.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +1.0 +175 + 0 +142 +0.0208333333333333 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0208333333333333 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +1.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +1.0 +179 + 0 +144 +0.0208333333333333 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0208333333333333 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +1.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +1.0 +147 +0.0208333333333333 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0208333333333333 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +1.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +0.0 +147 +1.0 + 0 +MLEADERSTYLE + 5 +66 +102 +{ACAD_REACTORS +330 +65 +102 +} +330 +65 +100 +AcDbMLeaderStyle +179 + 2 +170 + 2 +171 + 1 +172 + 0 + 90 + 2 + 40 +0.0 + 41 +0.0 +173 + 1 + 91 +-1056964608 +340 +5A + 92 + -2 +290 + 1 + 42 +0.09 +291 + 1 + 43 +0.36 + 3 +Standard + 44 +0.18 +300 + +342 +55 +174 + 1 +178 + 6 +175 + 1 +176 + 0 + 93 +-1056964608 + 45 +0.18 +292 + 0 +297 + 0 + 46 +0.18 + 94 +-1056964608 + 47 +1.0 + 49 +1.0 +140 +1.0 +293 + 1 +141 +0.0 +294 + 1 +177 + 0 +142 +1.0 +295 + 0 +296 + 0 +143 +0.125 +271 + 0 +272 + 9 +273 + 9 +298 + 0 + 0 +MLINESTYLE + 5 +5F +102 +{ACAD_REACTORS +330 +5E +102 +} +330 +5E +100 +AcDbMlineStyle + 2 +STANDARD + 70 + 0 + 3 + + 62 + 256 + 51 +90.0 + 52 +90.0 + 71 + 2 + 49 +0.5 + 62 + 256 + 6 +BYLAYER + 49 +-0.5 + 62 + 256 + 6 +BYLAYER + 0 +ACDBPLACEHOLDER + 5 +F +102 +{ACAD_REACTORS +330 +E +102 +} +330 +E + 0 +SCALE + 5 +43 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1:1 +140 +1.0 +141 +1.0 +290 + 1 + 0 +SCALE + 5 +44 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1/128" = 1'-0" +140 +0.0078125 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +45 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1/64" = 1'-0" +140 +0.015625 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +46 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1/32" = 1'-0" +140 +0.03125 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +47 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1/16" = 1'-0" +140 +0.0625 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +48 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +3/32" = 1'-0" +140 +0.09375 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +49 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1/8" = 1'-0" +140 +0.125 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +4A +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +3/16" = 1'-0" +140 +0.1875 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +4B +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1/4" = 1'-0" +140 +0.25 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +4C +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +3/8" = 1'-0" +140 +0.375 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +4D +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1/2" = 1'-0" +140 +0.5 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +4E +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +3/4" = 1'-0" +140 +0.75 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +4F +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1" = 1'-0" +140 +1.0 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +50 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1-1/2" = 1'-0" +140 +1.5 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +51 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +3" = 1'-0" +140 +3.0 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +52 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +6" = 1'-0" +140 +6.0 +141 +12.0 +290 + 0 + 0 +SCALE + 5 +53 +102 +{ACAD_REACTORS +330 +42 +102 +} +330 +42 +100 +AcDbScale + 70 + 0 +300 +1'-0" = 1'-0" +140 +12.0 +141 +12.0 +290 + 0 + 0 +ACDBSECTIONVIEWSTYLE + 5 +68 +102 +{ACAD_REACTORS +330 +67 +102 +} +330 +67 +100 +AcDbModelDocViewStyle + 70 + 0 + 3 +Imperial24 +290 + 0 +300 +Imperial24 + 90 + 0 +100 +AcDbSectionViewStyle + 70 + 0 + 71 + 0 + 90 + 78 + 71 + 1 +340 +55 + 62 + 256 + 40 +0.24 +340 +0 +340 +0 + 62 + 256 + 40 +0.24 +300 +I, O, Q, S, X, Z + 40 +0.48 + 90 + 3 + 40 +0.18 + 90 + 1 + 71 + 2 +340 +5C + 90 + 25 + 62 + 256 +340 +5C + 90 + 50 + 62 + 256 + 40 +0.24 + 40 +0.0 + 40 +0.24 + 71 + 3 +340 +55 + 62 + 256 + 40 +0.24 + 90 + 1 + 40 +0.75 + 90 + 1 +300 +%<\AcVar ViewType \f "%tc1">% %<\AcVar ViewSectionStartId>%-%<\AcVar ViewSectionEndId>%\PSCALE %<\AcVar ViewScale \f "%sn">% + 71 + 4 + 62 + 256 + 62 + 257 +300 +ANSI31 + 40 +1.0 + 90 + 0 +290 + 0 +290 + 0 + 90 + 6 + 40 +0.0 + 40 +1.570796326794896 + 40 +0.2617993877991494 + 40 +1.308996938995747 + 40 +-0.2617993877991494 + 40 +1.832595714594045 + 0 +TABLESTYLE + 5 +64 +102 +{ACAD_XDICTIONARY +360 +656 +102 +} +102 +{ACAD_REACTORS +330 +63 +102 +} +330 +63 +100 +AcDbTableStyle +280 + 0 + 3 +Standard + 70 + 0 + 71 + 0 + 40 +0.06 + 41 +0.06 +280 + 0 +281 + 0 + 7 +Standard +140 +0.18 +170 + 2 + 62 + 0 + 63 + 7 +283 + 0 + 90 + 512 + 91 + 0 + 1 + +274 + -2 +284 + 1 + 64 + 0 +275 + -2 +285 + 1 + 65 + 0 +276 + -2 +286 + 1 + 66 + 0 +277 + -2 +287 + 1 + 67 + 0 +278 + -2 +288 + 1 + 68 + 0 +279 + -2 +289 + 1 + 69 + 0 + 7 +Standard +140 +0.25 +170 + 5 + 62 + 0 + 63 + 7 +283 + 0 + 90 + 512 + 91 + 0 + 1 + +274 + -2 +284 + 1 + 64 + 0 +275 + -2 +285 + 1 + 65 + 0 +276 + -2 +286 + 1 + 66 + 0 +277 + -2 +287 + 1 + 67 + 0 +278 + -2 +288 + 1 + 68 + 0 +279 + -2 +289 + 1 + 69 + 0 + 7 +Standard +140 +0.18 +170 + 5 + 62 + 0 + 63 + 7 +283 + 0 + 90 + 512 + 91 + 0 + 1 + +274 + -2 +284 + 1 + 64 + 0 +275 + -2 +285 + 1 + 65 + 0 +276 + -2 +286 + 1 + 66 + 0 +277 + -2 +287 + 1 + 67 + 0 +278 + -2 +288 + 1 + 68 + 0 +279 + -2 +289 + 1 + 69 + 0 + 0 +VISUALSTYLE + 5 +2F +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +2dWireframe + 70 + 4 +177 + 3 +291 + 0 + 70 + 58 + 90 + 0 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +2E +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Basic + 70 + 7 +177 + 3 +291 + 1 + 70 + 58 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 0 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +35 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Brighten + 70 + 12 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +50.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +39 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +ColorChange + 70 + 16 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 8 +420 + 8421504 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 8 +420 + 8421504 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +32 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Conceptual + 70 + 9 +177 + 3 +291 + 0 + 70 + 58 + 90 + 3 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +179.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +34 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Dim + 70 + 11 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +-50.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +41 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +EdgeColorOff + 70 + 22 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 0 + 90 + 2 +176 + 0 + 90 + 0 +176 + 0 + 90 + 0 +176 + 0 + 40 +0.6 +176 + 0 + 40 +30.0 +176 + 0 + 62 + 7 +420 + 16777215 +176 + 0 + 90 + 1 +176 + 0 + 90 + 4 +176 + 0 + 62 + 7 +176 + 0 + 62 + 257 +176 + 0 + 90 + 1 +176 + 0 + 90 + 1 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 8 +176 + 2 + 62 + 7 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 1 +176 + 0 + 90 + 6 +176 + 0 + 90 + 2 +176 + 0 + 62 + 7 +176 + 0 + 90 + 5 +176 + 0 + 90 + 0 +176 + 0 + 90 + 0 +176 + 0 +290 + 0 +176 + 0 + 90 + 1 +176 + 0 + 40 +0.0 +176 + 0 + 90 + 0 +176 + 0 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 0 + 40 +0.0 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 0 +176 + 0 + 62 + 18 +176 + 0 + 90 + 50 +176 + 0 + 90 + 3 +176 + 0 + 62 + 5 +420 + 255 +176 + 0 +290 + 0 +176 + 1 + 90 + 50 +176 + 0 + 90 + 50 +176 + 0 + 90 + 50 +176 + 0 +290 + 0 +176 + 1 + 90 + 50 +176 + 0 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 0 + 1 +strokes_ogs.tif +176 + 0 +290 + 0 +176 + 1 + 40 +1.0 +176 + 0 + 40 +1.0 +176 + 0 + 0 +VISUALSTYLE + 5 +38 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Facepattern + 70 + 15 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +2A +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Flat + 70 + 0 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 13 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +2B +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +FlatWithEdges + 70 + 1 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 13 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +2C +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Gouraud + 70 + 2 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 13 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +2D +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +GouraudWithEdges + 70 + 3 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 13 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +31 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Hidden + 70 + 6 +177 + 3 +291 + 0 + 70 + 58 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 40 +40.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +3F +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +JitterOff + 70 + 20 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 0 + 90 + 2 +176 + 0 + 90 + 0 +176 + 0 + 90 + 0 +176 + 0 + 40 +0.6 +176 + 0 + 40 +30.0 +176 + 0 + 62 + 7 +420 + 16777215 +176 + 0 + 90 + 1 +176 + 0 + 90 + 4 +176 + 0 + 62 + 7 +176 + 0 + 62 + 257 +176 + 0 + 90 + 1 +176 + 0 + 90 + 1 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 10 +176 + 2 + 62 + 7 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 1 +176 + 0 + 90 + 6 +176 + 0 + 90 + 2 +176 + 0 + 62 + 7 +176 + 0 + 90 + 5 +176 + 0 + 90 + 0 +176 + 0 + 90 + 0 +176 + 0 +290 + 0 +176 + 0 + 90 + 1 +176 + 0 + 40 +0.0 +176 + 0 + 90 + 0 +176 + 0 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 0 + 40 +0.0 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 0 +176 + 0 + 62 + 18 +176 + 0 + 90 + 50 +176 + 0 + 90 + 3 +176 + 0 + 62 + 5 +420 + 255 +176 + 0 +290 + 0 +176 + 1 + 90 + 50 +176 + 0 + 90 + 50 +176 + 0 + 90 + 50 +176 + 0 +290 + 0 +176 + 1 + 90 + 50 +176 + 0 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 0 + 1 +strokes_ogs.tif +176 + 0 +290 + 0 +176 + 1 + 40 +1.0 +176 + 0 + 40 +1.0 +176 + 0 + 0 +VISUALSTYLE + 5 +37 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Linepattern + 70 + 14 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 7 +176 + 1 + 90 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +40 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +OverhangOff + 70 + 21 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 0 + 90 + 2 +176 + 0 + 90 + 0 +176 + 0 + 90 + 0 +176 + 0 + 40 +0.6 +176 + 0 + 40 +30.0 +176 + 0 + 62 + 7 +420 + 16777215 +176 + 0 + 90 + 1 +176 + 0 + 90 + 4 +176 + 0 + 62 + 7 +176 + 0 + 62 + 257 +176 + 0 + 90 + 1 +176 + 0 + 90 + 1 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 9 +176 + 2 + 62 + 7 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 1 +176 + 0 + 90 + 6 +176 + 0 + 90 + 2 +176 + 0 + 62 + 7 +176 + 0 + 90 + 5 +176 + 0 + 90 + 0 +176 + 0 + 90 + 0 +176 + 0 +290 + 0 +176 + 0 + 90 + 1 +176 + 0 + 40 +0.0 +176 + 0 + 90 + 0 +176 + 0 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 0 + 40 +0.0 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 0 +176 + 0 + 62 + 18 +176 + 0 + 90 + 50 +176 + 0 + 90 + 3 +176 + 0 + 62 + 5 +420 + 255 +176 + 0 +290 + 0 +176 + 1 + 90 + 50 +176 + 0 + 90 + 50 +176 + 0 + 90 + 50 +176 + 0 +290 + 0 +176 + 1 + 90 + 50 +176 + 0 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 0 + 1 +strokes_ogs.tif +176 + 0 +290 + 0 +176 + 1 + 40 +1.0 +176 + 0 + 40 +1.0 +176 + 0 + 0 +VISUALSTYLE + 5 +33 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Realistic + 70 + 8 +177 + 3 +291 + 0 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 13 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +3E +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Shaded + 70 + 27 +177 + 3 +291 + 0 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 0 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 8 +420 + 7895160 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 5 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +3D +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Shaded with edges + 70 + 26 +177 + 3 +291 + 0 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 5 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +3A +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Shades of Gray + 70 + 23 +177 + 3 +291 + 0 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 62 + 7 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +40.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +3B +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Sketchy + 70 + 24 +177 + 3 +291 + 0 + 70 + 58 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 62 + 7 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +40.0 +176 + 1 + 90 + 11 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 6 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +36 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Thicken + 70 + 13 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 12 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +30 +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +Wireframe + 70 + 5 +177 + 3 +291 + 0 + 70 + 58 + 90 + 0 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +3C +102 +{ACAD_REACTORS +330 +29 +102 +} +330 +29 +100 +AcDbVisualStyle + 2 +X-Ray + 70 + 25 +177 + 3 +291 + 0 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.5 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 13 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +DICTIONARYVAR + 5 +351 +102 +{ACAD_REACTORS +330 +34B +102 +} +330 +34B +100 +DictionaryVariables +280 + 0 + 1 +1:1 + 0 +DICTIONARYVAR + 5 +34D +102 +{ACAD_REACTORS +330 +34B +102 +} +330 +34B +100 +DictionaryVariables +280 + 0 + 1 +STANDARD + 0 +DICTIONARYVAR + 5 +34C +102 +{ACAD_REACTORS +330 +34B +102 +} +330 +34B +100 +DictionaryVariables +280 + 0 + 1 +STANDARD + 0 +DICTIONARYVAR + 5 +34E +102 +{ACAD_REACTORS +330 +34B +102 +} +330 +34B +100 +DictionaryVariables +280 + 0 + 1 +Imperial24 + 0 +DICTIONARYVAR + 5 +34F +102 +{ACAD_REACTORS +330 +34B +102 +} +330 +34B +100 +DictionaryVariables +280 + 0 + 1 +Imperial24 + 0 +DICTIONARYVAR + 5 +353 +102 +{ACAD_REACTORS +330 +34B +102 +} +330 +34B +100 +DictionaryVariables +280 + 0 + 1 +1 + 0 +DICTIONARYVAR + 5 +354 +102 +{ACAD_REACTORS +330 +34B +102 +} +330 +34B +100 +DictionaryVariables +280 + 0 + 1 +15 + 0 +DICTIONARYVAR + 5 +352 +102 +{ACAD_REACTORS +330 +34B +102 +} +330 +34B +100 +DictionaryVariables +280 + 0 + 1 +0 + 0 +DICTIONARYVAR + 5 +350 +102 +{ACAD_REACTORS +330 +34B +102 +} +330 +34B +100 +DictionaryVariables +280 + 0 + 1 +0 + 0 +DICTIONARY + 5 +1A +330 +19 +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +BUMPTILE +360 +1C + 3 +DIFFUSETILE +360 +1B + 3 +OPACITYTILE +360 +1F + 3 +REFLECTIONTILE +360 +1E + 3 +REFRACTIONTILE +360 +20 + 3 +SPECULARTILE +360 +1D + 0 +DICTIONARY + 5 +12 +330 +11 +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +BUMPTILE +360 +14 + 3 +DIFFUSETILE +360 +13 + 3 +OPACITYTILE +360 +17 + 3 +REFLECTIONTILE +360 +16 + 3 +REFRACTIONTILE +360 +18 + 3 +SPECULARTILE +360 +15 + 0 +DICTIONARY + 5 +22 +330 +21 +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +BUMPTILE +360 +24 + 3 +DIFFUSETILE +360 +23 + 3 +OPACITYTILE +360 +27 + 3 +REFLECTIONTILE +360 +26 + 3 +REFRACTIONTILE +360 +28 + 3 +SPECULARTILE +360 +25 + 0 +DICTIONARY + 5 +656 +330 +64 +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +ACAD_ROUNDTRIP_2008_TABLESTYLE_CELLSTYLEMAP +360 +22F4 + 0 +XRECORD + 5 +1C +102 +{ACAD_REACTORS +330 +1A +102 +} +330 +1A +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +1B +102 +{ACAD_REACTORS +330 +1A +102 +} +330 +1A +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +1F +102 +{ACAD_REACTORS +330 +1A +102 +} +330 +1A +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +1E +102 +{ACAD_REACTORS +330 +1A +102 +} +330 +1A +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +20 +102 +{ACAD_REACTORS +330 +1A +102 +} +330 +1A +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +1D +102 +{ACAD_REACTORS +330 +1A +102 +} +330 +1A +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +14 +102 +{ACAD_REACTORS +330 +12 +102 +} +330 +12 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +13 +102 +{ACAD_REACTORS +330 +12 +102 +} +330 +12 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +17 +102 +{ACAD_REACTORS +330 +12 +102 +} +330 +12 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +16 +102 +{ACAD_REACTORS +330 +12 +102 +} +330 +12 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +18 +102 +{ACAD_REACTORS +330 +12 +102 +} +330 +12 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +15 +102 +{ACAD_REACTORS +330 +12 +102 +} +330 +12 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +24 +102 +{ACAD_REACTORS +330 +22 +102 +} +330 +22 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +23 +102 +{ACAD_REACTORS +330 +22 +102 +} +330 +22 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +27 +102 +{ACAD_REACTORS +330 +22 +102 +} +330 +22 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +26 +102 +{ACAD_REACTORS +330 +22 +102 +} +330 +22 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +28 +102 +{ACAD_REACTORS +330 +22 +102 +} +330 +22 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +25 +102 +{ACAD_REACTORS +330 +22 +102 +} +330 +22 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +CELLSTYLEMAP + 5 +22F4 +102 +{ACAD_REACTORS +330 +656 +102 +} +330 +656 +100 +AcDbCellStyleMap + 90 + 3 +300 +CELLSTYLE + 1 +TABLEFORMAT_BEGIN + 90 + 5 +170 + 1 + 91 + 0 + 92 + 32768 + 62 + 257 + 93 + 1 +300 +CONTENTFORMAT + 1 +CONTENTFORMAT_BEGIN + 90 + 0 + 91 + 0 + 92 + 512 + 93 + 0 +300 + + 40 +0.0 +140 +1.0 + 94 + 5 + 62 + 0 +340 +55 +144 +0.25 +309 +CONTENTFORMAT_END +171 + 1 +301 +MARGIN + 1 +CELLMARGIN_BEGIN + 40 +0.06 + 40 +0.06 + 40 +0.06 + 40 +0.06 + 40 +0.18 + 40 +0.18 +309 +CELLMARGIN_END + 94 + 6 + 95 + 1 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +0 + 93 + 0 + 40 +0.045 +309 +GRIDFORMAT_END + 95 + 2 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +0 + 93 + 0 + 40 +0.045 +309 +GRIDFORMAT_END + 95 + 4 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +0 + 93 + 0 + 40 +0.045 +309 +GRIDFORMAT_END + 95 + 8 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +0 + 93 + 0 + 40 +0.045 +309 +GRIDFORMAT_END + 95 + 16 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +0 + 93 + 0 + 40 +0.045 +309 +GRIDFORMAT_END + 95 + 32 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +0 + 93 + 0 + 40 +0.045 +309 +GRIDFORMAT_END +309 +TABLEFORMAT_END + 1 +CELLSTYLE_BEGIN + 90 + 1 + 91 + 1 +300 +_TITLE +309 +CELLSTYLE_END +300 +CELLSTYLE + 1 +TABLEFORMAT_BEGIN + 90 + 5 +170 + 1 + 91 + 0 + 92 + 0 + 62 + 257 + 93 + 1 +300 +CONTENTFORMAT + 1 +CONTENTFORMAT_BEGIN + 90 + 0 + 91 + 0 + 92 + 512 + 93 + 0 +300 + + 40 +0.0 +140 +1.0 + 94 + 5 + 62 + 0 +340 +55 +144 +0.18 +309 +CONTENTFORMAT_END +171 + 1 +301 +MARGIN + 1 +CELLMARGIN_BEGIN + 40 +0.06 + 40 +0.06 + 40 +0.06 + 40 +0.06 + 40 +0.18 + 40 +0.18 +309 +CELLMARGIN_END + 94 + 6 + 95 + 1 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +0 + 93 + 0 + 40 +0.045 +309 +GRIDFORMAT_END + 95 + 2 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +0 + 93 + 0 + 40 +0.045 +309 +GRIDFORMAT_END + 95 + 4 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +0 + 93 + 0 + 40 +0.045 +309 +GRIDFORMAT_END + 95 + 8 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +0 + 93 + 0 + 40 +0.045 +309 +GRIDFORMAT_END + 95 + 16 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +0 + 93 + 0 + 40 +0.045 +309 +GRIDFORMAT_END + 95 + 32 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +0 + 93 + 0 + 40 +0.045 +309 +GRIDFORMAT_END +309 +TABLEFORMAT_END + 1 +CELLSTYLE_BEGIN + 90 + 2 + 91 + 1 +300 +_HEADER +309 +CELLSTYLE_END +300 +CELLSTYLE + 1 +TABLEFORMAT_BEGIN + 90 + 5 +170 + 1 + 91 + 0 + 92 + 0 + 62 + 257 + 93 + 1 +300 +CONTENTFORMAT + 1 +CONTENTFORMAT_BEGIN + 90 + 0 + 91 + 0 + 92 + 512 + 93 + 0 +300 + + 40 +0.0 +140 +1.0 + 94 + 2 + 62 + 0 +340 +55 +144 +0.18 +309 +CONTENTFORMAT_END +171 + 1 +301 +MARGIN + 1 +CELLMARGIN_BEGIN + 40 +0.06 + 40 +0.06 + 40 +0.06 + 40 +0.06 + 40 +0.18 + 40 +0.18 +309 +CELLMARGIN_END + 94 + 6 + 95 + 1 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +0 + 93 + 0 + 40 +0.045 +309 +GRIDFORMAT_END + 95 + 2 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +0 + 93 + 0 + 40 +0.045 +309 +GRIDFORMAT_END + 95 + 4 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +0 + 93 + 0 + 40 +0.045 +309 +GRIDFORMAT_END + 95 + 8 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +0 + 93 + 0 + 40 +0.045 +309 +GRIDFORMAT_END + 95 + 16 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +0 + 93 + 0 + 40 +0.045 +309 +GRIDFORMAT_END + 95 + 32 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +0 + 93 + 0 + 40 +0.045 +309 +GRIDFORMAT_END +309 +TABLEFORMAT_END + 1 +CELLSTYLE_BEGIN + 90 + 3 + 91 + 2 +300 +_DATA +309 +CELLSTYLE_END + 0 +ENDSEC + 0 +SECTION + 2 +ACDSDATA + 70 + 2 + 71 + 8 + 0 +ACDSSCHEMA + 90 + 0 + 1 +AcDb_Thumbnail_Schema + 2 +AcDbDs::ID +280 + 10 + 91 + 8 + 2 +Thumbnail_Data +280 + 15 + 91 + 0 +101 +ACDSRECORD + 95 + 0 + 90 + 1 + 2 +AcDbDs::TreatedAsObjectData +280 + 1 +291 + 1 +101 +ACDSRECORD + 95 + 0 + 90 + 2 + 2 +AcDbDs::Legacy +280 + 1 +291 + 1 +101 +ACDSRECORD + 1 +AcDbDs::ID + 90 + 3 + 2 +AcDs:Indexable +280 + 1 +291 + 1 +101 +ACDSRECORD + 1 +AcDbDs::ID + 90 + 4 + 2 +AcDbDs::HandleAttribute +280 + 7 +282 + 1 + 0 +ACDSSCHEMA + 90 + 1 + 1 +AcDbDs::TreatedAsObjectDataSchema + 2 +AcDbDs::TreatedAsObjectData +280 + 1 + 91 + 0 + 0 +ACDSSCHEMA + 90 + 2 + 1 +AcDbDs::LegacySchema + 2 +AcDbDs::Legacy +280 + 1 + 91 + 0 + 0 +ACDSSCHEMA + 90 + 3 + 1 +AcDbDs::IndexedPropertySchema + 2 +AcDs:Indexable +280 + 1 + 91 + 0 + 0 +ACDSSCHEMA + 90 + 4 + 1 +AcDbDs::HandleAttributeSchema + 2 +AcDbDs::HandleAttribute +280 + 7 + 91 + 1 +284 + 1 + 0 +ACDSRECORD + 90 + 0 + 2 +AcDbDs::ID +280 + 10 +320 +72 + 2 +Thumbnail_Data +280 + 15 + 94 + 3606 +310 +89504E470D0A1A0A0000000D4948445200000100000000A90803000000F3C813C600000300504C5445212830FFFFFF2128300000000000000000000000000000000000000000000000000000330000660000990000CC0000FF0033000033330033660033990033CC0033FF0066000066330066660066990066CC0066FF0099 +310 +000099330099660099990099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF0000FF3300FF6600FF9900FFCC00FFFF3300003300333300663300993300CC3300FF3333003333333333663333993333CC3333FF3366003366333366663366993366CC3366FF3399003399333399663399993399CC3399FF33CC00 +310 +33CC3333CC6633CC9933CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF6600006600336600666600996600CC6600FF6633006633336633666633996633CC6633FF6666006666336666666666996666CC6666FF6699006699336699666699996699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066 +310 +FF3366FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF9933009933339933669933999933CC9933FF9966009966339966669966999966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC3399CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFFCC0000CC00 +310 +33CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFFCCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0000FF0033FF0066FF0099FF00CCFF00FFFF3300FF3333 +310 +FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33FFCC66FFCC99FFCCCCFFCCFFFFFF00FFFF33FFFF66FFFF99FFFFCCFFFFFF0000000D0D0D1A1A1A2828283535354343435050505D5D5D6B6B6B787878868686939393A1A1A1AEAEAEBB +310 +BBBBC9C9C9D6D6D6E4E4E4F1F1F1FFFFFF0000000000000000000000000000000000000000000000000000000000002E4550F1000003144944415478DAED9DDB6EC3300C43F5FFFFCBF7614B93D66D7C4D065424893DACC3024CC7B22EB6E34558966559D67708B65FDB7E0380BAFDD204200D008724231F5EA539EE4A0036 +310 +13B17D4912D8BCFE0F82A6FD7BC67F9AAC1803509B00323E109F63AF63FEAFE58503C4014327FDC9A680A8CF7D4900A11902C45DA066BA0C0140DC07CE47FEF8640FD0280251F7037BC013953000665F68A7C1C782C9A34150F400D0AF91B62A61899CD02A032418605EC40042CFFE689741E709821E40B429B04F817A85CC +310 +0FE0BDF81B03002E0003D9E1CD702E00134B65D8FBC9DCED70D9158F1608C7C32459011B838922797F2A755844F91DA63BE5EC8901AD38DEAD8F8220356204408C14C9E9E7C0589744571EE2C6463171F4BFA9514E39FCE8DA1FB4001E6DDFF944285AC36E00CC48E0E52CC8C9822FD694AF053886570DC0D99A37AE9A9F87 +310 +40E7AF6F053E8E7AA8BD0DBA60762E02BD1677C9FCC803606D60795CE0BFCCCFE2020B937AF291ACF35FC2FFD732DB8CF97816D949FC3F2ECEF8F267DF7C9404CBB5CDDC637A11E0AD98867004CC1A04075D9CE3E8C0BD1E9FD205E2BA8F67B63FAE8D6F6E00E55ED68A79BDADF3CC8B21CFA3A08860063057C47C567A4D8E +310 +A91743FA00EA9BE704FE5F037014F7A74783722F060E0378FDC402E09637E5E91C801FC0CD356CAAB3B3FD22E8E2026B86E15706B0E7B1DBABF87C9B01F73732548BE1173C4C9B40EEA530FE7B73E6B6799901C00006167FB5C7DFEF45DA030C801940D8050658A8CC017502513B03457957CAD9B887C28BE16B89401700E7 +310 +85F233AFBCF000C0E0D0735EA0788CE440D02304F0F95EEFCC01788578C77D8DF2B88F73029899E27C0030653F21806A713B7A02263F80E606608C00E08E810200A2F9D65B281098ACF308DB40AC2250E97D2BBF4F746BEE6CBFB3B7C1122E10151F287A683A00D1BBE882FA7EC09133A1F417242A1C01586B89150884B8FD +310 +277130F895FCDDBEFF0E030AFF4F765B0509D9F1DF93BB3080D636908E030494E74015807A080899FFA1595C98C7DCFBD401284BDD7E03B02CCBB22CCBB22CCBB22CCBB22CCBB22CCBB22CCBB2AC2FD60F04D22D723269A5C90000000049454E44AE426082DFDB9A0DF2F568874EB03CCE032F0404EEDD83125D01A852492D +310 +EF63CC4740DF35A17DBC700F61A0F28C06645295189A5037B9FB4F0984DCB20E8EFE5B8E6BB40F2D529EDF4877AAB92D00D2E147BBBBE44E15B4C4C1C89F00654D681F5E7D23FBE53FE1CF8E12A039551715EE53A778806CFF4EFB94036216C23BE03961BFE6776060A98AE6389976F2E93AF0ECADBF99D03E860CB423AE59 +310 +9CD6D48DDD5980A7A8106D81A21E1EFCEA47B48FE23B2AC42EEA0668996D800756368ECA19D5A42591C3D964049ABE9B06EFCE62DD5E3EA7310A10A2E10BA3F35009ADF3090E10675F13325CD1D9E73F55C5558850EE95A3D14284898A8DF6E82F8EAE84B45F71F0CF334D894AC922FF81EB8124C11A93F120AEDE191EA089 +310 +13F7BB41984BD006740F50444113D6421D11F51F0AEC405F8EF3800C546E13F88654510008B9B27AEC0E5110F2A380BCAB100A81238B78F4AFEF5B931A8E91DF51020081CE050611E03CA11389C5146FA56175A911F414BF7705E26FA2EF9A08B6931FEE9EAE08A9D843E4C81990686201D3DE0B15D9B0085BED23BBA0F26A +310 +043805986F737AF77D870012F0291E22EA696B3A70A7786487B502AD139110B706B4AF6008AD7740CD509440A9A019823F089C79BB157E81EAB8FD23E9D86938004A329C45E3D00A96CBC09A52260BC24E427A99E824E2910668999D20A7835FAE8AF44E824A08A9FA90442265BC5056845AB71D94C171AD50B017EE1168E0 +310 +90FF58F56380320B656EC65914DC419F372530775815E4618711DCF7AF11F445F2B38A6532549213A8AC3CBE9277710B39E14E00ED8846B8A0DA7422B7880218D8A9FA5E0DDF0493211614CB48E60082003A7016D95D0D3AA7860238F759DFAAE15BEFC8B0E215EE88B48EC27B8516E2B3034280F8B314128F6747EBE9F6D5 +310 +F0ADE225D217C88B438BAA2E9E22C9769C053CD99722B17BA062A7E0DC61658F4CEC03F87761CA4806BB3615FEF19A4AA7EA0BDBB7E41CCC664B9C5FA8E1A3ED909AA984BA93D07A33F1818488B3F55EC11837D0045073357CC570915D6CEA4891F4CA61D1D11BBB1CB78E0C84A87CCB8FC67E8A718EC00E77D5F0AEAB055D +310 +A2E050C46A802D918E2745C07023CB95E7AE4C5354C3430BE089DE815F844E20EED1358CE2E1F83123FA80C880C44F9CE8463C21209CBFC79542CD986D2E206097E344DD7C6439EC099BC894C8FA89B478BAB247EEBDD84603C02812A090D219AA89361393D32F3302FB276AF81EDB3CAE5A928751440EF60CFDD450BE5BA8 +310 +4E4C203090E0CD70ED2115989E7509B9DF47CC2CDA9CA40C495D405292A99B54277A29064536534C5125E75621ADB53B70A67C6E3800077C2C034EAF8232FD830A8202A89470A21AF52DAFB689B99FA48FB1C8D3AAF40AD6BC122B6A9DEC8ECCA2DD3397E62B84D9670928A34AA93851474A03FEFD420D3FA7BEC97E26F718 +310 +22A3B36E8072FC0F92A8F8D1BCA70D070292C7D16AD451A5404BED7F550D3F3F2906FA152D0F465FAA3EECBB34A1BE890729439C729E26C42027CC97B2F776A14A8C3E29F1390EBF886A7182F9E2F015E4F4C416831D3AE9F00392953B63FEA44AD904026891F42F4E0CC5CCD9BCBB0E51D239812FE8BA06E8A53C9CDA078C +310 +96841ABE280D7628BA89A75C28A2130A604D1A63F93381D10D00A30BF82349DC16DD425E18D85FFAC909B324D25E472062BEE6C8D1B256A310C890A954A12E0C40A0F7BDE68A3A77FB0DE49023C0217E5012AB5D0D4F42201E9EF420CBD92429F431272E35051CB8DD89FA2388601AD7F37D506C22E292028D9322E00E3E5A +310 +5358122C6AED68237D77224B50607E434114E16EE799CE935C80905C6A9BD42B810A892CC4D0D5F875A06A21C4FEEE929E668050252803C477CC6FC5E86C8F6DC8217BA7AD7F1004C8D21AB09F7DF10EF38B71A3E87571417E3600A0F33DC047E4F8469604C01339CC107CBC1E33D11E63DA96D2C07FBFBA845D2168F0915F +310 +777947892805E8738813CEF03223933DB687A4C5A442F1B6000EBB1044013C03E4BA9801F27D1455F87A390DD4FE13BCAC01569CF45045C577A5D77438F518C783C93E95A274A83E0112F3507307B9D4FC78F062D6F5785914FD820D7C021129529E2D354C5EDEB99607B497C27CB681D46ED33D16F8D47D76E45A2160E201 +310 +C6EAF9CC200D10121A1A804F08B559B46B3DC59FF296E87330E5132C09852431171D89C5BBECAB3900B27B8AC4BD36267096F0A14702C602CA108F9580FEBF34E828B9F80E6A84B8D0C756BCB335354010AF357D8AF20A06988A3551C8CCB0644B1C7DF07EC68EE8626FEAA953251487A97A4F3F796CD6C135C57C503C9671 +310 +DDE7B4829BDD1D5F8A2701E403103153E5D335B841573540E9275A657F56D00B65764DDE4E4A670D44FFFEBDD8A7D5F28925E5749CFBC7E9DCF7C1D44A80E4B17D3EA50A16FE091FB880FDF0F1B5AAD600544D3E8FE4EE06C81931A2E83E0E10BCCBFDFDBFAA7FDC9A889EA1F46DEF6C3DE10ECCC61DB726A9BD3618EFF2D5 +310 +E3AE00E66B85F767DB8353F51C03B48A08A2378C57DEED51E9BF2A131C2C76DD77710AF24EEFAAFFAD01381E335308B89CFC710600D1998C5F3CA2F09C8F1E532F8A82EEEEA0D3931CA07FBCD4D70D8E1E5300ED18E0874F3E3DC8049AB486BFD265DE32067CF8A7AE7FFC87CEAFB5D65A6BADB5D65A6BADB5D65A6BADB5D6 +310 +5A6BADB5D65A6BADB5D65A6BADB5D65A6BADB5D65A6BADB5D65A07AEFF00554FE27454DCB1F00000000049454E44AE426082 + 0 +ENDSEC + 0 +EOF diff --git a/testdata/barnsbury_extended2_axial.graph b/testdata/barnsbury_extended2_axial.graph new file mode 100644 index 00000000..6b9faa54 Binary files /dev/null and b/testdata/barnsbury_extended2_axial.graph differ diff --git a/testdata/barnsbury_extended2_drawing.graph b/testdata/barnsbury_extended2_drawing.graph new file mode 100644 index 00000000..2387b625 Binary files /dev/null and b/testdata/barnsbury_extended2_drawing.graph differ diff --git a/testdata/barnsbury_segment.graph b/testdata/barnsbury_segment.graph new file mode 100644 index 00000000..be6fb426 Binary files /dev/null and b/testdata/barnsbury_segment.graph differ diff --git a/testdata/barnsbury_segment_lines.mid b/testdata/barnsbury_segment_lines.mid new file mode 100644 index 00000000..05c244d7 --- /dev/null +++ b/testdata/barnsbury_segment_lines.mid @@ -0,0 +1,178 @@ +0,2.0012004,0,3,66.173325,365,4156801.8,88.617859,6618.5718,178,357.53516,22549.607,12216.636 +1,1.7398858,0,4,82.40506,983,9028389,89.036148,6680.416,178,355.85547,22340.854,12216.636 +2,2.0232198,0,4,243.39876,1211,9372838,87.789162,6583.7954,178,360.91016,22668.717,12216.636 +3,1.2413905,0,3,138.96246,487,4206866.5,84.789192,6377.4712,178,373.67969,23402.096,12216.636 +4,1.9381289,1,3,130.18936,330,4186343.2,89.3825,6714.5283,178,354.47656,22227.355,12216.636 +5,2.1624684,1,4,162.06264,692,5878021,90.132393,6768.0562,178,351.52734,22051.561,12216.636 +6,1.7826266,1,4,184.86253,1342,11232938,93.362,7145.4531,178,339.36719,20886.877,12216.636 +7,2.0335331,1,4,186.81696,1021,8303167,94.585724,7241.9897,178,334.97656,20608.453,12216.636 +8,2.0149293,1,3,70.41478,795,5818716.5,94.632072,7246.8599,178,334.8125,20594.604,12216.636 +9,4,2,5,64.546532,308,1653464.4,67.747787,4992.2837,178,467.67578,29895.375,12216.636 +10,2.6528366,2,5,53.262371,385,1758330.9,66.705902,4920.8042,178,474.98047,30329.635,12216.636 +11,3.3471634,2,4,10.496307,238,1142586.6,66.317581,4891.7046,178,477.76172,30510.059,12216.636 +12,4,3,5,136.73875,450,4882207.5,80.08831,6026.8027,178,395.61328,24763.744,12216.636 +13,4,3,6,144.35603,309,4674048.5,80.518425,6047.978,178,393.5,24677.041,12216.636 +14,4,3,5,208.19673,618,6827499,82.457573,6239.9404,178,384.24609,23917.889,12216.636 +15,3.6441982,4,4,8.9747467,0,86300.844,54.864071,3917.8215,178,577.5,38094.18,12216.636 +16,0.91864121,4,3,62.642906,408,1356859.4,61.200176,4461.4165,178,517.71094,33452.648,12216.636 +17,1.5875411,5,3,68.832535,189,772664.94,57.446114,4183.127,178,551.54297,35678.145,12216.636 +18,3.0086384,5,4,5.5661507,55,472367.16,57.439606,4182.6602,178,551.60547,35682.125,12216.636 +19,2.5961795,6,4,31.722631,347,1240084.2,67.549751,4859.6494,178,469.04688,30711.309,12216.636 +20,2.8942552,6,4,153.36557,17,792264.5,64.708687,4663.2021,178,489.64062,32005.088,12216.636 +21,4,7,5,78.798721,521,3768654.8,94.541626,6940.915,178,335.13281,21502.381,12216.636 +22,4,7,6,92.622635,1212,6392349,94.387596,6921.416,178,335.67969,21562.957,12216.636 +23,4,7,6,72.328705,2026,9513038,94.350273,6925.3647,178,335.8125,21550.662,12216.636 +24,3.0542002,7,5,78.076729,2484,10539197,94.411774,6929.8618,178,335.59375,21536.678,12216.636 +25,1.086924,7,4,38.178894,2364,9562418,94.596756,6949.0996,178,334.9375,21477.057,12216.636 +26,3.8588758,7,4,19.806421,183,1061214.2,70.44252,5291.4692,178,449.78516,28205.059,12216.636 +27,2.9553642,8,4,152.64659,251,1603799.8,67.250679,4869.6396,178,471.13281,30648.303,12216.636 +28,2.5628395,8,4,30.569248,568,1731472.4,65.794159,4767.6074,178,481.5625,31304.215,12216.636 +29,1.9056505,9,3,36.273235,29,378006.91,60.132584,4206.0908,178,526.90234,35483.352,12216.636 +30,1.9439689,9,3,20.292385,218,1091423.4,60.404408,4222.1895,178,524.53125,35348.059,12216.636 +31,2.9565058,10,4,63.638454,179,1265680.5,76.827156,5356.625,178,412.40625,27861.982,12216.636 +32,2.0050292,10,4,72.13398,318,1992266.2,76.798058,5353.8901,178,412.5625,27876.215,12216.636 +33,3.038465,10,5,69.456345,451,2690610.5,76.773346,5351.5645,178,412.69531,27888.332,12216.636 +34,4,10,5,85.215919,289,1667870.4,75.121597,5252.0879,178,421.76953,28416.547,12216.636 +35,4,11,4,107.46763,2,838417.31,63.447308,4644.291,178,499.375,32135.412,12216.636 +36,3.2855186,12,4,11.691815,194,1175906.4,91.489624,6918.437,178,346.3125,21572.242,12216.636 +37,1.7466468,12,4,67.515892,1345,8545044,93.415764,7065.1655,178,339.17188,21124.232,12216.636 +38,1.9949708,12,4,71.218079,1564,10169552,93.450203,7068.7441,178,339.04688,21113.537,12216.636 +39,2.9728639,12,5,69.910538,1838,11861826,93.480362,7072.0098,178,338.9375,21103.789,12216.636 +40,3.021472,12,5,149.26498,2287,15157395,92.603081,7028.9722,178,342.14844,21233.004,12216.636 +41,2.9785283,12,5,84.025612,2172,14630360,92.644333,7033.8105,178,341.99609,21218.398,12216.636 +42,4,12,6,193.21144,1244,11365588,92.635872,7033.4829,178,342.02734,21219.387,12216.636 +43,4,12,5,69.391472,768,7140941.5,93.896996,7157.6016,178,337.43359,20851.426,12216.636 +44,1.8460462,13,3,72.605972,316,1933160.2,78.073212,5514.459,178,405.82422,27064.521,12216.636 +45,3.079603,13,5,109.37788,478,2846059,77.863358,5500.2261,178,406.91797,27134.557,12216.636 +46,4,13,5,236.42712,473,4039082.2,78.030403,5565.8442,178,406.04688,26814.656,12216.636 +47,2.9256492,14,3,73.804344,175,1367621.2,65.590919,4713.0044,178,483.05469,31666.893,12216.636 +48,3.118978,15,4,1.1576769,21,52568.5,54.646725,3815.7188,178,579.79688,39113.523,12216.636 +49,2.881022,15,4,51.738968,143,588109.5,57.167553,4008.4851,178,554.23047,37232.57,12216.636 +50,0.67563176,16,2,57.332561,0,576803.94,65.119614,4571.0322,178,486.55078,32650.436,12216.636 +51,3.3243682,16,4,1.773312,279,1124254.5,64.529015,4523.1011,178,491.00391,32996.434,12216.636 +52,3.5566537,17,4,1.5755012,185,842638.75,76.248665,5384.1821,178,415.53516,27719.381,12216.636 +53,2.4433463,17,5,94.138809,909,2878055.8,76.660873,5397.0391,178,413.30078,27653.35,12216.636 +54,4,17,5,240.50478,375,3247603.5,76.669571,5422.1479,178,413.25391,27525.291,12216.636 +55,2.9502037,18,4,63.214619,480,4244460.5,103.37621,7594.2671,178,306.49219,19652.482,12216.636 +56,2.043396,18,4,55.795689,1247,10353393,102.60077,7508.9897,178,308.80859,19875.67,12216.636 +57,3.0064003,18,5,61.844196,1345,9701150,102.59558,7507.5396,178,308.82422,19879.51,12216.636 +58,4,18,6,57.726696,1684,8941627,102.73723,7506.4736,178,308.39844,19882.332,12216.636 +59,4,18,6,78.380333,1829,7873546.5,102.76196,7497.6934,178,308.32422,19905.615,12216.636 +60,2.3847485,18,5,76.566856,2421,9062067,103.37885,7527.7261,178,306.48438,19826.199,12216.636 +61,3.6152513,18,4,7.2528086,254,949294.31,80.944298,6096.1309,178,391.42969,24482.119,12216.636 +62,3.0376058,19,4,4.8203835,969,3415459,88.060799,6053.9453,178,359.79688,24652.717,12216.636 +63,2.0014875,19,4,57.263824,1257,4270006.5,88.909271,6120.3413,178,356.36328,24385.273,12216.636 +64,2.0467546,19,4,81.338486,1219,4250588,89.006836,6125.0562,178,355.97266,24366.502,12216.636 +65,2.9141521,19,5,69.343399,1026,3768641.5,89.135948,6129.8477,178,355.45703,24347.457,12216.636 +66,2.9891434,19,4,15.855036,146,408590.09,92.881973,6344.1655,178,341.12109,23524.953,12216.636 +67,4,20,5,0.50094116,218,1162905.5,95.223106,6722.3511,178,332.73438,22201.488,12216.636 +68,3.7623262,20,5,31.326914,1285,4497112,96.855942,6966.7446,178,327.125,21422.658,12216.636 +69,1.3914185,20,4,20.039038,3505,11620107,109.44092,7678.6113,178,289.50781,19436.613,12216.636 +70,1.9921591,20,4,80.945,3493,11790712,109.55621,7688.1909,178,289.20312,19412.395,12216.636 +71,1.5069535,20,4,54.103935,3332,11531442,110.02882,7732.5884,178,287.96094,19300.938,12216.636 +72,3.3471429,20,4,8.468255,2263,8132306,104.11933,7376.3535,178,304.30469,20233.059,12216.636 +73,2,21,2,79.482445,0,724714.19,68.040466,4773.4067,178,465.66406,31266.18,12216.636 +74,2,22,2,84.41777,0,884771.5,61.031174,4482.9517,178,519.14453,33291.949,12216.636 +75,2.0549963,23,3,141.50713,807,5807270,108.51846,7723.2334,178,291.96875,19324.314,12216.636 +76,2.0359912,23,4,75.595688,1018,8256845,108.48653,7714.8027,178,292.05469,19345.434,12216.636 +77,2.0393751,23,4,72.215797,1600,11373205,108.45172,7712.0181,178,292.14844,19352.418,12216.636 +78,2.9666958,23,5,73.287651,2234,14429388,108.67695,7731.8662,178,291.54297,19302.74,12216.636 +79,4,23,6,30.462101,3298,17047350,109.00117,7758.3276,178,290.67578,19236.904,12216.636 +80,2.9891434,23,4,41.801193,7,305486.44,81.780823,6039.9316,178,387.42578,24709.916,12216.636 +81,3.0975204,24,4,19.99411,1982,8221255.5,94.571388,6882.4766,178,335.02734,21684.955,12216.636 +82,1.8206327,24,4,81.959412,2197,8739249,94.774712,6903.2329,178,334.30859,21619.754,12216.636 +83,3.081847,24,5,61.298454,2277,8390308,94.681778,6897.7725,178,334.63672,21636.869,12216.636 +84,4,24,6,230.26486,1424,6303539,94.330521,6897.4736,178,335.88281,21637.807,12216.636 +85,3.2086754,24,4,11.345068,44,144973.97,94.284462,6899.8101,178,336.04688,21630.479,12216.636 +86,4,25,5,21.704504,197,477300.16,96.725426,6661.9341,178,327.56641,22402.832,12216.636 +87,4,25,6,156.13542,1787,5874959,98.494301,6724.2876,178,321.68359,22195.096,12216.636 +88,3.1397986,25,5,4.3709054,2150,9321218,104.76485,7310.2856,178,302.42969,20415.92,12216.636 +89,1.8853738,25,4,123.53465,3623,16552666,109.2331,7622.9595,178,290.05859,19578.512,12216.636 +90,2.9748278,25,5,88.042221,3490,16621146,109.28609,7624.9824,178,289.91797,19573.316,12216.636 +91,4,25,6,44.959156,3443,16985778,113.6598,7907.6191,178,278.76172,18873.721,12216.636 +92,3.2086754,25,4,32.158134,68,200538.19,101.16245,6671.1152,178,313.19922,22372,12216.636 +93,1.5234891,26,3,156.51314,880,4697371,104.36852,7220.9028,178,303.57812,20668.635,12216.636 +94,2.5515666,26,4,28.49353,680,4084668.8,101.46744,7087.5713,178,312.25781,21057.453,12216.636 +95,2.7092693,26,5,152.589,817,4337584,103.78361,7169.0215,178,305.28906,20818.209,12216.636 +96,4,26,5,4.3323708,614,2229197,76.315384,5204.4497,178,415.17188,28676.652,12216.636 +97,3.2741685,27,4,5.734199,492,997931.38,80.218208,5351.3374,178,394.97266,27889.516,12216.636 +98,2.7258315,27,5,58.77298,1042,3266476.5,81.474419,5444.9028,178,388.88281,27410.258,12216.636 +99,4,27,6,26.602385,1344,4041288.8,82.973801,5525.2549,178,381.85547,27011.643,12216.636 +100,4,27,5,7.6956849,33,207832.08,82.114479,5449.6763,178,385.85156,27386.25,12216.636 +101,3.3356996,28,4,14.008615,194,486196.19,70.869667,4749.543,178,447.07422,31423.277,12216.636 +102,2.6643004,28,5,51.947716,511,1172606.5,75.637886,5014.8662,178,418.89062,29760.754,12216.636 +103,3.2326641,28,5,24.983932,284,761697.12,76.392288,5051.4565,178,414.75391,29545.182,12216.636 +104,2.7673359,28,4,8.5771065,207,681293.75,82.713196,5482.2207,178,383.05859,27223.676,12216.636 +105,4,29,5,55.623226,382,1242717.2,74.394005,4952.0566,178,425.89453,30138.227,12216.636 +106,2.6909027,29,5,122.1385,689,2199216.8,73.854805,4909.8218,178,429.00391,30397.479,12216.636 +107,3.3090973,29,4,13.437029,331,745346.69,72.762947,4875.8032,178,435.44141,30609.561,12216.636 +108,2.9276934,30,4,81.830719,222,678286.44,89.582893,5963.4609,178,353.68359,25026.775,12216.636 +109,2.7533221,30,5,11.665026,481,3171357.2,90.295944,6051.2231,178,350.89062,24663.807,12216.636 +110,3.2466779,30,5,6.1998625,338,2045784.5,86.868698,5836.5537,178,364.73438,25570.945,12216.636 +111,4,30,6,5.4097123,2668,11407769,105.92642,7445.8682,178,299.11328,20044.162,12216.636 +112,3.0539846,30,5,67.115707,2883,12051203,105.87665,7443.2124,178,299.25391,20051.316,12216.636 +113,2.9460154,30,5,59.932568,2769,11646952,105.91536,7444.0581,178,299.14453,20049.037,12216.636 +114,3.1116269,30,5,95.806824,2047,9289722,105.9901,7445.4268,178,298.93359,20045.352,12216.636 +115,2.8883731,30,4,0.19636907,1405,6988613.5,107.35222,7529.5103,178,295.14062,19821.502,12216.636 +116,2.9463861,31,4,85.111755,76,584308.75,69.896194,4771.4482,178,453.30078,31279.014,12216.636 +117,2.9276934,31,4,7.8116097,118,404667.56,71.989281,4957.4209,178,440.12109,30105.613,12216.636 +118,2.7760887,32,3,80.504349,40,465632.84,67.132118,4718.7378,178,471.96484,31628.416,12216.636 +119,1.7224751,33,2,51.585476,7,210206.28,53.71521,3717.9077,178,589.85156,40142.523,12216.636 +120,4,34,5,100.73653,1167,7415106.5,108.31992,7600.376,178,292.50391,19636.688,12216.636 +121,4,34,6,104.9296,1762,9997418,108.30835,7603.0674,178,292.53516,19629.736,12216.636 +122,2.8438091,34,5,68.548241,2983,14175580,108.05441,7573.5566,178,293.22266,19706.225,12216.636 +123,2.1506054,34,4,42.451733,3055,14141106,107.82458,7557.7256,178,293.84766,19747.502,12216.636 +124,3.0055857,34,5,44.519382,3227,14320575,107.82172,7557.6279,178,293.85547,19747.756,12216.636 +125,3.1265831,34,5,83.344948,3250,14420084,107.70002,7561.4126,178,294.1875,19737.873,12216.636 +126,2.8734171,34,5,11.506542,3430,13727606,107.9753,7599.6616,178,293.4375,19638.531,12216.636 +127,4,34,6,6.0284462,2657,10569333,105.04842,7428.769,178,301.61328,20090.301,12216.636 +128,4,34,5,5.419879,326,1180875.9,86.131653,6176.9673,178,367.85547,24161.727,12216.636 +129,2,35,2,20.824474,0,212491.75,66.399551,4603.9497,178,477.17188,32416.992,12216.636 +130,2.315361,36,3,36.565041,182,517014.62,69.343452,4775.4722,178,456.91406,31252.656,12216.636 +131,0.87075675,37,2,15.346227,109,383297.66,64.659164,4430.2266,178,490.01562,33688.164,12216.636 +132,2.5553956,38,3,58.902714,107,482010.88,60.524754,4128.2837,178,523.48828,36152.117,12216.636 +133,4,39,5,29.471209,2132,7106502.5,102.01877,7046.436,178,310.57031,21180.381,12216.636 +134,3.0400231,39,5,0.41702437,1868,6555843,102.04957,7047.5352,178,310.47656,21177.078,12216.636 +135,1.8690072,39,4,143.56969,2082,7028887,103.00992,7118.877,178,307.58203,20964.852,12216.636 +136,3.0909696,39,5,220.49948,633,2843580.8,102.03416,7091.9126,178,310.52344,21044.562,12216.636 +137,3.3558173,39,4,4.6648011,60,48442.176,102.77367,7156.9517,178,308.28906,20853.32,12216.636 +138,4,40,5,5.8880019,1198,6602856.5,92.347939,6651.4351,178,343.09375,22438.195,12216.636 +139,2.8008873,40,5,86.80928,1314,6988477.5,90.596497,6541.2188,178,349.72656,22816.268,12216.636 +140,1.9834378,40,3,83.826813,874,4874680,89.554214,6493.5498,178,353.79688,22983.762,12216.636 +141,3.7738943,41,4,33.475399,963,7042259,84.994438,6210.7104,178,372.77734,24030.455,12216.636 +142,1.4153167,41,4,178.53447,1362,8652835,90.345222,6721.4429,178,350.69922,22204.488,12216.636 +143,1.2796584,41,4,116.47486,1233,6833815.5,91.196457,6782.4829,178,347.42578,22004.656,12216.636 +144,2.8869476,41,3,6.8355722,0,32039.699,81.984169,6130.0171,178,386.46484,24346.783,12216.636 +145,3.9999998,42,5,314.13025,147,2550125.8,75.341393,5244.0146,178,420.53906,28460.293,12216.636 +146,4,42,5,1.4020742,28,787264.31,73.82859,5159.4937,178,429.15625,28926.521,12216.636 +147,2,43,2,32.635479,0,340282.88,67.405479,4677.939,178,470.05078,31904.262,12216.636 +148,2.372308,44,4,55.385048,1325,2879153,77.915718,5145.1392,178,406.64453,29007.223,12216.636 +149,3.6276922,44,4,8.0672827,538,1295412.9,74.798775,5021.2231,178,423.58984,29723.076,12216.636 +150,2.6622484,45,4,4.1139636,523,1247895.5,72.8479,4776.5571,178,434.93359,31245.559,12216.636 +151,1.9825487,45,4,56.198662,461,1198154.6,72.054512,4745.6021,178,439.72266,31449.371,12216.636 +152,3.3552032,45,4,13.687597,169,627264.94,69.173141,4584.3516,178,458.03906,32555.576,12216.636 +153,3.7100596,46,4,5.1633153,55,157636.45,69.908241,4694.3491,178,453.22266,31792.736,12216.636 +154,0.85895824,46,4,48.794411,682,1540374.1,74.486237,4990.52,178,425.36719,29905.941,12216.636 +155,3.4309821,46,4,5.8241816,177,671997.44,69.014816,4629.6465,178,459.08984,32237.061,12216.636 +156,2.7051506,47,4,166.88625,383,2285897.5,70.657295,4891.9014,178,448.41797,30508.834,12216.636 +157,3.2948494,47,4,4.9959264,274,1980018.8,69.792152,4865.7471,178,453.97656,30672.824,12216.636 +158,0.98894149,48,2,114.23679,0,1195344.4,80.295242,6018.9507,178,394.59375,24796.049,12216.636 +159,1.182127,48,3,55.910877,274,2741649,80.140541,6005.0312,178,395.35547,24853.525,12216.636 +160,3.0480838,49,4,81.635147,126,1503485.5,81.069695,6023.3394,178,390.82422,24777.984,12216.636 +161,2.0113289,49,4,108.93696,334,2477706.5,81.778351,6069.8652,178,387.4375,24588.059,12216.636 +162,2.940587,49,4,30.296598,330,1952532.9,82.620514,6154.3496,178,383.48828,24250.523,12216.636 +163,3.1072955,50,3,40.717644,287,1715661.2,62.152149,4446.2324,178,509.78125,33566.891,12216.636 +164,1.1072954,51,1,63.598595,0,651424.19,44.939854,3176.8967,178,705.03125,46978.613,12216.636 +165,3.0436037,52,4,4.4063578,96,605797.19,66.459404,4746.5186,178,476.74219,31443.299,12216.636 +166,2.9563963,52,4,90.654068,109,1062591.8,67.1894,4814.7637,178,471.5625,30997.617,12216.636 +167,3.0721309,53,4,143.34143,93,2134044,75.842278,5481.8882,178,417.76172,27225.328,12216.636 +168,2.9278691,53,4,141.29507,294,2936599.2,76.411003,5523.6138,178,414.65234,27019.666,12216.636 +169,4,54,4,64.827652,299,1046788.9,60.478722,4116.709,178,523.88672,36253.766,12216.636 +170,1.9948233,55,3,26.562881,53,334537.75,46.611523,3140.5879,178,679.74609,47521.742,12216.636 +171,1.9981046,55,3,23.211634,55,313906.69,46.611523,3140.5879,178,679.74609,47521.742,12216.636 +172,1.9839985,56,2,62.202236,0,264440.84,42.862148,2839.1758,178,739.20703,52566.734,12216.636 +173,2.0713086,57,3,25.08102,68,396381.09,52.447456,3490.3325,178,604.10938,42759.883,12216.636 +174,1.9357636,57,3,25.400402,91,432314.75,55.001724,3657.7,178,576.05469,40803.289,12216.636 +175,2.0160015,58,2,63.467106,26,283843.69,43.754169,2897.7686,178,724.13672,51503.84,12216.636 +176,4,59,4,106.14331,8,866621.44,63.394745,4639.7456,178,499.78906,32166.893,12216.636 +177,4,60,4,245.73332,0,2100469,73.744011,5285.8833,178,429.64844,28234.865,12216.636 diff --git a/testdata/barnsbury_segment_lines.mif b/testdata/barnsbury_segment_lines.mif new file mode 100644 index 00000000..83981572 --- /dev/null +++ b/testdata/barnsbury_segment_lines.mif @@ -0,0 +1,377 @@ +Version 300 +Charset "WindowsLatin1" +Delimiter "," +Index 1 +CoordSys NonEarth Units "m" Bounds (530635.696268, 183499.852969) (531446.820644, 184583.962646) +Columns 13 + Depthmap_Ref Integer + Angular_Connectivity Float + Axial_Line_Ref Float + Connectivity Float + Segment_Length Float + T1024_Choice Float + T1024_Choice_Segment_Length_Wgt_ Float + T1024_Integration Float + T1024_Integration_Segment_Length_Wgt_ Float + T1024_Node_Count Float + T1024_Total_Depth Float + T1024_Total_Depth_Segment_Length_Wgt_ Float + T1024_Total_Segment_Length Float +Data + +LINE 530661.6919780188 184270.5626832811 530670.3012171048 184204.951785912 + PEN (1,2,0) +LINE 530670.3012171048 184204.951785912 530681.0222267658 184123.2471128816 + PEN (1,2,0) +LINE 530681.0222267658 184123.2471128816 530712.6887355548 183881.9170676302 + PEN (1,2,0) +LINE 530712.6887355548 183881.9170676302 530730.7679409641 183744.1356819843 + PEN (1,2,0) +LINE 530661.6919780187 184270.562683281 530782.0935715765 184320.087685171 + PEN (1,2,0) +LINE 530782.0935715765 184320.087685171 530931.9721717195 184381.7375166726 + PEN (1,2,0) +LINE 530931.9721717195 184381.7375166726 531102.9365496121 184452.0605986855 + PEN (1,2,0) +LINE 531102.9365496121 184452.0605986855 531275.7084119404 184523.1271564901 + PEN (1,2,0) +LINE 531275.7084119404 184523.1271564901 531340.8293390643 184549.9134634117 + PEN (1,2,0) +LINE 530782.0935715765 184320.087685171 530796.6615005322 184257.2066049815 + PEN (1,2,0) +LINE 530796.6615005322 184257.2066049815 530808.6826332469 184205.3185286112 + PEN (1,2,0) +LINE 530808.6826332469 184205.3185286112 530811.0516134852 184195.09305066 + PEN (1,2,0) +LINE 530670.3012171047 184204.9517859119 530796.6615005322 184257.2066049815 + PEN (1,2,0) +LINE 530796.6615005322 184257.2066049815 530930.0609102942 184312.3723725155 + PEN (1,2,0) +LINE 530930.0609102942 184312.3723725155 531122.4555083865 184391.9349110013 + PEN (1,2,0) +LINE 530804.6982026402 184201.4318404568 530811.0516134852 184195.0930506599 + PEN (1,2,0) +LINE 530811.0516134852 184195.0930506599 530855.3978358759 184150.8488818384 + PEN (1,2,0) +LINE 530755.4256480751 184153.3679956899 530804.6982026402 184201.4318404567 + PEN (1,2,0) +LINE 530804.6982026402 184201.4318404567 530808.6826332469 184205.3185286112 + PEN (1,2,0) +LINE 530755.4256480752 184153.36799569 530759.8102694125 184121.9498409454 + PEN (1,2,0) +LINE 530759.8102694125 184121.9498409454 530781.0080675455 183970.0562905679 + PEN (1,2,0) +LINE 530681.0222267658 184123.2471128815 530759.8102694125 184121.9498409453 + PEN (1,2,0) +LINE 530759.8102694125 184121.9498409453 530852.4203537111 184120.4249843892 + PEN (1,2,0) +LINE 530852.4203537111 184120.4249843892 530924.739253607 184119.2342290901 + PEN (1,2,0) +LINE 530924.739253607 184119.2342290901 531002.80539858 184117.9488434448 + PEN (1,2,0) +LINE 531002.80539858 184117.9488434448 531040.9791199062 184117.3203001314 + PEN (1,2,0) +LINE 531040.9791199062 184117.3203001314 531060.7828570851 184116.994224859 + PEN (1,2,0) +LINE 530837.552389062 183968.5041980529 530852.4203537111 184120.4249843893 + PEN (1,2,0) +LINE 530852.4203537111 184120.4249843893 530855.3978358759 184150.8488818385 + PEN (1,2,0) +LINE 530781.0080675455 183970.0562905679 530817.2676436539 183969.0609966963 + PEN (1,2,0) +LINE 530817.2676436539 183969.0609966963 530837.5523890621 183968.5041980528 + PEN (1,2,0) +LINE 530804.1027903862 183678.9148130685 530806.9873013139 183742.4878602049 + PEN (1,2,0) +LINE 530806.9873013139 183742.4878602049 530810.2568850133 183814.5477011403 + PEN (1,2,0) +LINE 530810.2568850133 183814.5477011403 530813.4051007051 183883.9326574047 + PEN (1,2,0) +LINE 530813.4051007051 183883.9326574047 530817.2676436539 183969.0609966964 + PEN (1,2,0) +LINE 530806.9873013139 183742.4878602049 530914.4265599075 183744.9570759712 + PEN (1,2,0) +LINE 530912.2449280558 183665.7794156555 530912.5669577819 183677.46679556 + PEN (1,2,0) +LINE 530912.5669577819 183677.46679556 530914.4265599076 183744.9570759712 + PEN (1,2,0) +LINE 530914.4265599076 183744.9570759712 530916.3881318528 183816.1481328081 + PEN (1,2,0) +LINE 530916.3881318528 183816.1481328081 530918.3136899534 183886.0321442102 + PEN (1,2,0) +LINE 530918.3136899534 183886.0321442102 530922.4249214346 184035.2404945642 + PEN (1,2,0) +LINE 530922.4249214346 184035.2404945642 530924.739253607 184119.2342290901 + PEN (1,2,0) +LINE 530924.739253607 184119.2342290901 530930.0609102943 184312.3723725156 + PEN (1,2,0) +LINE 530930.0609102943 184312.3723725156 530931.9721717195 184381.7375166726 + PEN (1,2,0) +LINE 530997.7409700139 184191.5792263541 531069.1018140045 184204.9679402672 + PEN (1,2,0) +LINE 531069.1018140045 184204.9679402672 531176.6039484286 184225.1374792238 + PEN (1,2,0) +LINE 531176.6039484286 184225.1374792238 531408.9765464333 184268.7352011949 + PEN (1,2,0) +LINE 530997.7409700138 184191.5792263541 531002.8053985799 184117.9488434448 + PEN (1,2,0) +LINE 531065.9075465151 184257.7680519287 531065.9774551002 184256.612487747 + PEN (1,2,0) +LINE 531065.9774551002 184256.612487747 531069.1018140046 184204.9679402672 + PEN (1,2,0) +LINE 531014.260003 184282.658893 531065.9075465151 184257.7680519287 + PEN (1,2,0) +LINE 531065.9075465151 184257.7680519287 531067.5050192737 184256.9981713527 + PEN (1,2,0) +LINE 531065.9774551002 184256.612487747 531067.5050192737 184256.9981713527 + PEN (1,2,0) +LINE 531067.5050192737 184256.9981713527 531158.7795115133 184280.0434063022 + PEN (1,2,0) +LINE 531158.7795115133 184280.0434063022 531391.9665625809 184338.919114588 + PEN (1,2,0) +LINE 531102.9365496121 184452.0605986855 531122.4555083866 184391.9349110013 + PEN (1,2,0) +LINE 531122.4555083866 184391.9349110013 531139.6837024501 184338.8656347355 + PEN (1,2,0) +LINE 531139.6837024501 184338.8656347355 531158.7795115134 184280.0434063022 + PEN (1,2,0) +LINE 531158.7795115134 184280.0434063022 531176.6039484288 184225.1374792239 + PEN (1,2,0) +LINE 531176.6039484288 184225.1374792239 531200.8056679327 184150.5871384435 + PEN (1,2,0) +LINE 531200.8056679327 184150.5871384435 531224.4474343648 184077.7616623912 + PEN (1,2,0) +LINE 531224.4474343648 184077.7616623912 531226.6869048447 184070.8632563747 + PEN (1,2,0) +LINE 531222.0221921728 184069.6481218071 531226.6869048446 184070.8632563747 + PEN (1,2,0) +LINE 531226.6869048446 184070.8632563747 531282.1014374334 184085.2984678934 + PEN (1,2,0) +LINE 531282.1014374334 184085.2984678934 531360.8131579099 184105.8024815699 + PEN (1,2,0) +LINE 531360.8131579099 184105.8024815699 531427.9171605199 184123.2827421834 + PEN (1,2,0) +LINE 531427.9171605199 184123.2827421834 531443.2601697572 184127.2795201643 + PEN (1,2,0) +LINE 531168.4909565911 183890.5617386632 531168.6344222261 183891.0416966056 + PEN (1,2,0) +LINE 531168.6344222261 183891.0416966056 531177.6062062277 183921.056403528 + PEN (1,2,0) +LINE 531177.6062062277 183921.056403528 531183.345230286 183940.256054913 + PEN (1,2,0) +LINE 531183.345230286 183940.256054913 531206.5272470647 184017.8104676549 + PEN (1,2,0) +LINE 531206.5272470647 184017.8104676549 531222.0221921728 184069.6481218071 + PEN (1,2,0) +LINE 531222.0221921728 184069.6481218071 531224.4474343648 184077.7616623912 + PEN (1,2,0) +LINE 531103.958023 183944.145791 531183.3452302859 183940.256054913 + PEN (1,2,0) +LINE 531275.7084119404 184523.1271564901 531297.5108320001 184441.573404 + PEN (1,2,0) +LINE 531340.8293390643 184549.9134634118 531374.1604658248 184412.3878235204 + PEN (1,2,0) +LINE 531374.1604658248 184412.3878235204 531391.9665625809 184338.9191145881 + PEN (1,2,0) +LINE 531391.9665625809 184338.9191145881 531408.9765464333 184268.7352011949 + PEN (1,2,0) +LINE 531408.9765464333 184268.7352011949 531426.238998241 184197.5095943315 + PEN (1,2,0) +LINE 531426.238998241 184197.5095943315 531433.4141573964 184167.9045839381 + PEN (1,2,0) +LINE 531433.4141573964 184167.9045839381 531443.2601697572 184127.2795201643 + PEN (1,2,0) +LINE 531040.9791199062 184117.3203001315 531060.55370366 184121.3946202041 + PEN (1,2,0) +LINE 531060.55370366 184121.3946202041 531140.7934071338 184138.0959834922 + PEN (1,2,0) +LINE 531140.7934071338 184138.0959834922 531200.8056679327 184150.5871384435 + PEN (1,2,0) +LINE 531200.8056679327 184150.5871384435 531426.238998241 184197.5095943315 + PEN (1,2,0) +LINE 531426.238998241 184197.5095943315 531437.3460188021 184199.8214471601 + PEN (1,2,0) +LINE 531379.770131822 183732.4495029183 531382.4238646072 183753.9911641308 + PEN (1,2,0) +LINE 531382.4238646072 183753.9911641308 531401.5139900263 183908.9551516768 + PEN (1,2,0) +LINE 531401.5139900263 183908.9551516768 531402.0484051576 183913.2932635508 + PEN (1,2,0) +LINE 531402.0484051576 183913.2932635508 531417.1525502533 184035.9010778593 + PEN (1,2,0) +LINE 531417.1525502533 184035.9010778593 531427.9171605199 184123.2827421833 + PEN (1,2,0) +LINE 531427.9171605199 184123.2827421833 531433.4141573964 184167.9045839381 + PEN (1,2,0) +LINE 531433.4141573964 184167.9045839381 531437.346018802 184199.8214471601 + PEN (1,2,0) +LINE 531375.1001237407 183572.3943911834 531387.3458877866 183728.4277266877 + PEN (1,2,0) +LINE 531387.3458877866 183728.4277266877 531389.5752537736 183756.833909406 + PEN (1,2,0) +LINE 531389.5752537736 183756.833909406 531401.5139900263 183908.9551516768 + PEN (1,2,0) +LINE 531401.5139900263 183908.9551516768 531401.8529595991 183913.2742413547 + PEN (1,2,0) +LINE 531297.7582437188 183720.3357738068 531303.0868777729 183722.4539565722 + PEN (1,2,0) +LINE 531303.0868777729 183722.4539565722 531357.7029968201 183744.1643838416 + PEN (1,2,0) +LINE 531357.7029968201 183744.1643838416 531382.4238646072 183753.9911641308 + PEN (1,2,0) +LINE 531382.4238646072 183753.9911641308 531389.5752537737 183756.8339094061 + PEN (1,2,0) +LINE 531299.4468674023 183775.0910818076 531311.8200189774 183768.5224902194 + PEN (1,2,0) +LINE 531311.8200189774 183768.5224902194 531357.7029968201 183744.1643838416 + PEN (1,2,0) +LINE 531357.7029968201 183744.1643838416 531379.7701318221 183732.4495029183 + PEN (1,2,0) +LINE 531379.7701318221 183732.4495029183 531387.3458877866 183728.4277266877 + PEN (1,2,0) +LINE 531304.3126897123 183959.5738054356 531306.4967095837 183903.9934713184 + PEN (1,2,0) +LINE 531306.4967095837 183903.9934713184 531311.2924203729 183781.9491568425 + PEN (1,2,0) +LINE 531311.2924203729 183781.9491568425 531311.8200189773 183768.5224902195 + PEN (1,2,0) +LINE 531075.4349141666 183881.5048417101 531156.8807901648 183889.4317520639 + PEN (1,2,0) +LINE 531156.8807901648 183889.4317520639 531168.4909565911 183890.5617386632 + PEN (1,2,0) +LINE 531168.4909565911 183890.5617386632 531174.6616614035 183891.1623169401 + PEN (1,2,0) +LINE 531174.6616614035 183891.1623169401 531180.0459325081 183891.6863537172 + PEN (1,2,0) +LINE 531180.0459325081 183891.6863537172 531246.8460016274 183898.1878266653 + PEN (1,2,0) +LINE 531246.8460016274 183898.1878266653 531306.4967095837 183903.9934713184 + PEN (1,2,0) +LINE 531306.4967095837 183903.9934713184 531401.8529595992 183913.2742413547 + PEN (1,2,0) +LINE 531401.8529595992 183913.2742413547 531402.0484051576 183913.2932635508 + PEN (1,2,0) +LINE 531056.0095225013 183972.3751082587 531073.8019170946 183889.1438577853 + PEN (1,2,0) +LINE 531073.8019170946 183889.1438577853 531075.4349141666 183881.5048417101 + PEN (1,2,0) +LINE 530986.8482115235 183887.4036937163 531004.8354864263 183965.872851334 + PEN (1,2,0) +LINE 531004.8354864263 183965.872851334 531056.0095225013 183972.3751082587 + PEN (1,2,0) +LINE 530712.6887355547 183881.9170676303 530813.4051007051 183883.9326574047 + PEN (1,2,0) +LINE 530813.4051007051 183883.9326574047 530918.3136899534 183886.0321442102 + PEN (1,2,0) +LINE 530918.3136899534 183886.0321442102 530986.8482115236 183887.4036937163 + PEN (1,2,0) +LINE 530986.8482115236 183887.4036937163 531029.2914457454 183888.2530904232 + PEN (1,2,0) +LINE 531029.2914457454 183888.2530904232 531073.8019170945 183889.1438577853 + PEN (1,2,0) +LINE 531073.8019170945 183889.1438577853 531157.1301833935 183890.8114676243 + PEN (1,2,0) +LINE 531157.1301833935 183890.8114676243 531168.6344222261 183891.0416966057 + PEN (1,2,0) +LINE 531168.6344222261 183891.0416966057 531174.6616614035 183891.1623169401 + PEN (1,2,0) +LINE 531174.6616614035 183891.1623169401 531180.0804551976 183891.2707607402 + PEN (1,2,0) +LINE 531246.8460016274 183898.1878266653 531247.100529 183877.364907 + PEN (1,2,0) +LINE 531380.713483092 184038.9336762212 531417.1525502533 184035.9010778593 + PEN (1,2,0) +LINE 531367.8635018886 184047.3232328322 531380.713483092 184038.9336762213 + PEN (1,2,0) +LINE 531360.8131579099 184105.8024815699 531367.8635018887 184047.323232832 + PEN (1,2,0) +LINE 531177.6062062277 183921.056403528 531180.0459325082 183891.6863537173 + PEN (1,2,0) +LINE 531180.0459325082 183891.6863537173 531180.0804551976 183891.2707607402 + PEN (1,2,0) +LINE 531180.0804551976 183891.2707607402 531191.9656390148 183748.1938739985 + PEN (1,2,0) +LINE 531191.9656390148 183748.1938739985 531210.2193315655 183528.4512480644 + PEN (1,2,0) +LINE 531210.2193315655 183528.4512480644 531210.6054995636 183523.8024588018 + PEN (1,2,0) +LINE 531204.5299233167 183526.934937537 531210.2193315655 183528.4512480644 + PEN (1,2,0) +LINE 531210.2193315655 183528.4512480644 531294.1006655393 183550.8068506498 + PEN (1,2,0) +LINE 531294.1006655393 183550.8068506498 531375.1001237407 183572.3943911835 + PEN (1,2,0) +LINE 530912.5669577818 183677.4667955601 530942.3204781786 183662.1263132498 + PEN (1,2,0) +LINE 530942.3204781786 183662.1263132498 531101.0050300843 183580.3108665743 + PEN (1,2,0) +LINE 531101.0050300843 183580.3108665743 531204.5299233167 183526.9349375371 + PEN (1,2,0) +LINE 531204.5299233167 183526.9349375371 531210.6054995636 183523.8024588018 + PEN (1,2,0) +LINE 531101.0050300843 183580.3108665743 531156.8807901648 183889.4317520638 + PEN (1,2,0) +LINE 531156.8807901648 183889.4317520638 531157.1301833934 183890.8114676243 + PEN (1,2,0) +LINE 531029.2914457454 183888.2530904232 531030.230687 183855.631128 + PEN (1,2,0) +LINE 531191.9656390148 183748.1938739985 531247.2509705561 183744.8718613147 + PEN (1,2,0) +LINE 531247.2509705561 183744.8718613147 531255.3037282097 183744.3879831807 + PEN (1,2,0) +LINE 531247.2509705561 183744.8718613147 531250.8112866409 183746.9331340065 + PEN (1,2,0) +LINE 531250.8112866409 183746.9331340065 531299.4468674023 183775.0910818077 + PEN (1,2,0) +LINE 531299.4468674023 183775.0910818077 531311.2924203731 183781.9491568425 + PEN (1,2,0) +LINE 531250.8112866409 183746.9331340066 531255.3037282097 183744.3879831806 + PEN (1,2,0) +LINE 531255.3037282097 183744.3879831806 531297.7582437188 183720.3357738067 + PEN (1,2,0) +LINE 531297.7582437188 183720.3357738067 531302.8256845656 183717.4648625085 + PEN (1,2,0) +LINE 531294.1006655394 183550.8068506498 531302.8256845657 183717.4648625084 + PEN (1,2,0) +LINE 531302.8256845657 183717.4648625084 531303.0868777729 183722.4539565722 + PEN (1,2,0) +LINE 530707.321114 183575.611283 530723.063264805 183688.7582135932 + PEN (1,2,0) +LINE 530723.063264805 183688.7582135932 530730.7679409641 183744.1356819843 + PEN (1,2,0) +LINE 530723.0632648049 183688.7582135932 530804.1027903862 183678.9148130685 + PEN (1,2,0) +LINE 530804.1027903862 183678.9148130685 530912.2449280557 183665.7794156555 + PEN (1,2,0) +LINE 530912.2449280557 183665.7794156555 530942.3204781786 183662.1263132498 + PEN (1,2,0) +LINE 531140.7934071338 184138.0959834922 531154.1331188128 184099.6254937419 + PEN (1,2,0) +LINE 531091.400795 184089.16428 531154.1331188127 184099.6254937418 + PEN (1,2,0) +LINE 531060.55370366 184121.3946202041 531060.7828570851 184116.994224859 + PEN (1,2,0) +LINE 531060.7828570851 184116.994224859 531065.4973380617 184026.4628259328 + PEN (1,2,0) +LINE 530922.4249214346 184035.2404945642 531065.4973380617 184026.4628259328 + PEN (1,2,0) +LINE 531065.4973380617 184026.4628259328 531206.5272470647 184017.8104676549 + PEN (1,2,0) +LINE 531282.1014374334 184085.2984678934 531294.5626424844 184021.6797343292 + PEN (1,2,0) +LINE 531268.4799450308 184016.6518545878 531294.5626424844 184021.6797343292 + PEN (1,2,0) +LINE 531294.5626424844 184021.6797343292 531317.3546726417 184026.0732824619 + PEN (1,2,0) +LINE 531268.4799450306 184016.6518545878 531279.5735313552 183955.446866539 + PEN (1,2,0) +LINE 531279.5735313554 183955.446866539 531304.3126897124 183959.5738054357 + PEN (1,2,0) +LINE 531304.3126897124 183959.5738054357 531329.3668766369 183963.7532967931 + PEN (1,2,0) +LINE 531317.3546726417 184026.0732824619 531329.3668766369 183963.7532967931 + PEN (1,2,0) +LINE 530810.2568850133 183814.5477011403 530916.3881318528 183816.148132808 + PEN (1,2,0) +LINE 531139.68370245 184338.8656347354 531374.1604658248 184412.3878235204 + PEN (1,2,0) diff --git a/testdata/barnsbury_segment_pline.mid b/testdata/barnsbury_segment_pline.mid new file mode 100644 index 00000000..b0c31332 --- /dev/null +++ b/testdata/barnsbury_segment_pline.mid @@ -0,0 +1,177 @@ +0,2.0012004,0,3,66.173325,365,4156801.8,88.617859,6618.5718,178,357.53516,22549.607,12216.636 +1,1.7398858,0,4,82.40506,983,9028389,89.036148,6680.416,178,355.85547,22340.854,12216.636 +2,2.0232198,0,4,243.39876,1211,9372838,87.789162,6583.7954,178,360.91016,22668.717,12216.636 +3,1.2413905,0,3,138.96246,487,4206866.5,84.789192,6377.4712,178,373.67969,23402.096,12216.636 +4,1.9381289,1,3,130.18936,330,4186343.2,89.3825,6714.5283,178,354.47656,22227.355,12216.636 +5,2.1624684,1,4,162.06264,692,5878021,90.132393,6768.0562,178,351.52734,22051.561,12216.636 +6,1.7826266,1,4,184.86253,1342,11232938,93.362,7145.4531,178,339.36719,20886.877,12216.636 +7,2.0335331,1,4,186.81696,1021,8303167,94.585724,7241.9897,178,334.97656,20608.453,12216.636 +9,4,2,5,64.546532,308,1653464.4,67.747787,4992.2837,178,467.67578,29895.375,12216.636 +10,2.6528366,2,5,53.262371,385,1758330.9,66.705902,4920.8042,178,474.98047,30329.635,12216.636 +11,3.3471634,2,4,10.496307,238,1142586.6,66.317581,4891.7046,178,477.76172,30510.059,12216.636 +12,4,3,5,136.73875,450,4882207.5,80.08831,6026.8027,178,395.61328,24763.744,12216.636 +13,4,3,6,144.35603,309,4674048.5,80.518425,6047.978,178,393.5,24677.041,12216.636 +14,4,3,5,208.19673,618,6827499,82.457573,6239.9404,178,384.24609,23917.889,12216.636 +15,3.6441982,4,4,8.9747467,0,86300.844,54.864071,3917.8215,178,577.5,38094.18,12216.636 +16,0.91864121,4,3,62.642906,408,1356859.4,61.200176,4461.4165,178,517.71094,33452.648,12216.636 +17,1.5875411,5,3,68.832535,189,772664.94,57.446114,4183.127,178,551.54297,35678.145,12216.636 +18,3.0086384,5,4,5.5661507,55,472367.16,57.439606,4182.6602,178,551.60547,35682.125,12216.636 +19,2.5961795,6,4,31.722631,347,1240084.2,67.549751,4859.6494,178,469.04688,30711.309,12216.636 +20,2.8942552,6,4,153.36557,17,792264.5,64.708687,4663.2021,178,489.64062,32005.088,12216.636 +21,4,7,5,78.798721,521,3768654.8,94.541626,6940.915,178,335.13281,21502.381,12216.636 +22,4,7,6,92.622635,1212,6392349,94.387596,6921.416,178,335.67969,21562.957,12216.636 +23,4,7,6,72.328705,2026,9513038,94.350273,6925.3647,178,335.8125,21550.662,12216.636 +24,3.0542002,7,5,78.076729,2484,10539197,94.411774,6929.8618,178,335.59375,21536.678,12216.636 +25,1.086924,7,4,38.178894,2364,9562418,94.596756,6949.0996,178,334.9375,21477.057,12216.636 +26,3.8588758,7,4,19.806421,183,1061214.2,70.44252,5291.4692,178,449.78516,28205.059,12216.636 +27,2.9553642,8,4,152.64659,251,1603799.8,67.250679,4869.6396,178,471.13281,30648.303,12216.636 +28,2.5628395,8,4,30.569248,568,1731472.4,65.794159,4767.6074,178,481.5625,31304.215,12216.636 +29,1.9056505,9,3,36.273235,29,378006.91,60.132584,4206.0908,178,526.90234,35483.352,12216.636 +30,1.9439689,9,3,20.292385,218,1091423.4,60.404408,4222.1895,178,524.53125,35348.059,12216.636 +31,2.9565058,10,4,63.638454,179,1265680.5,76.827156,5356.625,178,412.40625,27861.982,12216.636 +32,2.0050292,10,4,72.13398,318,1992266.2,76.798058,5353.8901,178,412.5625,27876.215,12216.636 +33,3.038465,10,5,69.456345,451,2690610.5,76.773346,5351.5645,178,412.69531,27888.332,12216.636 +34,4,10,5,85.215919,289,1667870.4,75.121597,5252.0879,178,421.76953,28416.547,12216.636 +35,4,11,4,107.46763,2,838417.31,63.447308,4644.291,178,499.375,32135.412,12216.636 +36,3.2855186,12,4,11.691815,194,1175906.4,91.489624,6918.437,178,346.3125,21572.242,12216.636 +37,1.7466468,12,4,67.515892,1345,8545044,93.415764,7065.1655,178,339.17188,21124.232,12216.636 +38,1.9949708,12,4,71.218079,1564,10169552,93.450203,7068.7441,178,339.04688,21113.537,12216.636 +39,2.9728639,12,5,69.910538,1838,11861826,93.480362,7072.0098,178,338.9375,21103.789,12216.636 +40,3.021472,12,5,149.26498,2287,15157395,92.603081,7028.9722,178,342.14844,21233.004,12216.636 +41,2.9785283,12,5,84.025612,2172,14630360,92.644333,7033.8105,178,341.99609,21218.398,12216.636 +42,4,12,6,193.21144,1244,11365588,92.635872,7033.4829,178,342.02734,21219.387,12216.636 +43,4,12,5,69.391472,768,7140941.5,93.896996,7157.6016,178,337.43359,20851.426,12216.636 +44,1.8460462,13,3,72.605972,316,1933160.2,78.073212,5514.459,178,405.82422,27064.521,12216.636 +45,3.079603,13,5,109.37788,478,2846059,77.863358,5500.2261,178,406.91797,27134.557,12216.636 +46,4,13,5,236.42712,473,4039082.2,78.030403,5565.8442,178,406.04688,26814.656,12216.636 +47,2.9256492,14,3,73.804344,175,1367621.2,65.590919,4713.0044,178,483.05469,31666.893,12216.636 +48,3.118978,15,4,1.1576769,21,52568.5,54.646725,3815.7188,178,579.79688,39113.523,12216.636 +49,2.881022,15,4,51.738968,143,588109.5,57.167553,4008.4851,178,554.23047,37232.57,12216.636 +50,0.67563176,16,2,57.332561,0,576803.94,65.119614,4571.0322,178,486.55078,32650.436,12216.636 +51,3.3243682,16,4,1.773312,279,1124254.5,64.529015,4523.1011,178,491.00391,32996.434,12216.636 +52,3.5566537,17,4,1.5755012,185,842638.75,76.248665,5384.1821,178,415.53516,27719.381,12216.636 +53,2.4433463,17,5,94.138809,909,2878055.8,76.660873,5397.0391,178,413.30078,27653.35,12216.636 +54,4,17,5,240.50478,375,3247603.5,76.669571,5422.1479,178,413.25391,27525.291,12216.636 +55,2.9502037,18,4,63.214619,480,4244460.5,103.37621,7594.2671,178,306.49219,19652.482,12216.636 +56,2.043396,18,4,55.795689,1247,10353393,102.60077,7508.9897,178,308.80859,19875.67,12216.636 +57,3.0064003,18,5,61.844196,1345,9701150,102.59558,7507.5396,178,308.82422,19879.51,12216.636 +58,4,18,6,57.726696,1684,8941627,102.73723,7506.4736,178,308.39844,19882.332,12216.636 +59,4,18,6,78.380333,1829,7873546.5,102.76196,7497.6934,178,308.32422,19905.615,12216.636 +60,2.3847485,18,5,76.566856,2421,9062067,103.37885,7527.7261,178,306.48438,19826.199,12216.636 +61,3.6152513,18,4,7.2528086,254,949294.31,80.944298,6096.1309,178,391.42969,24482.119,12216.636 +62,3.0376058,19,4,4.8203835,969,3415459,88.060799,6053.9453,178,359.79688,24652.717,12216.636 +63,2.0014875,19,4,57.263824,1257,4270006.5,88.909271,6120.3413,178,356.36328,24385.273,12216.636 +64,2.0467546,19,4,81.338486,1219,4250588,89.006836,6125.0562,178,355.97266,24366.502,12216.636 +65,2.9141521,19,5,69.343399,1026,3768641.5,89.135948,6129.8477,178,355.45703,24347.457,12216.636 +66,2.9891434,19,4,15.855036,146,408590.09,92.881973,6344.1655,178,341.12109,23524.953,12216.636 +67,4,20,5,0.50094116,218,1162905.5,95.223106,6722.3511,178,332.73438,22201.488,12216.636 +68,3.7623262,20,5,31.326914,1285,4497112,96.855942,6966.7446,178,327.125,21422.658,12216.636 +69,1.3914185,20,4,20.039038,3505,11620107,109.44092,7678.6113,178,289.50781,19436.613,12216.636 +70,1.9921591,20,4,80.945,3493,11790712,109.55621,7688.1909,178,289.20312,19412.395,12216.636 +71,1.5069535,20,4,54.103935,3332,11531442,110.02882,7732.5884,178,287.96094,19300.938,12216.636 +72,3.3471429,20,4,8.468255,2263,8132306,104.11933,7376.3535,178,304.30469,20233.059,12216.636 +73,2,21,2,79.482445,0,724714.19,68.040466,4773.4067,178,465.66406,31266.18,12216.636 +74,2,22,2,84.41777,0,884771.5,61.031174,4482.9517,178,519.14453,33291.949,12216.636 +75,2.0549963,23,3,141.50713,807,5807270,108.51846,7723.2334,178,291.96875,19324.314,12216.636 +76,2.0359912,23,4,75.595688,1018,8256845,108.48653,7714.8027,178,292.05469,19345.434,12216.636 +77,2.0393751,23,4,72.215797,1600,11373205,108.45172,7712.0181,178,292.14844,19352.418,12216.636 +78,2.9666958,23,5,73.287651,2234,14429388,108.67695,7731.8662,178,291.54297,19302.74,12216.636 +79,4,23,6,30.462101,3298,17047350,109.00117,7758.3276,178,290.67578,19236.904,12216.636 +80,2.9891434,23,4,41.801193,7,305486.44,81.780823,6039.9316,178,387.42578,24709.916,12216.636 +81,3.0975204,24,4,19.99411,1982,8221255.5,94.571388,6882.4766,178,335.02734,21684.955,12216.636 +82,1.8206327,24,4,81.959412,2197,8739249,94.774712,6903.2329,178,334.30859,21619.754,12216.636 +83,3.081847,24,5,61.298454,2277,8390308,94.681778,6897.7725,178,334.63672,21636.869,12216.636 +84,4,24,6,230.26486,1424,6303539,94.330521,6897.4736,178,335.88281,21637.807,12216.636 +85,3.2086754,24,4,11.345068,44,144973.97,94.284462,6899.8101,178,336.04688,21630.479,12216.636 +86,4,25,5,21.704504,197,477300.16,96.725426,6661.9341,178,327.56641,22402.832,12216.636 +87,4,25,6,156.13542,1787,5874959,98.494301,6724.2876,178,321.68359,22195.096,12216.636 +88,3.1397986,25,5,4.3709054,2150,9321218,104.76485,7310.2856,178,302.42969,20415.92,12216.636 +89,1.8853738,25,4,123.53465,3623,16552666,109.2331,7622.9595,178,290.05859,19578.512,12216.636 +90,2.9748278,25,5,88.042221,3490,16621146,109.28609,7624.9824,178,289.91797,19573.316,12216.636 +91,4,25,6,44.959156,3443,16985778,113.6598,7907.6191,178,278.76172,18873.721,12216.636 +92,3.2086754,25,4,32.158134,68,200538.19,101.16245,6671.1152,178,313.19922,22372,12216.636 +93,1.5234891,26,3,156.51314,880,4697371,104.36852,7220.9028,178,303.57812,20668.635,12216.636 +94,2.5515666,26,4,28.49353,680,4084668.8,101.46744,7087.5713,178,312.25781,21057.453,12216.636 +95,2.7092693,26,5,152.589,817,4337584,103.78361,7169.0215,178,305.28906,20818.209,12216.636 +96,4,26,5,4.3323708,614,2229197,76.315384,5204.4497,178,415.17188,28676.652,12216.636 +97,3.2741685,27,4,5.734199,492,997931.38,80.218208,5351.3374,178,394.97266,27889.516,12216.636 +98,2.7258315,27,5,58.77298,1042,3266476.5,81.474419,5444.9028,178,388.88281,27410.258,12216.636 +99,4,27,6,26.602385,1344,4041288.8,82.973801,5525.2549,178,381.85547,27011.643,12216.636 +100,4,27,5,7.6956849,33,207832.08,82.114479,5449.6763,178,385.85156,27386.25,12216.636 +101,3.3356996,28,4,14.008615,194,486196.19,70.869667,4749.543,178,447.07422,31423.277,12216.636 +102,2.6643004,28,5,51.947716,511,1172606.5,75.637886,5014.8662,178,418.89062,29760.754,12216.636 +103,3.2326641,28,5,24.983932,284,761697.12,76.392288,5051.4565,178,414.75391,29545.182,12216.636 +104,2.7673359,28,4,8.5771065,207,681293.75,82.713196,5482.2207,178,383.05859,27223.676,12216.636 +105,4,29,5,55.623226,382,1242717.2,74.394005,4952.0566,178,425.89453,30138.227,12216.636 +106,2.6909027,29,5,122.1385,689,2199216.8,73.854805,4909.8218,178,429.00391,30397.479,12216.636 +107,3.3090973,29,4,13.437029,331,745346.69,72.762947,4875.8032,178,435.44141,30609.561,12216.636 +108,2.9276934,30,4,81.830719,222,678286.44,89.582893,5963.4609,178,353.68359,25026.775,12216.636 +109,2.7533221,30,5,11.665026,481,3171357.2,90.295944,6051.2231,178,350.89062,24663.807,12216.636 +110,3.2466779,30,5,6.1998625,338,2045784.5,86.868698,5836.5537,178,364.73438,25570.945,12216.636 +111,4,30,6,5.4097123,2668,11407769,105.92642,7445.8682,178,299.11328,20044.162,12216.636 +112,3.0539846,30,5,67.115707,2883,12051203,105.87665,7443.2124,178,299.25391,20051.316,12216.636 +113,2.9460154,30,5,59.932568,2769,11646952,105.91536,7444.0581,178,299.14453,20049.037,12216.636 +114,3.1116269,30,5,95.806824,2047,9289722,105.9901,7445.4268,178,298.93359,20045.352,12216.636 +115,2.8883731,30,4,0.19636907,1405,6988613.5,107.35222,7529.5103,178,295.14062,19821.502,12216.636 +116,2.9463861,31,4,85.111755,76,584308.75,69.896194,4771.4482,178,453.30078,31279.014,12216.636 +117,2.9276934,31,4,7.8116097,118,404667.56,71.989281,4957.4209,178,440.12109,30105.613,12216.636 +118,2.7760887,32,3,80.504349,40,465632.84,67.132118,4718.7378,178,471.96484,31628.416,12216.636 +119,1.7224751,33,2,51.585476,7,210206.28,53.71521,3717.9077,178,589.85156,40142.523,12216.636 +120,4,34,5,100.73653,1167,7415106.5,108.31992,7600.376,178,292.50391,19636.688,12216.636 +121,4,34,6,104.9296,1762,9997418,108.30835,7603.0674,178,292.53516,19629.736,12216.636 +122,2.8438091,34,5,68.548241,2983,14175580,108.05441,7573.5566,178,293.22266,19706.225,12216.636 +123,2.1506054,34,4,42.451733,3055,14141106,107.82458,7557.7256,178,293.84766,19747.502,12216.636 +124,3.0055857,34,5,44.519382,3227,14320575,107.82172,7557.6279,178,293.85547,19747.756,12216.636 +125,3.1265831,34,5,83.344948,3250,14420084,107.70002,7561.4126,178,294.1875,19737.873,12216.636 +126,2.8734171,34,5,11.506542,3430,13727606,107.9753,7599.6616,178,293.4375,19638.531,12216.636 +127,4,34,6,6.0284462,2657,10569333,105.04842,7428.769,178,301.61328,20090.301,12216.636 +128,4,34,5,5.419879,326,1180875.9,86.131653,6176.9673,178,367.85547,24161.727,12216.636 +129,2,35,2,20.824474,0,212491.75,66.399551,4603.9497,178,477.17188,32416.992,12216.636 +130,2.315361,36,3,36.565041,182,517014.62,69.343452,4775.4722,178,456.91406,31252.656,12216.636 +131,0.87075675,37,2,15.346227,109,383297.66,64.659164,4430.2266,178,490.01562,33688.164,12216.636 +132,2.5553956,38,3,58.902714,107,482010.88,60.524754,4128.2837,178,523.48828,36152.117,12216.636 +133,4,39,5,29.471209,2132,7106502.5,102.01877,7046.436,178,310.57031,21180.381,12216.636 +134,3.0400231,39,5,0.41702437,1868,6555843,102.04957,7047.5352,178,310.47656,21177.078,12216.636 +135,1.8690072,39,4,143.56969,2082,7028887,103.00992,7118.877,178,307.58203,20964.852,12216.636 +136,3.0909696,39,5,220.49948,633,2843580.8,102.03416,7091.9126,178,310.52344,21044.562,12216.636 +137,3.3558173,39,4,4.6648011,60,48442.176,102.77367,7156.9517,178,308.28906,20853.32,12216.636 +138,4,40,5,5.8880019,1198,6602856.5,92.347939,6651.4351,178,343.09375,22438.195,12216.636 +139,2.8008873,40,5,86.80928,1314,6988477.5,90.596497,6541.2188,178,349.72656,22816.268,12216.636 +140,1.9834378,40,3,83.826813,874,4874680,89.554214,6493.5498,178,353.79688,22983.762,12216.636 +141,3.7738943,41,4,33.475399,963,7042259,84.994438,6210.7104,178,372.77734,24030.455,12216.636 +142,1.4153167,41,4,178.53447,1362,8652835,90.345222,6721.4429,178,350.69922,22204.488,12216.636 +143,1.2796584,41,4,116.47486,1233,6833815.5,91.196457,6782.4829,178,347.42578,22004.656,12216.636 +144,2.8869476,41,3,6.8355722,0,32039.699,81.984169,6130.0171,178,386.46484,24346.783,12216.636 +145,3.9999998,42,5,314.13025,147,2550125.8,75.341393,5244.0146,178,420.53906,28460.293,12216.636 +146,4,42,5,1.4020742,28,787264.31,73.82859,5159.4937,178,429.15625,28926.521,12216.636 +147,2,43,2,32.635479,0,340282.88,67.405479,4677.939,178,470.05078,31904.262,12216.636 +148,2.372308,44,4,55.385048,1325,2879153,77.915718,5145.1392,178,406.64453,29007.223,12216.636 +149,3.6276922,44,4,8.0672827,538,1295412.9,74.798775,5021.2231,178,423.58984,29723.076,12216.636 +150,2.6622484,45,4,4.1139636,523,1247895.5,72.8479,4776.5571,178,434.93359,31245.559,12216.636 +151,1.9825487,45,4,56.198662,461,1198154.6,72.054512,4745.6021,178,439.72266,31449.371,12216.636 +152,3.3552032,45,4,13.687597,169,627264.94,69.173141,4584.3516,178,458.03906,32555.576,12216.636 +153,3.7100596,46,4,5.1633153,55,157636.45,69.908241,4694.3491,178,453.22266,31792.736,12216.636 +154,0.85895824,46,4,48.794411,682,1540374.1,74.486237,4990.52,178,425.36719,29905.941,12216.636 +155,3.4309821,46,4,5.8241816,177,671997.44,69.014816,4629.6465,178,459.08984,32237.061,12216.636 +156,2.7051506,47,4,166.88625,383,2285897.5,70.657295,4891.9014,178,448.41797,30508.834,12216.636 +157,3.2948494,47,4,4.9959264,274,1980018.8,69.792152,4865.7471,178,453.97656,30672.824,12216.636 +158,0.98894149,48,2,114.23679,0,1195344.4,80.295242,6018.9507,178,394.59375,24796.049,12216.636 +159,1.182127,48,3,55.910877,274,2741649,80.140541,6005.0312,178,395.35547,24853.525,12216.636 +160,3.0480838,49,4,81.635147,126,1503485.5,81.069695,6023.3394,178,390.82422,24777.984,12216.636 +161,2.0113289,49,4,108.93696,334,2477706.5,81.778351,6069.8652,178,387.4375,24588.059,12216.636 +162,2.940587,49,4,30.296598,330,1952532.9,82.620514,6154.3496,178,383.48828,24250.523,12216.636 +163,3.1072955,50,3,40.717644,287,1715661.2,62.152149,4446.2324,178,509.78125,33566.891,12216.636 +164,1.1072954,51,1,63.598595,0,651424.19,44.939854,3176.8967,178,705.03125,46978.613,12216.636 +165,3.0436037,52,4,4.4063578,96,605797.19,66.459404,4746.5186,178,476.74219,31443.299,12216.636 +166,2.9563963,52,4,90.654068,109,1062591.8,67.1894,4814.7637,178,471.5625,30997.617,12216.636 +167,3.0721309,53,4,143.34143,93,2134044,75.842278,5481.8882,178,417.76172,27225.328,12216.636 +168,2.9278691,53,4,141.29507,294,2936599.2,76.411003,5523.6138,178,414.65234,27019.666,12216.636 +169,4,54,4,64.827652,299,1046788.9,60.478722,4116.709,178,523.88672,36253.766,12216.636 +170,1.9948233,55,3,26.562881,53,334537.75,46.611523,3140.5879,178,679.74609,47521.742,12216.636 +171,1.9981046,55,3,23.211634,55,313906.69,46.611523,3140.5879,178,679.74609,47521.742,12216.636 +172,1.9839985,56,2,62.202236,0,264440.84,42.862148,2839.1758,178,739.20703,52566.734,12216.636 +173,2.0713086,57,3,25.08102,68,396381.09,52.447456,3490.3325,178,604.10938,42759.883,12216.636 +174,1.9357636,57,3,25.400402,91,432314.75,55.001724,3657.7,178,576.05469,40803.289,12216.636 +175,2.0160015,58,2,63.467106,26,283843.69,43.754169,2897.7686,178,724.13672,51503.84,12216.636 +176,4,59,4,106.14331,8,866621.44,63.394745,4639.7456,178,499.78906,32166.893,12216.636 +177,4,60,4,245.73332,0,2100469,73.744011,5285.8833,178,429.64844,28234.865,12216.636 diff --git a/testdata/barnsbury_segment_pline.mif b/testdata/barnsbury_segment_pline.mif new file mode 100644 index 00000000..844eadc0 --- /dev/null +++ b/testdata/barnsbury_segment_pline.mif @@ -0,0 +1,378 @@ +Version 300 +Charset "WindowsLatin1" +Delimiter "," +Index 1 +CoordSys NonEarth Units "m" Bounds (530635.696268, 183499.852969) (531446.820644, 184583.962646) +Columns 13 + Depthmap_Ref Integer + Angular_Connectivity Float + Axial_Line_Ref Float + Connectivity Float + Segment_Length Float + T1024_Choice Float + T1024_Choice_Segment_Length_Wgt_ Float + T1024_Integration Float + T1024_Integration_Segment_Length_Wgt_ Float + T1024_Node_Count Float + T1024_Total_Depth Float + T1024_Total_Depth_Segment_Length_Wgt_ Float + T1024_Total_Segment_Length Float +Data + +LINE 530661.6919780188 184270.5626832811 530670.3012171048 184204.951785912 + PEN (1,2,0) +LINE 530670.3012171048 184204.951785912 530681.0222267658 184123.2471128816 + PEN (1,2,0) +LINE 530681.0222267658 184123.2471128816 530712.6887355548 183881.9170676302 + PEN (1,2,0) +LINE 530712.6887355548 183881.9170676302 530730.7679409641 183744.1356819843 + PEN (1,2,0) +LINE 530661.6919780187 184270.562683281 530782.0935715765 184320.087685171 + PEN (1,2,0) +LINE 530782.0935715765 184320.087685171 530931.9721717195 184381.7375166726 + PEN (1,2,0) +LINE 530931.9721717195 184381.7375166726 531102.9365496121 184452.0605986855 + PEN (1,2,0) +LINE 531102.9365496121 184452.0605986855 531275.7084119404 184523.1271564901 + PEN (1,2,0) +LINE 530782.0935715765 184320.087685171 530796.6615005322 184257.2066049815 + PEN (1,2,0) +LINE 530796.6615005322 184257.2066049815 530808.6826332469 184205.3185286112 + PEN (1,2,0) +LINE 530808.6826332469 184205.3185286112 530811.0516134852 184195.09305066 + PEN (1,2,0) +LINE 530670.3012171047 184204.9517859119 530796.6615005322 184257.2066049815 + PEN (1,2,0) +LINE 530796.6615005322 184257.2066049815 530930.0609102942 184312.3723725155 + PEN (1,2,0) +LINE 530930.0609102942 184312.3723725155 531122.4555083865 184391.9349110013 + PEN (1,2,0) +LINE 530804.6982026402 184201.4318404568 530811.0516134852 184195.0930506599 + PEN (1,2,0) +LINE 530811.0516134852 184195.0930506599 530855.3978358759 184150.8488818384 + PEN (1,2,0) +LINE 530755.4256480751 184153.3679956899 530804.6982026402 184201.4318404567 + PEN (1,2,0) +LINE 530804.6982026402 184201.4318404567 530808.6826332469 184205.3185286112 + PEN (1,2,0) +LINE 530755.4256480752 184153.36799569 530759.8102694125 184121.9498409454 + PEN (1,2,0) +LINE 530759.8102694125 184121.9498409454 530781.0080675455 183970.0562905679 + PEN (1,2,0) +LINE 530681.0222267658 184123.2471128815 530759.8102694125 184121.9498409453 + PEN (1,2,0) +LINE 530759.8102694125 184121.9498409453 530852.4203537111 184120.4249843892 + PEN (1,2,0) +LINE 530852.4203537111 184120.4249843892 530924.739253607 184119.2342290901 + PEN (1,2,0) +LINE 530924.739253607 184119.2342290901 531002.80539858 184117.9488434448 + PEN (1,2,0) +LINE 531002.80539858 184117.9488434448 531040.9791199062 184117.3203001314 + PEN (1,2,0) +LINE 531040.9791199062 184117.3203001314 531060.7828570851 184116.994224859 + PEN (1,2,0) +LINE 530837.552389062 183968.5041980529 530852.4203537111 184120.4249843893 + PEN (1,2,0) +LINE 530852.4203537111 184120.4249843893 530855.3978358759 184150.8488818385 + PEN (1,2,0) +LINE 530781.0080675455 183970.0562905679 530817.2676436539 183969.0609966963 + PEN (1,2,0) +LINE 530817.2676436539 183969.0609966963 530837.5523890621 183968.5041980528 + PEN (1,2,0) +LINE 530804.1027903862 183678.9148130685 530806.9873013139 183742.4878602049 + PEN (1,2,0) +LINE 530806.9873013139 183742.4878602049 530810.2568850133 183814.5477011403 + PEN (1,2,0) +LINE 530810.2568850133 183814.5477011403 530813.4051007051 183883.9326574047 + PEN (1,2,0) +LINE 530813.4051007051 183883.9326574047 530817.2676436539 183969.0609966964 + PEN (1,2,0) +LINE 530806.9873013139 183742.4878602049 530914.4265599075 183744.9570759712 + PEN (1,2,0) +LINE 530912.2449280558 183665.7794156555 530912.5669577819 183677.46679556 + PEN (1,2,0) +LINE 530912.5669577819 183677.46679556 530914.4265599076 183744.9570759712 + PEN (1,2,0) +LINE 530914.4265599076 183744.9570759712 530916.3881318528 183816.1481328081 + PEN (1,2,0) +LINE 530916.3881318528 183816.1481328081 530918.3136899534 183886.0321442102 + PEN (1,2,0) +LINE 530918.3136899534 183886.0321442102 530922.4249214346 184035.2404945642 + PEN (1,2,0) +LINE 530922.4249214346 184035.2404945642 530924.739253607 184119.2342290901 + PEN (1,2,0) +LINE 530924.739253607 184119.2342290901 530930.0609102943 184312.3723725156 + PEN (1,2,0) +LINE 530930.0609102943 184312.3723725156 530931.9721717195 184381.7375166726 + PEN (1,2,0) +LINE 530997.7409700139 184191.5792263541 531069.1018140045 184204.9679402672 + PEN (1,2,0) +LINE 531069.1018140045 184204.9679402672 531176.6039484286 184225.1374792238 + PEN (1,2,0) +LINE 531176.6039484286 184225.1374792238 531408.9765464333 184268.7352011949 + PEN (1,2,0) +LINE 530997.7409700138 184191.5792263541 531002.8053985799 184117.9488434448 + PEN (1,2,0) +LINE 531065.9075465151 184257.7680519287 531065.9774551002 184256.612487747 + PEN (1,2,0) +LINE 531065.9774551002 184256.612487747 531069.1018140046 184204.9679402672 + PEN (1,2,0) +LINE 531014.260003 184282.658893 531065.9075465151 184257.7680519287 + PEN (1,2,0) +LINE 531065.9075465151 184257.7680519287 531067.5050192737 184256.9981713527 + PEN (1,2,0) +LINE 531065.9774551002 184256.612487747 531067.5050192737 184256.9981713527 + PEN (1,2,0) +LINE 531067.5050192737 184256.9981713527 531158.7795115133 184280.0434063022 + PEN (1,2,0) +LINE 531158.7795115133 184280.0434063022 531391.9665625809 184338.919114588 + PEN (1,2,0) +LINE 531102.9365496121 184452.0605986855 531122.4555083866 184391.9349110013 + PEN (1,2,0) +LINE 531122.4555083866 184391.9349110013 531139.6837024501 184338.8656347355 + PEN (1,2,0) +LINE 531139.6837024501 184338.8656347355 531158.7795115134 184280.0434063022 + PEN (1,2,0) +LINE 531158.7795115134 184280.0434063022 531176.6039484288 184225.1374792239 + PEN (1,2,0) +LINE 531176.6039484288 184225.1374792239 531200.8056679327 184150.5871384435 + PEN (1,2,0) +LINE 531200.8056679327 184150.5871384435 531224.4474343648 184077.7616623912 + PEN (1,2,0) +LINE 531224.4474343648 184077.7616623912 531226.6869048447 184070.8632563747 + PEN (1,2,0) +LINE 531222.0221921728 184069.6481218071 531226.6869048446 184070.8632563747 + PEN (1,2,0) +LINE 531226.6869048446 184070.8632563747 531282.1014374334 184085.2984678934 + PEN (1,2,0) +LINE 531282.1014374334 184085.2984678934 531360.8131579099 184105.8024815699 + PEN (1,2,0) +LINE 531360.8131579099 184105.8024815699 531427.9171605199 184123.2827421834 + PEN (1,2,0) +LINE 531427.9171605199 184123.2827421834 531443.2601697572 184127.2795201643 + PEN (1,2,0) +LINE 531168.4909565911 183890.5617386632 531168.6344222261 183891.0416966056 + PEN (1,2,0) +LINE 531168.6344222261 183891.0416966056 531177.6062062277 183921.056403528 + PEN (1,2,0) +LINE 531177.6062062277 183921.056403528 531183.345230286 183940.256054913 + PEN (1,2,0) +LINE 531183.345230286 183940.256054913 531206.5272470647 184017.8104676549 + PEN (1,2,0) +LINE 531206.5272470647 184017.8104676549 531222.0221921728 184069.6481218071 + PEN (1,2,0) +LINE 531222.0221921728 184069.6481218071 531224.4474343648 184077.7616623912 + PEN (1,2,0) +LINE 531103.958023 183944.145791 531183.3452302859 183940.256054913 + PEN (1,2,0) +PLINE 3 +531297.5108320001 184441.573404 +531275.7084119404 184523.1271564901 +531340.8293390643 184549.9134634117 + PEN (1,2,0) +LINE 531340.8293390643 184549.9134634118 531374.1604658248 184412.3878235204 + PEN (1,2,0) +LINE 531374.1604658248 184412.3878235204 531391.9665625809 184338.9191145881 + PEN (1,2,0) +LINE 531391.9665625809 184338.9191145881 531408.9765464333 184268.7352011949 + PEN (1,2,0) +LINE 531408.9765464333 184268.7352011949 531426.238998241 184197.5095943315 + PEN (1,2,0) +LINE 531426.238998241 184197.5095943315 531433.4141573964 184167.9045839381 + PEN (1,2,0) +LINE 531433.4141573964 184167.9045839381 531443.2601697572 184127.2795201643 + PEN (1,2,0) +LINE 531040.9791199062 184117.3203001315 531060.55370366 184121.3946202041 + PEN (1,2,0) +LINE 531060.55370366 184121.3946202041 531140.7934071338 184138.0959834922 + PEN (1,2,0) +LINE 531140.7934071338 184138.0959834922 531200.8056679327 184150.5871384435 + PEN (1,2,0) +LINE 531200.8056679327 184150.5871384435 531426.238998241 184197.5095943315 + PEN (1,2,0) +LINE 531426.238998241 184197.5095943315 531437.3460188021 184199.8214471601 + PEN (1,2,0) +LINE 531379.770131822 183732.4495029183 531382.4238646072 183753.9911641308 + PEN (1,2,0) +LINE 531382.4238646072 183753.9911641308 531401.5139900263 183908.9551516768 + PEN (1,2,0) +LINE 531401.5139900263 183908.9551516768 531402.0484051576 183913.2932635508 + PEN (1,2,0) +LINE 531402.0484051576 183913.2932635508 531417.1525502533 184035.9010778593 + PEN (1,2,0) +LINE 531417.1525502533 184035.9010778593 531427.9171605199 184123.2827421833 + PEN (1,2,0) +LINE 531427.9171605199 184123.2827421833 531433.4141573964 184167.9045839381 + PEN (1,2,0) +LINE 531433.4141573964 184167.9045839381 531437.346018802 184199.8214471601 + PEN (1,2,0) +LINE 531375.1001237407 183572.3943911834 531387.3458877866 183728.4277266877 + PEN (1,2,0) +LINE 531387.3458877866 183728.4277266877 531389.5752537736 183756.833909406 + PEN (1,2,0) +LINE 531389.5752537736 183756.833909406 531401.5139900263 183908.9551516768 + PEN (1,2,0) +LINE 531401.5139900263 183908.9551516768 531401.8529595991 183913.2742413547 + PEN (1,2,0) +LINE 531297.7582437188 183720.3357738068 531303.0868777729 183722.4539565722 + PEN (1,2,0) +LINE 531303.0868777729 183722.4539565722 531357.7029968201 183744.1643838416 + PEN (1,2,0) +LINE 531357.7029968201 183744.1643838416 531382.4238646072 183753.9911641308 + PEN (1,2,0) +LINE 531382.4238646072 183753.9911641308 531389.5752537737 183756.8339094061 + PEN (1,2,0) +LINE 531299.4468674023 183775.0910818076 531311.8200189774 183768.5224902194 + PEN (1,2,0) +LINE 531311.8200189774 183768.5224902194 531357.7029968201 183744.1643838416 + PEN (1,2,0) +LINE 531357.7029968201 183744.1643838416 531379.7701318221 183732.4495029183 + PEN (1,2,0) +LINE 531379.7701318221 183732.4495029183 531387.3458877866 183728.4277266877 + PEN (1,2,0) +LINE 531304.3126897123 183959.5738054356 531306.4967095837 183903.9934713184 + PEN (1,2,0) +LINE 531306.4967095837 183903.9934713184 531311.2924203729 183781.9491568425 + PEN (1,2,0) +LINE 531311.2924203729 183781.9491568425 531311.8200189773 183768.5224902195 + PEN (1,2,0) +LINE 531075.4349141666 183881.5048417101 531156.8807901648 183889.4317520639 + PEN (1,2,0) +LINE 531156.8807901648 183889.4317520639 531168.4909565911 183890.5617386632 + PEN (1,2,0) +LINE 531168.4909565911 183890.5617386632 531174.6616614035 183891.1623169401 + PEN (1,2,0) +LINE 531174.6616614035 183891.1623169401 531180.0459325081 183891.6863537172 + PEN (1,2,0) +LINE 531180.0459325081 183891.6863537172 531246.8460016274 183898.1878266653 + PEN (1,2,0) +LINE 531246.8460016274 183898.1878266653 531306.4967095837 183903.9934713184 + PEN (1,2,0) +LINE 531306.4967095837 183903.9934713184 531401.8529595992 183913.2742413547 + PEN (1,2,0) +LINE 531401.8529595992 183913.2742413547 531402.0484051576 183913.2932635508 + PEN (1,2,0) +LINE 531056.0095225013 183972.3751082587 531073.8019170946 183889.1438577853 + PEN (1,2,0) +LINE 531073.8019170946 183889.1438577853 531075.4349141666 183881.5048417101 + PEN (1,2,0) +LINE 530986.8482115235 183887.4036937163 531004.8354864263 183965.872851334 + PEN (1,2,0) +LINE 531004.8354864263 183965.872851334 531056.0095225013 183972.3751082587 + PEN (1,2,0) +LINE 530712.6887355547 183881.9170676303 530813.4051007051 183883.9326574047 + PEN (1,2,0) +LINE 530813.4051007051 183883.9326574047 530918.3136899534 183886.0321442102 + PEN (1,2,0) +LINE 530918.3136899534 183886.0321442102 530986.8482115236 183887.4036937163 + PEN (1,2,0) +LINE 530986.8482115236 183887.4036937163 531029.2914457454 183888.2530904232 + PEN (1,2,0) +LINE 531029.2914457454 183888.2530904232 531073.8019170945 183889.1438577853 + PEN (1,2,0) +LINE 531073.8019170945 183889.1438577853 531157.1301833935 183890.8114676243 + PEN (1,2,0) +LINE 531157.1301833935 183890.8114676243 531168.6344222261 183891.0416966057 + PEN (1,2,0) +LINE 531168.6344222261 183891.0416966057 531174.6616614035 183891.1623169401 + PEN (1,2,0) +LINE 531174.6616614035 183891.1623169401 531180.0804551976 183891.2707607402 + PEN (1,2,0) +LINE 531246.8460016274 183898.1878266653 531247.100529 183877.364907 + PEN (1,2,0) +LINE 531380.713483092 184038.9336762212 531417.1525502533 184035.9010778593 + PEN (1,2,0) +LINE 531367.8635018886 184047.3232328322 531380.713483092 184038.9336762213 + PEN (1,2,0) +LINE 531360.8131579099 184105.8024815699 531367.8635018887 184047.323232832 + PEN (1,2,0) +LINE 531177.6062062277 183921.056403528 531180.0459325082 183891.6863537173 + PEN (1,2,0) +LINE 531180.0459325082 183891.6863537173 531180.0804551976 183891.2707607402 + PEN (1,2,0) +LINE 531180.0804551976 183891.2707607402 531191.9656390148 183748.1938739985 + PEN (1,2,0) +LINE 531191.9656390148 183748.1938739985 531210.2193315655 183528.4512480644 + PEN (1,2,0) +LINE 531210.2193315655 183528.4512480644 531210.6054995636 183523.8024588018 + PEN (1,2,0) +LINE 531204.5299233167 183526.934937537 531210.2193315655 183528.4512480644 + PEN (1,2,0) +LINE 531210.2193315655 183528.4512480644 531294.1006655393 183550.8068506498 + PEN (1,2,0) +LINE 531294.1006655393 183550.8068506498 531375.1001237407 183572.3943911835 + PEN (1,2,0) +LINE 530912.5669577818 183677.4667955601 530942.3204781786 183662.1263132498 + PEN (1,2,0) +LINE 530942.3204781786 183662.1263132498 531101.0050300843 183580.3108665743 + PEN (1,2,0) +LINE 531101.0050300843 183580.3108665743 531204.5299233167 183526.9349375371 + PEN (1,2,0) +LINE 531204.5299233167 183526.9349375371 531210.6054995636 183523.8024588018 + PEN (1,2,0) +LINE 531101.0050300843 183580.3108665743 531156.8807901648 183889.4317520638 + PEN (1,2,0) +LINE 531156.8807901648 183889.4317520638 531157.1301833934 183890.8114676243 + PEN (1,2,0) +LINE 531029.2914457454 183888.2530904232 531030.230687 183855.631128 + PEN (1,2,0) +LINE 531191.9656390148 183748.1938739985 531247.2509705561 183744.8718613147 + PEN (1,2,0) +LINE 531247.2509705561 183744.8718613147 531255.3037282097 183744.3879831807 + PEN (1,2,0) +LINE 531247.2509705561 183744.8718613147 531250.8112866409 183746.9331340065 + PEN (1,2,0) +LINE 531250.8112866409 183746.9331340065 531299.4468674023 183775.0910818077 + PEN (1,2,0) +LINE 531299.4468674023 183775.0910818077 531311.2924203731 183781.9491568425 + PEN (1,2,0) +LINE 531250.8112866409 183746.9331340066 531255.3037282097 183744.3879831806 + PEN (1,2,0) +LINE 531255.3037282097 183744.3879831806 531297.7582437188 183720.3357738067 + PEN (1,2,0) +LINE 531297.7582437188 183720.3357738067 531302.8256845656 183717.4648625085 + PEN (1,2,0) +LINE 531294.1006655394 183550.8068506498 531302.8256845657 183717.4648625084 + PEN (1,2,0) +LINE 531302.8256845657 183717.4648625084 531303.0868777729 183722.4539565722 + PEN (1,2,0) +LINE 530707.321114 183575.611283 530723.063264805 183688.7582135932 + PEN (1,2,0) +LINE 530723.063264805 183688.7582135932 530730.7679409641 183744.1356819843 + PEN (1,2,0) +LINE 530723.0632648049 183688.7582135932 530804.1027903862 183678.9148130685 + PEN (1,2,0) +LINE 530804.1027903862 183678.9148130685 530912.2449280557 183665.7794156555 + PEN (1,2,0) +LINE 530912.2449280557 183665.7794156555 530942.3204781786 183662.1263132498 + PEN (1,2,0) +LINE 531140.7934071338 184138.0959834922 531154.1331188128 184099.6254937419 + PEN (1,2,0) +LINE 531091.400795 184089.16428 531154.1331188127 184099.6254937418 + PEN (1,2,0) +LINE 531060.55370366 184121.3946202041 531060.7828570851 184116.994224859 + PEN (1,2,0) +LINE 531060.7828570851 184116.994224859 531065.4973380617 184026.4628259328 + PEN (1,2,0) +LINE 530922.4249214346 184035.2404945642 531065.4973380617 184026.4628259328 + PEN (1,2,0) +LINE 531065.4973380617 184026.4628259328 531206.5272470647 184017.8104676549 + PEN (1,2,0) +LINE 531282.1014374334 184085.2984678934 531294.5626424844 184021.6797343292 + PEN (1,2,0) +LINE 531268.4799450308 184016.6518545878 531294.5626424844 184021.6797343292 + PEN (1,2,0) +LINE 531294.5626424844 184021.6797343292 531317.3546726417 184026.0732824619 + PEN (1,2,0) +LINE 531268.4799450306 184016.6518545878 531279.5735313552 183955.446866539 + PEN (1,2,0) +LINE 531279.5735313554 183955.446866539 531304.3126897124 183959.5738054357 + PEN (1,2,0) +LINE 531304.3126897124 183959.5738054357 531329.3668766369 183963.7532967931 + PEN (1,2,0) +LINE 531317.3546726417 184026.0732824619 531329.3668766369 183963.7532967931 + PEN (1,2,0) +LINE 530810.2568850133 183814.5477011403 530916.3881318528 183816.148132808 + PEN (1,2,0) +LINE 531139.68370245 184338.8656347354 531374.1604658248 184412.3878235204 + PEN (1,2,0) diff --git a/testdata/gallery_connected.graph b/testdata/gallery_connected.graph index 4bec9d24..98e3a279 100644 Binary files a/testdata/gallery_connected.graph and b/testdata/gallery_connected.graph differ diff --git a/testdata/gallery_connected_merge_links.txt b/testdata/gallery_connected_merge_links.txt new file mode 100644 index 00000000..d0be734e --- /dev/null +++ b/testdata/gallery_connected_merge_links.txt @@ -0,0 +1,3 @@ +x1 y1 x2 y2 +1.32 7.24 4.88 5.24 +1.16 5.28 3.28 7.12 \ No newline at end of file diff --git a/testdata/gallery_connected_with_isovist.graph b/testdata/gallery_connected_with_isovist.graph new file mode 100644 index 00000000..371c0d9c Binary files /dev/null and b/testdata/gallery_connected_with_isovist.graph differ diff --git a/testdata/gallery_empty.graph b/testdata/gallery_empty.graph new file mode 100644 index 00000000..c66e3b91 Binary files /dev/null and b/testdata/gallery_empty.graph differ diff --git a/testdata/gallery_graph_vga.txt b/testdata/gallery_graph_vga.txt new file mode 100644 index 00000000..731b20eb --- /dev/null +++ b/testdata/gallery_graph_vga.txt @@ -0,0 +1,4333 @@ +Ref x y Connectivity Point First Moment Point Second Moment +65592 0.68 7.04 91 28.691513 11.32 +65593 0.68 7.08 102 38.375195 22.076799 +65594 0.68 7.12 135 73.011009 62.731201 +65595 0.68 7.16 136 72.054672 61.1968 +65596 0.68 7.2 106 42.236126 26.406401 +65597 0.68 7.24 84 27.227448 11.824 +65599 0.68 7.32 81 22.344883 7.3119998 +65600 0.68 7.36 89 23.430403 7.4815998 +65601 0.68 7.4 91 23.329962 7.2992001 +65602 0.68 7.44 90 23.028296 7.2096 +65603 0.68 7.48 84 22.413893 7.2863998 +65604 0.68 7.52 82 23.040989 7.7199998 +65606 0.68 7.6 87 38.340282 26.313601 +65607 0.68 7.64 97 44.365986 32.124802 +65608 0.68 7.68 108 51.783161 38.5056 +65609 0.68 7.72 109 53.244698 39.591999 +65610 0.68 7.76 95 38.697723 23.264 +131128 0.72 7.04 102 32.769993 13.744 +131129 0.72 7.08 113 40.958103 22.486401 +131130 0.72 7.12 145 73.255661 59.785599 +131131 0.72 7.16 143 70.484398 57.271999 +131132 0.72 7.2 115 40.43277 22.9568 +131133 0.72 7.24 100 27.023703 9.5056 +131135 0.72 7.32 96 23.956745 7.1680002 +131136 0.72 7.36 100 23.603025 6.7919998 +131137 0.72 7.4 99 23.024195 6.5760002 +131138 0.72 7.44 101 23.552282 6.744 +131139 0.72 7.48 99 23.681519 6.9759998 +131140 0.72 7.52 84 21.68857 6.8175998 +131142 0.72 7.6 102 39.809086 25.363199 +131143 0.72 7.64 111 45.547054 30.568001 +131144 0.72 7.68 120 53.093029 36.9744 +131145 0.72 7.72 122 55.905392 38.9072 +131146 0.72 7.76 107 43.013672 25.2064 +196664 0.76 7.04 102 30.459377 12.1008 +196665 0.76 7.08 112 37.266163 19.3776 +196666 0.76 7.12 149 72.022911 57.112 +196667 0.76 7.16 148 68.984161 53.7952 +196668 0.76 7.2 124 40.585949 21.235201 +196669 0.76 7.24 117 30.89657 10.6496 +196670 0.76 7.28 93 20.425934 5.5376 +196671 0.76 7.32 109 24.63987 6.7328 +196672 0.76 7.36 104 22.756449 6.072 +196673 0.76 7.4 101 21.336105 5.552 +196674 0.76 7.44 101 21.455666 5.6431999 +196675 0.76 7.48 102 22.463762 6.1328001 +196676 0.76 7.52 108 24.524914 6.9071999 +196677 0.76 7.56 89 20.552114 6.0367999 +196678 0.76 7.6 120 41.944683 23.112 +196679 0.76 7.64 123 48.517162 30.854401 +196680 0.76 7.68 126 54.098293 36.628799 +196681 0.76 7.72 123 52.332752 34.1856 +196682 0.76 7.76 105 38.426586 20.742399 +262200 0.8 7.04 102 29.137228 11.4064 +262201 0.8 7.08 110 33.311489 15.5616 +262202 0.8 7.12 146 66.708405 51.478401 +262203 0.8 7.16 141 62.477539 47.959999 +262204 0.8 7.2 109 31.902433 15.9952 +262205 0.8 7.24 86 19.30418 5.7951999 +262207 0.8 7.32 86 18.253939 4.7839999 +262208 0.8 7.36 95 18.948063 4.6799998 +262209 0.8 7.4 100 19.752245 4.8271999 +262210 0.8 7.44 99 19.693623 4.8992 +262211 0.8 7.48 97 19.821554 5.0976 +262212 0.8 7.52 84 18.721516 5.2048001 +262214 0.8 7.6 91 28.888416 15.744 +262215 0.8 7.64 106 38.802296 24.692801 +262216 0.8 7.68 121 48.852211 32.195202 +262217 0.8 7.72 117 45.911297 28.656 +262218 0.8 7.76 101 32.795208 15.568 +327736 0.84 7.04 92 22.003006 6.9120002 +327737 0.84 7.08 94 22.683102 8.4639997 +327738 0.84 7.12 137 60.210972 46.257599 +327739 0.84 7.16 128 54.657177 41.9856 +327740 0.84 7.2 95 25.367149 12.0608 +327741 0.84 7.24 81 17.433615 4.9295998 +327743 0.84 7.32 81 16.459587 4.0864 +327744 0.84 7.36 83 14.9294 3.3248 +327745 0.84 7.4 83 14.046597 2.9375999 +327746 0.84 7.44 85 14.626451 3.1312001 +327747 0.84 7.48 82 15.306084 3.6256001 +327748 0.84 7.52 82 17.155693 4.4944 +327750 0.84 7.6 82 23.939941 12.0352 +327751 0.84 7.64 94 33.640411 21.4272 +327752 0.84 7.68 109 42.131927 27.832001 +327753 0.84 7.72 105 37.923157 22.9296 +327754 0.84 7.76 85 21.76741 8.0607996 +393257 0.88 6.44 42 8.7469444 2.3471999 +393258 0.88 6.48 60 21.750759 13.072 +393259 0.88 6.52 52 14.967987 8.0271997 +393260 0.88 6.56 38 5.786551 1.1824 +393261 0.88 6.6 36 5.377718 0.99040002 +393262 0.88 6.64 32 5.0924959 0.95520002 +393264 0.88 6.72 19 2.6990466 0.50400001 +393265 0.88 6.76 23 3.3436391 0.63840002 +393266 0.88 6.8 41 15.748744 11.216 +393272 0.88 7.04 87 19.072384 5.4000001 +393273 0.88 7.08 89 19.278217 6.4335999 +393274 0.88 7.12 133 56.964733 42.820801 +393275 0.88 7.16 126 51.609089 38.284801 +393276 0.88 7.2 91 22.262644 9.2992001 +393277 0.88 7.24 82 17.050226 4.5455999 +393279 0.88 7.32 78 15.038219 3.52 +393280 0.88 7.36 76 12.657201 2.5504 +393281 0.88 7.4 77 11.78551 2.1296 +393282 0.88 7.44 74 11.138371 1.9904 +393283 0.88 7.48 76 12.657201 2.5504 +393284 0.88 7.52 79 15.342851 3.6127999 +393286 0.88 7.6 77 19.342884 7.9136 +393287 0.88 7.64 95 33.131908 20.52 +393288 0.88 7.68 104 38.88245 24.937599 +393289 0.88 7.72 100 34.074253 19.812799 +393290 0.88 7.76 80 17.995335 5.3839998 +458760 0.92 5.12 165 66.93367 33.513599 +458761 0.92 5.16 183 85.820915 58.868801 +458762 0.92 5.2 188 92.159378 70.945602 +458763 0.92 5.24 176 77.418388 53.990398 +458764 0.92 5.28 162 58.95348 29.9216 +458765 0.92 5.32 158 54.271576 24.651199 +458766 0.92 5.36 154 52.546402 23.444799 +458767 0.92 5.4 148 49.678761 20.870399 +458768 0.92 5.44 148 51.960201 22.4608 +458769 0.92 5.48 146 53.062256 22.820801 +458793 0.92 6.44 39 6.8312845 1.576 +458794 0.92 6.48 63 21.049376 11.9184 +458795 0.92 6.52 61 18.974976 10.8656 +458796 0.92 6.56 43 6.1693482 1.2431999 +458797 0.92 6.6 39 5.2229948 0.87840003 +458798 0.92 6.64 34 4.710113 0.78399998 +458800 0.92 6.72 23 2.7589223 0.44319999 +458801 0.92 6.76 26 3.3965585 0.60159999 +458802 0.92 6.8 50 20.402479 15.1504 +458808 0.92 7.04 86 18.348515 4.9503999 +458809 0.92 7.08 85 16.344223 4.1072001 +458810 0.92 7.12 132 54.408939 39.214401 +458811 0.92 7.16 124 49.052952 35.003201 +458812 0.92 7.2 87 18.252306 5.7312002 +458813 0.92 7.24 82 16.702732 4.2672 +458815 0.92 7.32 75 13.818519 3.0064001 +458816 0.92 7.36 74 11.961161 2.296 +458817 0.92 7.4 71 10.338152 1.7664 +458818 0.92 7.44 74 11.186681 2.0128 +458819 0.92 7.48 75 12.361161 2.4560001 +458820 0.92 7.52 75 13.795877 2.9888 +458822 0.92 7.6 73 15.458254 4.5840001 +458823 0.92 7.64 96 32.269508 18.8832 +458824 0.92 7.68 106 38.398075 23.4496 +458825 0.92 7.72 96 30.719749 16.9056 +458826 0.92 7.76 77 16.528574 4.6464 +524296 0.96 5.12 170 65.611618 31.686399 +524297 0.96 5.16 185 80.567383 52.260799 +524298 0.96 5.2 190 87.514908 65.3424 +524299 0.96 5.24 178 72.879311 49.139198 +524300 0.96 5.28 165 55.563362 27.107201 +524301 0.96 5.32 158 49.380257 21.0224 +524302 0.96 5.36 154 47.384045 19.467199 +524303 0.96 5.4 154 49.08913 20.5168 +524304 0.96 5.44 147 46.757408 18.3888 +524305 0.96 5.48 147 49.904499 20.448 +524329 0.96 6.44 39 6.4416518 1.3728 +524330 0.96 6.48 46 7.9989877 2.0544 +524331 0.96 6.52 66 20.554316 11.4752 +524332 0.96 6.56 45 6.0541601 1.128 +524333 0.96 6.6 43 5.1857195 0.75040001 +524334 0.96 6.64 41 5.1097188 0.75199997 +524335 0.96 6.68 41 5.6790199 0.94400001 +524336 0.96 6.72 37 5.1659374 0.93440002 +524337 0.96 6.76 36 5.5656357 1.1727999 +524338 0.96 6.8 62 24.947359 17.566401 +524344 0.96 7.04 83 17.354012 4.5071998 +524345 0.96 7.08 85 16.445538 4.0672002 +524346 0.96 7.12 132 53.135281 36.686401 +524347 0.96 7.16 125 48.64756 33.326401 +524348 0.96 7.2 84 16.055588 3.9375999 +524349 0.96 7.24 81 16.333506 4.0256 +524351 0.96 7.32 74 13.893401 3.1024001 +524352 0.96 7.36 71 11.475163 2.2272 +524353 0.96 7.4 71 10.798904 1.9967999 +524354 0.96 7.44 71 10.798904 1.9967999 +524355 0.96 7.48 74 12.493398 2.5792 +524356 0.96 7.52 74 13.893401 3.1024001 +524358 0.96 7.6 71 14.112141 3.536 +524359 0.96 7.64 98 32.997417 18.627199 +524360 0.96 7.68 107 37.744858 21.912001 +524361 0.96 7.72 96 29.768179 15.5696 +524362 0.96 7.76 73 14.958081 3.9247999 +589832 1 5.12 174 65.324028 31.7024 +589833 1 5.16 191 80.142052 50.982399 +589834 1 5.2 196 86.54007 63.283199 +589835 1 5.24 185 71.888695 46.6544 +589836 1 5.28 168 52.231857 23.878401 +589837 1 5.32 162 46.649288 18.4704 +589838 1 5.36 155 43.29681 16.132799 +589839 1 5.4 152 43.631756 16.4608 +589840 1 5.44 147 43.177715 15.8464 +589841 1 5.48 146 45.879856 17.52 +589843 1 5.56 212 107.25992 67.764801 +589844 1 5.6 216 101.99606 61.403198 +589845 1 5.64 220 100.21715 60.7136 +589846 1 5.68 230 100.38043 58.627201 +589847 1 5.72 241 106.37511 65.305603 +589848 1 5.76 241 99.900703 55.569599 +589849 1 5.8 252 105.71748 60.641602 +589850 1 5.84 256 105.91825 59.209599 +589851 1 5.88 264 109.86177 61.683201 +589852 1 5.92 281 125.52368 78.787201 +589853 1 5.96 414 484.10068 1121.304 +589854 1 6 427 514.89673 1218.8016 +589855 1 6.04 253 99.349129 51.179199 +589856 1 6.08 240 90.816658 44.7328 +589857 1 6.12 233 88.308632 43.911999 +589858 1 6.16 229 89.718727 47.023998 +589859 1 6.2 225 91.70388 50.416 +589860 1 6.24 224 95.526314 54.923199 +589861 1 6.28 222 99.456749 59.547199 +589862 1 6.32 221 105.13754 66.409599 +589863 1 6.36 218 109.76509 72.201599 +589864 1 6.4 218 116.79842 80.283203 +589865 1 6.44 38 6.3326063 1.3472 +589866 1 6.48 39 5.4957714 1.008 +589867 1 6.52 68 19.654495 9.8448 +589868 1 6.56 47 6.4240294 1.1440001 +589869 1 6.6 42 5.0604815 0.72000003 +589870 1 6.64 43 5.5340395 0.83359998 +589871 1 6.68 41 5.8814182 1.0048 +589872 1 6.72 39 5.7991133 1.112 +589873 1 6.76 38 6.1722555 1.3552001 +589874 1 6.8 69 27.144375 17.591999 +589880 1 7.04 83 17.990992 4.8112001 +589881 1 7.08 85 16.966961 4.2816 +589882 1 7.12 131 51.405739 33.8176 +589883 1 7.16 127 48.663898 31.766399 +589884 1 7.2 84 16.444794 4.0560002 +589885 1 7.24 77 15.48338 3.7423999 +589887 1 7.32 71 13.650023 3.1487999 +589888 1 7.36 71 12.374516 2.688 +589889 1 7.4 71 11.717723 2.4576001 +589890 1 7.44 71 11.717723 2.4576001 +589891 1 7.48 71 12.374516 2.688 +589892 1 7.52 74 14.837963 3.6256001 +589894 1 7.6 72 14.669329 3.6896 +589895 1 7.64 99 33.070095 17.879999 +589896 1 7.68 109 37.3717 20.3248 +589897 1 7.72 92 25.653166 11.376 +589898 1 7.76 76 16.4391 4.4688001 +655368 1.04 5.12 185 70.707703 36.068802 +655369 1.04 5.16 200 82.991837 52.3008 +655370 1.04 5.2 203 87.04554 61.891201 +655371 1.04 5.24 191 71.526306 45.0224 +655372 1.04 5.28 174 50.286263 20.8176 +655373 1.04 5.32 163 43.158165 15.6176 +655374 1.04 5.36 158 40.13126 13.1984 +655375 1.04 5.4 154 40.521576 13.8096 +655376 1.04 5.44 149 40.65221 13.8448 +655377 1.04 5.48 149 45.182354 16.939199 +655379 1.04 5.56 213 104.11543 64.856003 +655380 1.04 5.6 219 99.478401 58.495998 +655381 1.04 5.64 228 97.976906 54.903999 +655382 1.04 5.68 238 99.395859 54.068802 +655383 1.04 5.72 244 98.362595 51.804798 +655384 1.04 5.76 243 94.415054 48.214401 +655385 1.04 5.8 249 96.081779 49.919998 +655386 1.04 5.84 251 94.582077 47.883202 +655387 1.04 5.88 263 103.27004 56.969601 +655388 1.04 5.92 278 114.54057 66.804802 +655389 1.04 5.96 422 479.3187 1093.4528 +655390 1.04 6 435 512.56006 1198.8096 +655391 1.04 6.04 260 99.806122 52.195202 +655392 1.04 6.08 245 89.754799 44.1744 +655393 1.04 6.12 237 86.903336 43.299198 +655394 1.04 6.16 230 85.214706 43.187199 +655395 1.04 6.2 226 87.20829 46.649601 +655396 1.04 6.24 224 91.479836 51.872002 +655397 1.04 6.28 224 97.737518 59.113602 +655398 1.04 6.32 221 102.05476 64.420799 +655399 1.04 6.36 222 110.06548 73.523201 +655400 1.04 6.4 220 115.99121 80.251198 +655401 1.04 6.44 36 6.2744389 1.3408 +655402 1.04 6.48 36 5.3756485 1.0064 +655403 1.04 6.52 65 18.366755 8.4927998 +655404 1.04 6.56 57 14.743288 7.4591999 +655405 1.04 6.6 37 5.0503135 0.81279999 +655406 1.04 6.64 31 4.4612322 0.74400002 +655408 1.04 6.72 18 2.0062213 0.2608 +655409 1.04 6.76 29 4.2443638 0.83520001 +655410 1.04 6.8 62 22.122965 12.3728 +655416 1.04 7.04 78 17.31529 4.7168002 +655417 1.04 7.08 82 16.922358 4.3968 +655418 1.04 7.12 134 51.703262 32.113602 +655419 1.04 7.16 129 48.897488 30.327999 +655420 1.04 7.2 83 17.000641 4.3712001 +655421 1.04 7.24 78 17.008938 4.5071998 +655423 1.04 7.32 71 14.932616 3.8399999 +655424 1.04 7.36 71 13.714247 3.3792 +655425 1.04 7.4 71 13.088058 3.1487999 +655426 1.04 7.44 71 13.088058 3.1487999 +655427 1.04 7.48 71 13.714247 3.3792 +655428 1.04 7.52 72 15.301398 3.9760001 +655430 1.04 7.6 69 14.367953 3.6784 +655431 1.04 7.64 101 33.710976 17.348801 +655432 1.04 7.68 111 38.165024 19.993601 +655433 1.04 7.72 89 23.107052 8.8240004 +655434 1.04 7.76 74 16.567806 4.6016002 +720904 1.08 5.12 201 85.265106 52.6576 +720905 1.08 5.16 219 96.503235 64.750397 +720906 1.08 5.2 221 97.311829 68.9888 +720907 1.08 5.24 208 80.383865 50.900799 +720908 1.08 5.28 186 54.491756 22.559999 +720909 1.08 5.32 175 46.611843 17.1024 +720910 1.08 5.36 170 43.306866 14.6224 +720911 1.08 5.4 157 38.037258 11.4528 +720912 1.08 5.44 154 40.53104 13.4224 +720913 1.08 5.48 151 44.117947 15.9408 +720915 1.08 5.56 217 103.57859 64.193604 +720916 1.08 5.6 233 103.64909 60.2896 +720917 1.08 5.64 249 107.57411 60.627201 +720918 1.08 5.68 250 102.89072 55.972801 +720919 1.08 5.72 247 96.681618 50.2416 +720920 1.08 5.76 246 91.196266 44.812801 +720921 1.08 5.8 239 83.17421 38.007999 +720922 1.08 5.84 246 84.507332 37.819199 +720923 1.08 5.88 255 88.889984 40.588799 +720924 1.08 5.92 271 100.64622 50.7808 +720925 1.08 5.96 420 464.32104 1053.4784 +720926 1.08 6 438 502.4375 1162.8032 +720927 1.08 6.04 262 97.8004 51.7584 +720928 1.08 6.08 249 89.923332 45.880001 +720929 1.08 6.12 244 89.665329 46.944 +720930 1.08 6.16 240 90.501976 48.556801 +720931 1.08 6.2 236 90.68074 49.062401 +720932 1.08 6.24 229 91.16906 51.459202 +720933 1.08 6.28 223 92.68647 54.448002 +720934 1.08 6.32 222 99.409882 61.992001 +720935 1.08 6.36 221 106.10816 69.472 +720936 1.08 6.4 220 113.45081 77.686401 +720940 1.08 6.56 71 20.965086 9.7296 +720946 1.08 6.8 58 19.021942 9.3984003 +720952 1.08 7.04 75 17.761301 5.1423998 +720953 1.08 7.08 81 18.331873 5.2160001 +720954 1.08 7.12 139 52.725243 30.7488 +720955 1.08 7.16 133 49.985279 29.2656 +720956 1.08 7.2 79 17.34952 4.7792001 +720957 1.08 7.24 73 17.017426 4.848 +720959 1.08 7.32 71 16.617079 4.7616 +720960 1.08 7.36 71 15.479453 4.3007998 +720961 1.08 7.4 71 14.896123 4.0704002 +720962 1.08 7.44 71 14.896123 4.0704002 +720963 1.08 7.48 71 15.479453 4.3007998 +720964 1.08 7.52 71 16.617079 4.7616 +720966 1.08 7.6 64 14.093885 3.8624001 +720967 1.08 7.64 104 34.644493 16.924801 +720968 1.08 7.68 117 39.738735 19.649599 +720969 1.08 7.72 81 18.180265 5.0896001 +720970 1.08 7.76 71 17.073963 5.1023998 +786440 1.12 5.12 222 105.24494 74.950401 +786441 1.12 5.16 240 115.82227 85.521599 +786442 1.12 5.2 253 123.48015 94.019203 +786443 1.12 5.24 241 108.07349 77.270401 +786444 1.12 5.28 224 83.020248 47.596802 +786445 1.12 5.32 215 73.595093 38.5728 +786446 1.12 5.36 203 62.694839 28.452801 +786447 1.12 5.4 186 50.151707 17.6096 +786448 1.12 5.44 170 43.757755 13.9776 +786449 1.12 5.48 152 41.806175 14.0688 +786451 1.12 5.56 242 113.68269 70.447998 +786452 1.12 5.6 262 117.61987 69.388802 +786453 1.12 5.64 258 109.08047 61.127998 +786454 1.12 5.68 253 101.17253 54.131199 +786455 1.12 5.72 246 92.258011 46.4496 +786456 1.12 5.76 244 87.631058 42.244801 +786457 1.12 5.8 244 84.167381 38.785599 +786458 1.12 5.84 247 82.466782 36.235199 +786459 1.12 5.88 253 84.713264 37.368 +786460 1.12 5.92 273 96.743423 45.743999 +786461 1.12 5.96 426 458.5546 1023.6816 +786462 1.12 6 442 494.19498 1128.5728 +786463 1.12 6.04 258 88.356987 40.793598 +786464 1.12 6.08 246 82.552757 37.849602 +786465 1.12 6.12 241 82.612152 39.492802 +786466 1.12 6.16 239 86.160301 44.464001 +786467 1.12 6.2 244 95.288597 54.080002 +786468 1.12 6.24 242 98.977119 58.5168 +786469 1.12 6.28 243 104.77968 64.435204 +786470 1.12 6.32 241 109.4513 69.924797 +786471 1.12 6.36 228 109.72643 73.9328 +786472 1.12 6.4 225 117.03373 82.486397 +786476 1.12 6.56 62 18.218618 7.9503999 +786477 1.12 6.6 20 5.7555542 2.3664 +786481 1.12 6.76 26 9.8878822 7.0176001 +786482 1.12 6.8 52 15.839282 7.1055999 +786488 1.12 7.04 71 18.672298 5.9136 +786489 1.12 7.08 72 17.730001 5.4608002 +786490 1.12 7.12 146 54.847942 30.200001 +786491 1.12 7.16 138 51.301807 28.3536 +786492 1.12 7.2 72 17.730001 5.4608002 +786493 1.12 7.24 71 18.672298 5.9136 +786495 1.12 7.32 71 18.672298 5.9136 +786496 1.12 7.36 71 17.640558 5.4527998 +786497 1.12 7.4 71 17.111734 5.2224002 +786498 1.12 7.44 71 17.111734 5.2224002 +786499 1.12 7.48 71 17.640558 5.4527998 +786500 1.12 7.52 71 18.672298 5.9136 +786502 1.12 7.6 59 14.904503 4.6240001 +786503 1.12 7.64 96 29.163681 12.432 +786504 1.12 7.68 126 42.3022 19.742399 +786505 1.12 7.72 79 20.070566 6.2848001 +786506 1.12 7.76 60 15.316328 4.7936001 +851976 1.16 5.12 247 137.85081 120.576 +851977 1.16 5.16 270 151.72148 132.2672 +851978 1.16 5.2 292 165.85542 144.75681 +851979 1.16 5.24 287 154.61871 129.496 +851980 1.16 5.28 276 134.90776 104.0944 +851981 1.16 5.32 274 129.03339 95.625603 +851982 1.16 5.36 281 130.14626 92.582397 +851983 1.16 5.4 293 133.61781 90.351997 +851984 1.16 5.44 308 140.19199 90.9888 +851985 1.16 5.48 338 153.3654 94.945602 +851986 1.16 5.52 323 145.52142 87.147202 +851987 1.16 5.56 291 130.96355 77.620796 +851988 1.16 5.6 270 117.02744 67.513603 +851989 1.16 5.64 256 105.24823 58.243198 +851990 1.16 5.68 251 98.281158 52.102402 +851991 1.16 5.72 247 92.117355 46.6432 +851992 1.16 5.76 246 87.953003 42.596802 +851993 1.16 5.8 245 84.261154 39.119999 +851994 1.16 5.84 244 81.195435 36.302399 +851995 1.16 5.88 253 83.914749 37.035198 +851996 1.16 5.92 272 93.959808 43.112 +851997 1.16 5.96 430 453.24344 995.08478 +851998 1.16 6 445 490.14673 1106.0176 +851999 1.16 6.04 257 86.69474 39.7728 +852000 1.16 6.08 244 81.058929 37.406399 +852001 1.16 6.12 240 81.971413 39.647999 +852002 1.16 6.16 239 84.279007 42.436798 +852003 1.16 6.2 237 87.589386 46.651199 +852004 1.16 6.24 236 91.037178 50.579201 +852005 1.16 6.28 236 96.239716 56.395199 +852006 1.16 6.32 235 100.86439 61.4944 +852007 1.16 6.36 243 113.20556 73.472 +852008 1.16 6.4 243 119.58923 80.463997 +852009 1.16 6.44 230 124.9934 88.265602 +852010 1.16 6.48 202 120.33929 91.358398 +852011 1.16 6.52 186 112.75641 89.536003 +852012 1.16 6.56 205 121.87601 97.833603 +852013 1.16 6.6 147 104.7407 93.800003 +852017 1.16 6.76 57 24.833809 15.8864 +852018 1.16 6.8 44 9.9302855 3.1168001 +852026 1.16 7.12 163 64.784515 34.340801 +852027 1.16 7.16 144 52.896118 27.5376 +852040 1.16 7.68 161 54.438843 23.993601 +917512 1.2 5.12 246 137.57756 120.8672 +917513 1.2 5.16 266 145.94574 125.0512 +917514 1.2 5.2 291 163.59375 141.66879 +917515 1.2 5.24 292 157.85568 132.1456 +917516 1.2 5.28 281 139.88554 109.5632 +917517 1.2 5.32 288 139.58795 104.5824 +917518 1.2 5.36 294 140.4044 101.4096 +917519 1.2 5.4 306 143.38818 98.267197 +917520 1.2 5.44 326 151.76048 99.255997 +917521 1.2 5.48 343 154.67224 95.127998 +917522 1.2 5.52 324 146.0336 87.472 +917523 1.2 5.56 283 126.25783 74.622398 +917524 1.2 5.6 266 114.69285 65.886398 +917525 1.2 5.64 256 105.75358 58.568001 +917526 1.2 5.68 251 98.867958 52.4944 +917527 1.2 5.72 246 92.229454 46.787201 +917528 1.2 5.76 246 88.418091 42.8592 +917529 1.2 5.8 244 84.38665 39.264 +917530 1.2 5.84 244 81.63163 36.543999 +917531 1.2 5.88 249 81.821136 35.728001 +917532 1.2 5.92 267 90.160553 40.088001 +917533 1.2 5.96 431 446.59192 965.71362 +917534 1.2 6 448 484.36115 1074.9744 +917535 1.2 6.04 253 84.029564 37.750401 +917536 1.2 6.08 243 80.949265 37.364799 +917537 1.2 6.12 239 81.516022 39.057598 +917538 1.2 6.16 237 84.236641 42.568001 +917539 1.2 6.2 236 87.061523 45.857601 +917540 1.2 6.24 236 91.572906 50.911999 +917541 1.2 6.28 235 95.593376 55.372799 +917542 1.2 6.32 235 101.39097 61.849602 +917543 1.2 6.36 235 107.81452 69.081596 +917544 1.2 6.4 236 115.03149 77.115196 +917545 1.2 6.44 224 120.73614 85.5616 +917546 1.2 6.48 204 122.0304 92.711998 +917547 1.2 6.52 206 128.2571 101.7552 +917548 1.2 6.56 209 127.82599 104.0576 +917549 1.2 6.6 225 138.94206 115.36 +917550 1.2 6.64 296 281.39178 393.31039 +917551 1.2 6.68 408 566.22046 1167.9471 +917552 1.2 6.72 284 336.39551 594.68323 +917553 1.2 6.76 150 103.21446 103.5504 +917554 1.2 6.8 104 81.547478 91.2304 +917560 1.2 7.04 123 48.489231 23.683201 +917561 1.2 7.08 136 51.483582 24.532801 +917562 1.2 7.12 211 81.96315 41.385601 +917563 1.2 7.16 214 79.477837 38.636799 +917564 1.2 7.2 145 46.551247 19.3232 +917565 1.2 7.24 133 37.725071 13.4416 +917566 1.2 7.28 125 32.879261 10.5744 +917567 1.2 7.32 127 33.38826 10.8032 +917568 1.2 7.36 126 33.146534 10.9888 +917569 1.2 7.4 129 34.862225 12.0784 +917570 1.2 7.44 130 36.19965 13.2736 +917571 1.2 7.48 133 39.013191 15.4656 +917572 1.2 7.52 133 40.155506 16.511999 +917573 1.2 7.56 139 45.493504 20.4928 +917574 1.2 7.6 153 56.11797 28.1824 +917575 1.2 7.64 196 75.505066 38.720001 +917576 1.2 7.68 223 89.657806 47.004799 +917577 1.2 7.72 166 71.787148 41.1152 +917578 1.2 7.76 143 65.271507 38.875198 +983048 1.24 5.12 226 111.19139 83.587196 +983049 1.24 5.16 244 115.20014 82.891197 +983050 1.24 5.2 269 131.98523 98.745598 +983051 1.24 5.24 258 117.84138 83.568001 +983052 1.24 5.28 238 93.102699 56.872002 +983053 1.24 5.32 228 83.389168 47.502399 +983054 1.24 5.36 219 74.208733 37.777599 +983055 1.24 5.4 200 58.768185 23.524799 +983056 1.24 5.44 179 46.988922 14.9984 +983057 1.24 5.48 153 41.388813 13.384 +983059 1.24 5.56 241 114.04466 70.736 +983060 1.24 5.6 253 112.82687 66.112 +983061 1.24 5.64 253 107.04154 59.937599 +983062 1.24 5.68 251 100.87364 53.915199 +983063 1.24 5.72 247 94.982964 48.672001 +983064 1.24 5.76 243 88.497856 42.731201 +983065 1.24 5.8 243 85.190964 39.4352 +983066 1.24 5.84 241 81.150291 35.723202 +983067 1.24 5.88 241 79.221191 34.001598 +983068 1.24 5.92 260 86.263924 36.848 +983069 1.24 5.96 430 439.03693 935.7392 +983070 1.24 6 444 474.38684 1040.9856 +983071 1.24 6.04 243 78.911758 34.075199 +983072 1.24 6.08 235 78.057892 35.360001 +983073 1.24 6.12 233 80.854286 39.060799 +983074 1.24 6.16 233 84.477333 43.348801 +983075 1.24 6.2 232 88.26947 47.9856 +983076 1.24 6.24 232 93.976311 54.705601 +983077 1.24 6.28 232 98.922691 60.209599 +983078 1.24 6.32 231 104.93917 67.223999 +983079 1.24 6.36 229 111.31284 74.912003 +983080 1.24 6.4 225 118.26382 83.3936 +983085 1.24 6.6 104 43.611366 27.625601 +983086 1.24 6.64 182 145.63892 183.8288 +983087 1.24 6.68 342 482.53427 1052.408 +983088 1.24 6.72 237 254.80272 457.22079 +983089 1.24 6.76 119 58.939407 44.348801 +983093 1.24 6.92 56 19.161268 9.5200005 +983094 1.24 6.96 64 24.614416 13.7424 +983095 1.24 7 27 5.9395099 1.7312 +983096 1.24 7.04 122 46.055771 22.236799 +983097 1.24 7.08 140 49.332321 22.590401 +983098 1.24 7.12 215 81.874825 40.316799 +983099 1.24 7.16 217 80.37545 38.715199 +983100 1.24 7.2 162 49.517242 19.7696 +983101 1.24 7.24 141 39.438698 14.2912 +983102 1.24 7.28 136 36.811031 13.0736 +983103 1.24 7.32 134 35.556854 12.4656 +983104 1.24 7.36 133 35.167522 12.48 +983105 1.24 7.4 133 35.704964 13.1248 +983106 1.24 7.44 134 37.18478 14.4752 +983107 1.24 7.48 134 38.123543 15.3792 +983108 1.24 7.52 138 41.564789 18.019199 +983109 1.24 7.56 141 44.655117 20.534401 +983110 1.24 7.6 159 54.966751 27.019199 +983111 1.24 7.64 197 75.319725 38.248001 +983112 1.24 7.68 226 91.852943 48.383999 +983113 1.24 7.72 182 76.349548 43.209599 +983114 1.24 7.76 148 67.077255 41.273602 +1048584 1.28 5.12 209 93.102089 62.768002 +1048585 1.28 5.16 217 89.114914 55.596802 +1048586 1.28 5.2 245 106.78829 71.027199 +1048587 1.28 5.24 230 88.319824 51.944 +1048588 1.28 5.28 196 57.961826 24.448 +1048589 1.28 5.32 182 47.71101 16.6448 +1048590 1.28 5.36 173 42.742016 13.232 +1048591 1.28 5.4 165 40.523712 12.0752 +1048592 1.28 5.44 158 40.868656 12.7616 +1048593 1.28 5.48 150 42.373661 14.2864 +1048595 1.28 5.56 214 102.63988 62.616001 +1048596 1.28 5.6 226 100.09044 56.753601 +1048597 1.28 5.64 236 99.220131 53.332802 +1048598 1.28 5.68 239 95.853226 49.156799 +1048599 1.28 5.72 235 89.537338 43.737598 +1048600 1.28 5.76 238 87.294296 40.855999 +1048601 1.28 5.8 234 82.135612 36.68 +1048602 1.28 5.84 235 80.193428 34.782398 +1048603 1.28 5.88 233 77.306694 32.566399 +1048604 1.28 5.92 251 83.852402 35.529598 +1048605 1.28 5.96 428 432.6178 907.65442 +1048606 1.28 6 442 470.89304 1020.136 +1048607 1.28 6.04 234 77.957451 34.4576 +1048608 1.28 6.08 229 78.982841 36.689602 +1048609 1.28 6.12 229 81.513191 39.556801 +1048610 1.28 6.16 228 84.608826 43.396801 +1048611 1.28 6.2 226 86.842445 46.264 +1048612 1.28 6.24 226 91.560692 51.551998 +1048613 1.28 6.28 225 96.369446 56.9408 +1048614 1.28 6.32 222 101.70502 63.504002 +1048615 1.28 6.36 221 108.27577 70.984001 +1048616 1.28 6.4 219 114.38089 78.006401 +1048621 1.28 6.6 132 68.690628 51.454399 +1048622 1.28 6.64 207 143.63159 142.1248 +1048623 1.28 6.68 371 499.48904 1044.0352 +1048624 1.28 6.72 248 227.57787 347.01279 +1048625 1.28 6.76 149 69.554604 45.5952 +1048626 1.28 6.8 136 66.618172 44.636799 +1048627 1.28 6.84 145 73.476318 49.832001 +1048628 1.28 6.88 121 56.253052 35.812801 +1048629 1.28 6.92 142 63.874481 36.979198 +1048630 1.28 6.96 162 71.059273 39.633598 +1048631 1.28 7 135 52.015049 25.959999 +1048632 1.28 7.04 148 51.471992 23.6224 +1048633 1.28 7.08 166 55.420589 23.856001 +1048634 1.28 7.12 234 88.156425 42.119999 +1048635 1.28 7.16 228 84.057312 39.763199 +1048636 1.28 7.2 175 53.544636 21.0256 +1048637 1.28 7.24 147 40.873219 14.9568 +1048638 1.28 7.28 139 37.449818 13.4544 +1048639 1.28 7.32 138 36.900146 13.3536 +1048640 1.28 7.36 138 37.113739 13.7744 +1048641 1.28 7.4 138 37.787434 14.6288 +1048642 1.28 7.44 139 39.226917 16.0128 +1048643 1.28 7.48 139 40.738644 17.683201 +1048644 1.28 7.52 141 43.232285 19.915199 +1048645 1.28 7.56 146 47.168365 22.915199 +1048646 1.28 7.6 162 55.673046 28.040001 +1048647 1.28 7.64 201 78.53611 41.547199 +1048648 1.28 7.68 229 95.11747 51.694401 +1048649 1.28 7.72 189 79.816925 45.9072 +1048650 1.28 7.76 151 68.058823 42.790401 +1114120 1.32 5.12 182 70.116104 38.315201 +1114121 1.32 5.16 195 67.469933 32.398399 +1114122 1.32 5.2 226 87.010475 49.745602 +1114123 1.32 5.24 212 73.673073 38.233601 +1114124 1.32 5.28 179 47.304089 16.1472 +1114125 1.32 5.32 168 41.540936 12.8416 +1114126 1.32 5.36 164 40.57835 12.3152 +1114127 1.32 5.4 157 39.820122 12.3136 +1114128 1.32 5.44 152 40.880169 13.3136 +1114129 1.32 5.48 147 42.7761 14.8096 +1114131 1.32 5.56 208 102.36168 62.4352 +1114132 1.32 5.6 215 98.448242 56.524799 +1114133 1.32 5.64 220 94.703163 51.3232 +1114134 1.32 5.68 226 93.009445 47.881599 +1114135 1.32 5.72 231 91.326996 44.980801 +1114136 1.32 5.76 231 87.690491 41.439999 +1114137 1.32 5.8 232 85.2547 38.852798 +1114138 1.32 5.84 231 82.473885 36.476799 +1114139 1.32 5.88 230 80.176353 34.614399 +1114140 1.32 5.92 232 79.473091 33.911999 +1114141 1.32 5.96 428 428.37463 881.52478 +1114142 1.32 6 443 466.76746 991.65601 +1114143 1.32 6.04 228 80.650223 36.6912 +1114144 1.32 6.08 227 81.790878 38.337601 +1114145 1.32 6.12 226 83.452751 40.443199 +1114146 1.32 6.16 226 87.262276 44.952 +1114147 1.32 6.2 225 90.326309 48.636799 +1114148 1.32 6.24 224 95.340904 54.867199 +1114149 1.32 6.28 222 99.427879 59.774399 +1114150 1.32 6.32 222 106.40266 68.003197 +1114151 1.32 6.36 222 113.03217 75.639999 +1114152 1.32 6.4 220 118.75793 82.367996 +1114157 1.32 6.6 125 66.421387 51.248001 +1114158 1.32 6.64 194 119.09392 99.211197 +1114159 1.32 6.68 381 495.27811 1013.448 +1114160 1.32 6.72 222 153.69417 154.79201 +1114161 1.32 6.76 134 62.4729 41.855999 +1114162 1.32 6.8 122 56.932026 37.403198 +1114163 1.32 6.84 125 57.596317 35.848 +1114164 1.32 6.88 132 61.76355 37.944 +1114165 1.32 6.92 163 75.791054 45.419201 +1114166 1.32 6.96 188 88.060272 53.433601 +1114167 1.32 7 162 75.290657 48.504002 +1114168 1.32 7.04 159 62.77639 36.352001 +1114169 1.32 7.08 164 54.729908 23.6304 +1114170 1.32 7.12 235 87.942726 41.4688 +1114171 1.32 7.16 230 84.276009 39.302399 +1114172 1.32 7.2 175 53.388916 20.937599 +1114173 1.32 7.24 150 41.781322 15.2704 +1114174 1.32 7.28 141 38.018353 13.6176 +1114175 1.32 7.32 138 36.92532 13.3728 +1114176 1.32 7.36 139 37.527416 13.944 +1114177 1.32 7.4 137 37.50066 14.5472 +1114178 1.32 7.44 138 38.960922 15.9424 +1114179 1.32 7.48 139 40.888668 17.775999 +1114180 1.32 7.52 141 43.463345 20.073601 +1114181 1.32 7.56 146 47.31134 23.032 +1114182 1.32 7.6 161 55.668659 28.156799 +1114183 1.32 7.64 202 78.641563 41.534401 +1114184 1.32 7.68 229 95.039886 51.6432 +1114185 1.32 7.72 190 80.14769 46.019199 +1114186 1.32 7.76 150 67.770378 42.707199 +1179656 1.36 5.12 170 59.568604 27.475201 +1179657 1.36 5.16 186 59.43066 24.624001 +1179658 1.36 5.2 221 82.084381 44.030399 +1179659 1.36 5.24 201 63.314827 26.819201 +1179660 1.36 5.28 166 43.148964 14.064 +1179661 1.36 5.32 163 41.788754 13.2096 +1179662 1.36 5.36 156 40.355309 12.848 +1179663 1.36 5.4 150 40.130451 13.1568 +1179664 1.36 5.44 148 42.268894 14.6064 +1179665 1.36 5.48 149 46.076447 16.846399 +1179677 1.36 5.96 427 424.7395 856.65277 +1179678 1.36 6 380 441.20587 955.65277 +1179693 1.36 6.6 86 36.484356 23.952 +1179694 1.36 6.64 143 69.055405 47.563202 +1179695 1.36 6.68 331 446.42902 954.2912 +1179696 1.36 6.72 130 61.522186 45.057598 +1179697 1.36 6.76 45 7.919024 1.8784 +1179702 1.36 6.96 81 28.399715 14.1872 +1179704 1.36 7.04 123 46.49823 22.419201 +1179705 1.36 7.08 140 49.672371 22.854401 +1179706 1.36 7.12 229 90.67083 47.7216 +1179707 1.36 7.16 240 99.617096 58.9072 +1179708 1.36 7.2 170 59.986076 32.6208 +1179709 1.36 7.24 148 44.573105 19.1824 +1179710 1.36 7.28 141 38.716789 13.8336 +1179711 1.36 7.32 135 36.006298 12.6304 +1179712 1.36 7.36 133 35.388229 12.6496 +1179713 1.36 7.4 135 36.867722 13.8016 +1179714 1.36 7.44 136 38.251236 15.0672 +1179715 1.36 7.48 136 39.525829 16.363199 +1179716 1.36 7.52 140 43.300285 19.3424 +1179717 1.36 7.56 144 47.16922 22.382401 +1179718 1.36 7.6 160 57.462002 29.382401 +1179719 1.36 7.64 201 78.48597 41.177601 +1179720 1.36 7.68 229 93.863861 50.284801 +1179721 1.36 7.72 181 77.797424 45.487999 +1179722 1.36 7.76 151 69.687874 43.947201 +1245187 1.4 4.92 42 10.417987 3.576 +1245188 1.4 4.96 42 9.2337847 2.9024 +1245189 1.4 5 42 8.3405771 2.3664 +1245190 1.4 5.04 45 8.9505377 2.4560001 +1245191 1.4 5.08 58 12.344558 3.3296001 +1245192 1.4 5.12 179 61.151897 26.8032 +1245193 1.4 5.16 182 57.639931 23.233601 +1245194 1.4 5.2 219 80.398125 41.292801 +1245195 1.4 5.24 188 56.081787 21.0208 +1245196 1.4 5.28 166 46.143532 15.8352 +1245197 1.4 5.32 156 42.973881 14.5408 +1245198 1.4 5.36 155 43.596321 14.9776 +1245199 1.4 5.4 152 44.38921 15.704 +1245200 1.4 5.44 149 45.984169 16.983999 +1245201 1.4 5.48 149 49.333725 19.143999 +1245213 1.4 5.96 289 362.39203 803.15997 +1245214 1.4 6 296 401.52319 915.71838 +1245230 1.4 6.64 88 25.849367 10.1696 +1245231 1.4 6.68 327 434.84845 920.24957 +1245232 1.4 6.72 86 26.045444 11.0544 +1245238 1.4 6.96 50 16.939228 8.0640001 +1245240 1.4 7.04 123 48.747078 23.927999 +1245241 1.4 7.08 136 52.084644 25.0016 +1245242 1.4 7.12 213 80.430267 38.1744 +1245243 1.4 7.16 220 79.317871 35.936001 +1245244 1.4 7.2 147 47.4258 19.7216 +1245245 1.4 7.24 136 39.925068 14.8896 +1245246 1.4 7.28 147 54.313828 34.947201 +1245247 1.4 7.32 144 53.348759 36.188801 +1245248 1.4 7.36 139 45.266205 25.497601 +1245249 1.4 7.4 134 40.167675 18.913601 +1245250 1.4 7.44 130 36.19965 13.2736 +1245251 1.4 7.48 132 38.587986 15.2848 +1245252 1.4 7.52 137 43.072994 18.7008 +1245253 1.4 7.56 141 47.125225 21.857599 +1245254 1.4 7.6 153 56.67968 28.5984 +1245255 1.4 7.64 193 74.230766 38.187199 +1245256 1.4 7.68 227 91.081612 47.9216 +1245257 1.4 7.72 166 72.843925 42.150398 +1245258 1.4 7.76 147 67.652451 40.462399 +1310723 1.44 4.92 53 14.966986 5.8256001 +1310724 1.44 4.96 58 15.419645 5.7168002 +1310725 1.44 5 70 22.676468 11.5968 +1310726 1.44 5.04 100 36.472126 19.1504 +1310727 1.44 5.08 150 54.785149 25.799999 +1310728 1.44 5.12 165 59.108219 26.041599 +1310729 1.44 5.16 161 54.014061 22.3328 +1310730 1.44 5.2 217 80.499725 40.547199 +1310731 1.44 5.24 172 52.289356 19.625601 +1310732 1.44 5.28 154 46.425999 17.024 +1310733 1.44 5.32 154 46.648079 17.0928 +1310734 1.44 5.36 151 46.328548 17.1136 +1310735 1.44 5.4 150 47.680454 18.084801 +1310736 1.44 5.44 149 49.8955 19.672001 +1310737 1.44 5.48 149 53.050331 21.832001 +1310749 1.44 5.96 268 347.24921 773.9776 +1310750 1.44 6 272 384.58774 882.5072 +1310767 1.44 6.68 339 432.88809 899.40961 +1310774 1.44 6.96 54 16.141594 7.0144 +1310778 1.44 7.12 149 54.254265 25.247999 +1310779 1.44 7.16 143 49.218288 22.3328 +1310792 1.44 7.68 144 46.916862 20.499201 +1376259 1.48 4.92 59 21.449614 12.296 +1376260 1.48 4.96 77 32.645191 20.784 +1376261 1.48 5 78 30.294525 17.431999 +1376262 1.48 5.04 75 26.076345 12.4912 +1376264 1.48 5.12 31 7.9562602 2.7664001 +1376265 1.48 5.16 42 10.491853 3.4463999 +1376266 1.48 5.2 195 78.081009 40.409599 +1376267 1.48 5.24 63 21.245878 10.696 +1376283 1.48 5.88 88 32.133827 16.995199 +1376284 1.48 5.92 112 60.299961 54.708801 +1376285 1.48 5.96 263 336.78943 747.2912 +1376286 1.48 6 284 378.37604 854.23041 +1376287 1.48 6.04 89 32.786522 18.4624 +1376288 1.48 6.08 82 26.918541 12.1744 +1376303 1.48 6.68 345 424.33478 867.51038 +1376308 1.48 6.88 32 6.0233135 1.5312001 +1376309 1.48 6.92 44 10.319736 3.7823999 +1376310 1.48 6.96 55 14.817451 6.0064001 +1376311 1.48 7 33 6.6905565 1.832 +1376312 1.48 7.04 81 24.144417 9.1728001 +1376313 1.48 7.08 83 23.289831 8.5103998 +1376314 1.48 7.12 142 48.784927 22.68 +1376315 1.48 7.16 135 45.952545 21.291201 +1376316 1.48 7.2 82 23.409365 8.7264004 +1376317 1.48 7.24 80 23.538675 8.7872 +1376319 1.48 7.32 71 18.672298 5.9136 +1376320 1.48 7.36 71 17.640558 5.4527998 +1376321 1.48 7.4 71 17.111734 5.2224002 +1376322 1.48 7.44 71 17.111734 5.2224002 +1376323 1.48 7.48 71 17.640558 5.4527998 +1376324 1.48 7.52 72 19.104965 6.1008 +1376326 1.48 7.6 61 15.138167 4.6528001 +1376327 1.48 7.64 102 32.652061 14.488 +1376328 1.48 7.68 123 41.494232 19.455999 +1376329 1.48 7.72 82 20.283421 6.1855998 +1376330 1.48 7.76 62 15.90697 5.0528002 +1441795 1.52 4.92 69 29.836424 19.060801 +1441796 1.52 4.96 72 30.148283 18.6896 +1441797 1.52 5 60 19.974895 10.0096 +1441798 1.52 5.04 42 10.739431 4.6143999 +1441800 1.52 5.12 34 8.0922527 2.9568 +1441801 1.52 5.16 108 38.321426 17.4032 +1441802 1.52 5.2 173 69.179703 35.827202 +1441803 1.52 5.24 90 27.271202 10.3648 +1441819 1.52 5.88 85 26.072828 11.5984 +1441820 1.52 5.92 125 57.490608 45.028801 +1441821 1.52 5.96 258 328.18991 722.13599 +1441822 1.52 6 282 372.82413 833.58398 +1441823 1.52 6.04 89 29.179459 15.4368 +1441824 1.52 6.08 80 22.520805 8.5439997 +1441837 1.52 6.6 249 258.19824 422.97119 +1441838 1.52 6.64 291 354.75665 722.50879 +1441839 1.52 6.68 350 418.0278 839.58081 +1441840 1.52 6.72 296 341.0491 672.70239 +1441841 1.52 6.76 243 264.82916 453.92801 +1441844 1.52 6.88 33 5.3463125 1.1984 +1441845 1.52 6.92 45 9.7776852 3.3487999 +1441846 1.52 6.96 56 14.085178 5.3407998 +1441847 1.52 7 34 5.8544292 1.424 +1441848 1.52 7.04 84 22.699131 7.8495998 +1441849 1.52 7.08 91 23.144194 7.7184 +1441850 1.52 7.12 135 46.039051 22.1248 +1441851 1.52 7.16 130 43.464912 20.576 +1441852 1.52 7.2 90 22.396355 7.3712001 +1441853 1.52 7.24 80 21.188469 7.2816 +1441855 1.52 7.32 71 16.617079 4.7616 +1441856 1.52 7.36 71 15.479453 4.3007998 +1441857 1.52 7.4 71 14.896123 4.0704002 +1441858 1.52 7.44 71 14.896123 4.0704002 +1441859 1.52 7.48 72 15.856812 4.4432001 +1441860 1.52 7.52 72 17.017078 4.9215999 +1441862 1.52 7.6 67 14.759789 4.0208001 +1441863 1.52 7.64 102 33.809765 16.4272 +1441864 1.52 7.68 114 39.028557 19.467199 +1441865 1.52 7.72 80 17.924141 5.0240002 +1441866 1.52 7.76 72 17.330088 5.1680002 +1507331 1.56 4.92 55 19.384987 9.8304005 +1507332 1.56 4.96 56 19.041708 9.6767998 +1507333 1.56 5 49 14.817757 7.2416 +1507334 1.56 5.04 34 5.1768894 1.1792001 +1507335 1.56 5.08 47 11.980098 5.0911999 +1507336 1.56 5.12 60 19.768717 9.4960003 +1507337 1.56 5.16 82 30.850124 15.0352 +1507338 1.56 5.2 187 70.128418 34.537601 +1507339 1.56 5.24 83 25.144419 9.7600002 +1507355 1.56 5.88 86 23.537201 9.1887999 +1507356 1.56 5.92 128 52.324951 35.703999 +1507357 1.56 5.96 255 320.36963 697.77917 +1507358 1.56 6 279 364.2807 805.88641 +1507359 1.56 6.04 97 30.145798 14.9648 +1507360 1.56 6.08 79 19.716049 6.744 +1507373 1.56 6.6 256 247.30463 393.91199 +1507374 1.56 6.64 308 352.36646 700.72803 +1507375 1.56 6.68 341 403.74146 806.86078 +1507376 1.56 6.72 303 334.56653 648.84961 +1507377 1.56 6.76 255 251.64864 414.01761 +1507380 1.56 6.88 35 5.4053993 1.1328 +1507381 1.56 6.92 44 8.8297749 2.8176 +1507382 1.56 6.96 57 13.521199 4.7663999 +1507383 1.56 7 33 4.8911719 0.98879999 +1507384 1.56 7.04 89 22.59363 7.3856001 +1507385 1.56 7.08 91 21.454315 6.7584 +1507386 1.56 7.12 135 45.790794 22.7328 +1507387 1.56 7.16 128 41.85854 20.1968 +1507388 1.56 7.2 92 21.333698 6.5071998 +1507389 1.56 7.24 87 21.345631 6.8000002 +1507391 1.56 7.32 72 15.301398 3.9760001 +1507392 1.56 7.36 71 13.714247 3.3792 +1507393 1.56 7.4 71 13.088058 3.1487999 +1507394 1.56 7.44 71 13.088058 3.1487999 +1507395 1.56 7.48 72 14.058339 3.4976001 +1507396 1.56 7.52 72 15.301398 3.9760001 +1507398 1.56 7.6 69 14.38336 3.6847999 +1507399 1.56 7.64 100 32.941559 16.7568 +1507400 1.56 7.68 111 37.828407 19.6752 +1507401 1.56 7.72 88 23.215038 9.2816 +1507402 1.56 7.76 75 16.691599 4.5999999 +1572869 1.6 5 106 33.540142 12.8672 +1572870 1.6 5.04 107 30.979067 11.024 +1572871 1.6 5.08 107 28.700459 9.6000004 +1572872 1.6 5.12 107 26.962923 8.5248003 +1572873 1.6 5.16 120 34.218254 13.8896 +1572874 1.6 5.2 188 65.33342 31.360001 +1572875 1.6 5.24 126 35.454872 15.08 +1572876 1.6 5.28 111 28.607075 9.8479996 +1572877 1.6 5.32 108 27.579021 8.8992004 +1572878 1.6 5.36 107 28.906731 9.8079996 +1572879 1.6 5.4 106 30.775557 11.08 +1572880 1.6 5.44 105 33.095074 12.6864 +1572891 1.6 5.88 92 23.914549 8.5551996 +1572892 1.6 5.92 128 47.565628 28.489599 +1572893 1.6 5.96 253 313.45911 674.4848 +1572894 1.6 6 277 356.535 779.16479 +1572895 1.6 6.04 102 29.904795 13.5808 +1572896 1.6 6.08 80 18.453127 5.8000002 +1572908 1.6 6.56 149 70.874908 50.177601 +1572909 1.6 6.6 263 238.03102 367.18561 +1572910 1.6 6.64 311 347.41339 684.33759 +1572911 1.6 6.68 337 391.76797 775.95203 +1572912 1.6 6.72 306 329.27002 629.23358 +1572913 1.6 6.76 261 240.27705 382.0752 +1572914 1.6 6.8 136 57.111465 34.755199 +1572915 1.6 6.84 110 38.981159 18.876801 +1572916 1.6 6.88 33 4.6216531 0.84640002 +1572917 1.6 6.92 45 8.6902657 2.5616 +1572918 1.6 6.96 58 13.140449 4.3056002 +1572919 1.6 7 33 4.7784972 0.93120003 +1572920 1.6 7.04 88 20.590557 6.1631999 +1572921 1.6 7.08 90 19.80237 5.8304 +1572922 1.6 7.12 132 44.50029 22.9568 +1572923 1.6 7.16 126 40.586376 20.041599 +1572924 1.6 7.2 93 20.631918 6.0528002 +1572925 1.6 7.24 89 20.796692 6.2463999 +1572927 1.6 7.32 74 14.837963 3.6256001 +1572928 1.6 7.36 72 12.686926 2.7855999 +1572929 1.6 7.4 71 11.717723 2.4576001 +1572930 1.6 7.44 72 12.006167 2.5408001 +1572931 1.6 7.48 73 13.112132 2.9663999 +1572932 1.6 7.52 72 13.989435 3.2639999 +1572934 1.6 7.6 72 14.727295 3.72 +1572935 1.6 7.64 100 33.323078 17.944 +1572936 1.6 7.68 107 36.607193 20.0128 +1572937 1.6 7.72 93 27.004366 12.648 +1572938 1.6 7.76 74 15.634545 4.1343999 +1638405 1.64 5 104 30.228973 10.8096 +1638406 1.64 5.04 104 27.305202 9.0383997 +1638407 1.64 5.08 111 28.036549 9.1552 +1638408 1.64 5.12 111 25.956234 7.8720002 +1638409 1.64 5.16 132 36.346493 14.768 +1638410 1.64 5.2 179 60.948643 29.4592 +1638411 1.64 5.24 156 47.01733 20.636801 +1638412 1.64 5.28 113 25.170645 7.4159999 +1638413 1.64 5.32 110 25.870001 7.9439998 +1638414 1.64 5.36 108 26.879467 8.6927996 +1638415 1.64 5.4 106 28.628239 9.9055996 +1638416 1.64 5.44 105 31.102196 11.4848 +1638427 1.64 5.88 94 23.992495 8.4432001 +1638428 1.64 5.92 125 43.138798 23.3424 +1638429 1.64 5.96 253 307.89032 652.4176 +1638430 1.64 6 278 352.75854 760.00641 +1638431 1.64 6.04 104 29.407681 12.7568 +1638432 1.64 6.08 81 18.045052 5.4768 +1638444 1.64 6.56 144 57.998772 32.8368 +1638445 1.64 6.6 266 227.04224 336.66241 +1638446 1.64 6.64 314 341.94354 663.04962 +1638447 1.64 6.68 333 380.26965 746.05762 +1638448 1.64 6.72 307 322.71463 608.48962 +1638449 1.64 6.76 273 236.95343 361.0416 +1638450 1.64 6.8 133 50.103779 27.867201 +1638451 1.64 6.84 104 31.712662 13.048 +1638452 1.64 6.88 31 4.7147136 0.98879999 +1638453 1.64 6.92 46 8.7453232 2.4096 +1638454 1.64 6.96 59 12.948497 3.9807999 +1638455 1.64 7 30 4.3493905 0.86720002 +1638456 1.64 7.04 91 20.792582 6.0288 +1638457 1.64 7.08 91 19.30509 5.4496002 +1638458 1.64 7.12 131 44.178627 23.636801 +1638459 1.64 7.16 125 39.764809 20.049601 +1638460 1.64 7.2 93 19.760447 5.5423999 +1638461 1.64 7.24 89 19.733002 5.5215998 +1638463 1.64 7.32 73 13.555484 2.9935999 +1638464 1.64 7.36 74 12.493398 2.5792 +1638465 1.64 7.4 72 11.032143 2.0511999 +1638466 1.64 7.44 73 11.423811 2.1984 +1638467 1.64 7.48 72 11.758007 2.3072 +1638468 1.64 7.52 75 14.467733 3.4159999 +1638470 1.64 7.6 72 14.480923 3.6719999 +1638471 1.64 7.64 97 32.189903 18.132799 +1638472 1.64 7.68 105 36.462269 21.060801 +1638473 1.64 7.72 95 29.151518 15.1136 +1638474 1.64 7.76 76 15.959687 4.2495999 +1703941 1.68 5 105 29.200998 10.1936 +1703942 1.68 5.04 107 27.045214 8.8079996 +1703943 1.68 5.08 109 25.14806 7.5455999 +1703944 1.68 5.12 113 24.302929 6.8080001 +1703945 1.68 5.16 153 46.73637 22.5776 +1703946 1.68 5.2 174 57.118546 27.3424 +1703947 1.68 5.24 160 49.564838 22.819201 +1703948 1.68 5.28 114 23.127714 6.0447998 +1703949 1.68 5.32 112 24.111921 6.7680001 +1703950 1.68 5.36 108 25.181557 7.7375998 +1703951 1.68 5.4 105 26.410864 8.5872002 +1703952 1.68 5.44 102 27.662252 9.3168001 +1703963 1.68 5.88 99 25.978851 9.4768 +1703964 1.68 5.92 123 39.686211 19.396799 +1703965 1.68 5.96 253 302.30261 630.64478 +1703966 1.68 6 277 345.99835 734.73279 +1703967 1.68 6.04 104 28.348246 11.6176 +1703968 1.68 6.08 87 20.595198 6.816 +1703980 1.68 6.56 142 52.088741 26.739201 +1703981 1.68 6.6 272 220.76434 315.83359 +1703982 1.68 6.64 319 339.36288 649.55042 +1703983 1.68 6.68 332 371.40356 721.13599 +1703984 1.68 6.72 310 321.1333 604.36481 +1703985 1.68 6.76 273 226.19142 331.97281 +1703986 1.68 6.8 131 44.717018 22.5264 +1703987 1.68 6.84 101 27.331169 9.5696001 +1703988 1.68 6.88 29 5.1940899 1.2464 +1703989 1.68 6.92 38 6.1805968 1.3712 +1703990 1.68 6.96 63 13.561599 3.9424 +1703991 1.68 7 28 4.8462081 1.128 +1703992 1.68 7.04 92 20.882935 6.0560002 +1703993 1.68 7.08 96 20.797064 5.9583998 +1703994 1.68 7.12 132 45.530884 25.5296 +1703995 1.68 7.16 124 39.94175 21.1408 +1703996 1.68 7.2 99 23.633528 8.4560003 +1703997 1.68 7.24 90 19.842379 5.5408001 +1703999 1.68 7.32 75 13.918261 3.0880001 +1704000 1.68 7.36 74 12.024062 2.3408 +1704001 1.68 7.4 75 11.386681 2.0527999 +1704002 1.68 7.44 73 10.989633 1.9984 +1704003 1.68 7.48 75 12.480132 2.5488 +1704004 1.68 7.52 76 14.21991 3.1744001 +1704006 1.68 7.6 76 17.451048 6.0079999 +1704007 1.68 7.64 94 31.444889 18.5296 +1704008 1.68 7.68 104 37.434654 22.972799 +1704009 1.68 7.72 98 31.624578 17.375999 +1704010 1.68 7.76 77 16.366362 4.5232 +1769477 1.72 5 104 27.828571 9.3520002 +1769478 1.72 5.04 107 26.115921 8.2687998 +1769479 1.72 5.08 109 23.909519 6.8368001 +1769480 1.72 5.12 115 23.969769 6.48 +1769481 1.72 5.16 157 52.41098 30.694401 +1769482 1.72 5.2 172 56.30455 27.428801 +1769483 1.72 5.24 161 50.035015 23.524799 +1769484 1.72 5.28 117 23.370098 6.0159998 +1769485 1.72 5.32 111 22.800392 6.1040001 +1769486 1.72 5.36 110 24.599094 7.2128 +1769487 1.72 5.4 103 24.164181 7.2416 +1769488 1.72 5.44 101 26.450563 8.6176004 +1769499 1.72 5.88 99 26.225559 9.7440004 +1769500 1.72 5.92 119 36.350471 16.476801 +1769501 1.72 5.96 253 296.9805 609.47357 +1769502 1.72 6 278 341.36322 712.56317 +1769503 1.72 6.04 100 25.783735 9.8319998 +1769504 1.72 6.08 89 21.901335 7.6575999 +1769516 1.72 6.56 136 45.587566 21.0112 +1769517 1.72 6.6 276 216.16621 300.0704 +1769518 1.72 6.64 320 331.69208 625.56641 +1769519 1.72 6.68 335 364.71262 695.82721 +1769520 1.72 6.72 309 313.14508 582.6192 +1769521 1.72 6.76 274 218.25392 310.328 +1769522 1.72 6.8 130 41.241798 18.681601 +1769523 1.72 6.84 96 24.043129 7.5888 +1769524 1.72 6.88 32 6.4472461 1.7728 +1769525 1.72 6.92 43 7.6804147 1.8559999 +1769526 1.72 6.96 62 13.317303 3.8640001 +1769527 1.72 7 32 6.3409433 1.704 +1769528 1.72 7.04 99 23.866726 7.3807998 +1769529 1.72 7.08 100 23.496498 8.1087999 +1769530 1.72 7.12 134 46.609406 26.844801 +1769531 1.72 7.16 126 41.599094 22.995199 +1769532 1.72 7.2 102 26.495483 11.4896 +1769533 1.72 7.24 90 19.942865 5.6431999 +1769535 1.72 7.32 78 15.039348 3.5248001 +1769536 1.72 7.36 78 13.208932 2.7456 +1769537 1.72 7.4 78 12.398946 2.4128001 +1769538 1.72 7.44 79 12.46011 2.3648 +1769539 1.72 7.48 78 13.548032 2.9584 +1769540 1.72 7.52 80 15.901108 3.9119999 +1769542 1.72 7.6 80 21.251511 9.5472002 +1769543 1.72 7.64 93 31.716228 19.288 +1769544 1.72 7.68 106 39.049652 24.7792 +1769545 1.72 7.72 102 34.570621 19.812799 +1769546 1.72 7.76 80 18.046577 5.4335999 +1835013 1.76 5 101 26.05162 8.3039999 +1835014 1.76 5.04 107 25.628706 7.8592 +1835015 1.76 5.08 111 24.651609 7.1184001 +1835016 1.76 5.12 121 27.610903 9.0112 +1835017 1.76 5.16 162 57.684177 37.942402 +1835018 1.76 5.2 171 55.9403 27.5616 +1835019 1.76 5.24 159 49.683365 23.7952 +1835020 1.76 5.28 121 25.352613 7.0479999 +1835021 1.76 5.32 114 23.753483 6.4015999 +1835022 1.76 5.36 105 22.397604 6.1664 +1835023 1.76 5.4 103 23.960836 7.0416002 +1835024 1.76 5.44 100 25.66605 8.1183996 +1835035 1.76 5.88 96 25.94153 10.0576 +1835036 1.76 5.92 117 34.954933 15.296 +1835037 1.76 5.96 253 291.51703 588.4624 +1835038 1.76 6 281 339.24445 694.93439 +1835039 1.76 6.04 98 25.734337 10.1456 +1835040 1.76 6.08 91 23.990833 9.1087999 +1835052 1.76 6.56 124 37.176418 14.7504 +1835053 1.76 6.6 275 204.99234 273.18719 +1835054 1.76 6.64 325 330.60281 615.20319 +1835055 1.76 6.68 340 358.13306 670.29279 +1835056 1.76 6.72 308 307.33923 568.32642 +1835057 1.76 6.76 278 211.53795 287.45441 +1835058 1.76 6.8 122 36.062725 15.272 +1835059 1.76 6.84 91 21.8431 6.4784002 +1835060 1.76 6.88 33 5.4359469 1.2496001 +1835061 1.76 6.92 46 9.0090227 2.5552001 +1835062 1.76 6.96 59 12.71044 3.8271999 +1835063 1.76 7 35 5.8348846 1.3552001 +1835064 1.76 7.04 97 23.469893 7.3104 +1835065 1.76 7.08 108 28.393246 11.2704 +1835066 1.76 7.12 141 50.746086 30.087999 +1835067 1.76 7.16 132 44.860577 25.608 +1835068 1.76 7.2 108 29.933138 13.9648 +1835069 1.76 7.24 88 19.7896 5.7328 +1835071 1.76 7.32 80 16.159086 3.9935999 +1835072 1.76 7.36 85 15.91521 3.8144 +1835073 1.76 7.4 88 15.695617 3.5072 +1835074 1.76 7.44 90 16.425106 3.7872 +1835075 1.76 7.48 85 15.936421 3.8080001 +1835076 1.76 7.52 82 17.138847 4.4752002 +1835078 1.76 7.6 82 24.284025 12.528 +1835079 1.76 7.64 98 34.506317 21.625601 +1835080 1.76 7.68 110 41.497154 26.8256 +1835081 1.76 7.72 106 38.104664 22.912001 +1835082 1.76 7.76 86 22.483219 8.5567999 +1900549 1.8 5 100 26.4561 8.6496 +1900550 1.8 5.04 102 23.898556 6.9679999 +1900551 1.8 5.08 110 24.664074 6.9856 +1900552 1.8 5.12 129 34.880669 14.5136 +1900553 1.8 5.16 161 56.145508 34.743999 +1900554 1.8 5.2 171 56.466873 28.131201 +1900555 1.8 5.24 160 50.736176 24.6336 +1900556 1.8 5.28 127 29.618959 9.6831999 +1900557 1.8 5.32 110 22.760733 5.9359999 +1900558 1.8 5.36 104 22.435322 6.0544 +1900559 1.8 5.4 101 23.589909 6.8319998 +1900560 1.8 5.44 99 25.783669 8.1775999 +1900571 1.8 5.88 98 28.379307 11.672 +1900572 1.8 5.92 110 31.884623 13.44 +1900573 1.8 5.96 255 287.25287 568.5968 +1900574 1.8 6 282 334.46167 672.2688 +1900575 1.8 6.04 99 27.694965 11.672 +1900576 1.8 6.08 90 25.715246 10.8512 +1900588 1.8 6.56 111 31.011696 11.2704 +1900589 1.8 6.6 277 199.17665 257.48639 +1900590 1.8 6.64 327 325.68964 598.82562 +1900591 1.8 6.68 344 355.06354 655.96802 +1900592 1.8 6.72 313 301.82709 547.06079 +1900593 1.8 6.76 276 203.60538 270.92801 +1900594 1.8 6.8 112 32.74004 14.088 +1900595 1.8 6.84 88 22.689419 7.4496002 +1900596 1.8 6.88 35 5.268044 1.056 +1900597 1.8 6.92 47 9.388896 2.8064001 +1900598 1.8 6.96 58 12.74391 4.0496001 +1900599 1.8 7 39 6.6145105 1.512 +1900600 1.8 7.04 114 33.698605 13.3504 +1900601 1.8 7.08 128 40.336849 18.996799 +1900602 1.8 7.12 157 59.214581 35.335999 +1900603 1.8 7.16 155 55.868698 32.0448 +1900604 1.8 7.2 138 41.540627 19.5536 +1900605 1.8 7.24 123 30.408176 9.7088003 +1900606 1.8 7.28 65 14.382514 4.1360002 +1900607 1.8 7.32 109 23.232391 6 +1900608 1.8 7.36 107 21.784542 5.4144001 +1900609 1.8 7.4 105 20.855827 5.1087999 +1900610 1.8 7.44 105 20.937033 5.1728001 +1900611 1.8 7.48 106 21.799471 5.5711999 +1900612 1.8 7.52 109 23.548716 6.3392 +1900613 1.8 7.56 59 13.16826 4.0128002 +1900614 1.8 7.6 122 39.86166 20.7696 +1900615 1.8 7.64 126 46.456577 27.948799 +1900616 1.8 7.68 132 53.049545 34.032001 +1900617 1.8 7.72 128 50.90974 31.184 +1900618 1.8 7.76 109 36.358337 17.318399 +1966085 1.84 5 99 26.850645 8.7040005 +1966086 1.84 5.04 100 24.458662 7.2736001 +1966087 1.84 5.08 108 26.779778 9.2159996 +1966088 1.84 5.12 127 35.266022 14.5696 +1966089 1.84 5.16 150 45.680565 21.374399 +1966090 1.84 5.2 171 57.256329 28.7712 +1966091 1.84 5.24 163 53.083187 26.041599 +1966092 1.84 5.28 129 33.709217 12.8064 +1966093 1.84 5.32 106 22.898537 6.1231999 +1966094 1.84 5.36 102 22.927736 6.296 +1966095 1.84 5.4 100 24.672245 7.4271998 +1966096 1.84 5.44 99 27.050997 8.8559999 +1966107 1.84 5.88 97 30.470633 13.5824 +1966108 1.84 5.92 111 34.395092 15.3888 +1966109 1.84 5.96 260 284.88397 550.59363 +1966110 1.84 6 285 331.16534 651.99042 +1966111 1.84 6.04 96 28.830515 12.9936 +1966112 1.84 6.08 84 25.357422 11.24 +1966124 1.84 6.56 94 27.003283 10.392 +1966125 1.84 6.6 279 194.35161 242.76801 +1966126 1.84 6.64 333 321.65436 579.19843 +1966127 1.84 6.68 350 350.92413 635.12958 +1966128 1.84 6.72 317 299.18933 534.95038 +1966129 1.84 6.76 274 194.16458 248.25121 +1966130 1.84 6.8 93 28.727888 13.7808 +1966132 1.84 6.88 38 6.2843246 1.4016 +1966133 1.84 6.92 47 9.7038107 3.0752001 +1966134 1.84 6.96 58 13.296454 4.5167999 +1966135 1.84 7 40 6.6949558 1.4848 +1966136 1.84 7.04 107 32.256802 12.96 +1966137 1.84 7.08 125 42.16502 21.742399 +1966138 1.84 7.12 155 60.218964 36.9664 +1966139 1.84 7.16 154 57.981598 34.787201 +1966140 1.84 7.2 135 43.48848 22.1168 +1966141 1.84 7.24 125 33.053497 11.2848 +1966142 1.84 7.28 107 25.425043 7.2031999 +1966143 1.84 7.32 110 24.544771 6.5872002 +1966144 1.84 7.36 102 21.595726 5.6064 +1966145 1.84 7.4 101 20.972654 5.3983998 +1966146 1.84 7.44 101 21.091574 5.4896002 +1966147 1.84 7.48 102 21.915285 5.8559999 +1966148 1.84 7.52 107 23.942425 6.5696001 +1966149 1.84 7.56 103 25.240126 7.9456 +1966150 1.84 7.6 120 41.738804 23.448 +1966151 1.84 7.64 122 47.411034 29.937599 +1966152 1.84 7.68 127 53.163315 35.3088 +1966153 1.84 7.72 127 54.339512 35.659199 +1966154 1.84 7.76 109 40.036774 21.5072 +2031621 1.88 5 98 28.47743 9.6543999 +2031622 1.88 5.04 100 26.474697 8.2959995 +2031623 1.88 5.08 105 28.455574 10.5104 +2031624 1.88 5.12 121 37.4762 17.430401 +2031625 1.88 5.16 148 48.271687 23.496 +2031626 1.88 5.2 178 60.292068 30.108801 +2031627 1.88 5.24 161 52.860703 25.995199 +2031628 1.88 5.28 122 35.239731 15.0976 +2031629 1.88 5.32 106 26.174126 8.1744003 +2031630 1.88 5.36 100 24.396278 7.0799999 +2031631 1.88 5.4 100 26.684328 8.4560003 +2031632 1.88 5.44 100 29.367298 10.0928 +2031643 1.88 5.88 85 28.823233 13.672 +2031644 1.88 5.92 105 36.08765 17.7216 +2031645 1.88 5.96 271 284.88239 534.18402 +2031646 1.88 6 291 331.03284 636.43518 +2031647 1.88 6.04 89 30.737764 15.7184 +2031648 1.88 6.08 81 27.145617 12.8144 +2031661 1.88 6.6 276 184.20358 215.608 +2031662 1.88 6.64 336 317.6022 563.86078 +2031663 1.88 6.68 353 344.26614 611.34082 +2031664 1.88 6.72 320 295.76074 521.44159 +2031665 1.88 6.76 262 185.78323 230.26559 +2031668 1.88 6.88 36 6.1236434 1.4112 +2031669 1.88 6.92 46 9.9162254 3.3504 +2031670 1.88 6.96 56 13.305697 4.8207998 +2031671 1.88 7 46 10.687746 3.8432 +2031672 1.88 7.04 96 28.237085 10.6816 +2031673 1.88 7.08 109 37.478687 20.3696 +2031674 1.88 7.12 144 56.910702 36.84 +2031675 1.88 7.16 139 54.334923 34.9184 +2031676 1.88 7.2 116 39.979095 22.5968 +2031677 1.88 7.24 85 23.883541 9.0240002 +2031679 1.88 7.32 82 20.204309 6.0511999 +2031680 1.88 7.36 96 22.505251 6.4847999 +2031681 1.88 7.4 96 22.107399 6.3248 +2031682 1.88 7.44 95 21.712606 6.1855998 +2031683 1.88 7.48 93 22.221878 6.5823998 +2031684 1.88 7.52 83 21.09626 6.5247998 +2031686 1.88 7.6 94 37.365715 24.559999 +2031687 1.88 7.64 102 42.217468 29.1472 +2031688 1.88 7.68 109 48.096294 34.571201 +2031689 1.88 7.72 112 50.42522 35.9776 +2031690 1.88 7.76 96 35.598904 20.099199 +2097162 1.92 5.2 201 67.989166 33.211201 +2097181 1.92 5.96 281 284.27429 518.04163 +2097182 1.92 6 289 327.13849 616.2384 +2097197 1.92 6.6 278 173.26363 188.62241 +2097198 1.92 6.64 338 311.96161 543.48322 +2097199 1.92 6.68 357 340.14005 592.12799 +2097200 1.92 6.72 327 292.79022 504.04639 +2097201 1.92 6.76 270 177.71747 208.10561 +2097204 1.92 6.88 33 6.2336969 1.6016001 +2097205 1.92 6.92 48 11.146693 3.9647999 +2097206 1.92 6.96 59 15.541656 6.2416 +2097207 1.92 7 33 6.6905565 1.832 +2097208 1.92 7.04 91 28.672241 11.3232 +2097209 1.92 7.08 101 37.928616 21.792 +2097210 1.92 7.12 140 58.013214 38.756802 +2097211 1.92 7.16 137 56.931339 38.3344 +2097212 1.92 7.2 101 41.643024 27.3216 +2097213 1.92 7.24 85 28.036398 12.4784 +2097215 1.92 7.32 80 21.99575 7.1968002 +2097216 1.92 7.36 79 20.201742 6.3456001 +2097217 1.92 7.4 86 21.884943 6.8576002 +2097218 1.92 7.44 88 22.62866 7.1616001 +2097219 1.92 7.48 82 21.420656 6.8927999 +2097220 1.92 7.52 82 23.021715 7.7231998 +2097222 1.92 7.6 86 37.489185 25.532801 +2097223 1.92 7.64 98 44.414448 32.102402 +2097224 1.92 7.68 104 49.48093 36.644798 +2097225 1.92 7.72 109 53.157696 39.5536 +2097226 1.92 7.76 95 39.239952 24.120001 +2162693 1.96 5 110 39.920303 18.7248 +2162694 1.96 5.04 111 36.994022 16.257601 +2162695 1.96 5.08 113 35.361492 14.792 +2162696 1.96 5.12 133 50.736244 30.208 +2162697 1.96 5.16 148 62.688541 44.700802 +2162698 1.96 5.2 205 72.598892 37.3344 +2162699 1.96 5.24 141 36.297443 11.68 +2162700 1.96 5.28 107 26.263237 8.1104002 +2162701 1.96 5.32 102 25.007254 7.7136002 +2162702 1.96 5.36 102 26.610947 8.7728004 +2162703 1.96 5.4 96 26.51631 9.2256002 +2162704 1.96 5.44 91 27.06925 9.7840004 +2162705 1.96 5.48 72 18.980307 6.2736001 +2162706 1.96 5.52 75 18.038202 5.5664001 +2162707 1.96 5.56 75 16.364847 4.5696001 +2162708 1.96 5.6 80 16.92267 4.4784002 +2162709 1.96 5.64 81 17.221333 4.6128001 +2162710 1.96 5.68 85 19.726995 5.9632001 +2162711 1.96 5.72 81 20.35327 6.9903998 +2162712 1.96 5.76 80 22.439497 8.8495998 +2162713 1.96 5.8 83 26.678169 11.7392 +2162716 1.96 5.92 97 32.592308 16.1392 +2162717 1.96 5.96 280 281.72928 502.0784 +2162718 1.96 6 296 324.54831 597.87842 +2162719 1.96 6.04 74 21.185783 8.3056002 +2162722 1.96 6.16 77 22.41048 8.6303997 +2162723 1.96 6.2 77 20.162447 7.1184001 +2162724 1.96 6.24 82 19.800385 6.3792 +2162725 1.96 6.28 83 19.184225 5.8592 +2162726 1.96 6.32 81 17.617865 4.9424 +2162727 1.96 6.36 85 20.31863 6.5472002 +2162728 1.96 6.4 83 21.311005 7.4768 +2162729 1.96 6.44 72 17.018276 5.1343999 +2162730 1.96 6.48 72 18.980307 6.2736001 +2162732 1.96 6.56 184 100.2803 85.260803 +2162733 1.96 6.6 278 163.8279 164.92 +2162734 1.96 6.64 339 308.28836 529.08643 +2162735 1.96 6.68 364 336.99185 571.76959 +2162736 1.96 6.72 332 292.57672 493.8576 +2162737 1.96 6.76 276 166.83261 176.8688 +2162738 1.96 6.8 173 92.199066 76.5728 +2162739 1.96 6.84 118 41.931713 18.867201 +2162742 1.96 6.96 71 20.761024 8.8048 +2162746 1.96 7.12 113 54.289612 40.416 +2162747 1.96 7.16 134 59.605541 41.964802 +2228229 2 5 111 40.659767 20.854401 +2228230 2 5.04 114 37.4846 17.153601 +2228231 2 5.08 114 34.044781 14.3616 +2228232 2 5.12 139 48.850243 27.027201 +2228233 2 5.16 171 64.671761 40.131199 +2228234 2 5.2 198 76.011169 45.454399 +2228235 2 5.24 162 47.443104 19.728001 +2228236 2 5.28 125 30.794863 9.8448 +2228237 2 5.32 114 27.402746 8.4848003 +2228238 2 5.36 104 25.143894 7.8800001 +2228239 2 5.4 97 23.653833 7.3200002 +2228240 2 5.44 90 24.419842 8.2016001 +2228241 2 5.48 76 20.466681 7.7872 +2228242 2 5.52 79 17.924244 5.4527998 +2228243 2 5.56 85 17.818701 4.9376001 +2228244 2 5.6 92 19.968998 5.7616 +2228245 2 5.64 94 21.843006 7.1696 +2228246 2 5.68 98 24.54838 8.8752003 +2228247 2 5.72 98 26.629082 10.6064 +2228248 2 5.76 94 28.408993 12.5392 +2228249 2 5.8 89 29.495028 14.0352 +2228251 2 5.88 87 25.399734 9.8895998 +2228252 2 5.92 119 37.875122 16.2992 +2228253 2 5.96 293 284.00552 488.728 +2228254 2 6 310 327.03973 584.3584 +2228255 2 6.04 96 26.366732 9.8095999 +2228256 2 6.08 73 20.246466 7.6384001 +2228258 2 6.16 79 22.093275 8.4960003 +2228259 2 6.2 89 23.173359 8.4560003 +2228260 2 6.24 90 21.391472 7.1343999 +2228261 2 6.28 91 20.484171 6.3856001 +2228262 2 6.32 90 19.628683 5.8671999 +2228263 2 6.36 89 19.283873 5.6208 +2228264 2 6.4 90 20.785023 6.4671998 +2228265 2 6.44 89 23.490685 8.448 +2228266 2 6.48 76 20.575188 7.8895998 +2228268 2 6.56 194 92.469322 68.771202 +2228269 2 6.6 285 159.87183 150.69279 +2228270 2 6.64 352 309.03357 514.0752 +2228271 2 6.68 374 334.96548 552.47998 +2228272 2 6.72 340 294.10104 485.59039 +2228273 2 6.76 282 161.97426 159.77119 +2228274 2 6.8 190 87.811859 64.727997 +2228275 2 6.84 121 39.456356 16.4928 +2228276 2 6.88 29 4.8961244 1.08 +2228277 2 6.92 60 16.335417 6.3903999 +2228278 2 6.96 79 23.211899 9.8224001 +2228279 2 7 36 8.0005789 2.4288001 +2228280 2 7.04 29 4.2823467 0.72799999 +2228281 2 7.08 32 4.0847077 0.60479999 +2228282 2 7.12 123 57.08083 43.734402 +2228283 2 7.16 127 59.629173 44.944 +2228284 2 7.2 37 5.8038549 1.168 +2228285 2 7.24 40 8.8077078 2.7679999 +2293765 2.04 5 134 74.655685 71.681602 +2293766 2.04 5.04 139 69.089783 60.136002 +2293767 2.04 5.08 142 64.216743 52.302399 +2293768 2.04 5.12 159 66.225967 48.369598 +2293769 2.04 5.16 194 85.424156 62.827202 +2293770 2.04 5.2 220 103.32905 77.975998 +2293771 2.04 5.24 184 70.973579 45.414398 +2293772 2.04 5.28 153 46.023476 21.382401 +2293773 2.04 5.32 136 36.30093 13.4336 +2293774 2.04 5.36 125 32.022083 10.88 +2293775 2.04 5.4 114 27.555025 8.2992001 +2293776 2.04 5.44 98 24.019798 7.4288001 +2293777 2.04 5.48 102 42.813881 30.8064 +2293778 2.04 5.52 129 46.813576 28.628799 +2293779 2.04 5.56 133 46.413982 26.535999 +2293780 2.04 5.6 131 44.488884 24.216 +2293781 2.04 5.64 131 43.646503 23.0144 +2293782 2.04 5.68 123 37.386662 16.704 +2293783 2.04 5.72 117 34.943401 15.5056 +2293784 2.04 5.76 111 32.838509 14.536 +2293785 2.04 5.8 93 30.814243 15.0208 +2293787 2.04 5.88 121 42.077148 21.5504 +2293788 2.04 5.92 160 57.061874 27.7456 +2293789 2.04 5.96 329 302.06073 487.82721 +2293790 2.04 6 350 345.94989 581.54718 +2293791 2.04 6.04 139 48.130466 23.728001 +2293792 2.04 6.08 113 39.215134 20.8272 +2293794 2.04 6.16 102 35.857304 20.247999 +2293795 2.04 6.2 110 35.003597 18.3696 +2293796 2.04 6.24 115 35.517448 17.3808 +2293797 2.04 6.28 117 35.62397 17.087999 +2293798 2.04 6.32 128 44.468655 26.120001 +2293799 2.04 6.36 127 46.050823 29.1616 +2293800 2.04 6.4 126 46.283455 30.118401 +2293801 2.04 6.44 129 50.70475 35.134399 +2293802 2.04 6.48 104 49.171303 39.9744 +2293804 2.04 6.56 213 87.989754 54.347198 +2293805 2.04 6.6 309 164.61203 144.55521 +2293806 2.04 6.64 383 323.78207 517.52802 +2293807 2.04 6.68 400 346.32837 545.57599 +2293808 2.04 6.72 370 310.27881 486.88321 +2293809 2.04 6.76 314 181.96284 172.576 +2293810 2.04 6.8 216 104.75198 83.0784 +2293811 2.04 6.84 154 70.988571 55.849602 +2293812 2.04 6.88 54 13.969804 4.9439998 +2293813 2.04 6.92 84 22.507929 8.5087996 +2293814 2.04 6.96 96 29.211536 12.7632 +2293815 2.04 7 56 16.001844 7.0864 +2293816 2.04 7.04 30 3.9217474 0.60479999 +2293817 2.04 7.08 49 7.6117167 1.6447999 +2293818 2.04 7.12 132 64.113037 49.916801 +2293819 2.04 7.16 139 70.363998 54.5952 +2293820 2.04 7.2 66 20.17219 10.7664 +2293821 2.04 7.24 61 24.034628 16.339199 +2359301 2.08 5 140 89.178246 106.8192 +2359302 2.08 5.04 144 86.597389 101.264 +2359303 2.08 5.08 161 89.297523 98.152 +2359304 2.08 5.12 173 89.888542 93.968002 +2359305 2.08 5.16 204 106.62606 105.088 +2359306 2.08 5.2 245 141.67859 137.91521 +2359307 2.08 5.24 211 109.78284 103.9632 +2359308 2.08 5.28 180 83.301079 77.574402 +2359309 2.08 5.32 175 81.785873 74.950401 +2359310 2.08 5.36 171 79.140343 71.134399 +2359311 2.08 5.4 174 79.907494 68.912003 +2359312 2.08 5.44 181 80.494835 66.014397 +2359313 2.08 5.48 187 80.558868 63.6768 +2359314 2.08 5.52 177 79.014824 61.700802 +2359315 2.08 5.56 169 76.21579 59.169601 +2359316 2.08 5.6 161 71.684547 55.220798 +2359317 2.08 5.64 157 70.12706 53.764801 +2359318 2.08 5.68 154 68.081177 51.091202 +2359319 2.08 5.72 154 68.053848 49.939201 +2359320 2.08 5.76 159 69.41954 49.264 +2359321 2.08 5.8 168 71.818077 48.737598 +2359322 2.08 5.84 177 76.555298 49.9888 +2359323 2.08 5.88 181 79.60157 51.374401 +2359324 2.08 5.92 206 91.585045 57.318401 +2359325 2.08 5.96 360 326.33109 499.02719 +2359326 2.08 6 385 371.35223 590.36798 +2359327 2.08 6.04 185 82.286728 52.484798 +2359328 2.08 6.08 174 76.432861 49.287998 +2359329 2.08 6.12 178 75.893166 48.923199 +2359330 2.08 6.16 166 72.165901 48.472 +2359331 2.08 6.2 159 69.575966 48.0928 +2359332 2.08 6.24 152 66.923538 47.655998 +2359333 2.08 6.28 149 65.81337 48.497601 +2359334 2.08 6.32 149 65.67643 49.1856 +2359335 2.08 6.36 149 65.871277 49.911999 +2359336 2.08 6.4 150 66.308228 50.526402 +2359337 2.08 6.44 157 68.673302 51.934399 +2359338 2.08 6.48 171 73.634361 55.358398 +2359339 2.08 6.52 236 100.42136 67.2192 +2359340 2.08 6.56 256 114.98533 79.512001 +2359341 2.08 6.6 350 194.10223 161.6288 +2359342 2.08 6.64 421 359.96951 550.40637 +2359343 2.08 6.68 425 370.25702 564.79199 +2359344 2.08 6.72 397 337.42932 513.79041 +2359345 2.08 6.76 326 186.69667 170.65601 +2359346 2.08 6.8 222 98.901466 75.222397 +2359347 2.08 6.84 189 84.594917 68.835197 +2359348 2.08 6.88 137 68.860207 65.795197 +2359349 2.08 6.92 138 75.5821 73.990402 +2359350 2.08 6.96 146 82.2967 81.288002 +2359351 2.08 7 121 69.863831 76.846397 +2359352 2.08 7.04 117 69.892143 80.582397 +2359353 2.08 7.08 114 71.953468 85.310402 +2359354 2.08 7.12 184 128.3018 140.29601 +2359355 2.08 7.16 179 129.79042 145.48959 +2359356 2.08 7.2 112 79.37368 100.7408 +2359357 2.08 7.24 100 77.669327 103.9776 +2424837 2.12 5 133 71.801277 66.491203 +2424838 2.12 5.04 139 69.060364 60.056 +2424839 2.12 5.08 148 66.837822 52.688 +2424840 2.12 5.12 157 64.488396 46.585602 +2424841 2.12 5.16 192 82.185387 58.142399 +2424842 2.12 5.2 232 115.39113 90.076797 +2424843 2.12 5.24 187 76.510239 52.112 +2424844 2.12 5.28 152 45.777275 21.316799 +2424845 2.12 5.32 138 37.462227 14.0768 +2424846 2.12 5.36 124 31.479498 10.52 +2424847 2.12 5.4 114 27.555025 8.2992001 +2424848 2.12 5.44 98 24.019798 7.4288001 +2424849 2.12 5.48 102 41.739704 29.3808 +2424850 2.12 5.52 128 45.991562 27.854401 +2424851 2.12 5.56 132 45.855312 26.052799 +2424852 2.12 5.6 130 43.537373 23.489599 +2424853 2.12 5.64 128 41.241177 20.844801 +2424854 2.12 5.68 123 37.209629 16.5648 +2424855 2.12 5.72 116 34.29842 15.0896 +2424856 2.12 5.76 111 32.838509 14.536 +2424857 2.12 5.8 93 30.814243 15.0208 +2424859 2.12 5.88 122 42.213745 21.2528 +2424860 2.12 5.92 159 57.539261 28.8064 +2424861 2.12 5.96 327 293.11151 457.0528 +2424862 2.12 6 350 338.32288 548.6944 +2424863 2.12 6.04 134 46.746914 23.396799 +2424864 2.12 6.08 114 40.609035 22.1024 +2424866 2.12 6.16 105 36.963699 20.662399 +2424867 2.12 6.2 110 34.535542 17.614401 +2424868 2.12 6.24 113 33.954453 16.1408 +2424869 2.12 6.28 117 34.976231 16.2416 +2424870 2.12 6.32 125 41.704193 23.164801 +2424871 2.12 6.36 127 45.438385 28.4496 +2424872 2.12 6.4 125 45.362587 29.270399 +2424873 2.12 6.44 127 49.167938 33.7584 +2424874 2.12 6.48 102 46.729992 36.993599 +2424876 2.12 6.56 197 69.768814 32.8368 +2424877 2.12 6.6 306 149.74509 106.4064 +2424878 2.12 6.64 388 320.78146 491.95999 +2424879 2.12 6.68 401 338.81396 513.0816 +2424880 2.12 6.72 373 306.29239 462.29599 +2424881 2.12 6.76 304 157.34274 121.9168 +2424882 2.12 6.8 195 84.032906 60.529598 +2424883 2.12 6.84 158 73.568115 58.4352 +2424884 2.12 6.88 60 16.015747 5.6336002 +2424885 2.12 6.92 83 24.141743 10.1424 +2424886 2.12 6.96 93 30.897537 14.8256 +2424887 2.12 7 64 18.660824 7.9664001 +2424888 2.12 7.04 35 5.6108823 1.1776 +2424889 2.12 7.08 55 11.071246 3.3584001 +2424890 2.12 7.12 127 68.909927 58.487999 +2424891 2.12 7.16 129 71.71521 60.903999 +2424892 2.12 7.2 77 26.489727 14.0592 +2424893 2.12 7.24 68 25.926464 16.681601 +2490373 2.16 5 110 39.382359 19.433599 +2490374 2.16 5.04 116 39.060928 18.416 +2490375 2.16 5.08 118 36.635838 16.056 +2490376 2.16 5.12 125 36.000813 14.1776 +2490377 2.16 5.16 160 52.733555 26.3696 +2490378 2.16 5.2 215 94.393799 64.8592 +2490379 2.16 5.24 174 63.712208 38.5504 +2490380 2.16 5.28 127 32.327065 10.864 +2490381 2.16 5.32 117 29.393942 9.7279997 +2490382 2.16 5.36 105 25.809628 8.3232002 +2490383 2.16 5.4 99 24.648048 7.8175998 +2490384 2.16 5.44 89 24.29335 8.1856003 +2490385 2.16 5.48 76 20.466681 7.7872 +2490386 2.16 5.52 79 17.924244 5.4527998 +2490387 2.16 5.56 86 18.484432 5.3807998 +2490388 2.16 5.6 90 19.322777 5.5296001 +2490389 2.16 5.64 94 21.843006 7.1696 +2490390 2.16 5.68 96 23.902161 8.6431999 +2490391 2.16 5.72 96 25.722212 10.1936 +2490392 2.16 5.76 96 28.999216 12.6304 +2490393 2.16 5.8 89 29.495028 14.0352 +2490395 2.16 5.88 84 25.890617 10.8112 +2490396 2.16 5.92 118 39.995693 19.212799 +2490397 2.16 5.96 293 268.75092 429.12799 +2490398 2.16 6 310 311.20053 516.39038 +2490399 2.16 6.04 93 27.482956 11.2416 +2490400 2.16 6.08 75 21.836847 8.5872002 +2490402 2.16 6.16 79 22.093275 8.4960003 +2490403 2.16 6.2 92 24.449011 9.0047998 +2490404 2.16 6.24 91 21.816679 7.3151999 +2490405 2.16 6.28 91 20.484171 6.3856001 +2490406 2.16 6.32 89 19.084623 5.5711999 +2490407 2.16 6.36 90 19.677826 5.776 +2490408 2.16 6.4 90 20.810917 6.4944 +2490409 2.16 6.44 88 22.952539 8.1583996 +2490410 2.16 6.48 75 20.049068 7.6128001 +2490412 2.16 6.56 168 61.781628 31.1408 +2490413 2.16 6.6 279 136.63336 96.6576 +2490414 2.16 6.64 361 306.23697 473.97281 +2490415 2.16 6.68 379 321.98416 488.336 +2490416 2.16 6.72 352 293.013 447.84799 +2490417 2.16 6.76 273 133.3428 94.924797 +2490418 2.16 6.8 161 56.290684 26.6432 +2490419 2.16 6.84 126 41.77129 17.6528 +2490420 2.16 6.88 36 7.4910388 2.0192001 +2490421 2.16 6.92 62 21.87215 11.1136 +2490422 2.16 6.96 76 28.231615 14.9424 +2490423 2.16 7 46 11.753185 3.8527999 +2490424 2.16 7.04 37 7.2004895 1.8448 +2490425 2.16 7.08 53 13.739306 5.3007998 +2490426 2.16 7.12 113 66.988457 60.980801 +2490427 2.16 7.16 109 65.056038 59.8368 +2490428 2.16 7.2 61 17.38118 7.1631999 +2490429 2.16 7.24 47 10.978067 3.4175999 +2555909 2.2 5 113 42.029846 20.236799 +2555910 2.2 5.04 113 38.414845 17.2672 +2555911 2.2 5.08 116 37.204807 15.944 +2555912 2.2 5.12 118 35.474571 14.232 +2555913 2.2 5.16 134 48.33107 27.260799 +2555914 2.2 5.2 218 93.742989 62.9744 +2555915 2.2 5.24 165 62.776459 39.903999 +2555916 2.2 5.28 111 28.723185 9.6239996 +2555917 2.2 5.32 104 26.315592 8.5696001 +2555918 2.2 5.36 105 28.512197 9.9968004 +2555919 2.2 5.4 98 27.693491 9.9535999 +2555920 2.2 5.44 92 27.720402 10.208 +2555921 2.2 5.48 72 18.980307 6.2736001 +2555922 2.2 5.52 75 18.038202 5.5664001 +2555923 2.2 5.56 75 16.364847 4.5696001 +2555924 2.2 5.6 79 16.578577 4.3600001 +2555925 2.2 5.64 81 17.221333 4.6128001 +2555926 2.2 5.68 82 18.363094 5.3232002 +2555927 2.2 5.72 84 21.715763 7.6304002 +2555928 2.2 5.76 79 21.642504 8.2144003 +2555929 2.2 5.8 82 25.930908 11.1808 +2555932 2.2 5.92 94 37.022778 21.4576 +2555933 2.2 5.96 280 260.80179 418.40161 +2555934 2.2 6 297 302.47021 498.55679 +2555935 2.2 6.04 77 24.45722 10.6784 +2555938 2.2 6.16 77 22.41048 8.6303997 +2555939 2.2 6.2 77 20.162447 7.1184001 +2555940 2.2 6.24 85 21.245399 7.0816002 +2555941 2.2 6.28 83 19.184225 5.8592 +2555942 2.2 6.32 81 17.617865 4.9424 +2555943 2.2 6.36 84 20.014 6.4544001 +2555944 2.2 6.4 83 21.311005 7.4768 +2555945 2.2 6.44 72 17.018276 5.1343999 +2555946 2.2 6.48 72 18.980307 6.2736001 +2555948 2.2 6.56 146 59.417389 34.028801 +2555949 2.2 6.6 265 128.44019 88.660797 +2555950 2.2 6.64 355 301.33881 459.28961 +2555951 2.2 6.68 375 321.34589 482.1232 +2555952 2.2 6.72 347 289.32343 436.65759 +2555953 2.2 6.76 267 130.33327 91.145599 +2555954 2.2 6.8 143 54.44194 28.1968 +2555955 2.2 6.84 119 42.222919 18.952 +2621450 2.24 5.2 202 84.652992 57.161598 +2621467 2.24 5.88 78 25.895033 12.512 +2621468 2.24 5.92 119 84.370705 110.9232 +2621469 2.24 5.96 276 257.06857 409.7616 +2621470 2.24 6 294 297.31488 483.71841 +2621471 2.24 6.04 80 27.622271 14.904 +2621472 2.24 6.08 72 22.196745 10.0976 +2621485 2.24 6.6 262 127.48661 86.440002 +2621486 2.24 6.64 354 295.53598 434.9184 +2621487 2.24 6.68 372 316.90759 466.7088 +2621488 2.24 6.72 349 287.5694 424.39359 +2621489 2.24 6.76 247 123.65753 85.820801 +2686981 2.28 5 84 23.211514 7.5952001 +2686982 2.28 5.04 86 21.663166 6.5440001 +2686983 2.28 5.08 86 19.688118 5.4095998 +2686984 2.28 5.12 87 18.261698 4.5616002 +2686985 2.28 5.16 111 26.696648 9.0207996 +2686986 2.28 5.2 182 77.99823 55.9296 +2686987 2.28 5.24 157 57.453087 34.0144 +2686988 2.28 5.28 175 99.033318 89.540802 +2686989 2.28 5.32 171 98.229385 89.463997 +2686990 2.28 5.36 139 61.185558 41.478401 +2686991 2.28 5.4 112 40.286095 21.372801 +2686992 2.28 5.44 94 28.659739 11.0352 +2687003 2.28 5.88 79 23.500954 10.7184 +2687004 2.28 5.92 126 66.872566 71.289597 +2687005 2.28 5.96 263 251.60129 400.74399 +2687006 2.28 6 289 291.47525 467.99841 +2687007 2.28 6.04 86 26.192947 12.9488 +2687008 2.28 6.08 70 17.86659 6.664 +2687021 2.28 6.6 255 124.92155 84.081596 +2687022 2.28 6.64 347 278.71524 384.66559 +2687023 2.28 6.68 373 315.67099 454.37601 +2687024 2.28 6.72 348 288.46765 417.8432 +2687025 2.28 6.76 239 120.48944 82.9776 +2752517 2.32 5 85 22.023762 6.9488001 +2752518 2.32 5.04 85 19.515556 5.5664001 +2752519 2.32 5.08 88 18.479792 4.8112001 +2752520 2.32 5.12 97 19.965464 5.112 +2752521 2.32 5.16 108 21.574352 5.224 +2752522 2.32 5.2 167 71.883057 54.649601 +2752523 2.32 5.24 164 63.913261 41.419201 +2752524 2.32 5.28 188 99.227203 85.456001 +2752525 2.32 5.32 175 95.433533 84.222397 +2752526 2.32 5.36 138 56.511669 36.529598 +2752527 2.32 5.4 108 33.706818 15.3984 +2752528 2.32 5.44 93 25.81868 9.1359997 +2752539 2.32 5.88 86 23.378195 9.4608002 +2752540 2.32 5.92 118 50.599609 43.639999 +2752541 2.32 5.96 258 250.10574 397.39999 +2752542 2.32 6 286 286.75342 453.58401 +2752543 2.32 6.04 90 25.158506 11.6272 +2752544 2.32 6.08 74 16.805161 5.2463999 +2752546 2.32 6.16 102 31.047518 11.5488 +2752547 2.32 6.2 105 31.124329 11.8848 +2752548 2.32 6.24 112 34.870495 15.0704 +2752549 2.32 6.28 120 40.177811 19.5312 +2752550 2.32 6.32 136 54.215992 32.528 +2752551 2.32 6.36 140 57.908974 35.528 +2752552 2.32 6.4 142 60.458412 37.2752 +2752553 2.32 6.44 134 55.885948 33.366402 +2752554 2.32 6.48 118 43.341579 20.8992 +2752556 2.32 6.56 119 45.353798 24.9888 +2752557 2.32 6.6 255 124.69859 83.939201 +2752558 2.32 6.64 345 267.16428 347.77121 +2752559 2.32 6.68 370 312.37186 440.31201 +2752560 2.32 6.72 348 289.70126 411.25601 +2752561 2.32 6.76 250 122.13171 82.950401 +2752562 2.32 6.8 117 45.499245 26.7264 +2818053 2.36 5 85 21.170202 6.5359998 +2818054 2.36 5.04 88 19.809267 5.6896 +2818055 2.36 5.08 94 20.11404 5.6160002 +2818056 2.36 5.12 98 19.376902 4.8927999 +2818057 2.36 5.16 108 21.485765 5.5999999 +2818058 2.36 5.2 159 68.333122 54.387199 +2818059 2.36 5.24 165 66.732353 45.876801 +2818060 2.36 5.28 194 98.245445 81.496002 +2818061 2.36 5.32 184 96.21595 81.136002 +2818062 2.36 5.36 141 54.049385 32.819199 +2818063 2.36 5.4 101 27.076134 10.424 +2818064 2.36 5.44 88 21.92823 6.7184 +2818075 2.36 5.88 84 20.133968 7.0847998 +2818076 2.36 5.92 114 39.15403 23.112 +2818077 2.36 5.96 255 246.96518 389.15839 +2818078 2.36 6 282 280.18747 437.34079 +2818079 2.36 6.04 91 24.42363 10.9664 +2818080 2.36 6.08 72 14.299877 3.5632 +2818082 2.36 6.16 100 27.15284 9.0095997 +2818083 2.36 6.2 105 28.232088 10.0448 +2818084 2.36 6.24 111 30.729425 12.0864 +2818085 2.36 6.28 120 36.371861 16.576 +2818086 2.36 6.32 136 49.887554 28.6768 +2818087 2.36 6.36 140 53.443562 31.408001 +2818088 2.36 6.4 143 56.591671 33.396801 +2818089 2.36 6.44 134 51.857227 29.604799 +2818090 2.36 6.48 115 37.895733 16.5952 +2818092 2.36 6.56 131 44.555428 20.968 +2818093 2.36 6.6 252 121.90993 80.806396 +2818094 2.36 6.64 339 257.42096 321.53601 +2818095 2.36 6.68 371 312.40714 430.72479 +2818096 2.36 6.72 345 286.63297 398.95679 +2818097 2.36 6.76 247 119.73451 80.523201 +2818098 2.36 6.8 124 40.670734 19.5536 +2818099 2.36 6.84 101 30.889687 12.8016 +2883589 2.4 5 87 21.76808 6.8192 +2883590 2.4 5.04 92 21.417067 6.5056 +2883591 2.4 5.08 95 20.425541 5.8512001 +2883592 2.4 5.12 98 19.338196 4.9871998 +2883593 2.4 5.16 110 23.548876 7.2672 +2883594 2.4 5.2 149 63.79744 53.396801 +2883595 2.4 5.24 166 72.14373 55.459202 +2883596 2.4 5.28 196 96.457588 77.075203 +2883597 2.4 5.32 192 96.139763 77.020798 +2883598 2.4 5.36 138 49.180237 27.649599 +2883599 2.4 5.4 99 24.355532 8.1968002 +2883600 2.4 5.44 89 22.076612 6.8239999 +2883601 2.4 5.48 99 28.338076 9.3936005 +2883602 2.4 5.52 99 26.283968 8.2575998 +2883603 2.4 5.56 98 24.314575 7.2336001 +2883604 2.4 5.6 98 23.407227 6.7584 +2883605 2.4 5.64 99 24.140123 7.6767998 +2883606 2.4 5.68 106 29.500341 11.568 +2883607 2.4 5.72 107 31.035128 12.4 +2883608 2.4 5.76 111 36.073177 16.4576 +2883609 2.4 5.8 117 43.332603 22.2864 +2883611 2.4 5.88 81 17.579962 5.1231999 +2883612 2.4 5.92 116 38.129456 19.742399 +2883613 2.4 5.96 254 246.81224 385.8176 +2883614 2.4 6 281 277.85074 426.63199 +2883615 2.4 6.04 88 21.146307 8.0847998 +2883616 2.4 6.08 73 13.954205 3.2576001 +2883618 2.4 6.16 98 23.925661 7.0640001 +2883619 2.4 6.2 103 24.620855 7.7663999 +2883620 2.4 6.24 108 26.172426 9.0640001 +2883621 2.4 6.28 118 31.93001 13.32 +2883622 2.4 6.32 136 46.120518 25.264 +2883623 2.4 6.36 141 50.217499 28.203199 +2883624 2.4 6.4 143 52.627251 29.5632 +2883625 2.4 6.44 135 48.889046 26.559999 +2883626 2.4 6.48 112 33.37841 13.2912 +2883628 2.4 6.56 140 46.455849 20.4496 +2883629 2.4 6.6 250 122.30885 81.734398 +2883630 2.4 6.64 333 246.16293 295.42719 +2883631 2.4 6.68 376 315.11633 423.06079 +2883632 2.4 6.72 346 286.73163 391.32321 +2883633 2.4 6.76 245 119.48609 80.689598 +2883634 2.4 6.8 133 42.102222 18.5056 +2883635 2.4 6.84 102 27.904093 9.9904003 +2949125 2.44 5 91 24.069202 7.9791999 +2949126 2.44 5.04 93 22.6196 7.2512002 +2949127 2.44 5.08 95 20.936886 6.1152 +2949128 2.44 5.12 99 20.556149 5.6399999 +2949129 2.44 5.16 108 25.568607 9.5120001 +2949130 2.44 5.2 146 65.384041 57.155201 +2949131 2.44 5.24 157 69.650795 57.556801 +2949132 2.44 5.28 199 95.012352 72.447998 +2949133 2.44 5.32 196 96.458672 74.358398 +2949134 2.44 5.36 136 44.814804 22.3088 +2949135 2.44 5.4 93 21.479176 6.4112 +2949136 2.44 5.44 91 23.507652 7.6128001 +2949137 2.44 5.48 99 25.868111 7.9408002 +2949138 2.44 5.52 99 23.656672 6.8048 +2949139 2.44 5.56 99 22.028542 5.9888 +2949140 2.44 5.6 101 22.955265 7.2704 +2949141 2.44 5.64 104 24.870157 8.7679996 +2949142 2.44 5.68 107 27.143057 10.2272 +2949143 2.44 5.72 110 30.178013 12.1952 +2949144 2.44 5.76 117 37.633255 18.0592 +2949145 2.44 5.8 117 41.247566 21.555201 +2949147 2.44 5.88 79 16.4041 4.3280001 +2949148 2.44 5.92 113 36.26059 18.2752 +2949149 2.44 5.96 255 248.32645 383.55841 +2949150 2.44 6 281 275.1554 414.90399 +2949151 2.44 6.04 87 20.586992 7.6176 +2949152 2.44 6.08 72 13.940583 3.3840001 +2949154 2.44 6.16 98 22.458633 6.2016001 +2949155 2.44 6.2 100 21.186428 5.6799998 +2949156 2.44 6.24 106 22.930782 6.9520001 +2949157 2.44 6.28 116 28.086861 10.4752 +2949158 2.44 6.32 135 42.002838 21.3664 +2949159 2.44 6.36 141 46.87661 24.9328 +2949160 2.44 6.4 143 49.256073 26.190399 +2949161 2.44 6.44 135 45.918346 23.6224 +2949162 2.44 6.48 108 28.810131 9.9407997 +2949164 2.44 6.56 151 53.251259 25.142401 +2949165 2.44 6.6 244 119.00291 79.587196 +2949166 2.44 6.64 327 238.09438 278.47839 +2949167 2.44 6.68 378 314.86804 412.784 +2949168 2.44 6.72 341 267.39624 334.8576 +2949169 2.44 6.76 236 114.9444 78.233597 +2949170 2.44 6.8 139 45.787209 20.9408 +2949171 2.44 6.84 105 28.342794 9.7296 +3014661 2.48 5 93 26.343472 9.3439999 +3014662 2.48 5.04 94 23.997847 7.848 +3014663 2.48 5.08 96 22.414553 6.7584 +3014664 2.48 5.12 99 21.962479 6.3392 +3014665 2.48 5.16 110 28.677963 11.6144 +3014666 2.48 5.2 143 68.010849 61.513599 +3014667 2.48 5.24 138 61.245945 54.243198 +3014668 2.48 5.28 201 93.792572 68.136002 +3014669 2.48 5.32 205 99.893875 73.563202 +3014670 2.48 5.36 119 33.049381 12.7136 +3014671 2.48 5.4 95 23.788391 7.7168002 +3014672 2.48 5.44 90 24.336477 8.2096004 +3014673 2.48 5.48 99 23.890995 6.8080001 +3014674 2.48 5.52 99 21.55685 5.6719999 +3014675 2.48 5.56 99 19.836058 4.8559999 +3014676 2.48 5.6 102 21.354502 6.5888 +3014677 2.48 5.64 107 24.065447 8.2287998 +3014678 2.48 5.68 110 26.175636 9.4927998 +3014679 2.48 5.72 117 32.794746 14.5872 +3014680 2.48 5.76 118 36.913143 18.593599 +3014681 2.48 5.8 120 41.129978 21.5984 +3014683 2.48 5.88 80 17.537695 5.0159998 +3014684 2.48 5.92 115 39.088902 21.027201 +3014685 2.48 5.96 257 250.46022 381.34879 +3014686 2.48 6 280 271.25156 401.6976 +3014687 2.48 6.04 87 22.522314 9.8752003 +3014688 2.48 6.08 73 15.164352 4.0879998 +3014690 2.48 6.16 96 20.586645 5.1968002 +3014691 2.48 6.2 98 19.164841 4.5728002 +3014692 2.48 6.24 104 20.403437 5.3263998 +3014693 2.48 6.28 114 25.351692 8.5888004 +3014694 2.48 6.32 132 36.997169 16.7808 +3014695 2.48 6.36 141 44.165913 22.1168 +3014696 2.48 6.4 144 46.904133 23.440001 +3014697 2.48 6.44 135 43.542473 21.120001 +3014698 2.48 6.48 102 24.23518 7.0128002 +3014700 2.48 6.56 153 57.65152 29.739201 +3014701 2.48 6.6 232 113.18958 76.792 +3014702 2.48 6.64 316 216.93454 229.54559 +3014703 2.48 6.68 387 319.26297 406.25919 +3014704 2.48 6.72 336 250.19733 290.2048 +3014705 2.48 6.76 228 110.93597 76.228798 +3014706 2.48 6.8 143 50.915245 26.024 +3014707 2.48 6.84 109 30.73826 11.0784 +3080197 2.52 5 92 27.492918 9.9807997 +3080198 2.52 5.04 92 24.954393 8.4015999 +3080199 2.52 5.08 98 25.468073 8.3456001 +3080200 2.52 5.12 98 23.871679 7.408 +3080201 2.52 5.16 112 33.886379 16.351999 +3080202 2.52 5.2 143 72.09565 66.588799 +3080203 2.52 5.24 133 62.650902 56.481602 +3080204 2.52 5.28 209 96.720192 66.649597 +3080205 2.52 5.32 213 102.5191 71.6912 +3080206 2.52 5.36 98 24.545853 7.9744 +3080207 2.52 5.4 95 26.026886 9.0752001 +3080208 2.52 5.44 92 27.531065 10.1632 +3080209 2.52 5.48 99 22.448984 5.9952002 +3080210 2.52 5.52 99 20.027828 4.8592 +3080211 2.52 5.56 99 18.23999 4.0432 +3080212 2.52 5.6 108 23.114809 7.7536001 +3080213 2.52 5.64 112 24.451399 8.1904001 +3080214 2.52 5.68 117 29.080223 11.8704 +3080215 2.52 5.72 121 34.797466 17.0704 +3080216 2.52 5.76 121 36.525146 17.945601 +3080217 2.52 5.8 118 36.525784 17 +3080219 2.52 5.88 77 17.906757 5.5823998 +3080220 2.52 5.92 113 40.990875 24.180799 +3080221 2.52 5.96 260 252.92873 378.81921 +3080222 2.52 6 281 270.72192 393.29599 +3080223 2.52 6.04 85 22.815947 10.3744 +3080224 2.52 6.08 72 16.118212 4.8080001 +3080226 2.52 6.16 95 19.840269 4.8207998 +3080227 2.52 6.2 97 18.326664 4.1264 +3080228 2.52 6.24 102 18.849606 4.4303999 +3080229 2.52 6.28 111 22.382889 6.3776002 +3080230 2.52 6.32 131 34.457516 14.3072 +3080231 2.52 6.36 142 42.616314 20.027201 +3080232 2.52 6.4 144 44.738503 20.958401 +3080233 2.52 6.44 135 41.774498 19.052799 +3080234 2.52 6.48 97 21.706116 5.6960001 +3080236 2.52 6.56 152 60.740761 33.8176 +3080237 2.52 6.6 220 109.53291 77.198402 +3080238 2.52 6.64 306 195.06593 186.5696 +3080239 2.52 6.68 400 325.23215 400.6608 +3080240 2.52 6.72 327 236.74025 265.18079 +3080241 2.52 6.76 219 108.00165 76.419197 +3080242 2.52 6.8 143 53.766697 29.2736 +3080243 2.52 6.84 107 32.848911 13.4768 +3145740 2.56 5.28 193 96.018463 65.720001 +3145741 2.56 5.32 223 106.57522 70.559998 +3145745 2.56 5.48 100 22.015041 5.7024002 +3145746 2.56 5.52 99 19.094389 4.3663998 +3145747 2.56 5.56 104 20.665718 5.9424 +3145748 2.56 5.6 111 23.1805 7.4032001 +3145749 2.56 5.64 120 28.053198 10.6688 +3145750 2.56 5.68 122 31.910679 14.4912 +3145751 2.56 5.72 120 31.543627 13.9184 +3145752 2.56 5.76 116 30.527962 12.5392 +3145753 2.56 5.8 115 31.318863 11.5856 +3145755 2.56 5.88 77 20.508144 7.8783998 +3145756 2.56 5.92 107 42.286747 28.382401 +3145757 2.56 5.96 264 255.88359 376.22079 +3145758 2.56 6 283 269.96823 384.19199 +3145759 2.56 6.04 85 26.858656 14.1808 +3145760 2.56 6.08 72 18.031601 5.9856 +3145762 2.56 6.16 95 20.142962 4.9903998 +3145763 2.56 6.2 96 18.240326 4.1264 +3145764 2.56 6.24 98 17.296539 3.6656001 +3145765 2.56 6.28 107 20.187422 4.9823999 +3145766 2.56 6.32 129 32.257652 12.2928 +3145767 2.56 6.36 142 41.14254 18.08 +3145768 2.56 6.4 145 43.569824 19.076799 +3145769 2.56 6.44 135 40.618332 17.420799 +3145770 2.56 6.48 92 20.469498 5.2575998 +3145772 2.56 6.56 147 63.753483 38.316799 +3145773 2.56 6.6 206 107.17625 79.827202 +3145774 2.56 6.64 279 159.04871 130.0768 +3145775 2.56 6.68 413 329.58594 395.19199 +3145776 2.56 6.72 311 206.54886 204.6944 +3145777 2.56 6.76 208 107.22983 79.923203 +3145778 2.56 6.8 139 58.079079 35.065601 +3145779 2.56 6.84 110 39.836937 19.856001 +3211267 2.6 4.92 98 48.64201 36.0256 +3211268 2.6 4.96 95 43.277508 29.6112 +3211269 2.6 5 82 29.831656 16.628799 +3211270 2.6 5.04 66 18.134392 7.6672001 +3211271 2.6 5.08 57 14.110662 5.5760002 +3211272 2.6 5.12 47 9.1046562 2.0480001 +3211276 2.6 5.28 172 89.331169 61.200001 +3211277 2.6 5.32 204 103.39691 67.7472 +3211281 2.6 5.48 101 22.249674 5.8256001 +3211282 2.6 5.52 100 19.163813 4.3488002 +3211283 2.6 5.56 113 24.38604 7.6592002 +3211284 2.6 5.6 121 27.538715 9.7376003 +3211285 2.6 5.64 125 31.26116 13.1584 +3211286 2.6 5.68 124 30.814224 12.776 +3211287 2.6 5.72 116 26.17038 8.6960001 +3211288 2.6 5.76 115 27.651682 9.2639999 +3211289 2.6 5.8 113 29.450909 10.232 +3211291 2.6 5.88 79 24.460316 10.5664 +3211292 2.6 5.92 105 48.894188 38.396801 +3211293 2.6 5.96 267 258.28711 373.12961 +3211294 2.6 6 285 269.24326 375.68961 +3211295 2.6 6.04 84 30.326359 17.601601 +3211296 2.6 6.08 72 20.171656 7.3376002 +3211298 2.6 6.16 93 20.431986 5.3039999 +3211299 2.6 6.2 95 18.749771 4.4432001 +3211300 2.6 6.24 96 17.480474 3.8448 +3211301 2.6 6.28 103 19.029057 4.3712001 +3211302 2.6 6.32 127 31.005703 11.04 +3211303 2.6 6.36 143 40.692532 16.752001 +3211304 2.6 6.4 145 42.608047 17.496 +3211305 2.6 6.44 133 38.505741 15.0032 +3211306 2.6 6.48 89 21.076752 5.6960001 +3211309 2.6 6.6 193 108.80457 85.924797 +3211310 2.6 6.64 257 136.99849 101.128 +3211311 2.6 6.68 434 340.03873 402.28961 +3211312 2.6 6.72 268 142.80251 104.4944 +3211313 2.6 6.76 190 106.15475 84.361603 +3276803 2.64 4.92 89 39.030582 28.2768 +3276804 2.64 4.96 100 45.446362 32.950401 +3276805 2.64 5 104 45.810898 31.0256 +3276806 2.64 5.04 87 29.249048 15.3072 +3276807 2.64 5.08 63 15.819238 6.4640002 +3276808 2.64 5.12 47 7.9607825 1.5872 +3276812 2.64 5.28 175 86.442856 56.364799 +3276813 2.64 5.32 205 100.8286 63.350399 +3276817 2.64 5.48 103 23.44799 6.4000001 +3276818 2.64 5.52 111 25.572342 8.1071997 +3276819 2.64 5.56 128 31.362982 11.1584 +3276820 2.64 5.6 131 33.340488 13.3296 +3276821 2.64 5.64 125 28.586546 10.0576 +3276822 2.64 5.68 117 24.177649 6.8656001 +3276823 2.64 5.72 117 25.811478 7.8544002 +3276824 2.64 5.76 116 28.05913 9.2335997 +3276825 2.64 5.8 116 31.020525 10.8896 +3276829 2.64 5.96 269 257.93427 365.048 +3276830 2.64 6 279 267.87546 368.20319 +3276834 2.64 6.16 93 21.876867 6.1135998 +3276835 2.64 6.2 93 19.774544 5.1216002 +3276836 2.64 6.24 95 18.680397 4.5103998 +3276837 2.64 6.28 98 18.644131 4.3424001 +3276838 2.64 6.32 121 27.859432 8.4720001 +3276839 2.64 6.36 144 40.846245 15.8976 +3276840 2.64 6.4 145 42.221409 16.382401 +3276845 2.64 6.6 180 112.16918 93.377602 +3276846 2.64 6.64 183 109.00253 89.897598 +3276847 2.64 6.68 451 341.84482 396.02719 +3276848 2.64 6.72 185 107.38881 87.731201 +3276849 2.64 6.76 172 108.93419 91.822403 +3342339 2.68 4.92 68 16.231276 5.3600001 +3342340 2.68 4.96 83 28.388485 17.971201 +3342341 2.68 5 101 41.172039 28.590401 +3342342 2.68 5.04 114 47.761585 31.385599 +3342343 2.68 5.08 106 38.255936 20.491199 +3342344 2.68 5.12 53 9.8327141 2.7360001 +3342348 2.68 5.28 208 96.584366 58.201599 +3342349 2.68 5.32 231 105.43041 61.998402 +3342353 2.68 5.48 104 24.78664 7.1087999 +3342354 2.68 5.52 140 38.764961 14.3152 +3342355 2.68 5.56 140 36.986313 13.7792 +3342356 2.68 5.6 129 28.843645 8.5791998 +3342357 2.68 5.64 125 26.718136 7.4352002 +3342358 2.68 5.68 124 27.455744 8.1456003 +3342359 2.68 5.72 121 28.394812 9.1775999 +3342360 2.68 5.76 122 32.382023 12.0912 +3342361 2.68 5.8 121 35.528988 14.176 +3342365 2.68 5.96 269 260.9852 362.992 +3342366 2.68 6 269 263.84412 360.03839 +3342370 2.68 6.16 93 23.828762 7.224 +3342371 2.68 6.2 93 21.847223 6.2319999 +3342372 2.68 6.24 93 20.44768 5.5408001 +3342373 2.68 6.28 95 19.957327 5.1919999 +3342374 2.68 6.32 112 25.204681 7.0464001 +3342375 2.68 6.36 145 41.330524 15.3424 +3342376 2.68 6.4 144 42.226788 15.7232 +3342379 2.68 6.52 246 162.1927 154.55521 +3342380 2.68 6.56 256 180.69125 191.7504 +3342381 2.68 6.6 267 198.45714 225.9744 +3342382 2.68 6.64 294 232.48856 300.12 +3342383 2.68 6.68 457 346.3465 400.44958 +3342384 2.68 6.72 293 225.49335 287.52802 +3342385 2.68 6.76 266 197.77563 226.744 +3342386 2.68 6.8 258 183.93323 197.68159 +3342387 2.68 6.84 243 162.47705 158.35361 +3407875 2.72 4.92 86 31.022507 18.2416 +3407876 2.72 4.96 88 29.352249 16.4704 +3407877 2.72 5 91 28.34428 14.9472 +3407878 2.72 5.04 119 48.332653 31.846399 +3407879 2.72 5.08 148 62.577179 38.535999 +3407880 2.72 5.12 176 70.439438 37.915199 +3407881 2.72 5.16 241 110.62124 63.755199 +3407882 2.72 5.2 236 104.97357 59.617599 +3407883 2.72 5.24 226 97.36895 54.023998 +3407884 2.72 5.28 259 108.34807 59.5312 +3407885 2.72 5.32 264 111.97591 61.7024 +3407886 2.72 5.36 225 100.81319 62.6464 +3407887 2.72 5.4 220 106.24221 75.436798 +3407888 2.72 5.44 208 101.02329 69.496002 +3407889 2.72 5.48 188 58.596161 22.3456 +3407890 2.72 5.52 161 46.732681 17.4048 +3407891 2.72 5.56 142 36.218613 11.8112 +3407892 2.72 5.6 137 34.348446 11.456 +3407893 2.72 5.64 134 33.812729 11.7664 +3407894 2.72 5.68 132 34.142315 12.472 +3407895 2.72 5.72 132 36.046364 14.0032 +3407896 2.72 5.76 129 36.989223 15.0144 +3407897 2.72 5.8 128 39.44965 16.889601 +3407901 2.72 5.96 310 286.4483 377.23999 +3407902 2.72 6 314 289.42984 372.87201 +3407906 2.72 6.16 92 26.002573 8.5760002 +3407907 2.72 6.2 92 24.211964 7.6016002 +3407908 2.72 6.24 92 22.958916 6.9247999 +3407909 2.72 6.28 93 22.41054 6.5616002 +3407910 2.72 6.32 96 22.667059 6.5279999 +3407911 2.72 6.36 144 41.810989 15.1216 +3407912 2.72 6.4 143 42.580166 15.504 +3407915 2.72 6.52 241 147.74417 133.74561 +3407916 2.72 6.56 262 174.20126 178.008 +3407917 2.72 6.6 278 193.54166 214.84 +3407918 2.72 6.64 339 248.11678 300.37119 +3407919 2.72 6.68 451 344.42502 397.18561 +3407920 2.72 6.72 353 258.95291 306.55359 +3407921 2.72 6.76 277 194.16962 216.08 +3407922 2.72 6.8 256 172.25639 178.9872 +3407923 2.72 6.84 241 150.56526 140.424 +3473411 2.76 4.92 97 38.222267 23.8736 +3473412 2.76 4.96 97 35.21537 21.134399 +3473413 2.76 5 99 33.788208 19.32 +3473414 2.76 5.04 103 33.022175 17.591999 +3473415 2.76 5.08 106 32.294415 15.9456 +3473416 2.76 5.12 166 68.0877 40.543999 +3473417 2.76 5.16 281 121.87315 68.416 +3473418 2.76 5.2 265 112.50618 61.156799 +3473419 2.76 5.24 256 104.76728 55.414398 +3473420 2.76 5.28 281 112.43497 58.971199 +3473421 2.76 5.32 284 114.44407 59.993599 +3473422 2.76 5.36 267 111.49501 65.422401 +3473423 2.76 5.4 257 113.30338 74.876801 +3473424 2.76 5.44 275 120.11343 75.907204 +3473425 2.76 5.48 171 50.516453 18.1952 +3473426 2.76 5.52 149 40.779076 13.6848 +3473427 2.76 5.56 145 39.255268 13.4112 +3473428 2.76 5.6 142 38.608486 13.6496 +3473429 2.76 5.64 140 38.307564 13.9168 +3473430 2.76 5.68 140 39.751347 15.2464 +3473431 2.76 5.72 138 41.198982 16.816 +3473432 2.76 5.76 137 42.997688 18.2864 +3473433 2.76 5.8 137 45.90205 20.649599 +3473434 2.76 5.84 104 40.100235 20.5856 +3473435 2.76 5.88 80 34.294888 19.867201 +3473436 2.76 5.92 96 41.426548 24.2976 +3473437 2.76 5.96 339 300.6102 381.67841 +3473438 2.76 6 340 301.94342 375.94879 +3473447 2.76 6.36 135 41.202343 15.0608 +3473448 2.76 6.4 140 42.740696 15.5952 +3473451 2.76 6.52 244 138.44972 116.2112 +3473452 2.76 6.56 269 167.47571 164.93919 +3473453 2.76 6.6 290 189.93753 200.73759 +3473454 2.76 6.64 362 262.75052 307.9296 +3473455 2.76 6.68 447 341.43793 391.95679 +3473456 2.76 6.72 371 271.96927 316.992 +3473457 2.76 6.76 285 189.21687 204.9696 +3473458 2.76 6.8 261 163.38513 163.24159 +3473459 2.76 6.84 241 138.76552 120.3728 +3538945 2.8 4.84 26 6.7065015 2.2368 +3538946 2.8 4.88 26 6.5531263 2.1472001 +3538947 2.8 4.92 83 28.496723 15.6704 +3538948 2.8 4.96 80 23.925625 12.1648 +3538949 2.8 5 78 21.16482 10.2432 +3538950 2.8 5.04 72 15.67489 5.7856002 +3538951 2.8 5.08 62 9.9602785 2.184 +3538952 2.8 5.12 50 7.4355497 1.304 +3538953 2.8 5.16 260 124.12385 74.337601 +3538954 2.8 5.2 275 117.29893 64.307198 +3538955 2.8 5.24 280 112.5738 58.2896 +3538956 2.8 5.28 289 112.39914 56.792 +3538957 2.8 5.32 280 107.39648 54.017601 +3538958 2.8 5.36 285 117.72711 67.961601 +3538959 2.8 5.4 259 107.3278 65.120003 +3538960 2.8 5.44 206 93.585457 61.366402 +3538961 2.8 5.48 106 31.140366 10.648 +3538962 2.8 5.52 117 31.289972 9.9152002 +3538963 2.8 5.56 126 34.094898 11.168 +3538964 2.8 5.6 129 35.049408 11.6688 +3538965 2.8 5.64 132 37.212387 13.1856 +3538966 2.8 5.68 133 39.371006 15.104 +3538967 2.8 5.72 133 41.114185 16.6112 +3538968 2.8 5.76 131 42.996151 18.4464 +3538969 2.8 5.8 126 45.285759 20.7376 +3538973 2.8 5.96 294 272.00146 357.16479 +3538974 2.8 6 322 281.62576 353.504 +3538983 2.8 6.36 117 36.949284 13.9008 +3538984 2.8 6.4 133 42.106956 15.8176 +3538987 2.8 6.52 247 129.5679 101.3136 +3538988 2.8 6.56 268 157.72998 148.89439 +3538989 2.8 6.6 297 185.45547 189.7664 +3538990 2.8 6.64 379 275.80621 319.26721 +3538991 2.8 6.68 444 340.36185 391.10721 +3538992 2.8 6.72 382 281.42587 325 +3538993 2.8 6.76 291 184.13937 192.4608 +3538994 2.8 6.8 266 157.36371 150.59039 +3538995 2.8 6.84 246 131.83324 106.7088 +3604481 2.84 4.84 27 6.093677 1.8368 +3604482 2.84 4.88 26 5.6515098 1.6752 +3604483 2.84 4.92 57 11.497465 2.8975999 +3604484 2.84 4.96 56 9.8414907 2.2 +3604485 2.84 5 54 8.3163071 1.592 +3604486 2.84 5.04 52 7.6277027 1.3744 +3604487 2.84 5.08 50 7.4611697 1.3424 +3604488 2.84 5.12 47 7.9607825 1.5872 +3604489 2.84 5.16 277 136.71858 87.1744 +3604490 2.84 5.2 277 124.14661 73.121597 +3604491 2.84 5.24 296 121.54653 65.060799 +3604492 2.84 5.28 302 117.67924 59.284801 +3604493 2.84 5.32 289 109.03543 53.807999 +3604494 2.84 5.36 292 120.48146 70.7472 +3604495 2.84 5.4 241 97.944984 59.056 +3604496 2.84 5.44 209 90.072014 56.2384 +3604509 2.84 5.96 357 292.26901 361.384 +3604510 2.84 6 388 323.79016 380.65759 +3604519 2.84 6.36 108 33.510082 12.7024 +3604520 2.84 6.4 123 40.08849 15.7376 +3604523 2.84 6.52 245 119.31032 85.467201 +3604524 2.84 6.56 273 150.6747 133.26401 +3604525 2.84 6.6 302 180.11603 176.5936 +3604526 2.84 6.64 389 281.88303 322.81281 +3604527 2.84 6.68 452 344.49945 394.25601 +3604528 2.84 6.72 390 287.9043 332.4848 +3604529 2.84 6.76 298 178.45212 177.5264 +3604530 2.84 6.8 270 149.62213 135.3024 +3604531 2.84 6.84 240 118.1138 87.705597 +3604533 2.84 6.92 83 22.786308 7.4144001 +3604534 2.84 6.96 83 21.408356 6.7424002 +3604535 2.84 7 85 21.418526 6.7600002 +3604536 2.84 7.04 91 24.370354 8.4879999 +3604537 2.84 7.08 95 27.755751 10.9856 +3604538 2.84 7.12 96 29.312677 11.8704 +3604539 2.84 7.16 100 33.079517 14.008 +3670017 2.88 4.84 30 5.9509678 1.5728 +3670018 2.88 4.88 28 5.2330184 1.3487999 +3670019 2.88 4.92 54 11.487489 2.8831999 +3670020 2.88 4.96 52 9.7762432 2.2176001 +3670021 2.88 5 50 8.514657 1.744 +3670022 2.88 5.04 50 8.4282379 1.7072001 +3670023 2.88 5.08 48 8.4430065 1.7728 +3670024 2.88 5.12 47 9.1046562 2.0480001 +3670025 2.88 5.16 312 163.02496 111.3744 +3670026 2.88 5.2 314 151.51718 96.8144 +3670027 2.88 5.24 326 146.46187 87.718399 +3670028 2.88 5.28 344 146.73788 82.524803 +3670029 2.88 5.32 332 133.28098 70.120003 +3670030 2.88 5.36 316 131.34325 76.972801 +3670031 2.88 5.4 247 96.807465 55.708801 +3670032 2.88 5.44 216 89.959999 53.062401 +3670033 2.88 5.48 150 64.653793 34.686401 +3670034 2.88 5.52 207 86.033112 43.936001 +3670035 2.88 5.56 199 76.41256 35.590401 +3670036 2.88 5.6 176 65.001961 28.9664 +3670037 2.88 5.64 152 61.369392 30.2528 +3670038 2.88 5.68 177 74.408974 38.4464 +3670039 2.88 5.72 202 76.720749 35.785599 +3670040 2.88 5.76 245 94.979286 44.507198 +3670041 2.88 5.8 256 97.916206 45.203201 +3670042 2.88 5.84 268 105.376 51.0144 +3670043 2.88 5.88 290 124.66447 69.939201 +3670044 2.88 5.92 344 187.12149 148.88161 +3670045 2.88 5.96 503 376.34308 419.7536 +3670046 2.88 6 514 384.3222 422.47681 +3670047 2.88 6.04 318 166.44257 119.4352 +3670048 2.88 6.08 302 156.61765 111.2592 +3670049 2.88 6.12 296 160.57521 119.816 +3670050 2.88 6.16 295 167.1246 129.6032 +3670051 2.88 6.2 294 176.49124 143.27521 +3670052 2.88 6.24 289 182.5011 153.976 +3670053 2.88 6.28 288 191.16454 166.7536 +3670054 2.88 6.32 71 22.495737 9.7200003 +3670055 2.88 6.36 110 35.567551 14.4432 +3670056 2.88 6.4 120 39.479145 16.062401 +3670057 2.88 6.44 116 38.260769 15.3984 +3670059 2.88 6.52 247 113.14834 75.171204 +3670060 2.88 6.56 276 142.98814 118.4576 +3670061 2.88 6.6 312 179.97034 169.392 +3670062 2.88 6.64 397 287.1626 326.19519 +3670063 2.88 6.68 452 343.83701 392.6976 +3670064 2.88 6.72 402 292.3714 333.94241 +3670065 2.88 6.76 310 180.29175 172.1328 +3670066 2.88 6.8 269 140.29514 119.2512 +3670067 2.88 6.84 241 110.88404 75.633598 +3670069 2.88 6.92 83 20.4732 6.0704002 +3670070 2.88 6.96 84 19.183294 5.4447999 +3670071 2.88 7 89 20.759233 6.368 +3670072 2.88 7.04 96 24.871632 9.1232004 +3670073 2.88 7.08 97 25.77951 9.5951996 +3670074 2.88 7.12 102 29.413937 11.5408 +3670075 2.88 7.16 102 31.487103 12.8192 +3735553 2.92 4.84 34 5.8792844 1.3376 +3735554 2.92 4.88 28 4.5862141 1.0304 +3735561 2.92 5.16 358 212.15204 171.88161 +3735562 2.92 5.2 379 210.00166 162.07359 +3735563 2.92 5.24 398 209.23906 153.424 +3735564 2.92 5.28 422 212.07173 147.45599 +3735565 2.92 5.32 414 198.07924 130.6416 +3735566 2.92 5.36 428 213.42834 149.5696 +3735567 2.92 5.4 375 167.29056 101.1056 +3735568 2.92 5.44 236 93.123802 52.246399 +3735569 2.92 5.48 273 135.15883 88.478401 +3735570 2.92 5.52 320 146.57327 85.662399 +3735571 2.92 5.56 314 140.19608 79.2864 +3735572 2.92 5.6 301 132.3887 73.584 +3735573 2.92 5.64 237 94.256035 46.361599 +3735574 2.92 5.68 198 79.710411 41.547199 +3735575 2.92 5.72 310 131.13956 69.406403 +3735576 2.92 5.76 324 140.14577 77.084801 +3735577 2.92 5.8 326 141.29926 78.660797 +3735578 2.92 5.84 322 140.28928 79.876801 +3735579 2.92 5.88 330 148.23357 89.142403 +3735580 2.92 5.92 374 199.45123 153.99519 +3735581 2.92 5.96 520 386.2941 426.78241 +3735582 2.92 6 528 392.22583 428.31201 +3735583 2.92 6.04 331 170.52539 123.1584 +3735584 2.92 6.08 309 158.33998 114.616 +3735585 2.92 6.12 308 164.93591 124.9456 +3735586 2.92 6.16 304 170.90851 134.80479 +3735587 2.92 6.2 300 177.83286 146.2592 +3735588 2.92 6.24 292 182.70215 156.056 +3735589 2.92 6.28 290 191.18771 169.0656 +3735590 2.92 6.32 90 28.14035 11.672 +3735591 2.92 6.36 121 41.322639 18.1152 +3735592 2.92 6.4 120 39.718739 16.719999 +3735593 2.92 6.44 119 40.707737 17.417601 +3735595 2.92 6.52 246 106.26759 64.956802 +3735596 2.92 6.56 277 134.53978 103.4864 +3735597 2.92 6.6 316 175.88043 159.17599 +3735598 2.92 6.64 410 299.52469 342.104 +3735599 2.92 6.68 456 343.86163 389.88321 +3735600 2.92 6.72 405 293.24362 333.58081 +3735601 2.92 6.76 320 178.73674 162.84801 +3735602 2.92 6.8 271 133.84842 107.1408 +3735603 2.92 6.84 241 103.35139 64.139198 +3735605 2.92 6.92 83 18.575243 4.9952002 +3735606 2.92 6.96 87 18.707726 5.3072 +3735607 2.92 7 97 22.903288 7.6799998 +3735608 2.92 7.04 102 24.907566 8.7552004 +3735609 2.92 7.08 104 26.486828 9.592 +3735610 2.92 7.12 105 28.274229 10.5248 +3735611 2.92 7.16 103 29.388485 11.184 +3801088 2.96 4.8 85 41.581909 29.2064 +3801089 2.96 4.84 58 13.859875 4.7536001 +3801090 2.96 4.88 30 4.5404897 0.89279997 +3801091 2.96 4.92 193 129.37222 117.2784 +3801092 2.96 4.96 192 116.09351 98.3424 +3801093 2.96 5 186 101.59654 79.564796 +3801094 2.96 5.04 172 81.4235 56.063999 +3801095 2.96 5.08 127 39.823441 15.872 +3801096 2.96 5.12 92 27.770664 11.2768 +3801097 2.96 5.16 382 235.87764 206.4128 +3801098 2.96 5.2 420 239.7036 198.6656 +3801099 2.96 5.24 435 237.36275 188.4384 +3801100 2.96 5.28 455 238.19411 178.72 +3801101 2.96 5.32 447 223.56174 159.5744 +3801102 2.96 5.36 467 241.29996 178.06081 +3801103 2.96 5.4 468 236.99042 168.29601 +3801104 2.96 5.44 450 216.2874 144.16319 +3801105 2.96 5.48 405 188.88159 117.4624 +3801106 2.96 5.52 374 170.54704 102.6848 +3801107 2.96 5.56 362 161.16765 93.444801 +3801108 2.96 5.6 356 155.45341 87.601601 +3801109 2.96 5.64 352 150.75609 82.908798 +3801110 2.96 5.68 352 149.30342 81.737602 +3801111 2.96 5.72 350 148.8269 81.806396 +3801112 2.96 5.76 343 145.94128 80.6912 +3801113 2.96 5.8 339 144.5766 81.065598 +3801114 2.96 5.84 337 143.96118 82.239998 +3801115 2.96 5.88 339 147.61288 87.367996 +3801116 2.96 5.92 397 206.3087 154.8752 +3801117 2.96 5.96 539 395.32129 430.9584 +3801118 2.96 6 540 396.14984 428.86081 +3801119 2.96 6.04 334 165.94984 117.4064 +3801120 2.96 6.08 316 157.32072 113.0928 +3801121 2.96 6.12 312 163.14531 122.9376 +3801122 2.96 6.16 308 168.91061 132.6864 +3801123 2.96 6.2 305 175.74461 143.5296 +3801124 2.96 6.24 297 181.3558 153.93919 +3801125 2.96 6.28 291 188.44608 165.8096 +3801126 2.96 6.32 104 33.364124 13.9712 +3801127 2.96 6.36 125 41.763016 18.164801 +3801128 2.96 6.4 139 47.316441 20.624001 +3801129 2.96 6.44 130 46.336147 21.084801 +3801131 2.96 6.52 249 102.71947 58.257599 +3801132 2.96 6.56 277 126.43604 89.457603 +3801133 2.96 6.6 325 175.80861 153.2128 +3801134 2.96 6.64 419 304.79086 346.74399 +3801135 2.96 6.68 459 343.69019 387.80161 +3801136 2.96 6.72 414 295.46216 332.00961 +3801137 2.96 6.76 338 186.93533 164.0448 +3801138 2.96 6.8 293 141.04265 105.7984 +3801139 2.96 6.84 255 110.78763 68.323196 +3801141 2.96 6.92 83 17.128313 4.1887999 +3801142 2.96 6.96 100 23.130611 7.3568001 +3801143 2.96 7 106 24.39456 7.9424 +3801144 2.96 7.04 109 25.525942 8.4848003 +3801145 2.96 7.08 107 25.276199 8.3936005 +3801146 2.96 7.12 107 27.00593 9.4239998 +3801147 2.96 7.16 108 29.962065 11.1632 +3866624 3 4.8 269 285.2059 384.064 +3866625 3 4.84 306 286.14209 368.616 +3866626 3 4.88 316 281.14218 351.73761 +3866627 3 4.92 310 273.35226 332.5968 +3866628 3 4.96 312 263.85147 309.83679 +3866629 3 5 322 259.8038 294.31039 +3866630 3 5.04 332 252.69942 273.3168 +3866631 3 5.08 345 246.62799 253.92641 +3866632 3 5.12 374 249.69357 243.4688 +3866633 3 5.16 444 264.87527 236.3136 +3866634 3 5.2 457 263.85822 226.2016 +3866635 3 5.24 465 258.03333 211.2928 +3866636 3 5.28 477 255.05229 198.79201 +3866637 3 5.32 469 244.33694 187.384 +3866638 3 5.36 484 255.58507 195.84801 +3866639 3 5.4 481 246.41516 180.75681 +3866640 3 5.44 466 227.62523 158.5632 +3866641 3 5.48 428 200.38931 132.008 +3866642 3 5.52 408 190.89244 123.6544 +3866643 3 5.56 393 181.09453 115.0656 +3866644 3 5.6 373 168.28201 104.6224 +3866645 3 5.64 369 164.16472 100.4464 +3866646 3 5.68 365 159.90039 96.188797 +3866647 3 5.72 358 156.15387 93.7808 +3866648 3 5.76 357 155.86826 93.590401 +3866649 3 5.8 353 153.51762 92.344002 +3866650 3 5.84 352 155.09401 94.873596 +3866651 3 5.88 356 158.59486 98.5504 +3866652 3 5.92 410 208.02751 150.216 +3866653 3 5.96 547 397.59076 430.3584 +3866654 3 6 550 397.54211 425.90079 +3866655 3 6.04 345 165.2907 112.7184 +3866656 3 6.08 331 162.29266 114.8864 +3866657 3 6.12 324 166.16064 123.1776 +3866658 3 6.16 318 169.6765 131.0864 +3866659 3 6.2 308 172.95802 140.13921 +3866660 3 6.24 306 181.82072 152.93919 +3866661 3 6.28 293 187.83348 164.7776 +3866662 3 6.32 111 35.56448 14.9712 +3866663 3 6.36 155 51.711483 22.249599 +3866664 3 6.4 184 68.285156 31.9744 +3866665 3 6.44 185 75.544006 39.409599 +3866667 3 6.52 251 96.904282 49.8288 +3866668 3 6.56 280 119.34347 76.624001 +3866669 3 6.6 344 183.02953 153.0768 +3866670 3 6.64 446 321.07849 356.39679 +3866671 3 6.68 497 375.69952 419.1568 +3866672 3 6.72 463 339.43518 376.8544 +3866673 3 6.76 392 235.65625 216.6208 +3866674 3 6.8 346 186.42545 155.37601 +3866675 3 6.84 314 167.43939 139.81599 +3866677 3 6.92 99 21.90798 6.0256 +3866678 3 6.96 117 27.258326 8.4175997 +3866679 3 7 118 26.564445 8.0880003 +3866680 3 7.04 113 24.881172 7.5567999 +3866681 3 7.08 111 25.387308 8.1280003 +3866682 3 7.12 111 27.838657 9.8559999 +3866683 3 7.16 122 46.272751 35.766399 +3932160 3.04 4.8 300 306.1478 405.21759 +3932161 3.04 4.84 320 299.5354 383.90561 +3932162 3.04 4.88 326 291.02536 363.00641 +3932163 3.04 4.92 317 279.61249 341.9024 +3932164 3.04 4.96 321 271.3609 322.09921 +3932165 3.04 5 329 265.8786 305.0528 +3932166 3.04 5.04 339 259.02194 286.44321 +3932167 3.04 5.08 375 268.3595 279.59201 +3932168 3.04 5.12 408 269.8913 265.90561 +3932169 3.04 5.16 456 277.92145 257.24799 +3932170 3.04 5.2 459 270.13348 241.696 +3932171 3.04 5.24 468 265.42044 228.4496 +3932172 3.04 5.28 478 262.75681 217.336 +3932173 3.04 5.32 474 253.80664 205.7744 +3932174 3.04 5.36 492 264.13156 211.27679 +3932175 3.04 5.4 492 260.94006 203.70239 +3932176 3.04 5.44 474 238.14188 176.0368 +3932177 3.04 5.48 444 215.88725 153.2832 +3932178 3.04 5.52 418 200.89526 140.26241 +3932179 3.04 5.56 404 193.81007 133.39841 +3932180 3.04 5.6 396 187.50414 126.7472 +3932181 3.04 5.64 385 179.59515 119.5456 +3932182 3.04 5.68 376 171.62955 112.3072 +3932183 3.04 5.72 367 166.64774 108.1744 +3932184 3.04 5.76 366 165.46899 106.4592 +3932185 3.04 5.8 366 165.85594 106.4912 +3932186 3.04 5.84 366 165.61865 106.4048 +3932187 3.04 5.88 367 166.86472 107.7472 +3932188 3.04 5.92 421 212.84048 151.0224 +3932189 3.04 5.96 567 413.94699 444.96799 +3932190 3.04 6 569 414.15894 442.37439 +3932191 3.04 6.04 367 182.38228 128.2368 +3932192 3.04 6.08 353 179.01418 129.6944 +3932193 3.04 6.12 351 184.35657 137.70399 +3932194 3.04 6.16 346 187.8327 144.6608 +3932195 3.04 6.2 346 194.46359 154.0704 +3932196 3.04 6.24 346 201.18672 164.336 +3932197 3.04 6.28 358 212.4406 177.3904 +3932198 3.04 6.32 393 239.18513 200.5632 +3932199 3.04 6.36 380 243.6611 213.416 +3932200 3.04 6.4 373 245.28171 222.8448 +3932201 3.04 6.44 368 244.07941 227.6848 +3932202 3.04 6.48 369 243.03621 232.216 +3932203 3.04 6.52 431 271.83929 255.4704 +3932204 3.04 6.56 443 289.05621 281.936 +3932205 3.04 6.6 490 349.74985 365.2384 +3932206 3.04 6.64 579 486.22412 579.52161 +3932207 3.04 6.68 618 535.16101 647.20001 +3932208 3.04 6.72 565 481.20602 587.50403 +3932209 3.04 6.76 483 365.36923 417.08801 +3932210 3.04 6.8 432 306.61496 348.7168 +3932211 3.04 6.84 407 281.94812 326.86401 +3932212 3.04 6.88 356 259.74207 320.87521 +3932213 3.04 6.92 282 224.78014 308.26559 +3932214 3.04 6.96 259 218.97029 315.37921 +3932215 3.04 7 247 214.1096 317.09439 +3932216 3.04 7.04 238 211.9409 321.4256 +3932217 3.04 7.08 232 212.01784 328.0144 +3932218 3.04 7.12 226 209.70573 327.16641 +3932219 3.04 7.16 222 212.46121 336.21921 +3997696 3.08 4.8 297 303.10629 401.19519 +3997697 3.08 4.84 316 295.11691 378.4512 +3997698 3.08 4.88 324 287.88385 358.95041 +3997699 3.08 4.92 314 276.25323 337.832 +3997700 3.08 4.96 319 269.50211 319.76001 +3997701 3.08 5 326 263.26926 302.33759 +3997702 3.08 5.04 352 269.14133 294.09439 +3997703 3.08 5.08 369 265.4147 277.82559 +3997704 3.08 5.12 402 268.10809 265.43359 +3997705 3.08 5.16 447 272.81335 253.97279 +3997706 3.08 5.2 455 267.15765 239.6192 +3997707 3.08 5.24 463 263.10223 227.0896 +3997708 3.08 5.28 478 262.97372 217.4512 +3997709 3.08 5.32 477 255.58261 206.26401 +3997710 3.08 5.36 493 264.64627 210.8416 +3997711 3.08 5.4 488 257.13675 198.8528 +3997712 3.08 5.44 467 234.63095 174.0096 +3997713 3.08 5.48 436 211.99486 151.1264 +3997714 3.08 5.52 420 202.09621 141.024 +3997715 3.08 5.56 404 193.03607 132.71201 +3997716 3.08 5.6 392 186.21957 126.4448 +3997717 3.08 5.64 387 182.71283 122.4976 +3997718 3.08 5.68 385 179.71841 118.8912 +3997719 3.08 5.72 373 171.39308 111.7968 +3997720 3.08 5.76 368 168.05602 108.9632 +3997721 3.08 5.8 367 167.604 108.488 +3997722 3.08 5.84 368 169.01961 110.008 +3997723 3.08 5.88 371 171.03979 111.8784 +3997724 3.08 5.92 415 203.6002 138.0192 +3997725 3.08 5.96 574 419.28796 449.4368 +3997726 3.08 6 571 415.51892 443.40961 +3997727 3.08 6.04 375 188.35931 133.28 +3997728 3.08 6.08 357 183.07394 133.9088 +3997729 3.08 6.12 352 186.59917 140.7952 +3997730 3.08 6.16 351 191.35672 147.8976 +3997731 3.08 6.2 350 197.88655 157.8 +3997732 3.08 6.24 350 204.04774 167.1904 +3997733 3.08 6.28 358 214.15875 179.8624 +3997734 3.08 6.32 387 239.15179 202.976 +3997735 3.08 6.36 369 239.0824 211.744 +3997736 3.08 6.4 362 238.38428 216.6848 +3997737 3.08 6.44 362 240.58443 224.13921 +3997738 3.08 6.48 375 248.6382 233.8096 +3997739 3.08 6.52 429 267.45822 250.0208 +3997740 3.08 6.56 446 289.85107 281.40161 +3997741 3.08 6.6 493 350.22226 364.064 +3997742 3.08 6.64 583 487.20367 577.44958 +3997743 3.08 6.68 624 539.53442 651.18878 +3997744 3.08 6.72 568 478.31674 578.36157 +3997745 3.08 6.76 481 356.44235 398.53439 +3997746 3.08 6.8 419 286.80704 315.71359 +3997747 3.08 6.84 394 261.37863 290.46881 +3997748 3.08 6.88 318 226.71831 272.77759 +3997749 3.08 6.92 282 211.39117 274.7088 +3997750 3.08 6.96 254 204.65642 282.34079 +3997751 3.08 7 243 204.45125 293.1264 +3997752 3.08 7.04 237 206.15927 304.11359 +3997753 3.08 7.08 233 208.21883 313.60959 +3997754 3.08 7.12 229 211.37726 324.74399 +3997755 3.08 7.16 227 216.45682 337.50879 +4063232 3.12 4.8 247 246.4873 316.37439 +4063233 3.12 4.84 273 240.50584 294.71841 +4063234 3.12 4.88 281 234.4556 278.48959 +4063235 3.12 4.92 271 222.22125 257.30881 +4063236 3.12 4.96 287 228.27834 255.37601 +4063237 3.12 5 304 232.91679 250.2464 +4063238 3.12 5.04 313 227.80765 234.112 +4063239 3.12 5.08 336 235.28737 231.79041 +4063240 3.12 5.12 353 232.49414 218.30881 +4063241 3.12 5.16 425 245.85609 210.9904 +4063242 3.12 5.2 430 241.84695 201.8688 +4063243 3.12 5.24 440 238.49185 190.44321 +4063244 3.12 5.28 453 237.72368 181.9856 +4063245 3.12 5.32 454 233.30954 174.44 +4063246 3.12 5.36 473 244.03697 181.1008 +4063247 3.12 5.4 470 237.36023 170.2128 +4063248 3.12 5.44 452 219.23354 151.304 +4063249 3.12 5.48 412 191.60184 124.9424 +4063250 3.12 5.52 399 185.56627 119.4672 +4063251 3.12 5.56 378 173.86888 109.96 +4063252 3.12 5.6 376 170.61494 106.0528 +4063253 3.12 5.64 372 167.78447 103.3648 +4063254 3.12 5.68 371 166.4176 102.2128 +4063255 3.12 5.72 365 163.99062 100.7472 +4063256 3.12 5.76 359 160.41261 98.526398 +4063257 3.12 5.8 354 156.70488 95.270401 +4063258 3.12 5.84 348 152.16412 91.513603 +4063259 3.12 5.88 355 155.51407 94.015999 +4063260 3.12 5.92 388 181.09587 116.1984 +4063261 3.12 5.96 556 401.72137 430.8848 +4063262 3.12 6 550 395.73163 423.65121 +4063263 3.12 6.04 349 168.6797 116.4256 +4063264 3.12 6.08 323 159.94722 115.52 +4063265 3.12 6.12 319 164.16309 123.4976 +4063266 3.12 6.16 312 168.40761 132.57761 +4063267 3.12 6.2 303 171.78307 140.7424 +4063268 3.12 6.24 301 180.11104 153.0992 +4063269 3.12 6.28 290 186.83986 165.37601 +4063270 3.12 6.32 115 41.985519 21.104 +4063271 3.12 6.36 142 50.748955 24.8944 +4063272 3.12 6.4 167 64.232712 32.617599 +4063273 3.12 6.44 158 67.213646 37.175999 +4063275 3.12 6.52 241 87.386703 39.969601 +4063276 3.12 6.56 274 106.20513 57.431999 +4063277 3.12 6.6 333 171.00977 135.37601 +4063278 3.12 6.64 446 320.51633 350.26401 +4063279 3.12 6.68 505 387.19986 434.23361 +4063280 3.12 6.72 464 337.05276 366.90561 +4063281 3.12 6.76 390 229.02234 201.5984 +4063282 3.12 6.8 333 170.82875 134.56799 +4063283 3.12 6.84 297 153.19315 123.4096 +4063285 3.12 6.92 93 19.674591 5.1567998 +4063286 3.12 6.96 123 29.640238 9.5391998 +4063287 3.12 7 114 25.315889 7.6528001 +4063288 3.12 7.04 112 24.913868 7.7487998 +4063289 3.12 7.08 111 25.320509 8.0704002 +4063290 3.12 7.12 110 26.996445 9.2032003 +4063291 3.12 7.16 108 28.932966 10.56 +4128768 3.16 4.8 42 13.327939 5.7839999 +4128769 3.16 4.84 39 6.889689 1.5776 +4128770 3.16 4.88 29 4.73382 1.0592 +4128771 3.16 4.92 168 104.91836 88.203201 +4128772 3.16 4.96 168 91.781197 70.092796 +4128773 3.16 5 150 67.815201 43.0784 +4128774 3.16 5.04 127 48.152073 25.881599 +4128775 3.16 5.08 113 38.803425 19.087999 +4128776 3.16 5.12 69 19.397087 7.7600002 +4128777 3.16 5.16 355 215.65956 186.3136 +4128778 3.16 5.2 375 211.64218 174.64799 +4128779 3.16 5.24 396 210.51851 163.48959 +4128780 3.16 5.28 416 213.29005 156.7616 +4128781 3.16 5.32 420 211.78104 152.424 +4128782 3.16 5.36 436 220.36288 157.12959 +4128783 3.16 5.4 425 206.77844 139.5824 +4128784 3.16 5.44 413 192.6102 124.3616 +4128785 3.16 5.48 362 168.94011 106.16 +4128786 3.16 5.52 351 160.44887 97.444801 +4128787 3.16 5.56 353 159.13219 93.531197 +4128788 3.16 5.6 348 154.98006 89.2192 +4128789 3.16 5.64 350 152.74246 84.956802 +4128790 3.16 5.68 346 148.50285 82.171204 +4128791 3.16 5.72 340 146.15814 81.227203 +4128792 3.16 5.76 337 146.00421 82.6064 +4128793 3.16 5.8 333 144.77597 83.649597 +4128794 3.16 5.84 333 143.80528 83.420799 +4128795 3.16 5.88 340 148.97957 88.5056 +4128796 3.16 5.92 363 165.87131 104.3856 +4128797 3.16 5.96 546 394.01614 422.9888 +4128798 3.16 6 536 385.72137 414.896 +4128799 3.16 6.04 333 160.13019 109.2224 +4128800 3.16 6.08 310 152.57179 108.7024 +4128801 3.16 6.12 305 157.37149 117.232 +4128802 3.16 6.16 301 163.42891 127.32 +4128803 3.16 6.2 300 172.11256 139.4464 +4128804 3.16 6.24 293 178.54353 150.536 +4128805 3.16 6.28 289 186.43147 162.8528 +4128806 3.16 6.32 112 43.682781 23.568001 +4128807 3.16 6.36 119 45.730396 24.8304 +4128808 3.16 6.4 121 47.800858 26.420799 +4128809 3.16 6.44 109 44.055561 24.5872 +4128811 3.16 6.52 236 88.245117 42.123199 +4128812 3.16 6.56 262 103.58092 56.768002 +4128813 3.16 6.6 326 166.77905 130.99361 +4128814 3.16 6.64 431 310.00848 340.59521 +4128815 3.16 6.68 480 370.276 420.2496 +4128816 3.16 6.72 427 304.66785 333.16 +4128817 3.16 6.76 337 178.358 144.0032 +4128818 3.16 6.8 273 115.20872 68.985603 +4128819 3.16 6.84 243 96.810638 52.190399 +4128821 3.16 6.92 83 17.128313 4.1887999 +4128822 3.16 6.96 97 21.272156 6.2336001 +4128823 3.16 7 111 27.025276 9.3535995 +4128824 3.16 7.04 110 26.065348 8.7952003 +4128825 3.16 7.08 107 25.454184 8.5727997 +4128826 3.16 7.12 105 26.04426 8.9535999 +4128827 3.16 7.16 106 28.961067 10.608 +4194305 3.2 4.84 30 5.7652979 1.4912 +4194306 3.2 4.88 27 5.0522752 1.3135999 +4194307 3.2 4.92 75 26.693171 14.4528 +4194308 3.2 4.96 83 32.136166 19.524799 +4194309 3.2 5 77 25.613506 13.4784 +4194310 3.2 5.04 68 17.73901 6.552 +4194311 3.2 5.08 68 18.388031 6.9200001 +4194312 3.2 5.12 68 19.094198 7.0704002 +4194313 3.2 5.16 326 189.39143 154.87041 +4194314 3.2 5.2 335 180.91406 139.9456 +4194315 3.2 5.24 340 169.00072 119.7968 +4194316 3.2 5.28 347 156.54019 96.582397 +4194317 3.2 5.32 343 150.37836 90.086403 +4194318 3.2 5.36 333 142.24568 83.118401 +4194319 3.2 5.4 265 97.877777 48.865601 +4194320 3.2 5.44 204 77.11097 40.420799 +4194321 3.2 5.48 208 106.26859 73.059196 +4194322 3.2 5.52 248 103.83669 55.268799 +4194323 3.2 5.56 251 99.81015 48.624001 +4194324 3.2 5.6 241 96.757286 48.048 +4194325 3.2 5.64 184 76.418167 40.326401 +4194326 3.2 5.68 180 72.889717 37.633598 +4194327 3.2 5.72 251 101.16173 52.2528 +4194328 3.2 5.76 283 115.87157 60.712002 +4194329 3.2 5.8 300 127.66702 71.083199 +4194330 3.2 5.84 312 136.29858 79.152 +4194331 3.2 5.88 326 148.26349 90.889603 +4194332 3.2 5.92 351 168.81058 112.9264 +4194333 3.2 5.96 538 389.75046 420.35519 +4194334 3.2 6 526 381.0748 412.71841 +4194335 3.2 6.04 320 157.44823 108.408 +4194336 3.2 6.08 303 152.73003 108.7696 +4194337 3.2 6.12 296 155.50166 115.5184 +4194338 3.2 6.16 296 163.6087 126.7648 +4194339 3.2 6.2 295 171.69041 138.35361 +4194340 3.2 6.24 288 177.28717 148.6192 +4194341 3.2 6.28 288 187.5023 162.936 +4194342 3.2 6.32 101 42.141998 24.523199 +4194343 3.2 6.36 104 42.948174 25.419201 +4194344 3.2 6.4 103 42.006329 24.8992 +4194345 3.2 6.44 93 39.828022 23.740801 +4194347 3.2 6.52 230 87.913895 43.980801 +4194348 3.2 6.56 255 102.92833 58.041599 +4194349 3.2 6.6 313 158.90723 123.3424 +4194350 3.2 6.64 428 305.2117 329.35681 +4194351 3.2 6.68 488 383.7525 436.328 +4194352 3.2 6.72 422 303.99194 332.65921 +4194353 3.2 6.76 316 165.76581 133.7552 +4194354 3.2 6.8 252 102.16079 59.1488 +4194355 3.2 6.84 229 86.95871 43.279999 +4194357 3.2 6.92 83 18.575243 4.9952002 +4194358 3.2 6.96 86 18.24155 4.9552002 +4194359 3.2 7 98 23.307735 7.8175998 +4194360 3.2 7.04 106 27.177498 10.0816 +4194361 3.2 7.08 103 26.312174 9.5967999 +4194362 3.2 7.12 105 28.274229 10.5248 +4194363 3.2 7.16 103 29.424183 11.2224 +4259841 3.24 4.84 27 6.0168109 1.7920001 +4259842 3.24 4.88 27 5.832253 1.7104 +4259843 3.24 4.92 71 21.333469 10.1584 +4259844 3.24 4.96 81 28.698267 16.9648 +4259845 3.24 5 81 26.454065 14.4048 +4259846 3.24 5.04 72 18.256544 7.2351999 +4259847 3.24 5.08 70 17.251848 6.1167998 +4259848 3.24 5.12 69 17.703981 6.1872001 +4259849 3.24 5.16 275 137.60223 91.332802 +4259850 3.24 5.2 274 127.27692 79.689598 +4259851 3.24 5.24 275 117.72443 68.344002 +4259852 3.24 5.28 280 110.39739 58.041599 +4259853 3.24 5.32 272 107.02144 58.6464 +4259854 3.24 5.36 260 100.69891 53.703999 +4259855 3.24 5.4 215 77.945946 39.755199 +4259856 3.24 5.44 195 77.610741 43.625599 +4259857 3.24 5.48 128 52.066845 26.740801 +4259858 3.24 5.52 173 69.55941 34.926399 +4259859 3.24 5.56 172 64.802238 30.246401 +4259860 3.24 5.6 157 57.638287 25.9984 +4259861 3.24 5.64 142 58.275364 29.686399 +4259862 3.24 5.68 174 72.292641 36.848 +4259863 3.24 5.72 191 70.891571 31.915199 +4259864 3.24 5.76 227 88.659538 43.513599 +4259865 3.24 5.8 245 97.323059 49.073601 +4259866 3.24 5.84 259 103.53677 52.870399 +4259867 3.24 5.88 282 121.46165 68.430397 +4259868 3.24 5.92 311 151.72411 102.344 +4259869 3.24 5.96 525 377.97293 410.08319 +4259870 3.24 6 511 370.18506 403.18561 +4259871 3.24 6.04 298 147.75584 99.7136 +4259872 3.24 6.08 287 145.1375 101.1264 +4259873 3.24 6.12 283 148.22972 107.0688 +4259874 3.24 6.16 282 155.47636 117.5696 +4259875 3.24 6.2 280 164.30658 131.0304 +4259876 3.24 6.24 284 177.65083 148.83681 +4259877 3.24 6.28 282 185.34163 160.6432 +4259878 3.24 6.32 89 41.818237 26.312 +4259879 3.24 6.36 96 40.436947 24.856001 +4259880 3.24 6.4 97 42.221485 26.504 +4259881 3.24 6.44 87 40.034889 25.028799 +4259883 3.24 6.52 229 91.553207 48.7808 +4259884 3.24 6.56 250 104.68884 62.9328 +4259885 3.24 6.6 300 151.96605 118.9456 +4259886 3.24 6.64 418 296.58411 316.95999 +4259887 3.24 6.68 494 390.99408 442.4512 +4259888 3.24 6.72 416 303.50266 332.92319 +4259889 3.24 6.76 305 159.99535 129.94881 +4259890 3.24 6.8 250 105.62165 64.900803 +4259891 3.24 6.84 227 91.348122 50.1936 +4259893 3.24 6.92 83 20.4732 6.0704002 +4259894 3.24 6.96 84 19.183294 5.4447999 +4259895 3.24 7 90 21.136593 6.5103998 +4259896 3.24 7.04 97 25.44014 9.4463997 +4259897 3.24 7.08 105 30.302172 12.344 +4259898 3.24 7.12 100 28.700823 11.272 +4259899 3.24 7.16 100 30.329388 12.056 +4325377 3.28 4.84 26 6.6675682 2.2096 +4325378 3.28 4.88 26 6.5166049 2.1328001 +4325379 3.28 4.92 67 16.109274 5.7407999 +4325380 3.28 4.96 79 24.191868 12.7184 +4325381 3.28 5 84 26.795893 14.72 +4325382 3.28 5.04 75 18.343124 7.3376002 +4325383 3.28 5.08 70 15.504112 5.0367999 +4325384 3.28 5.12 69 16.066582 5.1536002 +4325385 3.28 5.16 242 113.23853 69.006401 +4325386 3.28 5.2 231 97.006844 53.731201 +4325387 3.28 5.24 231 89.743546 46.231998 +4325388 3.28 5.28 244 91.149643 45.248001 +4325389 3.28 5.32 250 99.231262 55.019199 +4325390 3.28 5.36 236 92.355324 49.454399 +4325391 3.28 5.4 194 72.953621 39.428799 +4325392 3.28 5.44 187 76.101768 43.548801 +4325403 3.28 5.88 44 10.038424 3.0864 +4325404 3.28 5.92 104 46.874172 31.5504 +4325405 3.28 5.96 348 284.89667 348.78879 +4325406 3.28 6 340 279.56198 342.44159 +4325407 3.28 6.04 62 20.797184 10.968 +4325408 3.28 6.08 38 7.4723382 1.9152 +4325415 3.28 6.36 92 42.082451 27.617599 +4325416 3.28 6.4 87 42.028797 27.992001 +4325419 3.28 6.52 226 95.450111 54.820801 +4325420 3.28 6.56 242 105.59325 67.059196 +4325421 3.28 6.6 290 149.43929 120.7184 +4325422 3.28 6.64 407 289.14459 310.24481 +4325423 3.28 6.68 503 400.80969 451.27521 +4325424 3.28 6.72 420 307.24136 335.78561 +4325425 3.28 6.76 291 152.99718 127.0768 +4325426 3.28 6.8 245 109.38222 73.422401 +4325427 3.28 6.84 220 92.002289 53.076801 +4325429 3.28 6.92 83 22.786308 7.4144001 +4325430 3.28 6.96 83 21.408356 6.7424002 +4325431 3.28 7 85 21.686769 7.1487999 +4325432 3.28 7.04 90 24.00281 8.368 +4325433 3.28 7.08 96 28.436926 11.4496 +4325434 3.28 7.12 102 33.125443 14.4032 +4325435 3.28 7.16 100 33.578781 14.5904 +4390915 3.32 4.92 66 14.990209 5.2031999 +4390916 3.32 4.96 73 18.611401 8.4736004 +4390917 3.32 5 85 25.633595 13.5424 +4390918 3.32 5.04 81 20.973816 9.2720003 +4390919 3.32 5.08 71 14.538219 4.3151999 +4390920 3.32 5.12 71 15.570145 4.6367998 +4390921 3.32 5.16 215 96.697273 55.492802 +4390922 3.32 5.2 209 87.671967 48.099201 +4390923 3.32 5.24 209 81.504868 42.265598 +4390924 3.32 5.28 230 88.296219 45.4384 +4390925 3.32 5.32 240 98.161697 55.152 +4390926 3.32 5.36 219 87.66909 47.380798 +4390927 3.32 5.4 184 73.970482 42.9744 +4390928 3.32 5.44 181 77.149773 45.563202 +4390939 3.32 5.88 58 14.61967 5.0960002 +4390940 3.32 5.92 115 40.677982 19.937599 +4390941 3.32 5.96 318 275.23666 347.33441 +4390942 3.32 6 305 262.57748 335.11041 +4390943 3.32 6.04 82 24.917185 10.4352 +4390944 3.32 6.08 73 33.350075 25.6304 +4390951 3.32 6.36 87 42.554436 29.0832 +4390952 3.32 6.4 86 44.204044 31.132799 +4390953 3.32 6.44 9 0.67803377 0.056000002 +4390955 3.32 6.52 226 100.44596 60.798401 +4390956 3.32 6.56 239 110.97665 75.731201 +4390957 3.32 6.6 275 147.229 126.8944 +4390958 3.32 6.64 400 285.42752 308.70721 +4390959 3.32 6.68 511 403.04703 446.608 +4390960 3.32 6.72 412 296.58502 318.10559 +4390961 3.32 6.76 282 154.54916 136.1696 +4390962 3.32 6.8 237 112.16035 80.5504 +4390963 3.32 6.84 221 98.028473 60.2048 +4456451 3.36 4.92 69 15.808177 5.4559999 +4456452 3.36 4.96 68 13.359553 4.0208001 +4456453 3.36 5 86 25.114708 12.7104 +4456454 3.36 5.04 87 23.729494 10.9536 +4456455 3.36 5.08 72 13.885287 3.7423999 +4456456 3.36 5.12 72 15.037488 4.1408 +4456457 3.36 5.16 198 89.29718 50.431999 +4456458 3.36 5.2 196 84.911949 47.492802 +4456459 3.36 5.24 191 78.324951 42.464001 +4456460 3.36 5.28 224 89.980637 48.547199 +4456461 3.36 5.32 240 102.23216 58.2784 +4456462 3.36 5.36 190 77.044121 42.475201 +4456463 3.36 5.4 180 77.433578 46.313599 +4456464 3.36 5.44 174 77.778572 47.454399 +4456475 3.36 5.88 69 18.826794 7.1279998 +4456476 3.36 5.92 98 30.655605 13.488 +4456477 3.36 5.96 312 273.68289 350.03519 +4456478 3.36 6 296 259.03159 337.02881 +4456479 3.36 6.04 74 19.497139 7.2096 +4456480 3.36 6.08 59 17.626604 7.888 +4456487 3.36 6.36 86 45.378212 32.491199 +4456488 3.36 6.4 82 45.096119 33.5536 +4456489 3.36 6.44 12 1.1826197 0.16159999 +4456491 3.36 6.52 219 104.75481 68.358398 +4456492 3.36 6.56 235 117.89436 87.9776 +4456493 3.36 6.6 260 147.96555 135.6864 +4456494 3.36 6.64 386 269.81708 289.6528 +4456495 3.36 6.68 521 405.2955 442.91199 +4456496 3.36 6.72 402 286.02222 306.0864 +4456497 3.36 6.76 269 154.95058 144.8736 +4456498 3.36 6.8 236 119.02737 89.931198 +4456499 3.36 6.84 216 102.58612 67.292801 +4521987 3.4 4.92 65 14.051261 4.5344 +4521988 3.4 4.96 71 14.987683 4.8319998 +4521989 3.4 5 80 19.29541 7.8144002 +4521990 3.4 5.04 91 25.207209 11.512 +4521991 3.4 5.08 74 14.03632 3.5583999 +4521992 3.4 5.12 71 13.962708 3.4400001 +4521993 3.4 5.16 189 88.361374 50.763199 +4521994 3.4 5.2 187 85.483803 49.832001 +4521995 3.4 5.24 187 82.760773 47.348801 +4521996 3.4 5.28 223 93.70871 52.366402 +4521997 3.4 5.32 240 107.04491 63.015999 +4521998 3.4 5.36 180 80.270615 47.3344 +4521999 3.4 5.4 178 83.948471 54.700802 +4522000 3.4 5.44 175 83.726578 52.9408 +4522011 3.4 5.88 62 17.826691 7.2431998 +4522012 3.4 5.92 79 20.414181 7.2607999 +4522013 3.4 5.96 314 273.72491 353.00479 +4522014 3.4 6 295 263.09473 347.19839 +4522015 3.4 6.04 65 17.114332 6.5296001 +4522016 3.4 6.08 57 16.266886 6.6528001 +4522023 3.4 6.36 83 46.978073 35.073601 +4522024 3.4 6.4 82 48.138897 37.248001 +4522025 3.4 6.44 18 3.034009 0.70719999 +4522027 3.4 6.52 215 109.43261 75.3936 +4522028 3.4 6.56 226 122.3838 97.0784 +4522029 3.4 6.6 255 155.66858 150.8848 +4522030 3.4 6.64 364 254.77324 279.9664 +4522031 3.4 6.68 532 407.7717 441.65121 +4522032 3.4 6.72 383 267.93436 286.78079 +4522033 3.4 6.76 257 158.68805 155.528 +4522034 3.4 6.8 229 126.30561 102.7536 +4522035 3.4 6.84 217 111.39352 77.7136 +4587523 3.44 4.92 59 11.272802 2.8192 +4587524 3.44 4.96 66 13.404613 4.0640001 +4587525 3.44 5 73 14.911999 4.4400001 +4587526 3.44 5.04 94 25.628658 10.8448 +4587527 3.44 5.08 85 19.23628 6.2543998 +4587528 3.44 5.12 70 13.510636 3.1503999 +4587532 3.44 5.28 184 87.265923 53.387199 +4587533 3.44 5.32 225 107.50577 65.248001 +4587547 3.44 5.88 55 16.347317 6.7343998 +4587548 3.44 5.92 61 17.929689 7.4432001 +4587549 3.44 5.96 320 274.43207 356.784 +4587550 3.44 6 305 271.99124 359.05759 +4587551 3.44 6.04 59 17.108496 6.9679999 +4587552 3.44 6.08 54 16.288822 6.8671999 +4587563 3.44 6.52 214 116.50597 84.760002 +4587564 3.44 6.56 227 132.735 111.3808 +4587565 3.44 6.6 246 162.22377 163.20959 +4587566 3.44 6.64 284 209.13023 251.856 +4587567 3.44 6.68 541 406.59702 437.60159 +4587568 3.44 6.72 296 208.37917 242.5984 +4587569 3.44 6.76 249 166.24361 168.9968 +4587570 3.44 6.8 230 136.85611 117.6336 +4587571 3.44 6.84 216 119.03523 88.265602 +4653059 3.48 4.92 53 9.7860441 2.1456001 +4653060 3.48 4.96 55 9.6227465 2.1631999 +4653061 3.48 5 65 12.731128 3.4576001 +4653062 3.48 5.04 104 29.844608 12.288 +4653063 3.48 5.08 107 28.701813 10.7264 +4653064 3.48 5.12 67 12.803747 2.8943999 +4653068 3.48 5.28 175 87.678726 57.439999 +4653069 3.48 5.32 214 105.90837 66.776001 +4653083 3.48 5.88 153 91.236832 75.337601 +4653084 3.48 5.92 173 111.46124 98.939201 +4653085 3.48 5.96 319 273.52127 361.29919 +4653086 3.48 6 321 279.25226 368.31201 +4653087 3.48 6.04 170 106.83343 92.526398 +4653088 3.48 6.08 153 93.950623 81.172798 +4653099 3.48 6.52 279 184.00923 156.0896 +4653100 3.48 6.56 280 182.20584 155.1792 +4653101 3.48 6.6 279 178.2612 150.56 +4653102 3.48 6.64 279 176.21028 148.1264 +4653103 3.48 6.68 546 401.89478 430.09439 +4653104 3.48 6.72 279 175.60222 146.9856 +4653105 3.48 6.76 281 179.05898 150.448 +4653106 3.48 6.8 283 183.84343 155.7536 +4653107 3.48 6.84 285 189.1093 160.8672 +4718595 3.52 4.92 53 11.153886 2.7504001 +4718596 3.52 4.96 53 10.258481 2.4047999 +4718597 3.52 5 53 9.7986956 2.2320001 +4718598 3.52 5.04 53 9.7986956 2.2320001 +4718599 3.52 5.08 136 36.515694 12.8288 +4718600 3.52 5.12 53 11.153886 2.7504001 +4718604 3.52 5.28 197 101.64323 68.876801 +4718605 3.52 5.32 228 108.93305 69.020798 +4718619 3.52 5.88 154 84.795479 66.756798 +4718620 3.52 5.92 185 107.9444 91.236801 +4718621 3.52 5.96 315 273.60031 367.36639 +4718622 3.52 6 320 278.55991 373.29761 +4718623 3.52 6.04 176 102.96487 85.7584 +4718624 3.52 6.08 150 82.604904 65.092796 +4718635 3.52 6.52 279 174.56334 142.79359 +4718636 3.52 6.56 281 173.94872 143.8768 +4718637 3.52 6.6 285 170.19998 137.8992 +4718638 3.52 6.64 350 199.14301 153.2128 +4718639 3.52 6.68 529 395.41711 427.35999 +4718640 3.52 6.72 365 207.49899 157.99519 +4718641 3.52 6.76 286 170.35776 137.4144 +4718642 3.52 6.8 284 174.69962 142.6832 +4718643 3.52 6.84 284 178.73549 146.6992 +4784133 3.56 5 113 37.637146 15.3488 +4784134 3.56 5.04 115 34.503574 12.9872 +4784135 3.56 5.08 154 42.56052 14.6336 +4784136 3.56 5.12 132 36.775688 13.6352 +4784137 3.56 5.16 152 70.46386 58.822399 +4784138 3.56 5.2 167 88.366745 81.705597 +4784139 3.56 5.24 183 104.89032 102.5216 +4784140 3.56 5.28 234 106.96112 70.217598 +4784141 3.56 5.32 233 107.29855 69.996803 +4784142 3.56 5.36 114 32.078686 11.4752 +4784143 3.56 5.4 114 35.139694 13.5712 +4784144 3.56 5.44 111 36.618893 14.8096 +4784155 3.56 5.88 154 75.37542 53.497601 +4784156 3.56 5.92 191 104.98361 84.700798 +4784157 3.56 5.96 315 274.51901 374.3056 +4784158 3.56 6 322 280.11679 380.64001 +4784159 3.56 6.04 181 99.676407 80.113602 +4784160 3.56 6.08 151 74.961555 54.513599 +4784171 3.56 6.52 283 167.9126 132.4944 +4784172 3.56 6.56 286 166.22685 131.70399 +4784173 3.56 6.6 297 164.85274 126.8512 +4784174 3.56 6.64 368 210.00127 162.336 +4784175 3.56 6.68 510 386.5878 425.73441 +4784176 3.56 6.72 406 261.6387 241.1024 +4784177 3.56 6.76 302 167.18726 127.6304 +4784178 3.56 6.8 290 169.08952 133.6544 +4784179 3.56 6.84 288 171.28506 134.8208 +4849669 3.6 5 114 35.091648 13.5728 +4849670 3.6 5.04 123 34.921398 12.784 +4849671 3.6 5.08 144 38.394089 12.9232 +4849672 3.6 5.12 143 36.483582 11.7696 +4849673 3.6 5.16 158 62.884594 46.462399 +4849674 3.6 5.2 171 84.542656 75.841599 +4849675 3.6 5.24 186 101.04 96.783997 +4849676 3.6 5.28 228 104.20677 71.198402 +4849677 3.6 5.32 226 105.26564 72.255997 +4849678 3.6 5.36 131 36.904808 13.7936 +4849679 3.6 5.4 115 32.951805 12.2096 +4849680 3.6 5.44 112 34.515949 13.2928 +4849691 3.6 5.88 156 68.553345 43.372799 +4849692 3.6 5.92 203 107.34419 82.113602 +4849693 3.6 5.96 313 273.23203 379.952 +4849694 3.6 6 325 282.0802 388.90881 +4849695 3.6 6.04 186 96.419052 73.776001 +4849696 3.6 6.08 146 63.308136 39.528 +4849707 3.6 6.52 284 159.94545 121.0656 +4849708 3.6 6.56 293 160.14421 120.928 +4849709 3.6 6.6 307 162.11749 118.656 +4849710 3.6 6.64 396 245.95044 220.4416 +4849711 3.6 6.68 495 376.45529 422.52802 +4849712 3.6 6.72 418 283.85822 285.47519 +4849713 3.6 6.76 313 164.95998 119.7632 +4849714 3.6 6.8 299 163.69766 123.0592 +4849715 3.6 6.84 289 162.56738 121.9584 +4915205 3.64 5 117 34.660728 12.9792 +4915206 3.64 5.04 126 34.173012 11.968 +4915207 3.64 5.08 142 36.938423 12.208 +4915208 3.64 5.12 143 35.345108 11.1696 +4915209 3.64 5.16 161 57.077602 36.708801 +4915210 3.64 5.2 179 82.745964 70.935997 +4915211 3.64 5.24 202 105.2439 95.414398 +4915212 3.64 5.28 223 102.25796 72.734398 +4915213 3.64 5.32 216 100.42537 71.982399 +4915214 3.64 5.36 152 48.425785 21.9296 +4915215 3.64 5.4 115 30.590506 10.6592 +4915216 3.64 5.44 109 31.153164 11.192 +4915227 3.64 5.88 151 59.021183 31.881599 +4915228 3.64 5.92 210 106.3511 77.425598 +4915229 3.64 5.96 315 273.56274 386.92319 +4915230 3.64 6 324 281.64362 395.70239 +4915231 3.64 6.04 195 96.881264 70.246399 +4915232 3.64 6.08 146 56.138435 29.788799 +4915243 3.64 6.52 289 153.36447 109.8448 +4915244 3.64 6.56 298 155.55373 112.1152 +4915245 3.64 6.6 319 162.93791 114.3536 +4915246 3.64 6.64 408 266.7323 262.7648 +4915247 3.64 6.68 481 367.09738 422.88321 +4915248 3.64 6.72 428 297.8053 312.62561 +4915249 3.64 6.76 323 165.63701 115.9424 +4915250 3.64 6.8 304 159.0667 114.2512 +4915251 3.64 6.84 296 158.13094 113.5072 +4980741 3.68 5 115 31.84926 11.024 +4980742 3.68 5.04 131 35.147251 11.9856 +4980743 3.68 5.08 141 36.435745 12.0448 +4980744 3.68 5.12 142 34.554558 10.8448 +4980745 3.68 5.16 160 51.591976 29.384001 +4980746 3.68 5.2 183 81.420792 67.038399 +4980747 3.68 5.24 219 109.21953 93.384003 +4980748 3.68 5.28 221 101.8166 75.070396 +4980749 3.68 5.32 215 101.41496 75.440002 +4980750 3.68 5.36 165 57.301041 29.283199 +4980751 3.68 5.4 116 29.788738 10 +4980752 3.68 5.44 108 29.181211 9.8319998 +4980763 3.68 5.88 147 53.296783 26.1712 +4980764 3.68 5.92 221 108.55283 75.374397 +4980765 3.68 5.96 322 276.4371 395.84161 +4980766 3.68 6 332 285.353 405.4592 +4980767 3.68 6.04 206 98.509697 67.695999 +4980768 3.68 6.08 141 49.791374 23.7904 +4980779 3.68 6.52 290 147.28296 100.8576 +4980780 3.68 6.56 304 151.8914 104.3744 +4980781 3.68 6.6 329 165.65765 114.112 +4980782 3.68 6.64 411 275.94928 288.4592 +4980783 3.68 6.68 469 357.26855 422.10239 +4980784 3.68 6.72 432 311.68463 352.74081 +4980785 3.68 6.76 332 167.49342 114.6304 +4980786 3.68 6.8 310 155.25868 106.3856 +4980787 3.68 6.84 302 154.88715 106.1232 +5046277 3.72 5 118 33.841423 12.3792 +5046278 3.72 5.04 129 34.548061 11.728 +5046279 3.72 5.08 140 36.499531 12.1664 +5046280 3.72 5.12 141 34.567535 11.0064 +5046281 3.72 5.16 155 41.453159 15.7424 +5046282 3.72 5.2 198 87.227699 67.772797 +5046283 3.72 5.24 230 114.69283 94.8144 +5046284 3.72 5.28 219 102.88044 78.811203 +5046285 3.72 5.32 214 102.34213 78.692802 +5046286 3.72 5.36 164 59.806667 33.16 +5046287 3.72 5.4 120 32.692966 12.0528 +5046288 3.72 5.44 107 28.217854 9.1264 +5046299 3.72 5.88 135 43.395359 18.096001 +5046300 3.72 5.92 231 110.6135 74.047997 +5046301 3.72 5.96 331 280.10056 405.60321 +5046302 3.72 6 344 290.0437 414.82239 +5046303 3.72 6.04 214 99.142281 64.971199 +5046304 3.72 6.08 128 39.405678 15.5552 +5046315 3.72 6.52 295 144.21135 94.32 +5046316 3.72 6.56 309 149.26927 98.400002 +5046317 3.72 6.6 335 166.22925 112.6432 +5046318 3.72 6.64 414 280.33197 301.01599 +5046319 3.72 6.68 463 351.0303 421.0896 +5046320 3.72 6.72 436 323.82007 392.28961 +5046321 3.72 6.76 339 168.24883 113.0608 +5046322 3.72 6.8 318 155.04358 102.1008 +5046323 3.72 6.84 305 150.08501 97.8256 +5111813 3.76 5 121 37.404617 15.0848 +5111814 3.76 5.04 132 38.353199 14.464 +5111815 3.76 5.08 136 36.413818 12.5728 +5111816 3.76 5.12 146 37.00024 12.0064 +5111817 3.76 5.16 153 39.571491 13.8912 +5111818 3.76 5.2 209 92.075829 69.183998 +5111819 3.76 5.24 244 121.80574 97.644798 +5111820 3.76 5.28 220 105.93861 83.608002 +5111821 3.76 5.32 207 103.07091 82.9552 +5111822 3.76 5.36 160 61.18861 36.084801 +5111823 3.76 5.4 124 36.65136 15.1152 +5111824 3.76 5.44 107 29.307137 9.8752003 +5111835 3.76 5.88 122 37.137108 14.6672 +5111836 3.76 5.92 240 112.77154 74.070396 +5111837 3.76 5.96 347 286.68719 417.47198 +5111838 3.76 6 358 296.58817 427.6416 +5111839 3.76 6.04 224 100.75686 63.495998 +5111840 3.76 6.08 114 33.854713 12.7936 +5111851 3.76 6.52 299 141.98611 89.512001 +5111852 3.76 6.56 314 147.59059 93.528 +5111853 3.76 6.6 337 164.26064 109.52 +5111854 3.76 6.64 417 286.9361 320.12799 +5111855 3.76 6.68 453 343.44788 423.0816 +5111856 3.76 6.72 432 319.89462 395.4624 +5111857 3.76 6.76 344 168.46283 112.0896 +5111858 3.76 6.8 323 154.02339 98.537598 +5111859 3.76 6.84 313 149.66727 93.575996 +5177349 3.8 5 109 31.196402 10.6544 +5177350 3.8 5.04 126 37.119129 13.9024 +5177351 3.8 5.08 139 41.659462 16.3696 +5177352 3.8 5.12 141 37.751297 13.0432 +5177353 3.8 5.16 155 40.686817 14.4128 +5177354 3.8 5.2 224 98.344856 70.321602 +5177355 3.8 5.24 253 126.09697 98.214401 +5177356 3.8 5.28 217 107.69743 87.603203 +5177357 3.8 5.32 197 102.33067 86.049599 +5177358 3.8 5.36 161 66.170029 41.585602 +5177359 3.8 5.4 128 42.895687 20.6224 +5177360 3.8 5.44 111 34.124973 13.4512 +5177371 3.8 5.88 74 21.538057 8.9119997 +5177372 3.8 5.92 256 119.12682 78.294403 +5177373 3.8 5.96 364 292.68958 429.51041 +5177374 3.8 6 377 304.03152 440.52481 +5177375 3.8 6.04 238 102.69073 61.422401 +5177376 3.8 6.08 68 17.727894 6.0960002 +5177387 3.8 6.52 303 140.48882 85.760002 +5177388 3.8 6.56 319 148.98289 93.767998 +5177389 3.8 6.6 338 163.131 108.5744 +5177390 3.8 6.64 422 296.21005 346.5376 +5177391 3.8 6.68 449 339.70905 427.8208 +5177392 3.8 6.72 431 318.48309 402.37759 +5177393 3.8 6.76 349 169.20963 111.9536 +5177394 3.8 6.8 334 157.92419 99.395203 +5177395 3.8 6.84 318 148.97647 90.487999 +5242885 3.84 5 108 33.18716 12.0224 +5242886 3.84 5.04 113 33.364342 12.0176 +5242887 3.84 5.08 117 33.362137 11.9808 +5242888 3.84 5.12 132 37.969395 14.1136 +5242889 3.84 5.16 169 51.739338 21.5168 +5242890 3.84 5.2 249 107.68726 73.529602 +5242891 3.84 5.24 266 132.55066 100.816 +5242892 3.84 5.28 203 108.31637 92.385597 +5242893 3.84 5.32 190 104.76852 91.313599 +5242894 3.84 5.36 158 70.562195 47.4272 +5242895 3.84 5.4 130 49.633965 27.2768 +5242896 3.84 5.44 110 36.539612 15.456 +5242906 3.84 5.84 175 73.942566 41.2528 +5242907 3.84 5.88 192 83.670395 49.5536 +5242908 3.84 5.92 287 129.009 84.5728 +5242909 3.84 5.96 377 297.99008 442.24799 +5242910 3.84 6 388 308.68948 453.31839 +5242911 3.84 6.04 268 108.88148 61.371201 +5242912 3.84 6.08 187 81.851807 48.812801 +5242923 3.84 6.52 308 140.70105 83.739197 +5242924 3.84 6.56 324 149.95047 93.710403 +5242925 3.84 6.6 343 163.86635 108.5312 +5242926 3.84 6.64 424 307.28412 383.55521 +5242927 3.84 6.68 451 341.42999 438.616 +5242928 3.84 6.72 430 313.43472 399.44159 +5242929 3.84 6.76 354 170.25734 112.2816 +5242930 3.84 6.8 339 158.73792 99.094398 +5242931 3.84 6.84 323 149.0965 88.708801 +5308426 3.88 5.2 293 123.93092 79.9552 +5308427 3.88 5.24 278 137.9413 102.7584 +5308441 3.88 5.8 171 69.020195 35.774399 +5308442 3.88 5.84 194 78.37896 43.075199 +5308443 3.88 5.88 221 87.895699 48.6544 +5308444 3.88 5.92 301 137.89575 94.939201 +5308445 3.88 5.96 389 304.30341 456.36801 +5308446 3.88 6 396 312.4252 464.72159 +5308447 3.88 6.04 272 107.62782 58.720001 +5308448 3.88 6.08 222 90.24276 51.558399 +5308449 3.88 6.12 195 84.316086 49.7248 +5308450 3.88 6.16 172 73.635239 41.383999 +5308459 3.88 6.52 309 139.67505 82.152 +5308460 3.88 6.56 325 148.6674 92.311996 +5308461 3.88 6.6 345 163.41258 108.1808 +5308462 3.88 6.64 429 317.90216 420.3056 +5308463 3.88 6.68 454 342.99234 449.16479 +5308464 3.88 6.72 429 310.61417 402.83679 +5308465 3.88 6.76 358 171.02823 112.8048 +5308466 3.88 6.8 347 162.11028 101.0112 +5308467 3.88 6.84 334 155.43756 92.924797 +5373957 3.92 5 150 73.670654 50.235199 +5373958 3.92 5.04 149 65.661499 40.649601 +5373959 3.92 5.08 153 62.911175 36.849602 +5373960 3.92 5.12 159 60.251488 32.660801 +5373961 3.92 5.16 210 88.878517 56.787201 +5373962 3.92 5.2 286 132.76213 90.401604 +5373963 3.92 5.24 265 122.39809 84.777603 +5373964 3.92 5.28 150 44.697933 19.510401 +5373965 3.92 5.32 127 34.569172 11.9024 +5373966 3.92 5.36 119 33.554199 12.1136 +5373967 3.92 5.4 108 31.571213 11.8128 +5373968 3.92 5.44 99 31.342567 12.2672 +5373969 3.92 5.48 107 43.202358 23.304001 +5373970 3.92 5.52 110 39.581543 19.408001 +5373971 3.92 5.56 120 40.167877 17.763201 +5373972 3.92 5.6 124 40.048847 16.768 +5373973 3.92 5.64 122 38.610867 15.7536 +5373974 3.92 5.68 116 37.749878 16.0224 +5373975 3.92 5.72 88 29.603874 13.4864 +5373977 3.92 5.8 192 78.458076 43.134399 +5373978 3.92 5.84 215 84.097046 45.220798 +5373979 3.92 5.88 260 103.63313 57.129601 +5373980 3.92 5.92 332 159.71315 117.008 +5373981 3.92 5.96 419 324.58228 481.96161 +5373982 3.92 6 430 335.95377 493.11359 +5373983 3.92 6.04 302 127.30866 74.436798 +5373984 3.92 6.08 261 109.38262 64.6912 +5373985 3.92 6.12 223 95.992752 58.588799 +5373986 3.92 6.16 192 86.876244 54.348801 +5373988 3.92 6.24 103 34.957153 15.456 +5373989 3.92 6.28 124 41.605167 17.787201 +5373990 3.92 6.32 131 44.179832 18.812799 +5373991 3.92 6.36 139 49.607708 22.2432 +5373992 3.92 6.4 131 51.785755 26.467199 +5373993 3.92 6.44 106 42.808647 23.443199 +5373995 3.92 6.52 316 143.47762 85.1856 +5373996 3.92 6.56 332 151.53909 95.012802 +5373997 3.92 6.6 353 165.08064 109.2576 +5373998 3.92 6.64 434 320.62326 434.1264 +5373999 3.92 6.68 457 344.6965 459.79999 +5374000 3.92 6.72 437 316.72379 416.3504 +5374001 3.92 6.76 374 182.48108 122.9776 +5374002 3.92 6.8 364 175.40744 113.352 +5374003 3.92 6.84 355 170.86453 105.9072 +5439493 3.96 5 185 117.08573 112.1152 +5439494 3.96 5.04 191 112.57703 102.7488 +5439495 3.96 5.08 197 105.93747 90.097603 +5439496 3.96 5.12 204 97.703293 74.008003 +5439497 3.96 5.16 261 130.72487 96.532799 +5439498 3.96 5.2 297 152.69493 113.3136 +5439499 3.96 5.24 273 128.67374 88.870399 +5439500 3.96 5.28 198 70.046379 34.835201 +5439501 3.96 5.32 170 53.941669 23.452801 +5439502 3.96 5.36 145 42.912868 17.004801 +5439503 3.96 5.4 122 32.501381 11.088 +5439504 3.96 5.44 102 29.026098 10.304 +5439505 3.96 5.48 153 85.296722 67.243202 +5439506 3.96 5.52 175 86.432487 62.627201 +5439507 3.96 5.56 191 89.74118 61.571201 +5439508 3.96 5.6 194 84.298515 51.915199 +5439509 3.96 5.64 190 76.86618 42.6096 +5439510 3.96 5.68 171 60.687313 27.739201 +5439511 3.96 5.72 141 48.196354 21.4816 +5439513 3.96 5.8 225 89.903557 49.743999 +5439514 3.96 5.84 278 115.30897 64.2976 +5439515 3.96 5.88 332 145.04651 84.304001 +5439516 3.96 5.92 400 208.79576 161.0544 +5439517 3.96 5.96 483 370.88358 528.08801 +5439518 3.96 6 490 379.14676 537.09277 +5439519 3.96 6.04 363 165.97176 102.08 +5439520 3.96 6.08 325 145.84183 89.228798 +5439521 3.96 6.12 277 120.31478 72.9552 +5439522 3.96 6.16 220 97.325882 61.363201 +5439524 3.96 6.24 148 48.530956 20.2048 +5439525 3.96 6.28 174 65.999504 33.8288 +5439526 3.96 6.32 197 88.172066 56.905602 +5439527 3.96 6.36 200 96.457352 67.919998 +5439528 3.96 6.4 208 108.07849 81.5168 +5439529 3.96 6.44 202 115.37553 91.830399 +5439531 3.96 6.52 321 143.32928 84.496002 +5439532 3.96 6.56 347 156.30609 98.302399 +5439533 3.96 6.6 375 176.51581 117.7232 +5439534 3.96 6.64 459 337.15005 455.4592 +5439535 3.96 6.68 486 366.6636 487.15201 +5439536 3.96 6.72 466 340.78439 444.74881 +5439537 3.96 6.76 408 211.69891 151.90559 +5439538 3.96 6.8 399 210.28708 152.4064 +5439539 3.96 6.84 393 212.45503 156.064 +5505029 4 5 221 165.45439 185.3392 +5505030 4 5.04 229 161.80005 175.1456 +5505031 4 5.08 241 160.19992 166.4976 +5505032 4 5.12 258 161.24843 159.7424 +5505033 4 5.16 310 194.51041 183.4832 +5505034 4 5.2 344 221.51744 207.45441 +5505035 4 5.24 341 205.2357 181.5984 +5505036 4 5.28 286 158.2099 134.3568 +5505037 4 5.32 265 142.50206 118.7968 +5505038 4 5.36 258 136.15849 110.08 +5505039 4 5.4 249 129.25566 101.6464 +5505040 4 5.44 249 125.07973 94.492798 +5505041 4 5.48 250 121.78426 88.390404 +5505042 4 5.52 238 115.8061 82.091202 +5505043 4 5.56 237 113.90524 78.416 +5505044 4 5.6 236 110.88589 73.686401 +5505045 4 5.64 242 111.31292 71.192001 +5505046 4 5.68 249 111.78013 68.705597 +5505047 4 5.72 260 112.25354 66.116798 +5505048 4 5.76 282 117.07362 65.849602 +5505049 4 5.8 293 121.7231 67.7808 +5505050 4 5.84 310 127.08616 69.265602 +5505051 4 5.88 363 161.99287 95.816002 +5505052 4 5.92 414 220.96396 179.81599 +5505053 4 5.96 490 377.1395 544.74561 +5505054 4 6 498 385.00595 552.94562 +5505055 4 6.04 379 176.48697 112.7952 +5505056 4 6.08 354 160.30405 98.262398 +5505057 4 6.12 305 128.18185 74.446404 +5505058 4 6.16 289 123.01432 74.047997 +5505059 4 6.2 272 119.01837 74.419197 +5505060 4 6.24 248 115.15382 76.793602 +5505061 4 6.28 239 114.16952 79.110397 +5505062 4 6.32 228 113.31559 82.870399 +5505063 4 6.36 227 115.73747 87.203201 +5505064 4 6.4 233 120.86758 93.515198 +5505065 4 6.44 255 133.23369 102.8464 +5505066 4 6.48 334 178.95193 136.328 +5505067 4 6.52 474 257.5593 195.4064 +5505068 4 6.56 480 269.66663 215.0192 +5505069 4 6.6 487 282.43597 234.9408 +5505070 4 6.64 553 437.64215 581.55841 +5505071 4 6.68 569 463.68814 617.95679 +5505072 4 6.72 540 431.9949 570.9552 +5505073 4 6.76 475 297.66382 270.85919 +5505074 4 6.8 462 292.99069 269.37921 +5505075 4 6.84 449 288.84985 267.944 +5570565 4.04 5 226 169.46622 189.64481 +5570566 4.04 5.04 236 166.9639 180.0096 +5570567 4.04 5.08 248 165.63522 171.216 +5570568 4.04 5.12 265 165.21123 162.3744 +5570569 4.04 5.16 307 191.85428 181.63361 +5570570 4.04 5.2 347 225.13086 212.25281 +5570571 4.04 5.24 338 202.77597 178.88 +5570572 4.04 5.28 289 160.00456 136.23039 +5570573 4.04 5.32 272 146.90936 122.2992 +5570574 4.04 5.36 261 137.57834 111.4464 +5570575 4.04 5.4 258 132.72009 104.0336 +5570576 4.04 5.44 257 128.58575 97.300797 +5570577 4.04 5.48 257 125.27472 91.257599 +5570578 4.04 5.52 254 123.02786 86.451202 +5570579 4.04 5.56 249 119.0877 81.137604 +5570580 4.04 5.6 247 116.26254 76.776001 +5570581 4.04 5.64 253 115.63113 73.295998 +5570582 4.04 5.68 261 115.89314 70.547203 +5570583 4.04 5.72 279 119.4416 69.321602 +5570584 4.04 5.76 288 119.10681 66.964798 +5570585 4.04 5.8 297 121.75052 67.318398 +5570586 4.04 5.84 312 126.3956 68.300797 +5570587 4.04 5.88 364 163.61322 97.9776 +5570588 4.04 5.92 420 230.38477 199.79201 +5570589 4.04 5.96 494 382.50961 561.52319 +5570590 4.04 6 501 389.88315 569.4624 +5570591 4.04 6.04 387 181.46663 118.744 +5570592 4.04 6.08 361 164.21957 101.552 +5570593 4.04 6.12 306 126.65654 72.761597 +5570594 4.04 6.16 289 121.38583 72.585602 +5570595 4.04 6.2 274 118.78155 73.915199 +5570596 4.04 6.24 268 120.91976 78.590401 +5570597 4.04 6.28 238 113.24891 78.68 +5570598 4.04 6.32 235 116.26037 84.414398 +5570599 4.04 6.36 232 117.85336 88.519997 +5570600 4.04 6.4 239 123.75728 95.662399 +5570601 4.04 6.44 261 133.78737 102.9392 +5570602 4.04 6.48 366 185.87395 136.06081 +5570603 4.04 6.52 481 262.01947 200.776 +5570604 4.04 6.56 487 275.28873 221.8736 +5570605 4.04 6.6 489 284.27887 238.4016 +5570606 4.04 6.64 556 443.81863 599.19202 +5570607 4.04 6.68 566 463.72784 628.71039 +5570608 4.04 6.72 539 434.52194 584.21118 +5570609 4.04 6.76 480 305.80246 285.72321 +5570610 4.04 6.8 466 297.93945 276.21759 +5570611 4.04 6.84 456 296.29083 276.64319 +5636101 4.08 5 226 169.37532 188.7856 +5636102 4.08 5.04 232 165.11362 178.62399 +5636103 4.08 5.08 246 164.02502 169.67039 +5636104 4.08 5.12 276 178.13734 175.78239 +5636105 4.08 5.16 303 188.34338 179.05119 +5636106 4.08 5.2 351 226.74525 212.9216 +5636107 4.08 5.24 332 196.33717 172.01601 +5636108 4.08 5.28 285 157.63307 135.1344 +5636109 4.08 5.32 275 151.81807 127.736 +5636110 4.08 5.36 249 132.66187 109.5984 +5636111 4.08 5.4 245 129.65561 104.7456 +5636112 4.08 5.44 242 125.59612 97.798401 +5636113 4.08 5.48 234 120.2196 91.334396 +5636114 4.08 5.52 234 117.21037 85.7696 +5636115 4.08 5.56 236 115.60161 81.905602 +5636116 4.08 5.6 241 115.46832 78.487999 +5636117 4.08 5.64 248 115.23258 74.896004 +5636118 4.08 5.68 253 114.50205 71.499199 +5636119 4.08 5.72 268 118.02531 71.225601 +5636120 4.08 5.76 290 123.14875 71.047997 +5636121 4.08 5.8 300 127.12801 71.982399 +5636122 4.08 5.84 315 132.60551 74.024002 +5636123 4.08 5.88 368 169.48622 103.9744 +5636124 4.08 5.92 430 246.19586 227.9024 +5636125 4.08 5.96 497 391.44199 583.22717 +5636126 4.08 6 505 399.48822 591.59839 +5636127 4.08 6.04 391 188.57324 126.8368 +5636128 4.08 6.08 362 168.52315 106.2112 +5636129 4.08 6.12 310 132.42831 77.928001 +5636130 4.08 6.16 294 127.83385 78.015999 +5636131 4.08 6.2 284 127.00666 80.620796 +5636132 4.08 6.24 257 121.75768 82.401604 +5636133 4.08 6.28 251 122.72186 86.468803 +5636134 4.08 6.32 237 120.19675 89.199997 +5636135 4.08 6.36 238 124.23988 95.675201 +5636136 4.08 6.4 240 128.13878 101.4288 +5636137 4.08 6.44 265 143.87019 114.632 +5636138 4.08 6.48 316 190.69547 159.2608 +5636139 4.08 6.52 474 266.84833 213.024 +5636140 4.08 6.56 478 275.44342 229.0224 +5636141 4.08 6.6 490 294.9534 262.9584 +5636142 4.08 6.64 552 445.46164 613.39362 +5636143 4.08 6.68 568 472.28613 653.48322 +5636144 4.08 6.72 539 438.18146 598.27838 +5636145 4.08 6.76 484 318.10138 313.42401 +5636146 4.08 6.8 469 304.20184 288.2496 +5636147 4.08 6.84 458 301.13504 286.3248 +5701637 4.12 5 161 88.065269 72.468803 +5701638 4.12 5.04 161 78.387856 56.952 +5701639 4.12 5.08 168 74.913773 50.8592 +5701640 4.12 5.12 198 90.744408 62.915199 +5701641 4.12 5.16 223 100.22327 69.463997 +5701642 4.12 5.2 268 132.9408 98.529602 +5701643 4.12 5.24 248 104.4622 63.3312 +5701644 4.12 5.28 182 63.699406 32.075199 +5701645 4.12 5.32 155 50.391361 23.8752 +5701646 4.12 5.36 131 37.566898 14.8752 +5701647 4.12 5.4 117 32.165054 11.4128 +5701648 4.12 5.44 101 29.515745 10.8608 +5701649 4.12 5.48 153 86.781372 69.915199 +5701650 4.12 5.52 165 84.91188 64.820801 +5701651 4.12 5.56 176 81.621719 55.708801 +5701652 4.12 5.6 181 78.428665 49.2048 +5701653 4.12 5.64 180 71.164207 38.683201 +5701654 4.12 5.68 166 58.658363 26.739201 +5701655 4.12 5.72 137 46.550293 20.6896 +5701657 4.12 5.8 217 85.843216 46.577599 +5701658 4.12 5.84 267 108.36539 58.913601 +5701659 4.12 5.88 331 149.47006 91.849602 +5701660 4.12 5.92 413 245.20995 247.14079 +5701661 4.12 5.96 477 385.18423 594.39362 +5701662 4.12 6 486 393.4194 602.39838 +5701663 4.12 6.04 369 178.6145 122.5456 +5701664 4.12 6.08 321 145.57776 90.811203 +5701665 4.12 6.12 265 113.95901 68.608002 +5701666 4.12 6.16 215 95.404579 60.5504 +5701668 4.12 6.24 145 47.128368 19.340799 +5701669 4.12 6.28 166 59.400635 27.2512 +5701670 4.12 6.32 188 81.995392 50.894402 +5701671 4.12 6.36 195 95.115013 67.412804 +5701672 4.12 6.4 201 104.11246 77.019203 +5701673 4.12 6.44 185 109.25976 90.844803 +5701675 4.12 6.52 326 156.40135 105.1872 +5701676 4.12 6.56 346 165.61223 116.392 +5701677 4.12 6.6 361 182.82162 149.2128 +5701678 4.12 6.64 434 333.6077 495.93921 +5701679 4.12 6.68 461 363.35349 533.12 +5701680 4.12 6.72 439 329.82837 471.3728 +5701681 4.12 6.76 393 215.23076 186.55521 +5701682 4.12 6.8 381 196.49121 142.37759 +5701683 4.12 6.84 374 196.57542 141.5248 +5767173 4.16 5 142 65.945488 41.7584 +5767174 4.16 5.04 144 62.031853 37.236801 +5767175 4.16 5.08 145 57.827065 32.579201 +5767176 4.16 5.12 162 71.846611 47.998402 +5767177 4.16 5.16 195 83.580711 57.030399 +5767178 4.16 5.2 253 111.21772 74.756798 +5767179 4.16 5.24 228 87.13903 47.9408 +5767180 4.16 5.28 145 47.597496 22.766399 +5767181 4.16 5.32 136 45.349697 21.9632 +5767182 4.16 5.36 129 44.938625 22.952 +5767183 4.16 5.4 108 32.534645 12.616 +5767184 4.16 5.44 101 32.726177 13.1536 +5767185 4.16 5.48 108 44.398624 24.448 +5767186 4.16 5.52 111 40.359379 19.8144 +5767187 4.16 5.56 110 35.026638 14.7344 +5767188 4.16 5.6 120 39.162704 16.7904 +5767189 4.16 5.64 121 39.326359 16.743999 +5767190 4.16 5.68 112 36.203457 15.4176 +5767191 4.16 5.72 83 26.558512 11.5936 +5767193 4.16 5.8 191 79.883835 44.459202 +5767194 4.16 5.84 212 84.571281 45.6096 +5767195 4.16 5.88 265 113.1783 69.467201 +5767196 4.16 5.92 359 219.05226 250.504 +5767197 4.16 5.96 422 352.45587 584.64478 +5767198 4.16 6 429 360.37619 592.86877 +5767199 4.16 6.04 318 147.02336 101.2272 +5767200 4.16 6.08 258 110.61761 67.167999 +5767201 4.16 6.12 218 92.674591 54.8368 +5767202 4.16 6.16 195 90.388054 57.240002 +5767204 4.16 6.24 101 34.777298 15.688 +5767205 4.16 6.28 123 42.524769 18.799999 +5767206 4.16 6.32 131 45.948868 20.489599 +5767207 4.16 6.36 139 50.996998 23.604799 +5767208 4.16 6.4 132 52.454231 26.9216 +5767209 4.16 6.44 102 40.242054 21.136 +5767211 4.16 6.52 326 161.78127 114.1424 +5767212 4.16 6.56 336 165.1707 120.3552 +5767213 4.16 6.6 357 190.96338 171.1888 +5767214 4.16 6.64 418 328.46304 502.57599 +5767215 4.16 6.68 440 356.59857 544.34241 +5767216 4.16 6.72 414 315.03564 467.952 +5767217 4.16 6.76 374 209.02258 196.9088 +5767218 4.16 6.8 361 182.35919 132.2896 +5767219 4.16 6.84 360 185.48325 132.0784 +5832714 4.2 5.2 267 111.08842 71.167999 +5832715 4.2 5.24 197 76.277283 41.7248 +5832730 4.2 5.84 184 74.762497 39.4384 +5832731 4.2 5.88 221 96.870323 62.327999 +5832732 4.2 5.92 335 215.7368 274.74719 +5832733 4.2 5.96 389 339.23871 591.96161 +5832734 4.2 6 394 344.5383 597.44958 +5832735 4.2 6.04 290 130.81938 91.118401 +5832736 4.2 6.08 213 89.157845 52.748798 +5832737 4.2 6.12 190 82.602676 47.857601 +5832747 4.2 6.52 326 165.80527 120.8592 +5832748 4.2 6.56 337 170.68326 128.5808 +5832749 4.2 6.6 356 201.09894 196.0704 +5832750 4.2 6.64 412 330.11472 514.57922 +5832751 4.2 6.68 435 361.34894 564.6944 +5832752 4.2 6.72 409 316.79568 478.66241 +5832753 4.2 6.76 371 219.94376 230.7088 +5832754 4.2 6.8 347 174.92305 129.4016 +5832755 4.2 6.84 343 175.53416 127.2976 +5898245 4.24 5 100 29.432169 10.1104 +5898246 4.24 5.04 109 33.32774 13.6464 +5898247 4.24 5.08 120 39.281815 18.9536 +5898248 4.24 5.12 130 43.879318 22.232 +5898249 4.24 5.16 174 60.726379 30.6336 +5898250 4.24 5.2 227 93.268677 60.3344 +5898251 4.24 5.24 213 78.183037 40.996799 +5898252 4.24 5.28 136 44.146149 21.547199 +5898253 4.24 5.32 115 31.675648 11.752 +5898254 4.24 5.36 105 27.410803 8.8207998 +5898255 4.24 5.4 99 26.403931 8.3456001 +5898256 4.24 5.44 100 29.556654 10.2208 +5898268 4.24 5.92 327 226.07339 313.664 +5898269 4.24 5.96 379 342.07089 611.98077 +5898270 4.24 6 385 347.09174 616.11841 +5898271 4.24 6.04 284 132.12675 95.510399 +5898283 4.24 6.52 323 168.14743 127.1136 +5898284 4.24 6.56 333 172.10799 133.30721 +5898285 4.24 6.6 359 216.17926 231.2832 +5898286 4.24 6.64 410 336.0787 534.05121 +5898287 4.24 6.68 433 368.46088 587.42877 +5898288 4.24 6.72 403 320.29135 495.608 +5898289 4.24 6.76 370 226.68704 248.48959 +5898290 4.24 6.8 347 180.93201 139.808 +5898291 4.24 6.84 341 178.30933 133.0032 +5963781 4.28 5 101 27.776957 9.1168003 +5963782 4.28 5.04 101 24.927849 7.4752002 +5963783 4.28 5.08 132 41.090939 18.632 +5963784 4.28 5.12 151 48.945183 23.740801 +5963785 4.28 5.16 171 55.987751 27.395201 +5963786 4.28 5.2 207 81.966827 51.779202 +5963787 4.28 5.24 205 73.530777 37.996799 +5963788 4.28 5.28 147 43.889133 19.695999 +5963789 4.28 5.32 119 28.863575 9.1711998 +5963790 4.28 5.36 105 24.446136 7.0447998 +5963791 4.28 5.4 101 25.049604 7.5696001 +5963792 4.28 5.44 101 27.907068 9.224 +5963803 4.28 5.88 85 26.684565 11.544 +5963804 4.28 5.92 306 234.69208 357.1824 +5963805 4.28 5.96 369 346.85681 633.97278 +5963806 4.28 6 375 350.68781 637.09601 +5963807 4.28 6.04 253 127.02579 100.0368 +5963808 4.28 6.08 81 25.97006 11.5248 +5963819 4.28 6.52 326 175.62921 138.26241 +5963820 4.28 6.56 332 176.64764 141.54559 +5963821 4.28 6.6 360 227.67424 259.90079 +5963822 4.28 6.64 406 340.30609 549.07843 +5963823 4.28 6.68 431 374.60123 607.888 +5963824 4.28 6.72 401 324.87747 509.2272 +5963825 4.28 6.76 367 233.79533 268.1712 +5963826 4.28 6.8 343 183.34531 146.31841 +5963827 4.28 6.84 338 182.40436 142.0224 +6029317 4.32 5 113 33.072563 12.4432 +6029318 4.32 5.04 115 30.512991 10.5968 +6029319 4.32 5.08 126 34.017452 13.2464 +6029320 4.32 5.12 146 43.317387 19.4272 +6029321 4.32 5.16 204 93.96833 76.508797 +6029322 4.32 5.2 199 74.461731 43.763199 +6029323 4.32 5.24 200 70.972908 36.492802 +6029324 4.32 5.28 149 40.737537 16.3248 +6029325 4.32 5.32 125 29.022747 8.7648001 +6029326 4.32 5.36 108 23.870008 6.592 +6029327 4.32 5.4 105 25.177837 7.4703999 +6029328 4.32 5.44 101 26.710073 8.6096001 +6029339 4.32 5.88 133 43.602909 18.3568 +6029340 4.32 5.92 296 242.15787 386.54401 +6029341 4.32 5.96 352 348.90652 655.41919 +6029342 4.32 6 356 351.93237 658.3056 +6029343 4.32 6.04 243 127.67693 106.296 +6029344 4.32 6.08 136 45.930676 20.004801 +6029355 4.32 6.52 324 180.12865 147.4496 +6029356 4.32 6.56 332 183.05551 152.7056 +6029357 4.32 6.6 360 236.25809 278.23999 +6029358 4.32 6.64 406 348.27011 570.87842 +6029359 4.32 6.68 428 381.009 629.64001 +6029360 4.32 6.72 400 329.20084 519.61761 +6029361 4.32 6.76 367 242.24318 287.1008 +6029362 4.32 6.8 340 187.72357 155.5696 +6029363 4.32 6.84 335 187.72534 153.5056 +6094853 4.36 5 115 32.928185 12.0272 +6094854 4.36 5.04 114 28.351187 8.9919996 +6094855 4.36 5.08 117 26.826647 7.9520001 +6094856 4.36 5.12 144 40.038036 16.684799 +6094857 4.36 5.16 201 89.973602 71.790398 +6094858 4.36 5.2 194 69.31813 37.551998 +6094859 4.36 5.24 200 70.336067 35.812801 +6094860 4.36 5.28 145 37.248024 13.8496 +6094861 4.36 5.32 121 26.648153 7.6687999 +6094862 4.36 5.36 114 25.778414 7.5120001 +6094863 4.36 5.4 107 25.610348 7.7456002 +6094864 4.36 5.44 104 27.325058 8.8191996 +6094875 4.36 5.88 153 53.67907 24.2176 +6094876 4.36 5.92 295 249.49899 405.69281 +6094877 4.36 5.96 337 351.19833 677.45441 +6094878 4.36 6 341 353.40298 679.62878 +6094879 4.36 6.04 239 130.80273 114.6432 +6094880 4.36 6.08 145 49.995213 22.143999 +6094891 4.36 6.52 319 182.7356 154.3856 +6094892 4.36 6.56 329 186.2841 159.28799 +6094893 4.36 6.6 361 245.0983 296.65439 +6094894 4.36 6.64 407 355.77783 588.44958 +6094895 4.36 6.68 428 391.04211 656.64801 +6094896 4.36 6.72 398 334.92273 534.5376 +6094897 4.36 6.76 370 254.26639 311.0112 +6094898 4.36 6.8 339 192.65126 164.2944 +6094899 4.36 6.84 331 191.39301 162.416 +6160389 4.4 5 112 30.96237 10.6128 +6160390 4.4 5.04 116 29.624048 9.7664003 +6160391 4.4 5.08 120 28.221235 8.6591997 +6160392 4.4 5.12 137 36.00132 13.9728 +6160393 4.4 5.16 199 86.054825 65.857597 +6160394 4.4 5.2 195 69.567558 36.875198 +6160395 4.4 5.24 199 69.428581 35.0224 +6160396 4.4 5.28 137 32.897663 11.1216 +6160397 4.4 5.32 121 26.701374 7.7712002 +6160398 4.4 5.36 116 27.003815 8.2496004 +6160399 4.4 5.4 111 27.701252 8.9007998 +6160400 4.4 5.44 105 28.02039 9.2784004 +6160411 4.4 5.88 169 65.875565 33.52 +6160412 4.4 5.92 286 253.49394 424.2016 +6160413 4.4 5.96 331 356.86954 701.61603 +6160414 4.4 6 331 356.37314 701.01758 +6160415 4.4 6.04 231 132.81898 123.768 +6160416 4.4 6.08 162 61.890392 30.8976 +6160427 4.4 6.52 320 192.26317 170.528 +6160428 4.4 6.56 327 191.96828 169.7088 +6160429 4.4 6.6 363 258.77274 326.37759 +6160430 4.4 6.64 405 363.65207 611.33282 +6160431 4.4 6.68 430 401.91199 684.41443 +6160432 4.4 6.72 398 341.07672 548.34723 +6160433 4.4 6.76 368 264.02289 337.02719 +6160434 4.4 6.8 336 196.82739 172.0432 +6160435 4.4 6.84 326 194.93544 170.7888 +6225925 4.44 5 111 31.884279 11.4512 +6225926 4.44 5.04 117 31.191889 10.7104 +6225927 4.44 5.08 119 28.695505 8.9952002 +6225928 4.44 5.12 123 28.469143 8.9024 +6225929 4.44 5.16 195 82.17366 61.0896 +6225930 4.44 5.2 195 68.182961 34.062401 +6225931 4.44 5.24 199 69.878426 35.1824 +6225932 4.44 5.28 135 33.131821 11.6656 +6225933 4.44 5.32 120 27.276447 8.1456003 +6225934 4.44 5.36 114 27.670517 8.9104004 +6225935 4.44 5.4 114 30.199787 10.3376 +6225936 4.44 5.44 108 30.529306 10.752 +6225947 4.44 5.88 169 69.207413 37.675201 +6225948 4.44 5.92 283 260.10785 444.78241 +6225949 4.44 5.96 326 362.24142 725.66718 +6225950 4.44 6 329 363.40445 726.07037 +6225951 4.44 6.04 225 134.24167 129.696 +6225952 4.44 6.08 164 67.14035 36.580799 +6225963 4.44 6.52 314 196.16574 179.8416 +6225964 4.44 6.56 323 197.88448 181.4944 +6225965 4.44 6.6 363 267.3703 345.87039 +6225966 4.44 6.64 406 370.56467 626.8432 +6225967 4.44 6.68 432 413.07578 712.90723 +6225968 4.44 6.72 397 349.25906 570.03998 +6225969 4.44 6.76 368 274.95758 362.29919 +6225970 4.44 6.8 332 201.53105 182.06239 +6225971 4.44 6.84 324 202.86435 184.73599 +6291461 4.48 5 113 34.848801 13.3504 +6291462 4.48 5.04 114 31.880829 11.3248 +6291463 4.48 5.08 119 30.851049 10.2912 +6291464 4.48 5.12 122 29.63176 9.3839998 +6291465 4.48 5.16 188 78.624237 57.796799 +6291466 4.48 5.2 202 72.784462 36.5984 +6291467 4.48 5.24 201 71.295197 35.875198 +6291468 4.48 5.28 126 33.017735 12.8496 +6291469 4.48 5.32 116 27.761574 8.6688004 +6291470 4.48 5.36 115 29.873531 10.1024 +6291471 4.48 5.4 113 31.715975 11.3792 +6291472 4.48 5.44 108 32.547211 12.1872 +6291483 4.48 5.88 174 76.612839 45.467201 +6291484 4.48 5.92 284 268.90042 467.28961 +6291485 4.48 5.96 326 370.31882 752.07843 +6291486 4.48 6 330 371.98257 752.77283 +6291487 4.48 6.04 229 144.992 148.84641 +6291488 4.48 6.08 169 74.357368 43.996799 +6291499 4.48 6.52 314 204.57845 193.60001 +6291500 4.48 6.56 318 202.94313 191.9632 +6291501 4.48 6.6 361 278.01318 371.02719 +6291502 4.48 6.64 406 377.67078 643.43201 +6291503 4.48 6.68 431 422.06061 738.32483 +6291504 4.48 6.72 400 358.49643 587.5072 +6291505 4.48 6.76 367 283.78668 383.74719 +6291506 4.48 6.8 323 204.91855 191.632 +6291507 4.48 6.84 322 209.15439 195.6944 +6356997 4.52 5 112 37.037148 14.9888 +6356998 4.52 5.04 113 34.333866 12.9712 +6356999 4.52 5.08 112 30.941305 10.7552 +6357000 4.52 5.12 133 50.809017 37.510399 +6357001 4.52 5.16 151 60.359173 44.801601 +6357002 4.52 5.2 210 76.868217 38.532799 +6357003 4.52 5.24 199 71.943649 36.604801 +6357004 4.52 5.28 127 37.182869 15.6608 +6357005 4.52 5.32 113 30.153872 10.28 +6357006 4.52 5.36 113 31.989243 11.4672 +6357007 4.52 5.4 110 33.171955 12.5632 +6357008 4.52 5.44 110 36.106644 14.5472 +6357019 4.52 5.88 180 87.496834 57.745602 +6357020 4.52 5.92 289 279.39331 491.28799 +6357021 4.52 5.96 328 379.33331 779.53601 +6357022 4.52 6 334 381.28098 779.76642 +6357023 4.52 6.04 234 154.06967 162.8784 +6357024 4.52 6.08 174 86.327347 59.852798 +6357035 4.52 6.52 309 211.89519 207.0304 +6357036 4.52 6.56 314 209.3764 203.80161 +6357037 4.52 6.6 354 289.15295 400.42239 +6357038 4.52 6.64 407 384.19479 657.26398 +6357039 4.52 6.68 439 437.18692 771.10083 +6357040 4.52 6.72 403 369.09366 611.41278 +6357041 4.52 6.76 363 298.44095 422.46881 +6357042 4.52 6.8 324 221.27254 224.16319 +6357043 4.52 6.84 313 213.7773 207.1104 +6422538 4.56 5.2 223 83.248642 41.5424 +6422539 4.56 5.24 178 68.536537 36.481602 +6422555 4.56 5.88 176 95.444275 72.457603 +6422556 4.56 5.92 299 293.95441 518.896 +6422557 4.56 5.96 343 392.0264 808.16803 +6422558 4.56 6 344 392.77533 808.31519 +6422559 4.56 6.04 233 162.32092 178.9792 +6422560 4.56 6.08 172 96.405861 76.7808 +6422571 4.56 6.52 306 219.26566 219.41119 +6422572 4.56 6.56 311 222.48582 229.5248 +6422573 4.56 6.6 348 301.68768 434.6528 +6422574 4.56 6.64 405 392.16751 676.61603 +6422575 4.56 6.68 450 453.44873 805.3136 +6422576 4.56 6.72 402 377.23257 633.71039 +6422577 4.56 6.76 356 311.76816 457.99841 +6422578 4.56 6.8 315 227.97002 239.49921 +6422579 4.56 6.84 308 220.57246 219.784 +6488068 4.6 4.96 68 25.342285 12.0864 +6488069 4.6 5 78 30.417561 15.4496 +6488070 4.6 5.04 68 23.030581 10.6224 +6488071 4.6 5.08 42 9.1876049 2.8896 +6488072 4.6 5.12 48 12.655054 4.6448002 +6488073 4.6 5.16 121 39.643505 16.3104 +6488074 4.6 5.2 213 84.75589 43.987202 +6488075 4.6 5.24 170 68.420494 38.385601 +6488076 4.6 5.28 44 8.063261 1.8992 +6488077 4.6 5.32 26 4.0178785 0.83359998 +6488078 4.6 5.36 23 3.8602643 0.912 +6488079 4.6 5.4 22 4.1480699 1.0928 +6488080 4.6 5.44 22 4.8933415 1.4400001 +6488091 4.6 5.88 159 99.488785 87.751999 +6488092 4.6 5.92 273 299.83093 547.49762 +6488093 4.6 5.96 397 419.13861 843.55518 +6488094 4.6 6 387 422.02542 848.98718 +6488095 4.6 6.04 193 153.06657 186.8576 +6488096 4.6 6.08 156 97.300621 86.102402 +6488107 4.6 6.52 304 228.21217 234.5744 +6488108 4.6 6.56 311 239.59021 263.72961 +6488109 4.6 6.6 341 315.17841 467.6864 +6488110 4.6 6.64 389 397.65375 701.45758 +6488111 4.6 6.68 463 468.7627 839.54559 +6488112 4.6 6.72 395 386.44653 661.12158 +6488113 4.6 6.76 347 327.69431 501.9584 +6488114 4.6 6.8 316 246.69366 277.85281 +6488115 4.6 6.84 309 232.49518 238.4752 +6553604 4.64 4.96 101 59.18145 47.790401 +6553605 4.64 5 79 30.290758 15.7552 +6553606 4.64 5.04 80 30.676332 15.04 +6553607 4.64 5.08 39 10.798943 4.3248 +6553608 4.64 5.12 38 9.8691807 3.2 +6553609 4.64 5.16 89 32.254169 15.5808 +6553610 4.64 5.2 212 83.828842 43.982399 +6553611 4.64 5.24 169 70.059296 40.824001 +6553612 4.64 5.28 48 11.352739 3.5711999 +6553613 4.64 5.32 35 7.0392237 1.9263999 +6553614 4.64 5.36 28 5.3873882 1.4304 +6553615 4.64 5.4 23 4.4248018 1.1568 +6553616 4.64 5.44 24 5.7206497 1.7872 +6553619 4.64 5.56 240 129.23502 88.150398 +6553620 4.64 5.6 247 124.67947 80.843201 +6553621 4.64 5.64 255 122.22733 75.508797 +6553622 4.64 5.68 264 121.43034 71.984001 +6553623 4.64 5.72 273 122.24762 70.465599 +6553624 4.64 5.76 268 114.8168 63.4944 +6553625 4.64 5.8 267 110.01385 58.187199 +6553626 4.64 5.84 265 105.78947 54.035198 +6553627 4.64 5.88 266 104.1961 51.993599 +6553628 4.64 5.92 266 101.82307 49.712002 +6553629 4.64 5.96 530 486.02512 904.32159 +6553630 4.64 6 517 483.37317 904.39362 +6553631 4.64 6.04 263 100.76785 49.451199 +6553632 4.64 6.08 259 100.15928 49.7728 +6553633 4.64 6.12 258 101.60239 51.632 +6553634 4.64 6.16 255 103.77785 55.383999 +6553635 4.64 6.2 250 105.37714 58.7808 +6553636 4.64 6.24 247 108.3482 63.147202 +6553637 4.64 6.28 243 111.52805 67.619202 +6553638 4.64 6.32 244 119.10101 76.278397 +6553639 4.64 6.36 242 124.90104 83.3088 +6553640 4.64 6.4 243 133.44257 93.017601 +6553644 4.64 6.56 86 21.017136 5.9871998 +6553645 4.64 6.6 86 19.644417 5.3072 +6553646 4.64 6.64 86 18.818968 4.9056001 +6553647 4.64 6.68 470 481.22058 873.01282 +6553648 4.64 6.72 96 22.665855 6.6799998 +6553649 4.64 6.76 96 25.354136 8.6767998 +6553650 4.64 6.8 99 28.99967 11.0304 +6619140 4.68 4.96 116 76.496078 70.070396 +6619141 4.68 5 122 72.880157 62.2048 +6619142 4.68 5.04 147 77.532501 58.3088 +6619143 4.68 5.08 186 85.038689 53.366402 +6619144 4.68 5.12 188 81.034576 46.048 +6619145 4.68 5.16 186 73.813782 38.003201 +6619146 4.68 5.2 255 104.20734 57.335999 +6619147 4.68 5.24 258 105.37385 58.863998 +6619148 4.68 5.28 170 54.604095 21.4848 +6619149 4.68 5.32 165 51.228039 19.176001 +6619150 4.68 5.36 159 49.167332 18.1936 +6619151 4.68 5.4 154 48.720772 18.327999 +6619152 4.68 5.44 150 49.658947 19.361601 +6619153 4.68 5.48 147 51.928902 21.203199 +6619155 4.68 5.56 243 129.09261 89.127998 +6619156 4.68 5.6 257 127.25648 83.0112 +6619157 4.68 5.64 267 124.83909 76.934402 +6619158 4.68 5.68 276 123.72148 72.865601 +6619159 4.68 5.72 271 115.44196 65.028801 +6619160 4.68 5.76 270 109.92471 58.953602 +6619161 4.68 5.8 270 106.49425 55.32 +6619162 4.68 5.84 269 102.16472 50.948799 +6619163 4.68 5.88 274 102.4071 50.228802 +6619164 4.68 5.92 286 103.2551 48.728001 +6619165 4.68 5.96 531 494.51569 934.56158 +6619166 4.68 6 505 480.48798 926.31842 +6619167 4.68 6.04 271 98.462234 47.096001 +6619168 4.68 6.08 265 98.019562 47.945599 +6619169 4.68 6.12 264 100.35928 50.799999 +6619170 4.68 6.16 263 103.26722 54.388802 +6619171 4.68 6.2 259 105.16183 57.756802 +6619172 4.68 6.24 254 107.08556 61.292801 +6619173 4.68 6.28 249 110.68029 66.848 +6619174 4.68 6.32 246 117.08631 75.289597 +6619175 4.68 6.36 245 123.35952 82.472 +6619176 4.68 6.4 244 131.17125 91.638397 +6619179 4.68 6.52 85 20.604757 5.8031998 +6619180 4.68 6.56 86 18.7687 4.8720002 +6619181 4.68 6.6 92 18.73526 4.5535998 +6619182 4.68 6.64 178 68.29129 40.9072 +6619183 4.68 6.68 460 492.63138 909.49438 +6619184 4.68 6.72 214 95.186333 63.534401 +6619185 4.68 6.76 108 28.651815 10.8672 +6619186 4.68 6.8 112 35.156937 16.0336 +6619187 4.68 6.84 114 41.505768 21.865601 +6684676 4.72 4.96 65 35.133587 30.753599 +6684677 4.72 5 99 66.120819 64.288002 +6684678 4.72 5.04 126 81.993675 75.2528 +6684679 4.72 5.08 184 98.092308 75.619202 +6684680 4.72 5.12 220 102.6207 69.431999 +6684681 4.72 5.16 229 99.171417 62.3456 +6684682 4.72 5.2 275 123.76847 78.659203 +6684683 4.72 5.24 276 120.74655 74.398399 +6684684 4.72 5.28 193 64.193718 28.673599 +6684685 4.72 5.32 181 55.958279 22.028799 +6684686 4.72 5.36 172 50.440639 18.030399 +6684687 4.72 5.4 164 47.884727 16.809601 +6684688 4.72 5.44 154 46.856709 17.003201 +6684689 4.72 5.48 147 48.212299 18.5152 +6684691 4.72 5.56 250 127.4764 85.569603 +6684692 4.72 5.6 274 131.18167 82.865601 +6684693 4.72 5.64 284 129.80994 78.926399 +6684694 4.72 5.68 279 121.1924 70.676804 +6684695 4.72 5.72 275 113.68239 63.4464 +6684696 4.72 5.76 278 110.60752 59.510399 +6684697 4.72 5.8 276 105.55979 54.476799 +6684698 4.72 5.84 276 102.26431 50.916801 +6684699 4.72 5.88 282 101.94955 49.4608 +6684700 4.72 5.92 304 110.66743 53.161598 +6684701 4.72 5.96 524 498.63336 962.88159 +6684702 4.72 6 498 477.83334 944.90082 +6684703 4.72 6.04 281 99.655411 47.3936 +6684704 4.72 6.08 273 98.293877 47.694401 +6684705 4.72 6.12 272 101.05534 50.956799 +6684706 4.72 6.16 267 101.45684 52.662399 +6684707 4.72 6.2 267 105.67683 57.439999 +6684708 4.72 6.24 265 109.35533 62.212799 +6684709 4.72 6.28 261 112.79687 67.167999 +6684710 4.72 6.32 251 115.44904 72.878403 +6684711 4.72 6.36 244 118.9511 78.155197 +6684712 4.72 6.4 243 126.9421 87.222397 +6684715 4.72 6.52 88 19.925976 5.2783999 +6684716 4.72 6.56 91 18.500883 4.4928002 +6684717 4.72 6.6 111 23.400408 6.1135998 +6684718 4.72 6.64 215 99.329002 70.584 +6684719 4.72 6.68 462 505.23071 939.67358 +6684720 4.72 6.72 257 142.36018 120.2928 +6684721 4.72 6.76 144 49.295589 26.784 +6684722 4.72 6.8 140 57.718628 38.499199 +6684723 4.72 6.84 144 67.546402 49.398399 +6750216 4.76 5.12 241 126.05138 99.3312 +6750217 4.76 5.16 260 124.89553 90.249603 +6750218 4.76 5.2 301 149.76447 107.1792 +6750219 4.76 5.24 310 151.97447 107.1696 +6750220 4.76 5.28 240 98.890892 60.124802 +6750221 4.76 5.32 234 91.720634 52.326401 +6750222 4.76 5.36 221 80.477577 41.3344 +6750223 4.76 5.4 203 66.210129 28.233601 +6750224 4.76 5.44 177 51.461433 17.900801 +6750225 4.76 5.48 153 46.268379 16.571199 +6750227 4.76 5.56 292 146.60869 98.015999 +6750228 4.76 5.6 300 142.25043 90.667198 +6750229 4.76 5.64 293 132.57094 81.751999 +6750230 4.76 5.68 289 124.36207 73.528 +6750231 4.76 5.72 286 117.16612 65.848 +6750232 4.76 5.76 283 110.3746 58.919998 +6750233 4.76 5.8 281 105.49039 54.054401 +6750234 4.76 5.84 282 101.87502 49.788799 +6750235 4.76 5.88 290 103.27867 49.473598 +6750236 4.76 5.92 318 118.70315 59.260799 +6750237 4.76 5.96 524 506.61371 993.6944 +6750238 4.76 6 501 485.95761 974.85602 +6750239 4.76 6.04 291 102.16702 48.129601 +6750240 4.76 6.08 281 99.622826 47.982399 +6750241 4.76 6.12 276 100.24689 49.9408 +6750242 4.76 6.16 279 105.59521 55.254398 +6750243 4.76 6.2 278 108.91234 59.006401 +6750244 4.76 6.24 276 113.43774 64.968002 +6750245 4.76 6.28 277 119.35275 71.499199 +6750246 4.76 6.32 275 124.84217 78.371201 +6750247 4.76 6.36 265 127.31407 84.0336 +6750248 4.76 6.4 249 130.39983 91.5056 +6750251 4.76 6.52 90 19.351294 4.9152002 +6750252 4.76 6.56 119 27.59627 8.1440001 +6750253 4.76 6.6 155 47.836914 21.5888 +6750254 4.76 6.64 279 157.22244 130.89439 +6750255 4.76 6.68 492 547.95569 1007.3264 +6750256 4.76 6.72 323 235.73404 273.04001 +6750257 4.76 6.76 198 94.422012 69.400002 +6750258 4.76 6.8 177 88.234642 69.0448 +6750259 4.76 6.84 170 93.665993 79.620796 +6815752 4.8 5.12 263 159.85904 149.56799 +6815753 4.8 5.16 296 170.63861 152.12959 +6815754 4.8 5.2 337 199.5562 175.5152 +6815755 4.8 5.24 356 208.22437 179.6304 +6815756 4.8 5.28 305 162.67145 133.48 +6815757 4.8 5.32 297 154.84575 123.48 +6815758 4.8 5.36 308 157.63011 120.4064 +6815759 4.8 5.4 322 161.47871 117.9776 +6815760 4.8 5.44 338 168.22293 117.9712 +6815761 4.8 5.48 365 178.1993 118.4832 +6815762 4.8 5.52 372 176.33803 112.5472 +6815763 4.8 5.56 337 158.6853 100.2336 +6815764 4.8 5.6 308 140.68845 87.193604 +6815765 4.8 5.64 295 128.88879 77.203201 +6815766 4.8 5.68 289 121.40872 70.515198 +6815767 4.8 5.72 284 114.04677 63.563202 +6815768 4.8 5.76 282 108.58732 57.982399 +6815769 4.8 5.8 284 105.49833 53.987202 +6815770 4.8 5.84 287 103.8661 51.465599 +6815771 4.8 5.88 292 103.55003 49.675201 +6815772 4.8 5.92 331 131.87375 73.582397 +6815773 4.8 5.96 519 512.55774 1024.6016 +6815774 4.8 6 500 493.67084 1005.7088 +6815775 4.8 6.04 299 106.83577 51.619202 +6815776 4.8 6.08 285 100.41935 48.195202 +6815777 4.8 6.12 282 102.10297 50.886398 +6815778 4.8 6.16 280 104.44841 54.1008 +6815779 4.8 6.2 281 108.43563 58.246399 +6815780 4.8 6.24 280 112.68504 63.363201 +6815781 4.8 6.28 282 118.8515 69.857597 +6815782 4.8 6.32 284 125.54445 77.057602 +6815783 4.8 6.36 289 133.24413 84.452797 +6815784 4.8 6.4 296 142.41209 93.569603 +6815785 4.8 6.44 288 148.97034 102.744 +6815786 4.8 6.48 275 147.69745 107.12 +6815787 4.8 6.52 274 144.17676 108.08 +6815788 4.8 6.56 266 143.27884 112.5472 +6815789 4.8 6.6 278 154.35132 125.0736 +6815790 4.8 6.64 370 263.66269 266.16479 +6815791 4.8 6.68 542 619.04669 1116.88 +6815792 4.8 6.72 398 358.71567 509.4144 +6815793 4.8 6.76 252 156.59021 147.0448 +6815794 4.8 6.8 217 138.35579 136.9872 +6815795 4.8 6.84 208 138.56532 141.552 +6881288 4.84 5.12 270 162.44919 150.7632 +6881289 4.84 5.16 296 171.38646 153.6528 +6881290 4.84 5.2 338 200.93681 178.056 +6881291 4.84 5.24 354 208.82271 182.0912 +6881292 4.84 5.28 310 165.11208 135.60001 +6881293 4.84 5.32 309 162.0493 129.38721 +6881294 4.84 5.36 316 163.07828 125.2048 +6881295 4.84 5.4 336 170.44125 124.5024 +6881296 4.84 5.44 354 175.2309 121.04 +6881297 4.84 5.48 376 178.02142 115.3264 +6881298 4.84 5.52 354 165.15269 104.392 +6881299 4.84 5.56 318 147.57974 92.110397 +6881300 4.84 5.6 307 138.2617 83.655998 +6881301 4.84 5.64 299 130.10788 76.228798 +6881302 4.84 5.68 295 123.26687 69.662399 +6881303 4.84 5.72 289 116.03209 63.348801 +6881304 4.84 5.76 288 110.99865 58.1632 +6881305 4.84 5.8 289 108.04501 55.001598 +6881306 4.84 5.84 289 105.15712 51.9744 +6881307 4.84 5.88 297 107.43253 52.558399 +6881308 4.84 5.92 334 139.45978 83.872002 +6881309 4.84 5.96 513 518.62866 1056.0192 +6881310 4.84 6 493 497.91345 1034.64 +6881311 4.84 6.04 302 110.50415 55.030399 +6881312 4.84 6.08 284 99.370766 47.097599 +6881313 4.84 6.12 281 100.59311 49.2896 +6881314 4.84 6.16 278 102.07783 51.580799 +6881315 4.84 6.2 278 105.88176 55.756802 +6881316 4.84 6.24 279 110.23824 60.051201 +6881317 4.84 6.28 279 115.27534 65.700798 +6881318 4.84 6.32 282 121.21204 71.260803 +6881319 4.84 6.36 286 128.93832 79.056 +6881320 4.84 6.4 292 137.32787 87.444801 +6881321 4.84 6.44 295 147.93527 97.942398 +6881322 4.84 6.48 303 156.05125 107.5904 +6881323 4.84 6.52 295 156.31007 114.176 +6881324 4.84 6.56 283 154.22353 118.4128 +6881325 4.84 6.6 295 168.70222 135.65601 +6881326 4.84 6.64 387 302.0123 347.6048 +6881327 4.84 6.68 528 619.30365 1143.9041 +6881328 4.84 6.72 401 380.50388 563.33917 +6881329 4.84 6.76 257 161.88014 149.496 +6881330 4.84 6.8 223 140.52336 135.5696 +6881331 4.84 6.84 210 139.3932 140.2384 +6946824 4.88 5.12 257 141.64993 120.3952 +6946825 4.88 5.16 281 150.26085 122.7664 +6946826 4.88 5.2 303 161.89883 129.03999 +6946827 4.88 5.24 311 161.76492 126.2768 +6946828 4.88 5.28 266 112.8196 73.441597 +6946829 4.88 5.32 253 100.08851 60.153599 +6946830 4.88 5.36 240 89.044327 49.6576 +6946831 4.88 5.4 231 80.087898 40.056 +6946832 4.88 5.44 205 60.688377 23.132799 +6946833 4.88 5.48 164 43.486481 13.672 +6946835 4.88 5.56 272 134.31546 90.212799 +6946836 4.88 5.6 289 135.49271 86.049599 +6946837 4.88 5.64 293 130.97589 79.513603 +6946838 4.88 5.68 294 126.60983 74.350403 +6946839 4.88 5.72 295 122.78362 69.580803 +6946840 4.88 5.76 297 119.6748 65.524803 +6946841 4.88 5.8 298 116.93443 62.254398 +6946842 4.88 5.84 303 117.17518 61.233601 +6946843 4.88 5.88 310 120.48535 63.566399 +6946844 4.88 5.92 348 155.85977 100.624 +6946845 4.88 5.96 515 530.81659 1091.5472 +6946846 4.88 6 500 513.60162 1072.4944 +6946847 4.88 6.04 316 125.67477 68.892799 +6946848 4.88 6.08 296 111.03088 56.944 +6946849 4.88 6.12 287 108.10593 56.335999 +6946850 4.88 6.16 287 111.29408 60.097599 +6946851 4.88 6.2 282 112.0092 62.200001 +6946852 4.88 6.24 281 115.49922 66.169601 +6946853 4.88 6.28 283 121.77474 72.839996 +6946854 4.88 6.32 278 124.10552 76.328003 +6946855 4.88 6.36 275 129.79068 83.731201 +6946856 4.88 6.4 247 128.29137 89.172798 +6946859 4.88 6.52 106 26.908369 8.9231997 +6946860 4.88 6.56 157 51.603809 23.820801 +6946861 4.88 6.6 220 102.92867 69.919998 +6946862 4.88 6.64 335 285.27963 408.80481 +6946863 4.88 6.68 461 559.37195 1099.36 +6946864 4.88 6.72 369 364.23532 585.56641 +6946865 4.88 6.76 241 140.84627 118.1152 +6946866 4.88 6.8 206 115.38745 96.347198 +6946867 4.88 6.84 195 116.85154 105.3888 +7012360 4.92 5.12 230 108.00648 76.294403 +7012361 4.92 5.16 251 117.99065 84.099197 +7012362 4.92 5.2 270 131.07155 97.688004 +7012363 4.92 5.24 273 127.94871 93.627197 +7012364 4.92 5.28 220 73.31044 36.515202 +7012365 4.92 5.32 202 58.96883 24.593599 +7012366 4.92 5.36 186 48.671913 17.121599 +7012367 4.92 5.4 171 40.873589 11.9072 +7012368 4.92 5.44 162 39.592537 11.5888 +7012369 4.92 5.48 149 39.862839 12.6608 +7012371 4.92 5.56 251 130.53703 89.6912 +7012372 4.92 5.6 257 123.22181 79.692802 +7012373 4.92 5.64 269 121.00531 73.795197 +7012374 4.92 5.68 278 119.66403 69.259201 +7012375 4.92 5.72 284 118.34278 65.984001 +7012376 4.92 5.76 291 118.19249 63.942402 +7012377 4.92 5.8 292 115.62484 61.0368 +7012378 4.92 5.84 295 114.63945 59.180801 +7012379 4.92 5.88 310 125.05551 67.897598 +7012380 4.92 5.92 348 162.54489 108.936 +7012381 4.92 5.96 512 541.94452 1128.5439 +7012382 4.92 6 496 523.48602 1107.5424 +7012383 4.92 6.04 311 126.7425 70.939201 +7012384 4.92 6.08 292 112.47406 58.9888 +7012385 4.92 6.12 284 109.8588 58.380798 +7012386 4.92 6.16 283 112.37938 61.476799 +7012387 4.92 6.2 276 111.71053 62.382401 +7012388 4.92 6.24 276 117.58091 69.788803 +7012389 4.92 6.28 270 119.89943 74.0336 +7012390 4.92 6.32 264 124.45248 81.457603 +7012391 4.92 6.36 253 128.1942 88.721603 +7012392 4.92 6.4 250 134.58475 96.367996 +7012395 4.92 6.52 104 29.111048 10.768 +7012396 4.92 6.56 120 36.916149 16.865601 +7012397 4.92 6.6 166 75.649811 56.534401 +7012398 4.92 6.64 283 275.92596 477.52481 +7012399 4.92 6.68 394 511.87451 1080.0225 +7012400 4.92 6.72 330 359.38165 653.77118 +7012401 4.92 6.76 210 116.03286 93.817596 +7012402 4.92 6.8 176 86.394363 62.619202 +7012403 4.92 6.84 170 86.674629 65.062401 +7077896 4.96 5.12 209 86.039223 51.743999 +7077897 4.96 5.16 228 96.948875 62.632 +7077898 4.96 5.2 238 104.89588 73.804802 +7077899 4.96 5.24 245 106.74608 76.195198 +7077900 4.96 5.28 198 59.028324 25.867201 +7077901 4.96 5.32 181 46.04565 15.8048 +7077902 4.96 5.36 171 41.134903 12.8944 +7077903 4.96 5.4 162 37.735302 10.712 +7077904 4.96 5.44 154 37.751087 11.2032 +7077905 4.96 5.48 149 40.127056 12.9312 +7077907 4.96 5.56 246 129.5233 88.019203 +7077908 4.96 5.6 251 123.91936 80.903999 +7077909 4.96 5.64 257 119.45538 74.025597 +7077910 4.96 5.68 261 114.51888 67.080002 +7077911 4.96 5.72 272 114.72202 64.279999 +7077912 4.96 5.76 276 112.81989 60.870399 +7077913 4.96 5.8 282 113.08817 59.265598 +7077914 4.96 5.84 292 116.79713 60.6688 +7077915 4.96 5.88 309 130.1626 72.828796 +7077916 4.96 5.92 347 170.13162 119.2768 +7077917 4.96 5.96 503 548.42926 1161.3328 +7077918 4.96 6 489 531.71515 1141.4368 +7077919 4.96 6.04 314 137.36725 82.876801 +7077920 4.96 6.08 293 119.52432 65.766403 +7077921 4.96 6.12 288 118.62825 66.486397 +7077922 4.96 6.16 279 116.49083 66.795197 +7077923 4.96 6.2 272 115.82111 68.064003 +7077924 4.96 6.24 269 119.67442 73.835197 +7077925 4.96 6.28 260 120.4241 77.371201 +7077926 4.96 6.32 253 124.13023 83.470398 +7077927 4.96 6.36 252 130.40561 90.566399 +7077928 4.96 6.4 251 138.06085 99.260803 +7077931 4.96 6.52 107 34.091934 14.464 +7077932 4.96 6.56 122 43.965176 23.774401 +7077933 4.96 6.6 165 86.33255 72.222397 +7077934 4.96 6.64 270 284.69412 513.0672 +7077935 4.96 6.68 360 495.96912 1088.4784 +7077936 4.96 6.72 312 383.74921 788.24158 +7077937 4.96 6.76 189 104.42886 86.888 +7077938 4.96 6.8 155 67.842087 42.032001 +7077939 4.96 6.84 147 64.659386 39.5952 +7143432 5 5.12 189 68.636925 34.023998 +7143433 5 5.16 216 89.221336 56.4576 +7143434 5 5.2 226 98.96167 71.188797 +7143435 5 5.24 232 101.87588 75.4608 +7143436 5 5.28 186 53.807076 23.259199 +7143437 5 5.32 174 44.387531 15.5552 +7143438 5 5.36 169 42.096661 14.008 +7143439 5 5.4 154 36.043404 10.4048 +7143440 5 5.44 151 38.073978 11.8448 +7143441 5 5.48 149 41.081272 13.6992 +7143443 5 5.56 245 133.34746 91.801598 +7143444 5 5.6 248 125.6116 81.503998 +7143445 5 5.64 251 119.75078 73.9216 +7143446 5 5.68 255 115.75961 68.262398 +7143447 5 5.72 259 112.22642 62.9776 +7143448 5 5.76 267 112.24181 60.4496 +7143449 5 5.8 276 113.61813 59.228802 +7143450 5 5.84 282 115.62297 60.240002 +7143451 5 5.88 301 130.9525 74.512001 +7143452 5 5.92 343 177.44749 130.9088 +7143453 5 5.96 493 554.69794 1194.1104 +7143454 5 6 486 543.25946 1177.9088 +7143455 5 6.04 315 146.83084 94.209602 +7143456 5 6.08 294 127.83262 73.7024 +7143457 5 6.12 280 118.61005 66.388802 +7143458 5 6.16 274 118.74092 68.940804 +7143459 5 6.2 268 119.36779 71.756798 +7143460 5 6.24 264 123.28454 78.499199 +7143461 5 6.28 258 126.53695 84.209602 +7143462 5 6.32 256 131.9953 91.326401 +7143463 5 6.36 253 136.09894 96.580803 +7143464 5 6.4 252 143.91705 106.3952 +7143468 5 6.56 128 53.558598 32.971199 +7143469 5 6.6 163 94.442467 84.971199 +7143470 5 6.64 267 302.33621 563.38397 +7143471 5 6.68 344 495.42938 1114.4032 +7143472 5 6.72 302 399.29959 866.32159 +7143473 5 6.76 180 106.47968 94.809601 +7143474 5 6.8 144 64.892883 41.603199 +7208968 5.04 5.12 186 68.448418 33.913601 +7208969 5.04 5.16 210 88.598213 57.796799 +7208970 5.04 5.2 216 95.460991 70.734398 +7208971 5.04 5.24 221 99.247009 76.7136 +7208972 5.04 5.28 181 54.241177 24.7472 +7208973 5.04 5.32 170 44.713936 16.280001 +7208974 5.04 5.36 162 41.733135 14.7968 +7208975 5.04 5.4 157 40.557556 13.8384 +7208976 5.04 5.44 150 39.606411 13.1008 +7208977 5.04 5.48 148 42.008072 14.4656 +7274504 5.08 5.12 178 65.381821 31.8368 +7274505 5.08 5.16 204 88.90271 60.107201 +7274506 5.08 5.2 211 96.756683 74.345596 +7274507 5.08 5.24 218 102.59463 82.335999 +7274508 5.08 5.28 182 60.685886 32.502399 +7274509 5.08 5.32 168 47.817688 19.2288 +7274510 5.08 5.36 161 44.476276 17.096001 +7274511 5.08 5.4 155 42.468616 15.5856 +7274512 5.08 5.44 149 41.282612 14.3184 +7274513 5.08 5.48 149 44.779373 16.417601 +7340040 5.12 5.12 176 67.550606 34.030399 +7340041 5.12 5.16 202 92.958344 65.968002 +7340042 5.12 5.2 208 100.16633 79.643204 +7340043 5.12 5.24 217 106.7597 87.222397 +7340044 5.12 5.28 179 66.32412 40.952 +7340045 5.12 5.32 166 50.768524 21.846399 +7340046 5.12 5.36 161 48.456814 20.256001 +7340047 5.12 5.4 155 46.412476 18.7952 +7340048 5.12 5.44 152 46.928383 18.7904 +7340049 5.12 5.48 150 48.432838 19.1696 +7405576 5.16 5.12 175 71.363174 37.822399 +7405577 5.16 5.16 203 100.44492 75.209602 +7405578 5.16 5.2 208 106.25475 86.979202 +7405579 5.16 5.24 211 109.9676 93.344002 +7405580 5.16 5.28 178 70.961754 45.743999 +7405581 5.16 5.32 162 52.822296 23.739201 +7405582 5.16 5.36 161 52.753807 23.452801 +7405583 5.16 5.4 155 50.853527 22.3216 +7405584 5.16 5.44 150 49.344448 20.68 +7405585 5.16 5.48 148 50.383991 20.6336 +7471112 5.2 5.12 175 76.092041 41.928001 +7471113 5.2 5.16 205 109.62108 86.564796 +7471114 5.2 5.2 202 109.21878 92.599998 +7471115 5.2 5.24 209 115.41135 100.6688 +7471116 5.2 5.28 179 78.552864 53.811199 +7471117 5.2 5.32 162 58.598862 28.823999 +7471118 5.2 5.36 158 56.123917 26.478399 +7471119 5.2 5.4 156 56.065971 26.128 +7471120 5.2 5.44 153 56.01944 25.872 +7471121 5.2 5.48 149 55.871475 25.5184 diff --git a/testdata/gallery_two_pointmaps.graph b/testdata/gallery_two_pointmaps.graph new file mode 100644 index 00000000..329f4817 Binary files /dev/null and b/testdata/gallery_two_pointmaps.graph differ diff --git a/testdata/isovists.csv b/testdata/isovists.csv new file mode 100644 index 00000000..891d7d74 --- /dev/null +++ b/testdata/isovists.csv @@ -0,0 +1,3 @@ +id,x,y,angle,viewAngle +1,1.77,6.6,180,60 +2,3.1,5.6,90,90 diff --git a/testdata/polygons_drawing.graph b/testdata/polygons_drawing.graph new file mode 100644 index 00000000..7bf63aab Binary files /dev/null and b/testdata/polygons_drawing.graph differ diff --git a/testdata/rect1x1.graph b/testdata/rect1x1.graph new file mode 100644 index 00000000..aa08d2a2 Binary files /dev/null and b/testdata/rect1x1.graph differ diff --git a/testdata/simple_axial_lines.ntf b/testdata/simple_axial_lines.ntf new file mode 100644 index 00000000..0fb0ffca --- /dev/null +++ b/testdata/simple_axial_lines.ntf @@ -0,0 +1,41 @@ +01depthmapX test\0% +02Land-Line\0% +050001 Axial set 1\0% +050002 Axial s1% +et 2\0% +07depthmap 21000062000000001000006200000000100000531000000018400000000000000% +23000000 0001 0000000 0000000% +2100000000000033993014668 033294036321 0% +23000000 0001 0000000 0000000% +2100000000000048311025494 018859026891 0188591% +000000 0% +23000000 0001 0000000 0000000% +2100000000000044237011525 020838008614 0% +23000000 0001 0000000 0000000% +2100000000000004423021536 007101006286 0% +23000000 0001 0000000 0000000% +2100000000000003958000349 016880000931 0% +23000000 0001 0000000 0000000% +2100000000000014551004889 015366001280 0% +23000000 0001 0000000 0000000% +2100000000000034807011059 023748011.757 0% +23000000 0001 0000000 0000000% +2100000000000025494004889 024447013387 0% +23000000 0001 0000000 0000000% +2100000000000026658005122 014318005937 0% +23000000 0002 0000000 0000000% +2100000000000015599003026 015366013853 0% +23000000 0002 0000000 0000000% +2100000000000025844013154 010128012107 0% +23000000 0002 0000000 0000000% +2100000000000004423010360 004772017345 0% +23000000 0002 0000000 0000000% +2100000000000005005040745 003725035389 0% +23000000 0002 0000000 0000000% +2100000000000004540034807 000582039580 0% +23000000 0002 0000000 0000000% +2100000000000020605036670 002211030616 0% +23000000 0002 0000000 0000000% +2100000000000015133038882 013620022817 0% +23000000 0002 0000000 0000000% +2100000000000016996037252 000465035972 0% diff --git a/testdata/simple_axlines.graph b/testdata/simple_axlines.graph new file mode 100644 index 00000000..a1f4c74b Binary files /dev/null and b/testdata/simple_axlines.graph differ diff --git a/testdata/simple_axlines.mid b/testdata/simple_axlines.mid new file mode 100644 index 00000000..4dc7337d --- /dev/null +++ b/testdata/simple_axlines.mid @@ -0,0 +1,17 @@ +0,2,67.185654 +1,3,50.994308 +2,2,65.140717 +3,2,27.951588 +4,2,12.985298 +5,1,6.2235465 +6,2,11.059984 +7,3,8.5625963 +8,2,12.366808 +9,2,10.829045 +10,3,35.987316 +11,1,6.9935918 +12,1,10.242486 +13,2,6.2006397 +14,1,19.364029 +15,3,16.136318 +16,2,16.580376 diff --git a/testdata/simple_axlines.mif b/testdata/simple_axlines.mif new file mode 100644 index 00000000..fcd0f200 --- /dev/null +++ b/testdata/simple_axlines.mif @@ -0,0 +1,45 @@ +Version 300 +Charset "WindowsLatin1" +Delimiter "," +Index 1 +CoordSys NonEarth Units "m" Bounds (-50.000000, -50.000000) ( 50.000000, 50.000000) +Columns 3 + Depthmap_Ref Integer + Connectivity Float + Line_Length Float +Data + +LINE -48.31199068684517 25.49476135040745 18.85913853317811 26.89173457508731 + PEN (1,2,0) +LINE -33.9930151338766 -14.66821885913853 -33.29452852153667 36.32130384167637 + PEN (1,2,0) +LINE -44.23748544819558 -11.52502910360885 20.83818393480792 -8.614668218859139 + PEN (1,2,0) +LINE 4.423748544819557 -21.53667054714785 7.10128055878929 6.286379511059371 + PEN (1,2,0) +LINE 3.958090803259604 0.3492433061699651 16.88009313154831 -0.9313154831199069 + PEN (1,2,0) +LINE 14.55180442374854 4.889406286379511 15.36670547147846 -1.280558789289872 + PEN (1,2,0) +LINE -34.80791618160652 11.05937136204889 -23.74854481955763 11.17578579743888 + PEN (1,2,0) +LINE -25.49476135040745 4.889406286379511 -24.44703143189756 13.38766006984866 + PEN (1,2,0) +LINE -26.65890570430733 5.122235157159488 -14.31897555296857 5.937136204889407 + PEN (1,2,0) +LINE -15.59953434225844 3.026775320139697 -15.36670547147846 13.85331781140861 + PEN (1,2,0) +LINE -25.84400465657741 13.15483119906868 10.12805587892899 12.10710128055879 + PEN (1,2,0) +LINE 4.423748544819557 10.36088474970896 4.772991850989523 17.34575087310827 + PEN (1,2,0) +LINE -5.005820721769499 40.74505238649593 3.725261932479627 35.38998835855646 + PEN (1,2,0) +LINE -4.540162980209546 34.80791618160652 -0.5820721769499417 39.58090803259604 + PEN (1,2,0) +LINE -20.60535506402794 36.67054714784634 -2.211874272409779 30.61699650756694 + PEN (1,2,0) +LINE -15.13387660069849 38.88242142025611 -13.62048894062864 22.81722933643772 + PEN (1,2,0) +LINE -16.9965075669383 37.25261932479627 -0.4656577415599534 35.9720605355064 + PEN (1,2,0) diff --git a/testdata/simple_axlines_pline.mid b/testdata/simple_axlines_pline.mid new file mode 100644 index 00000000..4dc7337d --- /dev/null +++ b/testdata/simple_axlines_pline.mid @@ -0,0 +1,17 @@ +0,2,67.185654 +1,3,50.994308 +2,2,65.140717 +3,2,27.951588 +4,2,12.985298 +5,1,6.2235465 +6,2,11.059984 +7,3,8.5625963 +8,2,12.366808 +9,2,10.829045 +10,3,35.987316 +11,1,6.9935918 +12,1,10.242486 +13,2,6.2006397 +14,1,19.364029 +15,3,16.136318 +16,2,16.580376 diff --git a/testdata/simple_axlines_pline.mif b/testdata/simple_axlines_pline.mif new file mode 100644 index 00000000..1d4b4a35 --- /dev/null +++ b/testdata/simple_axlines_pline.mif @@ -0,0 +1,48 @@ +Version 300 +Charset "WindowsLatin1" +Delimiter "," +Index 1 +CoordSys NonEarth Units "m" Bounds (-50.000000, -50.000000) ( 50.000000, 50.000000) +Columns 3 + Depthmap_Ref Integer + Connectivity Float + Line_Length Float +Data + +PLINE 3 +-48.31199068684517 25.49476135040745 +18.85913853317811 26.89173457508731 +18.85913853317811 0 + PEN (1,2,0) +LINE -33.9930151338766 -14.66821885913853 -33.29452852153667 36.32130384167637 + PEN (1,2,0) +LINE -44.23748544819558 -11.52502910360885 20.83818393480792 -8.614668218859139 + PEN (1,2,0) +LINE 4.423748544819557 -21.53667054714785 7.10128055878929 6.286379511059371 + PEN (1,2,0) +LINE 3.958090803259604 0.3492433061699651 16.88009313154831 -0.9313154831199069 + PEN (1,2,0) +LINE 14.55180442374854 4.889406286379511 15.36670547147846 -1.280558789289872 + PEN (1,2,0) +LINE -34.80791618160652 11.05937136204889 -23.74854481955763 11.17578579743888 + PEN (1,2,0) +LINE -25.49476135040745 4.889406286379511 -24.44703143189756 13.38766006984866 + PEN (1,2,0) +LINE -26.65890570430733 5.122235157159488 -14.31897555296857 5.937136204889407 + PEN (1,2,0) +LINE -15.59953434225844 3.026775320139697 -15.36670547147846 13.85331781140861 + PEN (1,2,0) +LINE -25.84400465657741 13.15483119906868 10.12805587892899 12.10710128055879 + PEN (1,2,0) +LINE 4.423748544819557 10.36088474970896 4.772991850989523 17.34575087310827 + PEN (1,2,0) +LINE -5.005820721769499 40.74505238649593 3.725261932479627 35.38998835855646 + PEN (1,2,0) +LINE -4.540162980209546 34.80791618160652 -0.5820721769499417 39.58090803259604 + PEN (1,2,0) +LINE -20.60535506402794 36.67054714784634 -2.211874272409779 30.61699650756694 + PEN (1,2,0) +LINE -15.13387660069849 38.88242142025611 -13.62048894062864 22.81722933643772 + PEN (1,2,0) +LINE -16.9965075669383 37.25261932479627 -0.4656577415599534 35.9720605355064 + PEN (1,2,0) diff --git a/testdata/turns.dxf b/testdata/turns.dxf new file mode 100644 index 00000000..32d2ebc9 --- /dev/null +++ b/testdata/turns.dxf @@ -0,0 +1,12638 @@ + 0 +SECTION + 2 +HEADER + 9 +$ACADVER + 1 +AC1027 + 9 +$ACADMAINTVER + 70 + 125 + 9 +$DWGCODEPAGE + 3 +ANSI_1252 + 9 +$LASTSAVEDBY + 1 +petros + 9 +$REQUIREDVERSIONS +160 + 0 + 9 +$INSBASE + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$EXTMIN + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$EXTMAX + 10 +2.5 + 20 +1.5 + 30 +0.0 + 9 +$LIMMIN + 10 +0.0 + 20 +0.0 + 9 +$LIMMAX + 10 +420.0 + 20 +297.0 + 9 +$ORTHOMODE + 70 + 0 + 9 +$REGENMODE + 70 + 1 + 9 +$FILLMODE + 70 + 1 + 9 +$QTEXTMODE + 70 + 0 + 9 +$MIRRTEXT + 70 + 0 + 9 +$LTSCALE + 40 +1.0 + 9 +$ATTMODE + 70 + 1 + 9 +$TEXTSIZE + 40 +2.5 + 9 +$TRACEWID + 40 +1.0 + 9 +$TEXTSTYLE + 7 +Standard + 9 +$CLAYER + 8 +0 + 9 +$CELTYPE + 6 +ByLayer + 9 +$CECOLOR + 62 + 256 + 9 +$CELTSCALE + 40 +1.0 + 9 +$DISPSILH + 70 + 0 + 9 +$DIMSCALE + 40 +1.0 + 9 +$DIMASZ + 40 +2.5 + 9 +$DIMEXO + 40 +0.625 + 9 +$DIMDLI + 40 +3.75 + 9 +$DIMRND + 40 +0.0 + 9 +$DIMDLE + 40 +0.0 + 9 +$DIMEXE + 40 +1.25 + 9 +$DIMTP + 40 +0.0 + 9 +$DIMTM + 40 +0.0 + 9 +$DIMTXT + 40 +2.5 + 9 +$DIMCEN + 40 +2.5 + 9 +$DIMTSZ + 40 +0.0 + 9 +$DIMTOL + 70 + 0 + 9 +$DIMLIM + 70 + 0 + 9 +$DIMTIH + 70 + 0 + 9 +$DIMTOH + 70 + 0 + 9 +$DIMSE1 + 70 + 0 + 9 +$DIMSE2 + 70 + 0 + 9 +$DIMTAD + 70 + 1 + 9 +$DIMZIN + 70 + 8 + 9 +$DIMBLK + 1 + + 9 +$DIMASO + 70 + 1 + 9 +$DIMSHO + 70 + 1 + 9 +$DIMPOST + 1 + + 9 +$DIMAPOST + 1 + + 9 +$DIMALT + 70 + 0 + 9 +$DIMALTD + 70 + 3 + 9 +$DIMALTF + 40 +0.03937007874016 + 9 +$DIMLFAC + 40 +1.0 + 9 +$DIMTOFL + 70 + 1 + 9 +$DIMTVP + 40 +0.0 + 9 +$DIMTIX + 70 + 0 + 9 +$DIMSOXD + 70 + 0 + 9 +$DIMSAH + 70 + 0 + 9 +$DIMBLK1 + 1 + + 9 +$DIMBLK2 + 1 + + 9 +$DIMSTYLE + 2 +ISO-25 + 9 +$DIMCLRD + 70 + 0 + 9 +$DIMCLRE + 70 + 0 + 9 +$DIMCLRT + 70 + 0 + 9 +$DIMTFAC + 40 +1.0 + 9 +$DIMGAP + 40 +0.625 + 9 +$DIMJUST + 70 + 0 + 9 +$DIMSD1 + 70 + 0 + 9 +$DIMSD2 + 70 + 0 + 9 +$DIMTOLJ + 70 + 0 + 9 +$DIMTZIN + 70 + 8 + 9 +$DIMALTZ + 70 + 0 + 9 +$DIMALTTZ + 70 + 0 + 9 +$DIMUPT + 70 + 0 + 9 +$DIMDEC + 70 + 2 + 9 +$DIMTDEC + 70 + 2 + 9 +$DIMALTU + 70 + 2 + 9 +$DIMALTTD + 70 + 3 + 9 +$DIMTXSTY + 7 +Standard + 9 +$DIMAUNIT + 70 + 0 + 9 +$DIMADEC + 70 + 0 + 9 +$DIMALTRND + 40 +0.0 + 9 +$DIMAZIN + 70 + 0 + 9 +$DIMDSEP + 70 + 44 + 9 +$DIMATFIT + 70 + 3 + 9 +$DIMFRAC + 70 + 0 + 9 +$DIMLDRBLK + 1 + + 9 +$DIMLUNIT + 70 + 2 + 9 +$DIMLWD + 70 + -2 + 9 +$DIMLWE + 70 + -2 + 9 +$DIMTMOVE + 70 + 0 + 9 +$DIMFXL + 40 +1.0 + 9 +$DIMFXLON + 70 + 0 + 9 +$DIMJOGANG + 40 +0.7853981633974483 + 9 +$DIMTFILL + 70 + 0 + 9 +$DIMTFILLCLR + 70 + 0 + 9 +$DIMARCSYM + 70 + 0 + 9 +$DIMLTYPE + 6 + + 9 +$DIMLTEX1 + 6 + + 9 +$DIMLTEX2 + 6 + + 9 +$DIMTXTDIRECTION + 70 + 0 + 9 +$LUNITS + 70 + 2 + 9 +$LUPREC + 70 + 4 + 9 +$SKETCHINC + 40 +1.0 + 9 +$FILLETRAD + 40 +0.0 + 9 +$AUNITS + 70 + 0 + 9 +$AUPREC + 70 + 0 + 9 +$MENU + 1 +. + 9 +$ELEVATION + 40 +0.0 + 9 +$PELEVATION + 40 +0.0 + 9 +$THICKNESS + 40 +0.0 + 9 +$LIMCHECK + 70 + 0 + 9 +$CHAMFERA + 40 +0.0 + 9 +$CHAMFERB + 40 +0.0 + 9 +$CHAMFERC + 40 +0.0 + 9 +$CHAMFERD + 40 +0.0 + 9 +$SKPOLY + 70 + 0 + 9 +$TDCREATE + 40 +2458063.099826389 + 9 +$TDUCREATE + 40 +2458063.099826389 + 9 +$TDUPDATE + 40 +2458063.103020833 + 9 +$TDUUPDATE + 40 +2458063.103020833 + 9 +$TDINDWG + 40 +0.0032060185 + 9 +$TDUSRTIMER + 40 +0.0032060185 + 9 +$USRTIMER + 70 + 1 + 9 +$ANGBASE + 50 +0.0 + 9 +$ANGDIR + 70 + 0 + 9 +$PDMODE + 70 + 0 + 9 +$PDSIZE + 40 +0.0 + 9 +$PLINEWID + 40 +0.0 + 9 +$SPLFRAME + 70 + 0 + 9 +$SPLINETYPE + 70 + 6 + 9 +$SPLINESEGS + 70 + 8 + 9 +$HANDSEED + 5 +27E + 9 +$SURFTAB1 + 70 + 6 + 9 +$SURFTAB2 + 70 + 6 + 9 +$SURFTYPE + 70 + 6 + 9 +$SURFU + 70 + 6 + 9 +$SURFV + 70 + 6 + 9 +$UCSBASE + 2 + + 9 +$UCSNAME + 2 + + 9 +$UCSORG + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSXDIR + 10 +1.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSYDIR + 10 +0.0 + 20 +1.0 + 30 +0.0 + 9 +$UCSORTHOREF + 2 + + 9 +$UCSORTHOVIEW + 70 + 0 + 9 +$UCSORGTOP + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGBOTTOM + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGLEFT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGRIGHT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGFRONT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGBACK + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSBASE + 2 + + 9 +$PUCSNAME + 2 + + 9 +$PUCSORG + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSXDIR + 10 +1.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSYDIR + 10 +0.0 + 20 +1.0 + 30 +0.0 + 9 +$PUCSORTHOREF + 2 + + 9 +$PUCSORTHOVIEW + 70 + 0 + 9 +$PUCSORGTOP + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGBOTTOM + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGLEFT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGRIGHT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGFRONT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGBACK + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$USERI1 + 70 + 0 + 9 +$USERI2 + 70 + 0 + 9 +$USERI3 + 70 + 0 + 9 +$USERI4 + 70 + 0 + 9 +$USERI5 + 70 + 0 + 9 +$USERR1 + 40 +0.0 + 9 +$USERR2 + 40 +0.0 + 9 +$USERR3 + 40 +0.0 + 9 +$USERR4 + 40 +0.0 + 9 +$USERR5 + 40 +0.0 + 9 +$WORLDVIEW + 70 + 1 + 9 +$SHADEDGE + 70 + 3 + 9 +$SHADEDIF + 70 + 70 + 9 +$TILEMODE + 70 + 1 + 9 +$MAXACTVP + 70 + 64 + 9 +$PINSBASE + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PLIMCHECK + 70 + 0 + 9 +$PEXTMIN + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PEXTMAX + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PLIMMIN + 10 +0.0 + 20 +0.0 + 9 +$PLIMMAX + 10 +12.0 + 20 +9.0 + 9 +$UNITMODE + 70 + 0 + 9 +$VISRETAIN + 70 + 1 + 9 +$PLINEGEN + 70 + 0 + 9 +$PSLTSCALE + 70 + 1 + 9 +$TREEDEPTH + 70 + 3020 + 9 +$CMLSTYLE + 2 +Standard + 9 +$CMLJUST + 70 + 0 + 9 +$CMLSCALE + 40 +20.0 + 9 +$PROXYGRAPHICS + 70 + 1 + 9 +$MEASUREMENT + 70 + 1 + 9 +$CELWEIGHT +370 + -1 + 9 +$ENDCAPS +280 + 0 + 9 +$JOINSTYLE +280 + 0 + 9 +$LWDISPLAY +290 + 0 + 9 +$INSUNITS + 70 + 4 + 9 +$HYPERLINKBASE + 1 + + 9 +$STYLESHEET + 1 + + 9 +$XEDIT +290 + 1 + 9 +$CEPSNTYPE +380 + 0 + 9 +$PSTYLEMODE +290 + 1 + 9 +$FINGERPRINTGUID + 2 +{AFD1DA9D-7DA5-454D-AE1C-440A3E196D4F} + 9 +$VERSIONGUID + 2 +{9AECDF69-EDC8-E448-993E-6650646B9926} + 9 +$EXTNAMES +290 + 1 + 9 +$PSVPSCALE + 40 +0.0 + 9 +$OLESTARTUP +290 + 0 + 9 +$SORTENTS +280 + 127 + 9 +$INDEXCTL +280 + 0 + 9 +$HIDETEXT +280 + 1 + 9 +$XCLIPFRAME +280 + 2 + 9 +$HALOGAP +280 + 0 + 9 +$OBSCOLOR + 70 + 257 + 9 +$OBSLTYPE +280 + 0 + 9 +$INTERSECTIONDISPLAY +280 + 0 + 9 +$INTERSECTIONCOLOR + 70 + 257 + 9 +$DIMASSOC +280 + 2 + 9 +$PROJECTNAME + 1 + + 9 +$CAMERADISPLAY +290 + 0 + 9 +$LENSLENGTH + 40 +50.0 + 9 +$CAMERAHEIGHT + 40 +0.0 + 9 +$STEPSPERSEC + 40 +2.0 + 9 +$STEPSIZE + 40 +6.0 + 9 +$3DDWFPREC + 40 +2.0 + 9 +$PSOLWIDTH + 40 +5.0 + 9 +$PSOLHEIGHT + 40 +80.0 + 9 +$LOFTANG1 + 40 +1.570796326794896 + 9 +$LOFTANG2 + 40 +1.570796326794896 + 9 +$LOFTMAG1 + 40 +0.0 + 9 +$LOFTMAG2 + 40 +0.0 + 9 +$LOFTPARAM + 70 + 7 + 9 +$LOFTNORMALS +280 + 1 + 9 +$LATITUDE + 40 +37.795 + 9 +$LONGITUDE + 40 +-122.394 + 9 +$NORTHDIRECTION + 40 +0.0 + 9 +$TIMEZONE + 70 + -8000 + 9 +$LIGHTGLYPHDISPLAY +280 + 1 + 9 +$TILEMODELIGHTSYNCH +280 + 1 + 9 +$CMATERIAL +347 +EC + 9 +$SOLIDHIST +280 + 0 + 9 +$SHOWHIST +280 + 1 + 9 +$DWFFRAME +280 + 2 + 9 +$DGNFRAME +280 + 0 + 9 +$REALWORLDSCALE +290 + 1 + 9 +$INTERFERECOLOR + 62 + 1 + 9 +$INTERFEREOBJVS +345 +F9 + 9 +$INTERFEREVPVS +346 +F6 + 9 +$CSHADOW +280 + 0 + 9 +$SHADOWPLANELOCATION + 40 +0.0 + 0 +ENDSEC + 0 +SECTION + 2 +CLASSES + 0 +CLASS + 1 +ACDBDICTIONARYWDFLT + 2 +AcDbDictionaryWithDefault + 3 +ObjectDBX Classes + 90 + 0 + 91 + 1 +280 + 0 +281 + 0 + 0 +CLASS + 1 +DICTIONARYVAR + 2 +AcDbDictionaryVar + 3 +ObjectDBX Classes + 90 + 0 + 91 + 11 +280 + 0 +281 + 0 + 0 +CLASS + 1 +TABLESTYLE + 2 +AcDbTableStyle + 3 +ObjectDBX Classes + 90 + 4095 + 91 + 1 +280 + 0 +281 + 0 + 0 +CLASS + 1 +MATERIAL + 2 +AcDbMaterial + 3 +ObjectDBX Classes + 90 + 1153 + 91 + 3 +280 + 0 +281 + 0 + 0 +CLASS + 1 +VISUALSTYLE + 2 +AcDbVisualStyle + 3 +ObjectDBX Classes + 90 + 4095 + 91 + 24 +280 + 0 +281 + 0 + 0 +CLASS + 1 +SCALE + 2 +AcDbScale + 3 +ObjectDBX Classes + 90 + 1153 + 91 + 17 +280 + 0 +281 + 0 + 0 +CLASS + 1 +MLEADERSTYLE + 2 +AcDbMLeaderStyle + 3 +ACDB_MLEADERSTYLE_CLASS + 90 + 4095 + 91 + 2 +280 + 0 +281 + 0 + 0 +CLASS + 1 +CELLSTYLEMAP + 2 +AcDbCellStyleMap + 3 +ObjectDBX Classes + 90 + 1152 + 91 + 1 +280 + 0 +281 + 0 + 0 +CLASS + 1 +EXACXREFPANELOBJECT + 2 +ExAcXREFPanelObject + 3 +EXAC_ESW + 90 + 1025 + 91 + 0 +280 + 0 +281 + 0 + 0 +CLASS + 1 +NPOCOLLECTION + 2 +AcDbImpNonPersistentObjectsCollection + 3 +ObjectDBX Classes + 90 + 1153 + 91 + 0 +280 + 0 +281 + 0 + 0 +CLASS + 1 +LAYER_INDEX + 2 +AcDbLayerIndex + 3 +ObjectDBX Classes + 90 + 0 + 91 + 0 +280 + 0 +281 + 0 + 0 +CLASS + 1 +SPATIAL_INDEX + 2 +AcDbSpatialIndex + 3 +ObjectDBX Classes + 90 + 0 + 91 + 0 +280 + 0 +281 + 0 + 0 +CLASS + 1 +IDBUFFER + 2 +AcDbIdBuffer + 3 +ObjectDBX Classes + 90 + 0 + 91 + 0 +280 + 0 +281 + 0 + 0 +CLASS + 1 +ACDBSECTIONVIEWSTYLE + 2 +AcDbSectionViewStyle + 3 +ObjectDBX Classes + 90 + 1025 + 91 + 1 +280 + 0 +281 + 0 + 0 +CLASS + 1 +ACDBDETAILVIEWSTYLE + 2 +AcDbDetailViewStyle + 3 +ObjectDBX Classes + 90 + 1025 + 91 + 1 +280 + 0 +281 + 0 + 0 +ENDSEC + 0 +SECTION + 2 +TABLES + 0 +TABLE + 2 +VPORT + 5 +8 +330 +0 +100 +AcDbSymbolTable + 70 + 1 +1001 +ACAD +1000 +DbSaveVer +1071 + 30 + 0 +VPORT + 5 +EA +330 +8 +100 +AcDbSymbolTableRecord +100 +AcDbViewportTableRecord + 2 +*Active + 70 + 0 + 10 +0.0 + 20 +0.0 + 11 +1.0 + 21 +1.0 + 12 +1.001627717390972 + 22 +0.5962582929476006 + 13 +0.0 + 23 +0.0 + 14 +10.0 + 24 +10.0 + 15 +10.0 + 25 +10.0 + 16 +0.0 + 26 +0.0 + 36 +1.0 + 17 +0.0 + 27 +0.0 + 37 +0.0 + 40 +3.854413096348022 + 41 +1.394052044609665 + 42 +50.0 + 43 +0.0 + 44 +0.0 + 50 +0.0 + 51 +0.0 + 71 + 0 + 72 + 1000 + 73 + 1 + 74 + 3 + 75 + 0 + 76 + 1 + 77 + 0 + 78 + 0 +281 + 0 + 65 + 1 +110 +0.0 +120 +0.0 +130 +0.0 +111 +1.0 +121 +0.0 +131 +0.0 +112 +0.0 +122 +1.0 +132 +0.0 + 79 + 0 +146 +0.0 +348 +F5 + 60 + 3 + 61 + 5 +292 + 1 +282 + 1 +141 +0.0 +142 +0.0 + 63 + 250 +421 + 3355443 +1001 +ACAD_NAV_VCDISPLAY +1070 + 3 + 0 +ENDTAB + 0 +TABLE + 2 +LTYPE + 5 +5 +330 +0 +100 +AcDbSymbolTable + 70 + 2 + 0 +LTYPE + 5 +14 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByBlock + 70 + 0 + 3 + + 72 + 65 + 73 + 0 + 40 +0.0 + 0 +LTYPE + 5 +15 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByLayer + 70 + 0 + 3 + + 72 + 65 + 73 + 0 + 40 +0.0 + 0 +LTYPE + 5 +16 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +Continuous + 70 + 0 + 3 +Solid line + 72 + 65 + 73 + 0 + 40 +0.0 + 0 +ENDTAB + 0 +TABLE + 2 +LAYER + 5 +2 +102 +{ACAD_XDICTIONARY +360 +1FF +102 +} +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +LAYER + 5 +10 +102 +{ACAD_XDICTIONARY +360 +13C +102 +} +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +0 + 70 + 0 + 62 + 7 + 6 +Continuous +370 + -3 +390 +F +347 +EE +348 +0 + 0 +ENDTAB + 0 +TABLE + 2 +STYLE + 5 +3 +330 +0 +100 +AcDbSymbolTable + 70 + 2 + 0 +STYLE + 5 +11 +330 +3 +100 +AcDbSymbolTableRecord +100 +AcDbTextStyleTableRecord + 2 +Standard + 70 + 0 + 40 +0.0 + 41 +1.0 + 50 +0.0 + 71 + 0 + 42 +2.5 + 3 +arial.ttf + 4 + +1001 +ACAD +1000 +Arial +1071 + 34 + 0 +STYLE + 5 +132 +330 +3 +100 +AcDbSymbolTableRecord +100 +AcDbTextStyleTableRecord + 2 +Annotative + 70 + 0 + 40 +0.0 + 41 +1.0 + 50 +0.0 + 71 + 0 + 42 +2.5 + 3 +arial.ttf + 4 + +1001 +AcadAnnotative +1000 +AnnotativeData +1002 +{ +1070 + 1 +1070 + 1 +1002 +} +1001 +ACAD +1000 +Arial +1071 + 34 + 0 +ENDTAB + 0 +TABLE + 2 +VIEW + 5 +6 +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +ENDTAB + 0 +TABLE + 2 +UCS + 5 +7 +330 +0 +100 +AcDbSymbolTable + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +APPID + 5 +9 +330 +0 +100 +AcDbSymbolTable + 70 + 9 + 0 +APPID + 5 +12 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD + 70 + 0 + 0 +APPID + 5 +9E +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD_PSEXT + 70 + 0 + 0 +APPID + 5 +133 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +AcadAnnoPO + 70 + 0 + 0 +APPID + 5 +134 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +AcadAnnotative + 70 + 0 + 0 +APPID + 5 +135 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD_DSTYLE_DIMJAG + 70 + 0 + 0 +APPID + 5 +136 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD_DSTYLE_DIMTALN + 70 + 0 + 0 +APPID + 5 +165 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD_MLEADERVER + 70 + 0 + 0 +APPID + 5 +217 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD_NAV_VCDISPLAY + 70 + 0 + 0 +APPID + 5 +26C +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD_EXEMPT_FROM_CAD_STANDARDS + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +DIMSTYLE + 5 +A +330 +0 +100 +AcDbSymbolTable + 70 + 4 +100 +AcDbDimStyleTable + 71 + 2 +340 +27 +340 +137 + 0 +DIMSTYLE +105 +1B0 +330 +A +100 +AcDbSymbolTableRecord +100 +AcDbDimStyleTableRecord + 2 +Standard + 70 + 0 +340 +11 + 0 +DIMSTYLE +105 +137 +330 +A +100 +AcDbSymbolTableRecord +100 +AcDbDimStyleTableRecord + 2 +Annotative + 70 + 0 + 40 +0.0 + 41 +2.5 + 42 +0.625 + 43 +3.75 + 44 +1.25 + 73 + 0 + 74 + 0 + 77 + 1 + 78 + 8 +140 +2.5 +141 +2.5 +143 +0.03937007874016 +147 +0.625 +171 + 3 +172 + 1 +271 + 2 +272 + 2 +274 + 3 +278 + 44 +283 + 0 +284 + 8 +340 +11 +1001 +AcadAnnotative +1000 +AnnotativeData +1002 +{ +1070 + 1 +1070 + 1 +1002 +} +1001 +ACAD_DSTYLE_DIMJAG +1070 + 388 +1040 +1.5 +1001 +ACAD_DSTYLE_DIMTALN +1070 + 392 +1070 + 0 + 0 +DIMSTYLE +105 +27 +330 +A +100 +AcDbSymbolTableRecord +100 +AcDbDimStyleTableRecord + 2 +ISO-25 + 70 + 0 + 41 +2.5 + 42 +0.625 + 43 +3.75 + 44 +1.25 + 73 + 0 + 74 + 0 + 77 + 1 + 78 + 8 +140 +2.5 +141 +2.5 +143 +0.03937007874016 +147 +0.625 +171 + 3 +172 + 1 +271 + 2 +272 + 2 +274 + 3 +278 + 44 +283 + 0 +284 + 8 +340 +11 + 0 +ENDTAB + 0 +TABLE + 2 +BLOCK_RECORD + 5 +1 +330 +0 +100 +AcDbSymbolTable + 70 + 2 + 0 +BLOCK_RECORD + 5 +1F +102 +{ACAD_XDICTIONARY +360 +1CE +102 +} +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Model_Space +340 +22 + 70 + 0 +280 + 1 +281 + 0 + 0 +BLOCK_RECORD + 5 +D2 +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Paper_Space +340 +D3 + 70 + 0 +280 + 1 +281 + 0 + 0 +BLOCK_RECORD + 5 +D6 +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Paper_Space0 +340 +D7 + 70 + 0 +280 + 1 +281 + 0 + 0 +ENDTAB + 0 +ENDSEC + 0 +SECTION + 2 +BLOCKS + 0 +BLOCK + 5 +20 +330 +1F +100 +AcDbEntity + 8 +0 +100 +AcDbBlockBegin + 2 +*Model_Space + 70 + 0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +*Model_Space + 1 + + 0 +ENDBLK + 5 +21 +330 +1F +100 +AcDbEntity + 8 +0 +100 +AcDbBlockEnd + 0 +BLOCK + 5 +D4 +330 +D2 +100 +AcDbEntity + 67 + 1 + 8 +0 +100 +AcDbBlockBegin + 2 +*Paper_Space + 70 + 0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +*Paper_Space + 1 + + 0 +ENDBLK + 5 +D5 +330 +D2 +100 +AcDbEntity + 67 + 1 + 8 +0 +100 +AcDbBlockEnd + 0 +BLOCK + 5 +D8 +330 +D6 +100 +AcDbEntity + 67 + 1 + 8 +0 +100 +AcDbBlockBegin + 2 +*Paper_Space0 + 70 + 0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +*Paper_Space0 + 1 + + 0 +ENDBLK + 5 +D9 +330 +D6 +100 +AcDbEntity + 67 + 1 + 8 +0 +100 +AcDbBlockEnd + 0 +ENDSEC + 0 +SECTION + 2 +ENTITIES + 0 +LWPOLYLINE + 5 +26B +330 +1F +100 +AcDbEntity + 8 +0 +100 +AcDbPolyline + 90 + 12 + 70 + 1 + 43 +0.0 + 10 +1.0 + 20 +1.0 + 10 +1.0 + 20 +0.5 + 10 +0.5 + 20 +0.5 + 10 +0.5000000000000001 + 20 +1.0 + 10 +0.0000000000000001 + 20 +1.0 + 10 +0.0 + 20 +0.0 + 10 +1.499999999999999 + 20 +0.0 + 10 +1.5 + 20 +0.75 + 10 +2.0 + 20 +0.75 + 10 +2.0 + 20 +0.0 + 10 +2.5 + 20 +0.0 + 10 +2.5 + 20 +1.0 + 0 +ENDSEC + 0 +SECTION + 2 +OBJECTS + 0 +DICTIONARY + 5 +C +330 +0 +100 +AcDbDictionary +281 + 1 + 3 +ACAD_CIP_PREVIOUS_PRODUCT_INFO +350 +216 + 3 +ACAD_COLOR +350 +6B + 3 +ACAD_DETAILVIEWSTYLE +350 +21B + 3 +ACAD_GROUP +350 +D + 3 +ACAD_LAYOUT +350 +1A + 3 +ACAD_MATERIAL +350 +6A + 3 +ACAD_MLEADERSTYLE +350 +12D + 3 +ACAD_MLINESTYLE +350 +17 + 3 +ACAD_PLOTSETTINGS +350 +19 + 3 +ACAD_PLOTSTYLENAME +350 +E + 3 +ACAD_SCALELIST +350 +10C + 3 +ACAD_SECTIONVIEWSTYLE +350 +219 + 3 +ACAD_TABLESTYLE +350 +7E + 3 +ACAD_VISUALSTYLE +350 +EF + 3 +ACDB_RECOMPOSE_DATA +350 +27D + 3 +AcDbVariableDictionary +350 +5E + 0 +DICTIONARY + 5 +1FF +330 +2 +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +ACAD_LAYERSTATES +360 +200 + 0 +DICTIONARY + 5 +13C +330 +10 +100 +AcDbDictionary +280 + 1 +281 + 1 + 0 +DICTIONARY + 5 +1CE +330 +1F +100 +AcDbDictionary +280 + 1 +281 + 1 + 0 +XRECORD + 5 +216 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbXrecord +280 + 1 +300 +ACDMAC +300 +2017 +300 +ACDMAC_F_S + 0 +DICTIONARY + 5 +6B +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +DICTIONARY + 5 +21B +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Metric50 +350 +21C + 0 +DICTIONARY + 5 +D +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +DICTIONARY + 5 +1A +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Layout1 +350 +D3 + 3 +Layout2 +350 +D7 + 3 +Model +350 +22 + 0 +DICTIONARY + 5 +6A +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +ByBlock +350 +ED + 3 +ByLayer +350 +EC + 3 +Global +350 +EE + 0 +DICTIONARY + 5 +12D +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Annotative +350 +13B + 3 +Standard +350 +12E + 0 +DICTIONARY + 5 +17 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Standard +350 +18 + 0 +DICTIONARY + 5 +19 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +ACDBDICTIONARYWDFLT + 5 +E +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Normal +350 +F +100 +AcDbDictionaryWithDefault +340 +F + 0 +DICTIONARY + 5 +10C +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +A0 +350 +10D + 3 +A1 +350 +1BE + 3 +A2 +350 +1BF + 3 +A3 +350 +1C0 + 3 +A4 +350 +1C1 + 3 +A5 +350 +1C2 + 3 +A6 +350 +1C3 + 3 +A7 +350 +1C4 + 3 +A8 +350 +1C5 + 3 +A9 +350 +1C6 + 3 +B0 +350 +1C7 + 3 +B1 +350 +1C8 + 3 +B2 +350 +1C9 + 3 +B3 +350 +1CA + 3 +B4 +350 +1CB + 3 +B5 +350 +1CC + 3 +B6 +350 +1CD + 0 +DICTIONARY + 5 +219 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Metric50 +350 +21A + 0 +DICTIONARY + 5 +7E +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Standard +350 +7F + 0 +DICTIONARY + 5 +EF +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +2dWireframe +350 +F5 + 3 +Basic +350 +F4 + 3 +Brighten +350 +FB + 3 +ColorChange +350 +FF + 3 +Conceptual +350 +F8 + 3 +Dim +350 +FA + 3 +EdgeColorOff +350 +1E6 + 3 +Facepattern +350 +FE + 3 +Flat +350 +F0 + 3 +FlatWithEdges +350 +F1 + 3 +Gouraud +350 +F2 + 3 +GouraudWithEdges +350 +F3 + 3 +Hidden +350 +F7 + 3 +JitterOff +350 +1E4 + 3 +Linepattern +350 +FD + 3 +OverhangOff +350 +1E5 + 3 +Realistic +350 +F9 + 3 +Shaded +350 +1F3 + 3 +Shaded with edges +350 +1F2 + 3 +Shades of Gray +350 +1EF + 3 +Sketchy +350 +1F0 + 3 +Thicken +350 +FC + 3 +Wireframe +350 +F6 + 3 +X-Ray +350 +1F1 + 0 +XRECORD + 5 +27D +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbXrecord +280 + 1 + 90 + 1 +330 +7F +330 +21A +330 +21C + 0 +DICTIONARY + 5 +5E +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +CANNOSCALE +350 +146 + 3 +CENTEREXE +350 +259 + 3 +CENTERLTYPEFILE +350 +25A + 3 +CMLEADERSTYLE +350 +145 + 3 +CTABLESTYLE +350 +84 + 3 +CVIEWDETAILSTYLE +350 +227 + 3 +CVIEWSECTIONSTYLE +350 +228 + 3 +DIMASSOC +350 +5F + 3 +HIDETEXT +350 +63 + 3 +LAYEREVAL +350 +1AE + 3 +LAYERNOTIFY +350 +1AF + 0 +DICTIONARY + 5 +200 +102 +{ACAD_REACTORS +330 +1FF +102 +} +330 +1FF +100 +AcDbDictionary +281 + 1 + 0 +ACDBDETAILVIEWSTYLE + 5 +21C +102 +{ACAD_XDICTIONARY +360 +236 +102 +} +102 +{ACAD_REACTORS +330 +21B +102 +} +330 +21B +100 +AcDbModelDocViewStyle + 70 + 0 + 3 +Metric50 +290 + 0 +100 +AcDbDetailViewStyle + 70 + 0 + 71 + 0 + 90 + 3 + 71 + 1 +340 +11 + 62 + 256 + 40 +5.0 +340 +0 + 62 + 256 + 40 +5.0 +300 + + 40 +0.0 +280 + 1 + 71 + 2 +340 +16 + 90 + 25 + 62 + 256 + 71 + 3 +340 +11 + 62 + 256 + 40 +5.0 + 90 + 0 + 40 +15.0 + 90 + 1 +300 +%<\AcVar ViewDetailId>% (%<\AcVar ViewScale \f "%sn">%) + 71 + 4 +340 +16 + 90 + 25 + 62 + 256 +340 +16 + 90 + 25 + 62 + 256 +280 + 0 + 0 +LAYOUT + 5 +D3 +102 +{ACAD_REACTORS +330 +1A +102 +} +330 +1A +100 +AcDbPlotSettings + 1 + + 2 +C:\Documents and Settings\basas\Application Data\Autodesk\AutoCAD 2005\R16.1\enu\plotters\Default Windows System Printer.pc3 + 4 + + 6 + + 40 +0.0 + 41 +0.0 + 42 +0.0 + 43 +0.0 + 44 +0.0 + 45 +0.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 + 49 +0.0 +140 +0.0 +141 +0.0 +142 +1.0 +143 +1.0 + 70 + 688 + 72 + 0 + 73 + 0 + 74 + 5 + 7 + + 75 + 16 +147 +1.0 + 76 + 0 + 77 + 2 + 78 + 300 +148 +0.0 +149 +0.0 +100 +AcDbLayout + 1 +Layout1 + 70 + 1 + 71 + 1 + 10 +0.0 + 20 +0.0 + 11 +12.0 + 21 +9.0 + 12 +0.0 + 22 +0.0 + 32 +0.0 + 14 +0.0 + 24 +0.0 + 34 +0.0 + 15 +0.0 + 25 +0.0 + 35 +0.0 +146 +0.0 + 13 +0.0 + 23 +0.0 + 33 +0.0 + 16 +1.0 + 26 +0.0 + 36 +0.0 + 17 +0.0 + 27 +1.0 + 37 +0.0 + 76 + 0 +330 +D2 + 0 +LAYOUT + 5 +D7 +102 +{ACAD_REACTORS +330 +1A +102 +} +330 +1A +100 +AcDbPlotSettings + 1 + + 2 +C:\Documents and Settings\basas\Application Data\Autodesk\AutoCAD 2005\R16.1\enu\plotters\Default Windows System Printer.pc3 + 4 + + 6 + + 40 +0.0 + 41 +0.0 + 42 +0.0 + 43 +0.0 + 44 +0.0 + 45 +0.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 + 49 +0.0 +140 +0.0 +141 +0.0 +142 +1.0 +143 +1.0 + 70 + 688 + 72 + 0 + 73 + 0 + 74 + 5 + 7 + + 75 + 16 +147 +1.0 + 76 + 0 + 77 + 2 + 78 + 300 +148 +0.0 +149 +0.0 +100 +AcDbLayout + 1 +Layout2 + 70 + 1 + 71 + 2 + 10 +0.0 + 20 +0.0 + 11 +12.0 + 21 +9.0 + 12 +0.0 + 22 +0.0 + 32 +0.0 + 14 +0.0 + 24 +0.0 + 34 +0.0 + 15 +0.0 + 25 +0.0 + 35 +0.0 +146 +0.0 + 13 +0.0 + 23 +0.0 + 33 +0.0 + 16 +1.0 + 26 +0.0 + 36 +0.0 + 17 +0.0 + 27 +1.0 + 37 +0.0 + 76 + 0 +330 +D6 + 0 +LAYOUT + 5 +22 +102 +{ACAD_XDICTIONARY +360 +205 +102 +} +102 +{ACAD_REACTORS +330 +1A +102 +} +330 +1A +100 +AcDbPlotSettings + 1 + + 2 +none_device + 4 +ISO_A4_(210.00_x_297.00_MM) + 6 + + 40 +7.5 + 41 +20.0 + 42 +7.5 + 43 +20.0 + 44 +210.0 + 45 +297.0 + 46 +11.54999923706054 + 47 +-13.65000009536743 + 48 +0.0 + 49 +0.0 +140 +0.0 +141 +0.0 +142 +1.0 +143 +8.704084754739808 + 70 + 11952 + 72 + 1 + 73 + 0 + 74 + 0 + 7 + + 75 + 0 +147 +0.1148885871608098 + 76 + 0 + 77 + 2 + 78 + 300 +148 +0.0 +149 +0.0 +100 +AcDbLayout + 1 +Model + 70 + 1 + 71 + 0 + 10 +0.0 + 20 +0.0 + 11 +12.0 + 21 +9.0 + 12 +0.0 + 22 +0.0 + 32 +0.0 + 14 +0.0 + 24 +0.0 + 34 +0.0 + 15 +0.0 + 25 +0.0 + 35 +0.0 +146 +0.0 + 13 +0.0 + 23 +0.0 + 33 +0.0 + 16 +1.0 + 26 +0.0 + 36 +0.0 + 17 +0.0 + 27 +1.0 + 37 +0.0 + 76 + 0 +330 +1F +331 +EA +1001 +ACAD_PSEXT +1000 +None +1000 +None +1000 +Not applicable +1000 +The layout will not be plotted unless a new plotter configuration name is selected. +1070 + 0 + 0 +MATERIAL + 5 +ED +102 +{ACAD_XDICTIONARY +360 +1F9 +102 +} +102 +{ACAD_REACTORS +330 +6A +102 +} +330 +6A +100 +AcDbMaterial + 1 +ByBlock + 94 + 63 + 0 +MATERIAL + 5 +EC +102 +{ACAD_XDICTIONARY +360 +1F7 +102 +} +102 +{ACAD_REACTORS +330 +6A +102 +} +330 +6A +100 +AcDbMaterial + 1 +ByLayer + 94 + 63 + 0 +MATERIAL + 5 +EE +102 +{ACAD_XDICTIONARY +360 +173 +102 +} +102 +{ACAD_REACTORS +330 +6A +102 +} +330 +6A +100 +AcDbMaterial + 1 +Global + 43 +0.0007999999797903 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0007999999797903 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +1.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +0.0 + 43 +1.0 + 49 +0.0007999999797903 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0007999999797903 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +1.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +0.0 + 49 +1.0 +142 +0.0007999999797903 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0007999999797903 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +1.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +0.0 +142 +1.0 +144 +0.0007999999797903 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0007999999797903 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +1.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +0.0 +144 +1.0 + 94 + 63 +1001 +ACAD +1070 + -1 +1070 + 3 +1070 + 0 +1000 + +1071 + 0 +1070 + 0 + 0 +MLEADERSTYLE + 5 +13B +102 +{ACAD_REACTORS +330 +12D +102 +} +330 +12D +100 +AcDbMLeaderStyle +179 + 2 +170 + 2 +171 + 1 +172 + 0 + 90 + 2 + 40 +0.0 + 41 +0.0 +173 + 1 + 91 +-1056964608 +340 +14 + 92 + -2 +290 + 1 + 42 +2.0 +291 + 1 + 43 +8.0 + 3 +Standard + 44 +4.0 +300 + +342 +11 +174 + 1 +178 + 1 +175 + 1 +176 + 0 + 93 +-1056964608 + 45 +4.0 +292 + 0 +297 + 0 + 46 +4.0 + 94 +-1056964608 + 47 +1.0 + 49 +1.0 +140 +1.0 +293 + 1 +141 +0.0 +294 + 1 +177 + 0 +142 +1.0 +295 + 0 +296 + 1 +143 +3.75 +271 + 0 +272 + 9 +273 + 9 +298 + 0 + 0 +MLEADERSTYLE + 5 +12E +102 +{ACAD_REACTORS +330 +12D +102 +} +330 +12D +100 +AcDbMLeaderStyle +179 + 2 +170 + 2 +171 + 1 +172 + 0 + 90 + 2 + 40 +0.0 + 41 +0.0 +173 + 1 + 91 +-1056964608 +340 +14 + 92 + -2 +290 + 1 + 42 +2.0 +291 + 1 + 43 +8.0 + 3 +Standard + 44 +4.0 +300 + +342 +11 +174 + 1 +178 + 1 +175 + 1 +176 + 0 + 93 +-1056964608 + 45 +4.0 +292 + 0 +297 + 0 + 46 +4.0 + 94 +-1056964608 + 47 +1.0 + 49 +1.0 +140 +1.0 +293 + 1 +141 +0.0 +294 + 1 +177 + 0 +142 +1.0 +295 + 0 +296 + 0 +143 +3.75 +271 + 0 +272 + 9 +273 + 9 +298 + 0 + 0 +MLINESTYLE + 5 +18 +102 +{ACAD_REACTORS +330 +17 +102 +} +330 +17 +100 +AcDbMlineStyle + 2 +STANDARD + 70 + 0 + 3 + + 62 + 256 + 51 +90.0 + 52 +90.0 + 71 + 2 + 49 +0.5 + 62 + 256 + 6 +BYLAYER + 49 +-0.5 + 62 + 256 + 6 +BYLAYER + 0 +ACDBPLACEHOLDER + 5 +F +102 +{ACAD_REACTORS +330 +E +102 +} +330 +E + 0 +SCALE + 5 +10D +102 +{ACAD_REACTORS +330 +10C +102 +} +330 +10C +100 +AcDbScale + 70 + 0 +300 +1:1 +140 +1.0 +141 +1.0 +290 + 1 + 0 +SCALE + 5 +1BE +102 +{ACAD_REACTORS +330 +10C +102 +} +330 +10C +100 +AcDbScale + 70 + 0 +300 +1:2 +140 +1.0 +141 +2.0 +290 + 0 + 0 +SCALE + 5 +1BF +102 +{ACAD_REACTORS +330 +10C +102 +} +330 +10C +100 +AcDbScale + 70 + 0 +300 +1:4 +140 +1.0 +141 +4.0 +290 + 0 + 0 +SCALE + 5 +1C0 +102 +{ACAD_REACTORS +330 +10C +102 +} +330 +10C +100 +AcDbScale + 70 + 0 +300 +1:5 +140 +1.0 +141 +5.0 +290 + 0 + 0 +SCALE + 5 +1C1 +102 +{ACAD_REACTORS +330 +10C +102 +} +330 +10C +100 +AcDbScale + 70 + 0 +300 +1:8 +140 +1.0 +141 +8.0 +290 + 0 + 0 +SCALE + 5 +1C2 +102 +{ACAD_REACTORS +330 +10C +102 +} +330 +10C +100 +AcDbScale + 70 + 0 +300 +1:10 +140 +1.0 +141 +10.0 +290 + 0 + 0 +SCALE + 5 +1C3 +102 +{ACAD_REACTORS +330 +10C +102 +} +330 +10C +100 +AcDbScale + 70 + 0 +300 +1:16 +140 +1.0 +141 +16.0 +290 + 0 + 0 +SCALE + 5 +1C4 +102 +{ACAD_REACTORS +330 +10C +102 +} +330 +10C +100 +AcDbScale + 70 + 0 +300 +1:20 +140 +1.0 +141 +20.0 +290 + 0 + 0 +SCALE + 5 +1C5 +102 +{ACAD_REACTORS +330 +10C +102 +} +330 +10C +100 +AcDbScale + 70 + 0 +300 +1:30 +140 +1.0 +141 +30.0 +290 + 0 + 0 +SCALE + 5 +1C6 +102 +{ACAD_REACTORS +330 +10C +102 +} +330 +10C +100 +AcDbScale + 70 + 0 +300 +1:40 +140 +1.0 +141 +40.0 +290 + 0 + 0 +SCALE + 5 +1C7 +102 +{ACAD_REACTORS +330 +10C +102 +} +330 +10C +100 +AcDbScale + 70 + 0 +300 +1:50 +140 +1.0 +141 +50.0 +290 + 0 + 0 +SCALE + 5 +1C8 +102 +{ACAD_REACTORS +330 +10C +102 +} +330 +10C +100 +AcDbScale + 70 + 0 +300 +1:100 +140 +1.0 +141 +100.0 +290 + 0 + 0 +SCALE + 5 +1C9 +102 +{ACAD_REACTORS +330 +10C +102 +} +330 +10C +100 +AcDbScale + 70 + 0 +300 +2:1 +140 +2.0 +141 +1.0 +290 + 0 + 0 +SCALE + 5 +1CA +102 +{ACAD_REACTORS +330 +10C +102 +} +330 +10C +100 +AcDbScale + 70 + 0 +300 +4:1 +140 +4.0 +141 +1.0 +290 + 0 + 0 +SCALE + 5 +1CB +102 +{ACAD_REACTORS +330 +10C +102 +} +330 +10C +100 +AcDbScale + 70 + 0 +300 +8:1 +140 +8.0 +141 +1.0 +290 + 0 + 0 +SCALE + 5 +1CC +102 +{ACAD_REACTORS +330 +10C +102 +} +330 +10C +100 +AcDbScale + 70 + 0 +300 +10:1 +140 +10.0 +141 +1.0 +290 + 0 + 0 +SCALE + 5 +1CD +102 +{ACAD_REACTORS +330 +10C +102 +} +330 +10C +100 +AcDbScale + 70 + 0 +300 +100:1 +140 +100.0 +141 +1.0 +290 + 0 + 0 +ACDBSECTIONVIEWSTYLE + 5 +21A +102 +{ACAD_XDICTIONARY +360 +234 +102 +} +102 +{ACAD_REACTORS +330 +219 +102 +} +330 +219 +100 +AcDbModelDocViewStyle + 70 + 0 + 3 +Metric50 +290 + 0 +100 +AcDbSectionViewStyle + 70 + 0 + 71 + 0 + 90 + 102 + 71 + 1 +340 +11 + 62 + 256 + 40 +5.0 +340 +0 +340 +0 + 62 + 256 + 40 +5.0 +300 +I, O, Q, S, X, Z + 40 +10.0 + 90 + 0 + 40 +2.5 + 90 + 0 + 71 + 2 +340 +16 + 90 + 25 + 62 + 256 +340 +16 + 90 + 50 + 62 + 256 + 40 +5.0 + 40 +2.5 + 40 +5.0 + 71 + 3 +340 +11 + 62 + 256 + 40 +5.0 + 90 + 0 + 40 +15.0 + 90 + 1 +300 +%<\AcVar ViewSectionStartId>%-%<\AcVar ViewSectionEndId>% (%<\AcVar ViewScale \f "%sn">%) + 71 + 4 + 62 + 256 + 62 + 257 +300 +ANSI31 + 40 +1.0 + 90 + 0 +290 + 0 +290 + 0 + 90 + 6 + 40 +0.0 + 40 +1.570796326794896 + 40 +0.2617993877991494 + 40 +1.308996938995747 + 40 +-0.2617993877991494 + 40 +1.832595714594046 + 0 +TABLESTYLE + 5 +7F +102 +{ACAD_XDICTIONARY +360 +162 +102 +} +102 +{ACAD_REACTORS +330 +7E +102 +} +330 +7E +100 +AcDbTableStyle +280 + 0 + 3 +Standard + 70 + 0 + 71 + 0 + 40 +1.5 + 41 +1.5 +280 + 0 +281 + 0 + 7 +Standard +140 +4.5 +170 + 2 + 62 + 0 + 63 + 7 +283 + 0 + 90 + 512 + 91 + 0 + 1 + +274 + -2 +284 + 1 + 64 + 0 +275 + -2 +285 + 1 + 65 + 0 +276 + -2 +286 + 1 + 66 + 0 +277 + -2 +287 + 1 + 67 + 0 +278 + -2 +288 + 1 + 68 + 0 +279 + -2 +289 + 1 + 69 + 0 + 7 +Standard +140 +6.0 +170 + 5 + 62 + 0 + 63 + 7 +283 + 0 + 90 + 512 + 91 + 0 + 1 + +274 + -2 +284 + 1 + 64 + 0 +275 + -2 +285 + 1 + 65 + 0 +276 + -2 +286 + 1 + 66 + 0 +277 + -2 +287 + 1 + 67 + 0 +278 + -2 +288 + 1 + 68 + 0 +279 + -2 +289 + 1 + 69 + 0 + 7 +Standard +140 +4.5 +170 + 5 + 62 + 0 + 63 + 7 +283 + 0 + 90 + 512 + 91 + 0 + 1 + +274 + -2 +284 + 1 + 64 + 0 +275 + -2 +285 + 1 + 65 + 0 +276 + -2 +286 + 1 + 66 + 0 +277 + -2 +287 + 1 + 67 + 0 +278 + -2 +288 + 1 + 68 + 0 +279 + -2 +289 + 1 + 69 + 0 + 0 +VISUALSTYLE + 5 +F5 +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +2dWireframe + 70 + 4 +177 + 3 +291 + 0 + 70 + 58 + 90 + 0 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +F4 +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +Basic + 70 + 7 +177 + 3 +291 + 1 + 70 + 58 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 0 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +FB +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +Brighten + 70 + 12 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +50.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +FF +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +ColorChange + 70 + 16 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 8 +420 + 8421504 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 8 +420 + 8421504 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +F8 +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +Conceptual + 70 + 9 +177 + 3 +291 + 0 + 70 + 58 + 90 + 3 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +40.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +FA +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +Dim + 70 + 11 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +-50.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +1E6 +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +EdgeColorOff + 70 + 22 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 0 + 90 + 2 +176 + 0 + 90 + 0 +176 + 0 + 90 + 0 +176 + 0 + 40 +0.6 +176 + 0 + 40 +30.0 +176 + 0 + 62 + 7 +420 + 16777215 +176 + 0 + 90 + 1 +176 + 0 + 90 + 4 +176 + 0 + 62 + 7 +176 + 0 + 62 + 257 +176 + 0 + 90 + 1 +176 + 0 + 90 + 1 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 8 +176 + 2 + 62 + 7 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 1 +176 + 0 + 90 + 6 +176 + 0 + 90 + 2 +176 + 0 + 62 + 7 +176 + 0 + 90 + 5 +176 + 0 + 90 + 0 +176 + 0 + 90 + 0 +176 + 0 +290 + 0 +176 + 0 + 90 + 1 +176 + 0 + 40 +0.0 +176 + 0 + 90 + 0 +176 + 0 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +FE +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +Facepattern + 70 + 15 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +F0 +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +Flat + 70 + 0 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 13 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +F1 +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +FlatWithEdges + 70 + 1 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 13 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +F2 +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +Gouraud + 70 + 2 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 13 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +F3 +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +GouraudWithEdges + 70 + 3 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 13 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +F7 +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +Hidden + 70 + 6 +177 + 3 +291 + 0 + 70 + 58 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 40 +40.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +1E4 +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +JitterOff + 70 + 20 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 0 + 90 + 2 +176 + 0 + 90 + 0 +176 + 0 + 90 + 0 +176 + 0 + 40 +0.6 +176 + 0 + 40 +30.0 +176 + 0 + 62 + 7 +420 + 16777215 +176 + 0 + 90 + 1 +176 + 0 + 90 + 4 +176 + 0 + 62 + 7 +176 + 0 + 62 + 257 +176 + 0 + 90 + 1 +176 + 0 + 90 + 1 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 10 +176 + 2 + 62 + 7 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 1 +176 + 0 + 90 + 6 +176 + 0 + 90 + 2 +176 + 0 + 62 + 7 +176 + 0 + 90 + 5 +176 + 0 + 90 + 0 +176 + 0 + 90 + 0 +176 + 0 +290 + 0 +176 + 0 + 90 + 1 +176 + 0 + 40 +0.0 +176 + 0 + 90 + 0 +176 + 0 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +FD +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +Linepattern + 70 + 14 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 7 +176 + 1 + 90 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +1E5 +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +OverhangOff + 70 + 21 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 0 + 90 + 2 +176 + 0 + 90 + 0 +176 + 0 + 90 + 0 +176 + 0 + 40 +0.6 +176 + 0 + 40 +30.0 +176 + 0 + 62 + 7 +420 + 16777215 +176 + 0 + 90 + 1 +176 + 0 + 90 + 4 +176 + 0 + 62 + 7 +176 + 0 + 62 + 257 +176 + 0 + 90 + 1 +176 + 0 + 90 + 1 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 9 +176 + 2 + 62 + 7 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 1 +176 + 0 + 90 + 6 +176 + 0 + 90 + 2 +176 + 0 + 62 + 7 +176 + 0 + 90 + 5 +176 + 0 + 90 + 0 +176 + 0 + 90 + 0 +176 + 0 +290 + 0 +176 + 0 + 90 + 1 +176 + 0 + 40 +0.0 +176 + 0 + 90 + 0 +176 + 0 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +F9 +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +Realistic + 70 + 8 +177 + 3 +291 + 0 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 13 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +1F3 +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +Shaded + 70 + 27 +177 + 3 +291 + 0 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 0 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 8 +420 + 7895160 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 5 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +1F2 +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +Shaded with edges + 70 + 26 +177 + 3 +291 + 0 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 5 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +1EF +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +Shades of Gray + 70 + 23 +177 + 3 +291 + 0 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 62 + 7 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +40.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +1F0 +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +Sketchy + 70 + 24 +177 + 3 +291 + 0 + 70 + 58 + 90 + 1 +176 + 1 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 62 + 7 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +40.0 +176 + 1 + 90 + 11 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 6 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +FC +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +Thicken + 70 + 13 +177 + 3 +291 + 1 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 12 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 5 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +F6 +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +Wireframe + 70 + 5 +177 + 3 +291 + 0 + 70 + 58 + 90 + 0 +176 + 1 + 90 + 2 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 + 40 +0.6 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 4 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 257 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +VISUALSTYLE + 5 +1F1 +102 +{ACAD_REACTORS +330 +EF +102 +} +330 +EF +100 +AcDbVisualStyle + 2 +X-Ray + 70 + 25 +177 + 3 +291 + 0 + 70 + 58 + 90 + 2 +176 + 1 + 90 + 2 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +0.5 +176 + 1 + 40 +30.0 +176 + 1 + 62 + 7 +420 + 16777215 +176 + 1 + 90 + 1 +176 + 1 + 90 + 0 +176 + 1 + 62 + 7 +176 + 1 + 62 + 257 +176 + 1 + 90 + 1 +176 + 1 + 90 + 1 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 8 +176 + 1 + 62 + 7 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 1 +176 + 1 + 90 + 6 +176 + 1 + 90 + 2 +176 + 1 + 62 + 7 +176 + 1 + 90 + 3 +176 + 1 + 90 + 0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 13 +176 + 1 + 40 +0.0 +176 + 1 + 90 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 1 +176 + 1 +290 + 1 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 40 +0.0 +176 + 1 + 40 +1.0 +176 + 1 + 90 + 0 +176 + 1 + 62 + 18 +420 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 3 +176 + 1 + 62 + 5 +420 + 255 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 + 90 + 50 +176 + 1 +290 + 0 +176 + 1 + 90 + 50 +176 + 1 + 62 + 256 +176 + 0 + 40 +1.0 +176 + 0 + 90 + 2 +176 + 1 + 1 +strokes_ogs.tif +176 + 1 +290 + 0 +176 + 1 + 40 +1.0 +176 + 1 + 40 +1.0 +176 + 1 + 0 +DICTIONARYVAR + 5 +146 +102 +{ACAD_REACTORS +330 +5E +102 +} +330 +5E +100 +DictionaryVariables +280 + 0 + 1 +1:1 + 0 +DICTIONARYVAR + 5 +259 +102 +{ACAD_REACTORS +330 +5E +102 +} +330 +5E +100 +DictionaryVariables +280 + 0 + 1 +3.500000 + 0 +DICTIONARYVAR + 5 +25A +102 +{ACAD_REACTORS +330 +5E +102 +} +330 +5E +100 +DictionaryVariables +280 + 0 + 1 +acadiso.lin + 0 +DICTIONARYVAR + 5 +145 +102 +{ACAD_REACTORS +330 +5E +102 +} +330 +5E +100 +DictionaryVariables +280 + 0 + 1 +STANDARD + 0 +DICTIONARYVAR + 5 +84 +102 +{ACAD_REACTORS +330 +5E +102 +} +330 +5E +100 +DictionaryVariables +280 + 0 + 1 +STANDARD + 0 +DICTIONARYVAR + 5 +227 +102 +{ACAD_REACTORS +330 +5E +102 +} +330 +5E +100 +DictionaryVariables +280 + 0 + 1 +Metric50 + 0 +DICTIONARYVAR + 5 +228 +102 +{ACAD_REACTORS +330 +5E +102 +} +330 +5E +100 +DictionaryVariables +280 + 0 + 1 +Metric50 + 0 +DICTIONARYVAR + 5 +5F +102 +{ACAD_REACTORS +330 +5E +102 +} +330 +5E +100 +DictionaryVariables +280 + 0 + 1 +2 + 0 +DICTIONARYVAR + 5 +63 +102 +{ACAD_REACTORS +330 +5E +102 +} +330 +5E +100 +DictionaryVariables +280 + 0 + 1 +1 + 0 +DICTIONARYVAR + 5 +1AE +102 +{ACAD_REACTORS +330 +5E +102 +} +330 +5E +100 +DictionaryVariables +280 + 0 + 1 +0 + 0 +DICTIONARYVAR + 5 +1AF +102 +{ACAD_REACTORS +330 +5E +102 +} +330 +5E +100 +DictionaryVariables +280 + 0 + 1 +0 + 0 +DICTIONARY + 5 +236 +330 +21C +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +ACAD_XREC_ROUNDTRIP +360 +27C + 0 +DICTIONARY + 5 +205 +330 +22 +100 +AcDbDictionary +280 + 1 +281 + 1 + 0 +DICTIONARY + 5 +1F9 +330 +ED +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +FBXASSET +360 +1FA + 0 +DICTIONARY + 5 +1F7 +330 +EC +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +FBXASSET +360 +1F8 + 0 +DICTIONARY + 5 +173 +330 +EE +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +BUMPTILE +360 +175 + 3 +DIFFUSETILE +360 +174 + 3 +FBXASSET +360 +1FB + 3 +OPACITYTILE +360 +176 + 3 +REFLECTIONTILE +360 +177 + 0 +DICTIONARY + 5 +234 +330 +21A +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +ACAD_XREC_ROUNDTRIP +360 +27B + 0 +DICTIONARY + 5 +162 +330 +7F +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +ACAD_ROUNDTRIP_2008_TABLESTYLE_CELLSTYLEMAP +360 +27A + 0 +XRECORD + 5 +27C +102 +{ACAD_REACTORS +330 +236 +102 +} +330 +236 +100 +AcDbXrecord +280 + 1 +102 +DISPLAYNAME + 1 +Metric50 +102 +FLAGS + 90 + 0 + 0 +XRECORD + 5 +1FA +102 +{ACAD_REACTORS +330 +1F9 +102 +} +330 +1F9 +100 +AcDbXrecord +280 + 1 + 70 + 1 + 90 +429727718 + 1 +D62C5603-E3A1-4AEA-B7FB-FE5D8D0755AF +310 +504B03040A0000080000CC70623B3DEE336E79000000790000001B0000006175746F6465736B2D64657369676E2D7061636B6167652E786D6C3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D227574662D3822203F3E3C666F726D6174733E3C666F726D61743E687474703A2F2F736368656D612E +310 +6175746F6465736B2E636F6D2F64657369676E2D7061636B6167652F323030393C2F666F726D61743E3C2F666F726D6174733E504B0304140006080800CC70623BD486FD9CA0000000F4000000130000005B436F6E74656E745F54797065735D2E786D6C7D8EC10E82300C865F65E91D8A1E8C310C0EEA1BF002731658846E +310 +D98AC1B77784ABF1D8FE5FBFBF75BBCE937A534CCEB38643598122B6FEE978D0B0485F9C41B54DDD7D022595594E1A469170414C76A4D9A4D207E29CF43ECE46F218070CC6BECC4078ACAA135ACF422C856C0E68EA1BF5669944DDD7BCDE7B1F8E415D77AECB980613C2E4AC91FC167A2B244592486606FC29C8FD7F045B9A +310 +EF7053A7E60B504B0304140006080800CC70623B853B8169EB0000007C01000008000000636F72652E786D6C8D90416EC3201045AF62CDB6C206821CC7C244919D9CA01740401C94182C03558F5F9C3852BBEB6A467FFE9B197D7EFC9E1EC5975982F5AE035262288C535E5B377690E21535501C055FBC8FBF6C503839990E +310 +5619041F179FE64D52DE45E362569DD7661365082642A11EB9E920A89B99642953CC8E702F67A9EE7234257977194EC9EAE275C4EABCCF5EAD5940D4AC6F0E35A568B8F43562CD7046CD199FD07E60174276A7BE677B5EADB0E0D14EEFFB6A31321A0D82627C4084204C3F096B71DD52F6819B16635EADF63F509AF53FA164 +310 +5DDCD1EDDD17164090FCC8732078B56691CB33A85CD7DCC40F504B0304140006080800CC70623B55019EA25F0000007C00000007000000636E782E786D6C4DCB3B0E80201045D1AD90E915ED2CF8AC45050C11660C8261F98AB1B07AC9C97D42D718D865D3E909258CFD00CCE24AC6E326A164D74DC0B4128928FF32603847 +310 +2BA13128B1252AC747C6BAB984FC68F0B87FE8960A5C09FE86CFB69FBA01504B0304140006080800CC70623BDBABAAF470010000D40300000C0000006662782F636F72652E786D6CC553D16E823014FD95A6AF4B694182CC941A83FA05FB810A9511A125A5257EFE2E82712ECEB8A7F100CD39F7F69E734AF9FADC366850B6 +310 +AF8DCE7018308C942E4C59EB2AC3DE1D498AD15A706B8CFB56869196ADCAF00863C12B6B7C374385D14E6907A836A59A41D9F7CA615434B0C8705F7CAA5606D23BA8E84F41278B93AC54100640439DE0BDB320004D43C63716C7C399D30917DCFBBA9CD9BA8469F5B156168B24CED3F7248AC8769F27244EB73B92EED8862C +310 +B7F13E0C179B3C8F979C8ECD82BBBABDAA2BAC924E9558448CBD9330242CFA08E3154B5651FCC6D215639C8EE5774DBE2B5F6CF2B5768B68963BB5F5588420E442FC700B1139D4CB01F450C1E918227C2E09DF070D8140C84E1E9AAB8F1340832A9CB13130A5F1376A908D57309505ECF2A0DF179C4E9D30F5B239B87E3823 +310 +7A79C6F31DE1A8A5AEC08474B03C7837EAE4938639B44E5932B833D2C6B6B279CDC613877FA26EE21F4A2A4C63EC7F29A2F301D1F9F7A0E37D145F504B0304140006080800CC70623B9C113CC27E0000009D0000000B0000006662782F636E782E786D6C4DCCDF0A83201C86E15B91DFB94BFB330DD428C8FB886521330DA7 +310 +6397BF1A1DECE883878F57749FCDA1B7892F1BBC047A23808C7F84D9FA55424E0BE6803A256208E9EF06C84F9B91703228B1C690F78B66B34CD9A5439DF5CF0BFBF65E35BCA1B8D6A5C6F540381E886698B5741C695F9503EBA150A2F8958E3DC3EA0B504B0304140006080800CC70623B7DF2F77C2A010000120200003100 +310 +00006662782F41393633353835312D344632462D344230382D423046372D3739314545314133324237412F636F72652E786D6C8D51DB8EC22014FC15C2939B0D2DB4B45643319AE817EC0F6041255A68B86CFCFC856D4D76DF7CE190393373060EDB3DC707F856CE6B6B7A480A0C81328395DA5C7B18C3057510EC3873D686 +310 +3F34088C18550F330C39BB3A1BA7051AAC09CA84841A2BD5020AEF55806078A44B0FFD7053A328440C89E1EFC52486BBB8AA8214A99D789CF9E05200300FC927E4FB4D5B375D43103D5527440FB843077C5AA3F5861C8F645F5787F59E95B390B318B55CE45AA638FAA2957BD7248B390B7A7CC51F9C124149C82B8C378810 +310 +84AB2F42B7B8DD56F413775B8C5999E9FF4471926F8AA236A1AE96B8B3CC434E5839373893369E1FAF30EA395917409EB7F26AF8801C171837A4A6AC9C89E9F9C9B1A58BA30FD6A5EF5DDDCF894B9AD9B6A59C957943A9FCAE2FD5BC4DFE03504B0304140006080800CC70623BAD7543B64E01000033030000300000006662 +310 +782F41393633353835312D344632462D344230382D423046372D3739314545314133324237412F636E782E786D6CD593CD6EC32010845F0571AD6CE3D48AD20813A9873E410FBD12D82434182C7EAAE6EDBB2424CD25871E7B41D6EC30B3FA84F9E67BB2E40B4234DE8DB46F1925E094D7C6ED479AD3AE5951B2113C789FEE +310 +6C943839C1488B4C05DF079FE72A69D8C96C13AAD6B8631503449F83828872B949AC57D26200B826A308D316B4064D6E46FCDA41C05550DC9E483A00797BFD207EFB092A45DE9514C1BBD22178396BD39D891265658C238DEA00936C654E5E433CB65A26D9F6EDB5EBC14EBF49A45CB856E66048291F6939A9A81BB5C89177 +310 +38143CA680F4AA299D66A042CEB3354A2684DC9D8D178FE0D9B8B41CAAD720F880EE7EF93C0C18769E099ECC04D5A102C8049A8A05632F4DDF376CF1DE0F6BB65C2F8627B65A33C6BB62177CEBBDAD973006829F89F22E814B54F4BC2BE347F8AA8F681390B50FA73F804400B5F542E796F19FF974E7F78DB802FE05E20750 +310 +4B0304140006080800CC70623BE75B7789680500003C100000340000006662782F41393633353835312D344632462D344230382D423046372D3739314545314133324237412F6F626A656374732E786D6CAD575B8F9B3818FD2B887D06C22499CB8AA1CA655245D5B455A356FB305264C061D8018C6C3393D95FBFC7600890 +310 +A4CD5EF210B0B1BFEBF98E3F7B1FF6596ABC522E1296DF9BAE3D320D9A872C4AF2F8DE2CE5CEBA358D0FBEC719939D65A691938CDE9B6ADAF4BD98B3B2D05311DD91329583D9D5FC0F438434A7A611A644887B5384CF34233629258BA878B12322891DEFF6B66BD70BFB62634E8AE781D082709A4B588AF91C528CDA28B73F +310 +1C998EEF39EABBEFA97FBD6A7C7E9553F9D3D79FE442923C3C523610337627CB87ABE99D359D4CC6D6E4FACAB5E6ABF9D2726FC6A3C5F56271377BB88362213924694B38DD99FE47C48627A1E7D49F5A8BB5E1A74C0A599ED3B0F21F1E56366B89112D681E218F0915D0D6F17AD41FBA2A369DCF6335D62ABBD39779D5DDD1 +310 +11D4D8DE3CBB96B2E04FB8202E41051754A1AA8E8F76B4C6DFE810B580B1547F4B84911149794252234D024EF8BBE963A95AE27B3D310A9D5C215C7960FAEE415ED75694C6AFB17BCACA5D99A60A9AA65F217B0BFC53292ACB92BF283FAD0D3621576592CB5BED907C2FA8E9DF794E35E97BEA31BED21FEB401ABB94C44839 +310 +DCACBF0E1C5DA8DA5B2F4DFFD32AD86F543D9E565E7056502E157C00AD2671CD534549AB752FCA9CDA00677A313F04E51B22FF19E57B300579E3C97EB29F682D92935CEC18CF901B7B54FD8C51F362B56FC72FE0B3C1EAE335EDCCBF5AEC39ADB17DC238973F804BA5E6F6BFE7AF1FB32E523BE9F3BD571418E3631DCA4D48 +310 +5250CF639223210A9446CA30052EDF057BD35F8329C1ECD84552BF0DC8D18BE7BCE23BFE6BD960AB4A7DE79923A103BEBD80F911CBAA2C60DB19B01CF164A5583B772EE6D3FFA56666CBCDA74DC97724A48F9A58967497E489C4D979006FD7A05E227A1EBDD0F737C623387A9C844D3709995625106D157315F8B8392CD4E0 +310 +A0B9A720C4BE9829CEF37EA1E13111214D53925356365ADA634861B52519DD27A00AEB808EAF0628E6F435519D446F45CF2C9CF5214F0A15B2F6D06B79DA3EE3CBF7F56780D2F4E7EF73A0F5E5B02A38D07DC852C6B7C1FBB6664213E0C39E3EBA7FF4E1AD23EA2829407C85E586727488B751B2DB9502BC7B228A3FD68B6E +310 +A65A22397E690AA8D158D7E404EC8CDA235CC3B7D1898680131CEC2CDF2638C65196279577750F15884AEE19F94199155B92B13297978469D4F8D358DF0AEF7631E28DC8F0D9F437D5D39A83B2231A1D52D543813A824EF8D44BCFF2FA6A31BD1E8DAD87F1CCB526B3879935BF59CDADD5C37479BB1CDD4CA7B3556B516589 +310 +EF352754B706114D9C885EC9131DE6EFEB43D99AFE2391C2F958179413D7CFEF6B1B6DB1E7600F00DE6E5C67454A339A4BA2E0FBA85ED26F045D454F463DBFCE484C2F90F2E5E3666003662ED8F755951A7D1BECD5B30B550B2785C8E7320B7292A4838DDA71BBC863ED7613CAF659337A3354231D4FF4A182A54904C2898C +310 +98B28C4AD0CE056CCF332A80986E571EE9DBC305BB5FEB7E509220A58D25CF042D712A806AC0AD0C657FDEF80D2D9CEAA2EE4D1C76F60BFE74219A06527D6F82DF6412526107381E55E353090704D085B52408A8913C4ED159D79BDA71BB4BC506F4831350EB6F975CD22D69BF7AC49B91A2C0A9DDA3D5CA36AD20FC478E37 +310 +E61844E2352865EBCB61A275A65283CAAA9DD27703B4102F5AF51EF5F573B75CBB5AD38BC845F7A49F82A0966A49C2E3EA5EA0ECD326CD965F1DB402C6FA8B51A4658C5C5E2EC9E214602E55810345408596591009A82E7E7FFACA19EEA299B14A0081A705CB3296EBC14CDF658DCD336EA6D1136881AAEB87B81AB9EE53D5 +310 +F5EB8BC8362082DA24122F98680A4E7930C01A0079749CEA14382A0783E5EBA5A10F8C098456A03D6A4AEB6BB881E2513747552A5DB22C7EDAF83BD5528081A365F7FF06504B0304140006080000CC70623B000000000000000000000000350000006662782F41393633353835312D344632462D344230382D423046372D37 +310 +39314545314133324237412F76657274696365732E62696E504B0304140006080800CC70623BF270F1330600000004000000360000006662782F41393633353835312D344632462D344230382D423046372D3739314545314133324237412F747269616E676C65732E62696E636660600000504B0304140006080000CC7062 +310 +3B000000000000000000000000370000006662782F41393633353835312D344632462D344230382D423046372D3739314545314133324237412F617474726962757465732E62696E504B0304140006080800CC70623B08DA0BD19000000041010000360000006662782F41393633353835312D344632462D344230382D4230 +310 +46372D3739314545314133324237412F6469726563746F72792E786D6C858F410AC3201045AF22B36F53E9A60B35CBEEBAE80D244E44489C6234F4F835464A48035D0DF398FF9F8AF63D0E6CC63039F212F8F9020C7D47C6792B21C5FE7403D62A1188E2E60C98D7234A5830286103A55745067B9D86B8A3CF9C7F90C11DE6 +310 +07FB144396D7B6A82D282E9A152AD114D5EF2CB866EEE831B8EEA07A7BB5A8D7D61A2BAAEB7FD5F70921FF497D00504B0304140006080800CC70623BEDD1DC58FD000000A00100003B0000006662782F41393633353835312D344632462D344230382D423046372D3739314545314133324237412F7265736F75726365732F +310 +636F72652E786D6C8D504B6E833010BD0A9A6D65B00922041947112427E8052C33A156828DFCA97AFC9A40A576D7CDCCE87D344F8F9FBFE667F689CE6B6B3A6039850C8DB2A336530731DC4903D95970676DF82583CCC8193B5861107C72362E3BA4AC096842428D1D7107A5F7182053CF7474E0D507CE32973124857FE48B +310 +540F3961CEF244279DE03EB81420DB9EAC1384436FA353E879B1B182C7A8C75DA3C7F453DF353A1075D537A7BA6464B8F535A99AE14A9A2BBD90E350DD183B5CFABE3AF262350B1EF4FC9351399401471025A527C218A1E53BAB5A5AB765F5469B96525EACF23FA6B88CFF34456DC2A1DCE36E360F82A5202F42F062ED2BAD +310 +579969AFDD8A6F504B010214000A0000080000CC70623B3DEE336E79000000790000001B00000000000000000000000000000000006175746F6465736B2D64657369676E2D7061636B6167652E786D6C504B01021400140006080800CC70623BD486FD9CA0000000F40000001300000000000000000000000000B20000005B +310 +436F6E74656E745F54797065735D2E786D6C504B01021400140006080800CC70623B853B8169EB0000007C010000080000000000000000000000000083010000636F72652E786D6C504B01021400140006080800CC70623B55019EA25F0000007C000000070000000000000000000000000094020000636E782E786D6C504B +310 +01021400140006080800CC70623BDBABAAF470010000D40300000C00000000000000000000000000180300006662782F636F72652E786D6C504B01021400140006080800CC70623B9C113CC27E0000009D0000000B00000000000000000000000000B20400006662782F636E782E786D6C504B01021400140006080800CC70 +310 +623B7DF2F77C2A010000120200003100000000000000000000000000590500006662782F41393633353835312D344632462D344230382D423046372D3739314545314133324237412F636F72652E786D6C504B01021400140006080800CC70623BAD7543B64E010000330300003000000000000000000000000000D2060000 +310 +6662782F41393633353835312D344632462D344230382D423046372D3739314545314133324237412F636E782E786D6C504B01021400140006080800CC70623BE75B7789680500003C10000034000000000000000000000000006E0800006662782F41393633353835312D344632462D344230382D423046372D3739314545 +310 +314133324237412F6F626A656374732E786D6C504B01021400140006080000CC70623B0000000000000000000000003500000000000000000000000000280E00006662782F41393633353835312D344632462D344230382D423046372D3739314545314133324237412F76657274696365732E62696E504B01021400140006 +310 +080800CC70623BF270F133060000000400000036000000000000000000000000007B0E00006662782F41393633353835312D344632462D344230382D423046372D3739314545314133324237412F747269616E676C65732E62696E504B01021400140006080000CC70623B0000000000000000000000003700000000000000 +310 +000000000000D50E00006662782F41393633353835312D344632462D344230382D423046372D3739314545314133324237412F617474726962757465732E62696E504B01021400140006080800CC70623B08DA0BD1900000004101000036000000000000000000000000002A0F00006662782F41393633353835312D344632 +310 +462D344230382D423046372D3739314545314133324237412F6469726563746F72792E786D6C504B01021400140006080800CC70623BEDD1DC58FD000000A00100003B000000000000000000000000000E1000006662782F41393633353835312D344632462D344230382D423046372D3739314545314133324237412F7265 +310 +736F75726365732F636F72652E786D6C504B0506000000000E000E0080040000641100000000 + 0 +XRECORD + 5 +1F8 +102 +{ACAD_REACTORS +330 +1F7 +102 +} +330 +1F7 +100 +AcDbXrecord +280 + 1 + 70 + 1 + 90 +429727718 + 1 +30362254-06B7-45E0-A893-8CFA70E3D6BC +310 +504B03040A0000080000CC70623B3DEE336E79000000790000001B0000006175746F6465736B2D64657369676E2D7061636B6167652E786D6C3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D227574662D3822203F3E3C666F726D6174733E3C666F726D61743E687474703A2F2F736368656D612E +310 +6175746F6465736B2E636F6D2F64657369676E2D7061636B6167652F323030393C2F666F726D61743E3C2F666F726D6174733E504B0304140006080800CC70623BD486FD9CA0000000F4000000130000005B436F6E74656E745F54797065735D2E786D6C7D8EC10E82300C865F65E91D8A1E8C310C0EEA1BF002731658846E +310 +D98AC1B77784ABF1D8FE5FBFBF75BBCE937A534CCEB38643598122B6FEE978D0B0485F9C41B54DDD7D022595594E1A469170414C76A4D9A4D207E29CF43ECE46F218070CC6BECC4078ACAA135ACF422C856C0E68EA1BF5669944DDD7BCDE7B1F8E415D77AECB980613C2E4AC91FC167A2B244592486606FC29C8FD7F045B9A +310 +EF7053A7E60B504B0304140006080800CC70623B1EC5D7A3EB0000007C01000008000000636F72652E786D6C8D90416EC3201045AF82665B6103C6756C6122AB4D4ED00B204C5C94182C03558F5F9C3852BBEB6A467FFE9B197D71FC9E6FE8CBACC17AD7032D0820E3B41FAD9B7A48F1820F808E52ACDEC75F36404ECDA687 +310 +4D0629A6D5A76597B477D1B89855E747B38B2A041301E95B6E7A08FAD3CCAA50296647B8168BD2573599823EBB0CA76447F43862C7BCCF5EAC59410E4DDD9C7973C2755553CCCFA4C603E3040F1565ED3B1FDE4E432BCA0D9622DAF9795FAF464533826484B498524CD807E51D79ED187F21878E10516EF63F505AC67F42C9 +310 +BA58B1FDDD071640D2FCC87D2045B96591CB3DA85CB7DCE40F504B0304140006080800CC70623B55019EA25F0000007C00000007000000636E782E786D6C4DCB3B0E80201045D1AD90E915ED2CF8AC45050C11660C8261F98AB1B07AC9C97D42D718D865D3E909258CFD00CCE24AC6E326A164D74DC0B4128928FF32603847 +310 +2BA13128B1252AC747C6BAB984FC68F0B87FE8960A5C09FE86CFB69FBA01504B0304140006080800CC70623B8C9102E971010000D40300000C0000006662782F636F72652E786D6CC5535B6E833010BC8AE5DF0A6C08340F1947A84D4ED00B38C6A128602363A31CBFCB234A53A551FA553EC09AD9F5CE8C31DB9E9B1AF5CA +310 +7695D1198E428A91D2D214952E33ECDD315861B4E5CC1AE3BE9561A445A3323CC098B3D21ADFCE9034DA29ED00D5A6503328BA4E398C640D8B0C77F253352214DE4145770A5B214FA2546114020D759C75CE8200340D19DE981F0F6746269C33EFAB6266AB02A655C74A59CCF365BADC27CB5D902ED22848F6340DF238A141 +310 +BE88E2F57B92BFEDF23523433367AE6A2EEAA455C2A902F398D2751045018D3FA264435F3771F242571B4A1919CA6F9A7C5B3CD9E42BED16F12C776AEB308F40C848FC700B1139D4891EF410CEC810227CC6846F8386402064270EF5C5C709A05E49676C024C61FC95EA45ED154CA5211D1FF4FB8291A913A68E9B83EBBB33 +310 +E2A7673CDE118E5AE8124C0807CB8377834E366998436B950D7A7746DAD846D4CFD978E0F04FD455FC5D49D2D4C6FE9722321F10997F0F32DC47FE05504B0304140006080800CC70623BFFEA85907E0000009D0000000B0000006662782F636E782E786D6C4DCCD10A83201886E15B91FFDC95D95A811AB6F23E625948A6C3 +310 +E9D8E5AF46073BFAE0E1E365ED67B3E8ADC3CB78C7815C7240DA3DFC64DCC221C519D7805AC182F7F1EF06C88D9BE6703008B6049F9E274D7A1E938DBB5AE3D6131B2589BA0D3D965551E0B2EA732C9B9A624AAEB41E3A557677029960D9AFB4EF11165F504B0304140006080800CC70623B4FEEA4082C0100001202000031 +310 +0000006662782F39464131463745442D413632322D343644302D413938332D3331353338454246344243312F636F72652E786D6C8D515B6EC32010BC0AE2AB55850DD871ED0813254D72825EC00192A2C460F1A872FC42ED48ED5F7E00CDCECCCEB26C731F6FE05B39AFADE921293004CA082BB5B9F43086336A21D870E6AC +310 +0D7F68109861543DCC30E4ECE26C9C164858139409093556AA051CBC570102714B8F1E7AF1A5C6A11862480C7F2DA6415C878B2A4891CA89C7990F2E050073937C42DE1DB7E4F87ED8A36D4329AA9B3D46DBAEAD504556557BD81DEBDD0761E52CE42C462D17B996298E3E6BE59E35C962CE821E1FF18553435012728A7187 +310 +0841987E927A8D9B35ADDF70BBC6989599FE4F1427F9A4286A132ABAC49D651EF234CD5CE04CDA78BA3DC2A8FB645D00B9DF8B57E215725C60BCA2A463E54C4CE327C7A65E1C7DB02E7DEFCBF594B864C5CA6CDBD49C957943E9FA5D5FBAF336F90F504B0304140006080800CC70623BAD7543B64E01000033030000300000 +310 +006662782F39464131463745442D413632322D343644302D413938332D3331353338454246344243312F636E782E786D6CD593CD6EC32010845F0571AD6CE3D48AD20813A9873E410FBD12D82434182C7EAAE6EDBB2424CD25871E7B41D6EC30B3FA84F9E67BB2E40B4234DE8DB46F1925E094D7C6ED479AD3AE5951B2113C +310 +789FEE6C943839C1488B4C05DF079FE72A69D8C96C13AAD6B8631503449F83828872B949AC57D26200B826A308D316B4064D6E46FCDA41C05550DC9E483A00797BFD207EFB092A45DE9514C1BBD22178396BD39D891265658C238DEA00936C654E5E433CB65A26D9F6EDB5EBC14EBF49A45CB856E66048291F6939A9A81BB5 +310 +C8917738143CA680F4AA299D66A042CEB3354A2684DC9D8D178FE0D9B8B41CAAD720F880EE7EF93C0C18769E099ECC04D5A102C8049A8A05632F4DDF376CF1DE0F6BB65C2F8627B65A33C6BB62177CEBBDAD973006829F89F22E814B54F4BC2BE347F8AA8F681390B50FA73F804400B5F542E796F19FF974E7F78DB802FE05 +310 +E207504B0304140006080800CC70623B16AB87BA640500003C100000340000006662782F39464131463745442D413632322D343644302D413938332D3331353338454246344243312F6F626A656374732E786D6CAD575B6FA33818FD2B887DE6924B3BED8A326A92B68A663B534DD4D13E548A0C38942D60649B369D5FBFC7 +310 +600890A493BDE42160637FD7F31D7FF63E6FB3D478A55C242CBF3247B66B1A340F5994E4F19559CA8D75611A9F7D8F33263BCB4C232719BD32D5B4E97B316765A1A722BA21652A07B3B7B33F0D11D29C9A46981221AE4C113ED38CD8A4942CA2E2C58E882476BCD9DA23BB5ED8171B73523C0F841684D35CC252CCE79062D4 +310 +468DFA43D7747CCF51DF7D4FFDEB5593E3AB9CCA9FBEFE241792E4E19EB28198C968BAB8199F5D5A67D3E9C49A9E8F47D6EC76B6B0469F26EEFC7C3EBFBCBEB98462213924694B38DD98FE1D62C393D073EA4FADC5DAF04326852CCF6958F90F0F2B9BB5C48816348F90C7840A68EB78EDF68723159BCEE7891A6B95DDE9D3 +310 +BCEAEEE8086A6C6F9E5D4B59F0175C10A7A0820BAA5055C7473B5AE3CFDD452D602CD5DF12616444529E90D448938013FE6EFA58AA96F85E4F8C42275708571E98FE6827AF6B2B4AE3D7D83D64E5A64C53054DD3AF90BD06FEA9149565C94FCA0F6B834DC85599E4F2423B24DF0B6AFA979E534DFA9E7A4CC6FA631D486393 +310 +921829879BF5D781A373557BCB85E97FB90DB62B558F8795179C15944B051F40AB495CF35451D26A4727654E6D8033BD98EF82F21D91FF8AF2DD9982BCF1643BDD4EB516C9492E368C67C88DED563FC36D5EACF66DFF057C3658BDBFA69DF9578B3DA735B64F18C7F20770A9D45CFCF7FCF563D6456A277DBEF78A02637CA2 +310 +43B90A490AEAB94F72244481D24819A6C0E59B606BFA4B3025981DBB48EAB701D97BF19C577CC77F2D1B6C55A9EF3C732474C0B727303F625995056C3B02963D9EAC146BE78EC5FCEC7FA999EBC5EACBAAE41B12D27B4D2C0BBA49F244E2ECDC81B76B502F113D8F5EE8FB1BE3111CDD4FC2AA9B844CAB1288B68AB90A7CDC +310 +1C166AB0D3DC5310625FCC14E779BFD0709F8890A629C9292B1B2DED31A4B0DA928CEE135085754027E3018A397D4D5427D15BD1330B677DC8934285AC3DF45A9EB68FF8F2B8FC0A509AFEECFD0FF2DE25CC6047F7214B195F07EFEB9A094D800F7BFAE8FED187B78EA8A3A400F115961BCAD1215E47C966530AF0EE8128FE +310 +58CEBB996A8964FFA529A046635D9353B0336A8F700DDF46271A024E70B0B37C9DE01847591E54DED53D54202AB947E4076556AC49C6CA5C9E1226B7F1A7B1BE15DEED62C41B91E1B3E9AFAAA735036547343A925075041DF0A9979E893B391F8FCFA6967B3EFB644DCF6E5CEBFAE272625DCC6FAF3FB93793C5F90CE1EF57 +310 +407342756B10D1C489E8953CD1617E5CEECAD6F4EF8914CE5D5D504E5C3F1F9736DA62CFC11E00BCDDB8CC8A9466349744C1F75EBDA4DF09BA8A9E8C7A7E9991989E20E5DBDD6A6003664ED8F7A04A8DBE0DF6EAD9B9AA858342E47399053949D2C146EDB85DE4B176BB0965FBAC19BD19AA918E27FA50C1D22402E144464C +310 +59462568E704B6E71915404CB72B8FF4EDE184DDAF753F284990D2C6926782963815403548A70C657FDEF80D2D9CEAA2AE4C1C76F60BFE74219A06527D6582DF6412526107381E55E353090704D085B52408D0933C4ED159D79BDA71BB4BC506F4831350EB6F979CD22D69BF7AC49B91A2C0A9DDA3D5CA36AD20FC478E37E6 +310 +1844E2352865EBCB6EA275A652E3836BE04EFB400BF1A2556F515F1FBB35B2AB35BD889C744FFA1004B5544B121E57F70215746DD2F5E2C1412B602CBF19455AC6C8E5E9922C4E01E65215385004546899059180EAFCF7A707CE7017CD8CDB0410789AB32C63B91E5CEBBBACB17AC6CD347A022D5075FD106377347AAABA7E +310 +7D11590744509B44E205134DC1290F06580320F78E537D3D73540E06CB970B431F185308AD40BBD794D6D77003C5A36E8EAA54BA64597CD8F83BD552A080A365F7FF06504B0304140006080000CC70623B000000000000000000000000350000006662782F39464131463745442D413632322D343644302D413938332D3331 +310 +353338454246344243312F76657274696365732E62696E504B0304140006080800CC70623BF270F1330600000004000000360000006662782F39464131463745442D413632322D343644302D413938332D3331353338454246344243312F747269616E676C65732E62696E636660600000504B0304140006080000CC70623B +310 +000000000000000000000000370000006662782F39464131463745442D413632322D343644302D413938332D3331353338454246344243312F617474726962757465732E62696E504B0304140006080800CC70623B08DA0BD19000000041010000360000006662782F39464131463745442D413632322D343644302D413938 +310 +332D3331353338454246344243312F6469726563746F72792E786D6C858F410AC3201045AF22B36F53E9A60B35CBEEBAE80D244E44489C6234F4F835464A48035D0DF398FF9F8AF63D0E6CC63039F212F8F9020C7D47C6792B21C5FE7403D62A1188E2E60C98D7234A5830286103A55745067B9D86B8A3CF9C7F90C11DE607 +310 +FB144396D7B6A82D282E9A152AD114D5EF2CB866EEE831B8EEA07A7BB5A8D7D61A2BAAEB7FD5F70921FF497D00504B0304140006080800CC70623B0D6EF93BFE000000A00100003B0000006662782F39464131463745442D413632322D343644302D413938332D3331353338454246344243312F7265736F75726365732F63 +310 +6F72652E786D6C8D50596E833010BD0A9ADFCA60B334011947A8694ED00B586642AC041B79A97AFC9A40A5F6AF3F33A3B7689E1E3F7DCD8FEC139DD7D6F4C0720A191A65476DA61E62B892236427C19DB5E1970C322367EC618541F0C9D9B8EC90B226A009093576C41D94DE63804C3DD2D18357379C652E63480A7FCF17A9 +310 +EE72C29CE5894E3AC17D702940B63D59270887DE46A7D0F36263058F518FBB468FE9A7BE6A7420864373B8D4873369AA8691FA421B3294352543C5CAF65C0F6FEF43CB8BD52C78D0F34F46E550061C419494B6843142CB0F5677F4B52BEB177AEC28E5C52AFF638ACBF84F53D42654E51E77B379102C05791282176B5F693D +310 +CB4C7BED567C03504B010214000A0000080000CC70623B3DEE336E79000000790000001B00000000000000000000000000000000006175746F6465736B2D64657369676E2D7061636B6167652E786D6C504B01021400140006080800CC70623BD486FD9CA0000000F40000001300000000000000000000000000B20000005B +310 +436F6E74656E745F54797065735D2E786D6C504B01021400140006080800CC70623B1EC5D7A3EB0000007C010000080000000000000000000000000083010000636F72652E786D6C504B01021400140006080800CC70623B55019EA25F0000007C000000070000000000000000000000000094020000636E782E786D6C504B +310 +01021400140006080800CC70623B8C9102E971010000D40300000C00000000000000000000000000180300006662782F636F72652E786D6C504B01021400140006080800CC70623BFFEA85907E0000009D0000000B00000000000000000000000000B30400006662782F636E782E786D6C504B01021400140006080800CC70 +310 +623B4FEEA4082C0100001202000031000000000000000000000000005A0500006662782F39464131463745442D413632322D343644302D413938332D3331353338454246344243312F636F72652E786D6C504B01021400140006080800CC70623BAD7543B64E010000330300003000000000000000000000000000D5060000 +310 +6662782F39464131463745442D413632322D343644302D413938332D3331353338454246344243312F636E782E786D6C504B01021400140006080800CC70623B16AB87BA640500003C1000003400000000000000000000000000710800006662782F39464131463745442D413632322D343644302D413938332D3331353338 +310 +454246344243312F6F626A656374732E786D6C504B01021400140006080000CC70623B0000000000000000000000003500000000000000000000000000270E00006662782F39464131463745442D413632322D343644302D413938332D3331353338454246344243312F76657274696365732E62696E504B01021400140006 +310 +080800CC70623BF270F133060000000400000036000000000000000000000000007A0E00006662782F39464131463745442D413632322D343644302D413938332D3331353338454246344243312F747269616E676C65732E62696E504B01021400140006080000CC70623B0000000000000000000000003700000000000000 +310 +000000000000D40E00006662782F39464131463745442D413632322D343644302D413938332D3331353338454246344243312F617474726962757465732E62696E504B01021400140006080800CC70623B08DA0BD190000000410100003600000000000000000000000000290F00006662782F39464131463745442D413632 +310 +322D343644302D413938332D3331353338454246344243312F6469726563746F72792E786D6C504B01021400140006080800CC70623B0D6EF93BFE000000A00100003B000000000000000000000000000D1000006662782F39464131463745442D413632322D343644302D413938332D3331353338454246344243312F7265 +310 +736F75726365732F636F72652E786D6C504B0506000000000E000E0080040000641100000000 + 0 +XRECORD + 5 +175 +102 +{ACAD_REACTORS +330 +173 +102 +} +330 +173 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +174 +102 +{ACAD_REACTORS +330 +173 +102 +} +330 +173 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +1FB +102 +{ACAD_REACTORS +330 +173 +102 +} +330 +173 +100 +AcDbXrecord +280 + 1 + 70 + 0 + 90 +1673772943 + 1 +ECE7A1D2-D628-4531-984C-D00F80459256 +310 +504B03040A0000080000CC70623B3DEE336E79000000790000001B0000006175746F6465736B2D64657369676E2D7061636B6167652E786D6C3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D227574662D3822203F3E3C666F726D6174733E3C666F726D61743E687474703A2F2F736368656D612E +310 +6175746F6465736B2E636F6D2F64657369676E2D7061636B6167652F323030393C2F666F726D61743E3C2F666F726D6174733E504B0304140006080800CC70623BD486FD9CA0000000F4000000130000005B436F6E74656E745F54797065735D2E786D6C7D8EC10E82300C865F65E91D8A1E8C310C0EEA1BF002731658846E +310 +D98AC1B77784ABF1D8FE5FBFBF75BBCE937A534CCEB38643598122B6FEE978D0B0485F9C41B54DDD7D022595594E1A469170414C76A4D9A4D207E29CF43ECE46F218070CC6BECC4078ACAA135ACF422C856C0E68EA1BF5669944DDD7BCDE7B1F8E415D77AECB980613C2E4AC91FC167A2B244592486606FC29C8FD7F045B9A +310 +EF7053A7E60B504B0304140006080800CC70623BD9DDAED0EC0000007C01000008000000636F72652E786D6C8D90416EC3201045AF82665B61836D9CD8C2444DD39CA01740405C94182C03558F5F9C3852BBEB6A467FFE9B197D7EF89E6EE8CB2CC17A37002D0820E394D7D68D03A478C17B4007C117EFE32F1B20272733C0 +310 +2A83E0E3E2D3BC49CABB685CCCAAF3DA6CA20CC14440EA969B0182FA34932C648AD911AEC52CD5558EA6A0CF2EC329598D1E47ACCEFBECC59A050463A7EA5833865FEBDD0E37353BE3EE8DBDE3F6786A48D375FBF6CC78B9C282473B3DEFABC5C86834888A900E538A49F5419B9EB47DD5BC907D4F082F57FB1F28CDFA9F50 +310 +B22ED6D5F6EE030B20687EE43E10BC5CB3C8E51E54AE6B6EE207504B0304140006080800CC70623B55019EA25F0000007C00000007000000636E782E786D6C4DCB3B0E80201045D1AD90E915ED2CF8AC45050C11660C8261F98AB1B07AC9C97D42D718D865D3E909258CFD00CCE24AC6E326A164D74DC0B4128928FF326038 +310 +472BA13128B1252AC747C6BAB984FC68F0B87FE8960A5C09FE86CFB69FBA01504B0304140006080800CC70623BA24EB22D72010000D40300000C0000006662782F636F72652E786D6CC5535B6E833010BC8AE5DF0A6C5E49888CA3A6694ED00B38E05014B091B1518EDFE511A5A9D228FD2A1F60CDEC7A67C6986DCE4D8D7A +310 +69BA4AAB0C073EC548AA5C17952A33ECECD15B61B4E1CC686DBF9561A44423333CC098B3D268D7CE50AE9595CA02AA74216750749DB418E5352C32DCE59FB211BE70162ABA93DF8AFC244AE9073ED050C759670D0840D390E18DF9F1706664C23973AE2A66B62A605A75ACA4C13C4976E1364A12EF355A2EBD384AF65EFA96 +310 +BC7B8BED2EA6719AAE16FB8491A199335B351775B991C2CA02F390D2D40B028F861F41BCA68B7518BFD0D59A524686F29B26D7164F36B94AD9289CE54E6D1DE6010819891F6E21228B3AD1831EC219194284CF98F06DD01008846CC5A1BEF83801D4CBDC6A1303536877A57A513B0953A94FC707FDBE6064EA84A9E3E6E0FA +310 +EE8CF0E9198F7784A316AA0413C2C2F2E0ECA0934D1AE6D05A69BCDE9E91D2A611F573361E38FC1375157F5752AE6B6DFE4B11990F88CCBF0719EE23FF02504B0304140006080800CC70623B408A7D3B7C0000009D0000000B0000006662782F636E782E786D6C4DCCD10A83201886E15B91FFDC552A92A0064DBC8F581632 +310 +D3703A76F9ABD1C18E3E78F878E5F0D9027ABBFCF2292AE86E2D20171F69F6715550CB827B40839639A5F2770314A7CD293819B45C73AAFB45B35BA61ACAA1C1C7E7855C58C15BC331339661262CC762340413D68D77DA5B42298546CBE6573AF60CEB2F504B0304140006080800CC70623B449FB9BD290100001202000031 +310 +0000006662782F36394639363044362D344446342D343946362D394244322D3234314243333846323333332F636F72652E786D6C8D515B6EC32010BC0AE22B55850D98B871848994463E412FE002495162B07854397EA176A4F62F3F2C9A9D991D587EB84F37F0AD7D30CEF6905418026DA553C65E7A98E219ED203808EE9D +310 +8B7F6810D871D23D2C3014FCE25D9A57483A1BB58D19B54EE9151C43D0110279CB971E06F9A5A7B11A53CC8C70ADE6515EC78BAE4895DB992778883E0700CB907242D17643D7E2538BD869608875438BBAE38922CAC8F1BDD90DB4691A5E2F42C153326A951B95E398B3D1FE599322163C9AE9115F7A3D46ADA0A018778810 +310 +84E907617BDCEE297BC5BB3DC6BC2EF47FA234AB2745C9D8D8D035EE220B50105E2F0DC1954B9FB747187D9F9D8FA0CCDB042D5FA0C015C65B42DF78BD10F3F3B363CB56C7109DCFDFBBB97E662ED92EB62D13BC2E1BCAE5777DB9966D8A1F504B0304140006080800CC70623BAD7543B64E01000033030000300000006662 +310 +782F36394639363044362D344446342D343946362D394244322D3234314243333846323333332F636E782E786D6CD593CD6EC32010845F0571AD6CE3D48AD20813A9873E410FBD12D82434182C7EAAE6EDBB2424CD25871E7B41D6EC30B3FA84F9E67BB2E40B4234DE8DB46F1925E094D7C6ED479AD3AE5951B2113C789FEE +310 +6C943839C1488B4C05DF079FE72A69D8C96C13AAD6B8631503449F83828872B949AC57D26200B826A308D316B4064D6E46FCDA41C05550DC9E483A00797BFD207EFB092A45DE9514C1BBD22178396BD39D891265658C238DEA00936C654E5E433CB65A26D9F6EDB5EBC14EBF49A45CB856E66048291F6939A9A81BB5C89177 +310 +38143CA680F4AA299D66A042CEB3354A2684DC9D8D178FE0D9B8B41CAAD720F880EE7EF93C0C18769E099ECC04D5A102C8049A8A05632F4DDF376CF1DE0F6BB65C2F8627B65A33C6BB62177CEBBDAD973006829F89F22E814B54F4BC2BE347F8AA8F681390B50FA73F804400B5F542E796F19FF974E7F78DB802FE05E20750 +310 +4B0304140006080800CC70623B8D05915C650500003B100000340000006662782F36394639363044362D344446342D343946362D394244322D3234314243333846323333332F6F626A656374732E786D6CAD575B6FA33814FE2B887D06429276DA1565D4266D158D3A339A6846FB502932E050B66023DB74D2FDF5FB190C01 +310 +9276B2973C046C8ECFF53B17071F77456EBD502133CEAE6CDF9DD81665314F32965ED995DA3A17B6F5310C04E7AA47665B8C14F4CAD6DB7618A48257A5D94AE89654B91AEDDEDDFC61C998326A5B714EA4BCB265FC440BE2924AF184CA6737218AB8E976E7FA6E4338649B0A523E8D98964450A6A029F619B8588D52FE7039 +310 +B1BD30F0F4F730D0FF866AF6369557DB33949F31A9088B0F848DD8CCFCF9F2767A76E99CCDE733677E3EF59D9BBB9BA5E37F984D16E78BC5E5F5ED25044B25C0C96822E8D60EEFE11B91C581D77CEA34368A1F5329E68CD1B8B61F16D63A1B8E092D294B10C78C4A48EB593D192E7DED9BDEE7995E1B91FDEDD3ACEA9FE831 +310 +6A756F9F7D4D79F4274C90A7A04248AA51D5F8C718DAE06FB2F75AC4796EBE65D22A88A22223B995679120E2D50E41AA49C260C046A35368846B0BECD0DFF3EBEB8AD4F835768F69B9ADF25C43D30E6B646F807FAA64AD59F61715C7A54127C4AACA98BA3006A9D792DAE165E0D59B61A01FB3A9F9D838D2DAE62445C86166 +310 +F37564E842E7DE6A69879FEEA2DD5AE7E371E1A5E025154AC307D06A03D73EB5978C58FFA4C8E9033066E0F3BD53BEC1F39F91BE7B55103791EDE6BBB991A2046172CB4581D8B893FA674DDA17A77B3B7C413D1B511FD2743BFF8A38F03A658705E3ADF8015C3A3417FF3D7E439FF591DA0B5F18BC20C1B8981957AE6392A3 +310 +F43C640C01D1A0B4728E2DD4F26DB4B3C3152A252A3B4E913CEC1C72F012782FF88EFF8637AA552DBEF76408E8A8DE9E50F9E1CB3A2DA0DB1B6039A893B56063DC5B3E3FFB5F72E67AB9FEB4AEC496C4F4C1149625DD662C53E89D7BF0F6151A046260D1337DFDC94502430F83B0EE07A130A224BCAD7DAE1D9FB6CD422FF6 +310 +920702629C4BB9AE79C12F243C6432A6794E18E5552BA56B431AAB5D91317302B2B071E86C3A42B1A02F999E24061403B5D0EB639195DA655DD3EBEAB4FB862DDF579F014AD0E73C22F99E28DA57FB98E75C6CA2D74D53086D600F4786E0FE3144B771A8A7B900F03594DB8A633CBC49B2EDB69228BB479CF863B5E807AAAB +310 +23872F6DFEB4129B949CA33823F58830E86D65621E10047D9DB34D862E8EAC3C2ABC2F7B2C40D67CDFE01F5545B92105AF983AC54D93D69E56FB8E797F88913F898A9FEC705D3F9D1B54EC8426FB500D40A03BD0119B06E1B95DDC7EB8F6975367793EBD70E66733DFB9BC982F9CE564727731999F5D4ECFCE3B8D6A4DC2A0 +310 +6D50FD148437D110834A64C6CDDF57FBACB5C307A2A477DFE4939736CFEF2B175371E0E10CF0DD1D5C15654E0BCA14D1E87DD02FF93782A162C0A3D95F1524A52770F972BF1EE9809D13CE7DD599467F8ECE9ADD85CE85A34CD45355448C64F9E8A031DC2D596ACC6E5DD93D9B82DE2EF5CAF81363A8E47996A0DE24564A79 +310 +4115AACE09C55E14540231FDA13C319787134EBF34E3A022514E5B4D9E0826E25C02D5805B15ABE1BEF51B26383D445DD9E875EE33FE4C22DA16427D65A3BCA92CA6D28DD01DF5DC53330704308475351050232CCD31583787BA75774AFB06E5070DD0C8EF484E19968C5D83BA5B90B244D31E54D55A372320FE4786B7EA58 +310 +44E135AA5467CB7EA333A61683CC6A8C3257034C10CF46F40EF9F5BE59BE5BD30C3C72D235E95D10345C1D45445A5F0BB47E46A5EBE5570F9380B5FA629579952296A773720405982B9DE04011506178964401AA8BDF1FBF0A8EAB6861DD6580C0E38217056766716DAEB2D6FA0917D3E4116581EADB879C4E7CFFB11EFACD +310 +3D641311495D92C8676CB409A72D18610D803CE8A626049E8EC1887CB5B44CC39883690DDA8399B4B9855B481E7D71D4A9D22F96E5BB73BF5793020C02137BF837504B0304140006080000CC70623B000000000000000000000000350000006662782F36394639363044362D344446342D343946362D394244322D32343142 +310 +43333846323333332F76657274696365732E62696E504B0304140006080800CC70623BF270F1330600000004000000360000006662782F36394639363044362D344446342D343946362D394244322D3234314243333846323333332F747269616E676C65732E62696E636660600000504B0304140006080000CC70623B0000 +310 +00000000000000000000370000006662782F36394639363044362D344446342D343946362D394244322D3234314243333846323333332F617474726962757465732E62696E504B0304140006080800CC70623B08DA0BD19000000041010000360000006662782F36394639363044362D344446342D343946362D394244322D +310 +3234314243333846323333332F6469726563746F72792E786D6C858F410AC3201045AF22B36F53E9A60B35CBEEBAE80D244E44489C6234F4F835464A48035D0DF398FF9F8AF63D0E6CC63039F212F8F9020C7D47C6792B21C5FE7403D62A1188E2E60C98D7234A5830286103A55745067B9D86B8A3CF9C7F90C11DE607FB14 +310 +4396D7B6A82D282E9A152AD114D5EF2CB866EEE831B8EEA07A7BB5A8D7D61A2BAAEB7FD5F70921FF497D00504B0304140006080800CC70623BCA768048FE000000A00100003B0000006662782F36394639363044362D344446342D343946362D394244322D3234314243333846323333332F7265736F75726365732F636F72 +310 +652E786D6C8D50596E833010BD0A9ADFCA60D600328E9AA639412F609909B1126CE4A5EAF16B0295DABFFECC8CDEA2797AECF8353F924FB44E193D409E5248504B332A3D0D10FC95B4901C39B3C6F85F3248B49871801506CE266BC2B243D2688FDA47549B11775038871E12F988C7004EDE7016A9083E2ADC3D5D84BC8B09 +310 +D33C8D74D471E6BC8D0192EDC93A815B742658898E651BCB59086ADC356A8C3FD555A1055ED7E7E254D615792D0F075295F585746FF53B694EE78A565DD736979A65AB9933AFE69F8CD2A2F038022F28ED489E135A7CE4554F9BBEA85E68DB53CAB255FEC71496F19FA6A0B42F8B3DEE6673C0F318E4497096AD7DC5F52C33 +310 +EEB55BFE0D504B010214000A0000080000CC70623B3DEE336E79000000790000001B00000000000000000000000000000000006175746F6465736B2D64657369676E2D7061636B6167652E786D6C504B01021400140006080800CC70623BD486FD9CA0000000F40000001300000000000000000000000000B20000005B436F +310 +6E74656E745F54797065735D2E786D6C504B01021400140006080800CC70623BD9DDAED0EC0000007C010000080000000000000000000000000083010000636F72652E786D6C504B01021400140006080800CC70623B55019EA25F0000007C000000070000000000000000000000000095020000636E782E786D6C504B0102 +310 +1400140006080800CC70623BA24EB22D72010000D40300000C00000000000000000000000000190300006662782F636F72652E786D6C504B01021400140006080800CC70623B408A7D3B7C0000009D0000000B00000000000000000000000000B50400006662782F636E782E786D6C504B01021400140006080800CC70623B +310 +449FB9BD290100001202000031000000000000000000000000005A0500006662782F36394639363044362D344446342D343946362D394244322D3234314243333846323333332F636F72652E786D6C504B01021400140006080800CC70623BAD7543B64E010000330300003000000000000000000000000000D20600006662 +310 +782F36394639363044362D344446342D343946362D394244322D3234314243333846323333332F636E782E786D6C504B01021400140006080800CC70623B8D05915C650500003B10000034000000000000000000000000006E0800006662782F36394639363044362D344446342D343946362D394244322D32343142433338 +310 +46323333332F6F626A656374732E786D6C504B01021400140006080000CC70623B0000000000000000000000003500000000000000000000000000250E00006662782F36394639363044362D344446342D343946362D394244322D3234314243333846323333332F76657274696365732E62696E504B010214001400060808 +310 +00CC70623BF270F13306000000040000003600000000000000000000000000780E00006662782F36394639363044362D344446342D343946362D394244322D3234314243333846323333332F747269616E676C65732E62696E504B01021400140006080000CC70623B00000000000000000000000037000000000000000000 +310 +00000000D20E00006662782F36394639363044362D344446342D343946362D394244322D3234314243333846323333332F617474726962757465732E62696E504B01021400140006080800CC70623B08DA0BD190000000410100003600000000000000000000000000270F00006662782F36394639363044362D344446342D +310 +343946362D394244322D3234314243333846323333332F6469726563746F72792E786D6C504B01021400140006080800CC70623BCA768048FE000000A00100003B000000000000000000000000000B1000006662782F36394639363044362D344446342D343946362D394244322D3234314243333846323333332F7265736F +310 +75726365732F636F72652E786D6C504B0506000000000E000E0080040000621100000000 + 0 +XRECORD + 5 +176 +102 +{ACAD_REACTORS +330 +173 +102 +} +330 +173 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +177 +102 +{ACAD_REACTORS +330 +173 +102 +} +330 +173 +100 +AcDbXrecord +280 + 1 +270 + 1 +271 + 1 + 0 +XRECORD + 5 +27B +102 +{ACAD_REACTORS +330 +234 +102 +} +330 +234 +100 +AcDbXrecord +280 + 1 +102 +DISPLAYNAME + 1 +Metric50 +102 +FLAGS + 90 + 0 + 0 +CELLSTYLEMAP + 5 +27A +102 +{ACAD_REACTORS +330 +162 +102 +} +330 +162 +100 +AcDbCellStyleMap + 90 + 3 +300 +CELLSTYLE + 1 +TABLEFORMAT_BEGIN + 90 + 5 +170 + 1 + 91 + 0 + 92 + 32768 + 62 + 257 + 93 + 1 +300 +CONTENTFORMAT + 1 +CONTENTFORMAT_BEGIN + 90 + 0 + 91 + 0 + 92 + 512 + 93 + 0 +300 + + 40 +0.0 +140 +1.0 + 94 + 5 + 62 + 0 +340 +11 +144 +6.0 +309 +CONTENTFORMAT_END +171 + 1 +301 +MARGIN + 1 +CELLMARGIN_BEGIN + 40 +1.5 + 40 +1.5 + 40 +1.5 + 40 +1.5 + 40 +4.5 + 40 +4.5 +309 +CELLMARGIN_END + 94 + 6 + 95 + 1 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +14 + 93 + 0 + 40 +1.125 +309 +GRIDFORMAT_END + 95 + 2 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +14 + 93 + 0 + 40 +1.125 +309 +GRIDFORMAT_END + 95 + 4 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +14 + 93 + 0 + 40 +1.125 +309 +GRIDFORMAT_END + 95 + 8 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +14 + 93 + 0 + 40 +1.125 +309 +GRIDFORMAT_END + 95 + 16 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +14 + 93 + 0 + 40 +1.125 +309 +GRIDFORMAT_END + 95 + 32 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +14 + 93 + 0 + 40 +1.125 +309 +GRIDFORMAT_END +309 +TABLEFORMAT_END + 1 +CELLSTYLE_BEGIN + 90 + 1 + 91 + 1 +300 +_TITLE +309 +CELLSTYLE_END +300 +CELLSTYLE + 1 +TABLEFORMAT_BEGIN + 90 + 5 +170 + 1 + 91 + 0 + 92 + 0 + 62 + 257 + 93 + 1 +300 +CONTENTFORMAT + 1 +CONTENTFORMAT_BEGIN + 90 + 0 + 91 + 0 + 92 + 512 + 93 + 0 +300 + + 40 +0.0 +140 +1.0 + 94 + 5 + 62 + 0 +340 +11 +144 +4.5 +309 +CONTENTFORMAT_END +171 + 1 +301 +MARGIN + 1 +CELLMARGIN_BEGIN + 40 +1.5 + 40 +1.5 + 40 +1.5 + 40 +1.5 + 40 +4.5 + 40 +4.5 +309 +CELLMARGIN_END + 94 + 6 + 95 + 1 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +14 + 93 + 0 + 40 +1.125 +309 +GRIDFORMAT_END + 95 + 2 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +14 + 93 + 0 + 40 +1.125 +309 +GRIDFORMAT_END + 95 + 4 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +14 + 93 + 0 + 40 +1.125 +309 +GRIDFORMAT_END + 95 + 8 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +14 + 93 + 0 + 40 +1.125 +309 +GRIDFORMAT_END + 95 + 16 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +14 + 93 + 0 + 40 +1.125 +309 +GRIDFORMAT_END + 95 + 32 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +14 + 93 + 0 + 40 +1.125 +309 +GRIDFORMAT_END +309 +TABLEFORMAT_END + 1 +CELLSTYLE_BEGIN + 90 + 2 + 91 + 1 +300 +_HEADER +309 +CELLSTYLE_END +300 +CELLSTYLE + 1 +TABLEFORMAT_BEGIN + 90 + 5 +170 + 1 + 91 + 0 + 92 + 0 + 62 + 257 + 93 + 1 +300 +CONTENTFORMAT + 1 +CONTENTFORMAT_BEGIN + 90 + 0 + 91 + 0 + 92 + 512 + 93 + 0 +300 + + 40 +0.0 +140 +1.0 + 94 + 2 + 62 + 0 +340 +11 +144 +4.5 +309 +CONTENTFORMAT_END +171 + 1 +301 +MARGIN + 1 +CELLMARGIN_BEGIN + 40 +1.5 + 40 +1.5 + 40 +1.5 + 40 +1.5 + 40 +4.5 + 40 +4.5 +309 +CELLMARGIN_END + 94 + 6 + 95 + 1 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +14 + 93 + 0 + 40 +1.125 +309 +GRIDFORMAT_END + 95 + 2 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +14 + 93 + 0 + 40 +1.125 +309 +GRIDFORMAT_END + 95 + 4 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +14 + 93 + 0 + 40 +1.125 +309 +GRIDFORMAT_END + 95 + 8 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +14 + 93 + 0 + 40 +1.125 +309 +GRIDFORMAT_END + 95 + 16 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +14 + 93 + 0 + 40 +1.125 +309 +GRIDFORMAT_END + 95 + 32 +302 +GRIDFORMAT + 1 +GRIDFORMAT_BEGIN + 90 + 0 + 91 + 1 + 62 + 0 + 92 + -2 +340 +14 + 93 + 0 + 40 +1.125 +309 +GRIDFORMAT_END +309 +TABLEFORMAT_END + 1 +CELLSTYLE_BEGIN + 90 + 3 + 91 + 2 +300 +_DATA +309 +CELLSTYLE_END + 0 +ENDSEC + 0 +SECTION + 2 +ACDSDATA + 70 + 2 + 71 + 8 + 0 +ACDSSCHEMA + 90 + 0 + 1 +AcDb_Thumbnail_Schema + 2 +AcDbDs::ID +280 + 10 + 91 + 8 + 2 +Thumbnail_Data +280 + 15 + 91 + 0 +101 +ACDSRECORD + 95 + 0 + 90 + 1 + 2 +AcDbDs::TreatedAsObjectData +280 + 1 +291 + 1 +101 +ACDSRECORD + 95 + 0 + 90 + 2 + 2 +AcDbDs::Legacy +280 + 1 +291 + 1 +101 +ACDSRECORD + 1 +AcDbDs::ID + 90 + 3 + 2 +AcDs:Indexable +280 + 1 +291 + 1 +101 +ACDSRECORD + 1 +AcDbDs::ID + 90 + 4 + 2 +AcDbDs::HandleAttribute +280 + 7 +282 + 1 + 0 +ACDSSCHEMA + 90 + 1 + 1 +AcDbDs::TreatedAsObjectDataSchema + 2 +AcDbDs::TreatedAsObjectData +280 + 1 + 91 + 0 + 0 +ACDSSCHEMA + 90 + 2 + 1 +AcDbDs::LegacySchema + 2 +AcDbDs::Legacy +280 + 1 + 91 + 0 + 0 +ACDSSCHEMA + 90 + 3 + 1 +AcDbDs::IndexedPropertySchema + 2 +AcDs:Indexable +280 + 1 + 91 + 0 + 0 +ACDSSCHEMA + 90 + 4 + 1 +AcDbDs::HandleAttributeSchema + 2 +AcDbDs::HandleAttribute +280 + 7 + 91 + 1 +284 + 1 + 0 +ACDSRECORD + 90 + 0 + 2 +AcDbDs::ID +280 + 10 +320 +22 + 2 +Thumbnail_Data +280 + 15 + 94 + 997 +310 +89504E470D0A1A0A0000000D4948445200000100000000B70803000000CA14702D00000300504C54452128300000000000000000000000000000000000000000000000000000000000000000330000660000990000CC0000FF0033000033330033660033990033CC0033FF0066000066330066660066990066CC0066FF0099 +310 +000099330099660099990099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF0000FF3300FF6600FF9900FFCC00FFFF3300003300333300663300993300CC3300FF3333003333333333663333993333CC3333FF3366003366333366663366993366CC3366FF3399003399333399663399993399CC3399FF33CC00 +310 +33CC3333CC6633CC9933CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF6600006600336600666600996600CC6600FF6633006633336633666633996633CC6633FF6666006666336666666666996666CC6666FF6699006699336699666699996699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066 +310 +FF3366FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF9933009933339933669933999933CC9933FF9966009966339966669966999966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC3399CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFFCC0000CC00 +310 +33CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFFCCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0000FF0033FF0066FF0099FF00CCFF00FFFF3300FF3333 +310 +FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33FFCC66FFCC99FFCCCCFFCCFFFFFF00FFFF33FFFF66FFFF99FFFFCCFFFFFF0000000D0D0D1A1A1A2828283535354343435050505D5D5D6B6B6B787878868686939393A1A1A1AEAEAEBB +310 +BBBBC9C9C9D6D6D6E4E4E4F1F1F1FFFFFF000000000000000000000000000000000000000000000000000000000000544354A8000000A04944415478DAEDDAA10A00200C4041FFFF7FED16AB61E09CCA5D1C82F03018D61A0000000000000000000000000000000000C0D45782C7A3EE09109BF7E46B051040000104104000 +310 +010410E0B100D13FFF7F0136CD051040000104104000010410A03CC09EBFFDBB01721F920002082080000208208000020820800002082080000208208000450172D7DFEF5F9707000000000000000000000000000080F3060A83AEBAB9C3D29D0000000049454E44AE426082 + 0 +ENDSEC + 0 +EOF diff --git a/testdata/turns_connected.graph b/testdata/turns_connected.graph new file mode 100644 index 00000000..e56d8f7e Binary files /dev/null and b/testdata/turns_connected.graph differ diff --git a/tools/build-image/Dockerfile b/tools/build-image/Dockerfile new file mode 100644 index 00000000..31257f60 --- /dev/null +++ b/tools/build-image/Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:bionic +RUN apt-get -y update && apt-get install -y software-properties-common +RUN add-apt-repository --yes ppa:beineri/opt-qt-5.11.0-bionic +RUN add-apt-repository --yes ppa:deadsnakes/ppa +RUN add-apt-repository ppa:andrew-fuller/cmake +RUN apt-get -y update && apt-get install -y gcc g++ make git libgl1-mesa-dev libglu1-mesa-dev python3.5 clang vim wget qt5113d cmake build-essential qt511tools +VOLUME /mnt/code +WORKDIR /mnt/code + diff --git a/tools/build-image/readme.txt b/tools/build-image/readme.txt new file mode 100644 index 00000000..2708bd30 --- /dev/null +++ b/tools/build-image/readme.txt @@ -0,0 +1,6 @@ +This is the docker file to build the linux build image for depthmapX builds. +A build should be available in the docker cloud as blackseamonster/depthmapx-buildenv + +Run +docker run -it blackseamonster/depthmapx-buildenv bash +to start up the build image diff --git a/tools/build_and_upload.sh b/tools/build_and_upload.sh new file mode 100644 index 00000000..11bb8ad8 --- /dev/null +++ b/tools/build_and_upload.sh @@ -0,0 +1,48 @@ +#!/bin/sh +timestamp=$(date +%Y.%m.%d.%H.%M.%S) + +if [ $# -ne 3 ]; then + echo "Three arguments are required, runner, sync git path and location of server upload php file" + exit 1 +fi + +runner=$1 +gitpath=$2 +uploadpath=$3 + +cd "$(dirname "$0")" +rm -rf depthmapX/ +git clone $gitpath +currentcommit=$(git rev-parse HEAD) +cd depthmapX +mkdir build +cd build +cmake -DCMAKE_BUILD_TYPE=Release .. +make -j +cd ../RegressionTest +python3 RegressionTestRunner.py performance_regression.json +cd ../../ +mkdir -p runs +cd runs +rundir=run-$timestamp +mkdir $rundir +cp -r ../depthmapX/RegressionTest/rundir/* $rundir/ + +cd $rundir + +params="{\"time\":\"$timestamp\",\"runner\":\"$runner\",\"commit\":\"$currentcommit\",\"tests\":[" + +counter="0" +for i in $(find . | grep 'timings_[0-9]\+_[0-9]\+\.csv') +do + newparams=$(csvtool drop 1 $i | csvtool format ',"%(1)":"%(2)"' - | cut -c2-); + #newparams="${newparams// /_}" + if [ "$counter" -eq "1" ]; then + params="${params},"; + fi + params="${params}{\"file\":\"$i\",\"times\":{$newparams}}" + counter="1" +done + +params="${params}]}" +curl --data "$params" $uploadpath diff --git a/tools/graph.grammar b/tools/graph.grammar new file mode 100644 index 00000000..0c6cbcd5 --- /dev/null +++ b/tools/graph.grammar @@ -0,0 +1,373 @@ + + + + Grammar for depthmap GRAPH files + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/storePerformanceTest.php b/tools/storePerformanceTest.php new file mode 100644 index 00000000..aef71a78 --- /dev/null +++ b/tools/storePerformanceTest.php @@ -0,0 +1,9 @@ +getTimeStamp() . '.json'; + file_put_contents($fileName, $data, FILE_APPEND | LOCK_EX); +} +?> \ No newline at end of file diff --git a/depthmapX/version.h b/version.h similarity index 66% rename from depthmapX/version.h rename to version.h index 2b47707f..db82ec0e 100644 --- a/depthmapX/version.h +++ b/version.h @@ -17,16 +17,18 @@ #ifndef VERSION_H #define VERSION_H +#include "version_defs.h" + // use these to define the depthmap versions -#define DEPTHMAPX_VERSION 0.55 -#define DEPTHMAPX_MINOR_VERSION_RAW b // b Beta version, r is standard release, s is stable release, W - M - L for single OS +#define DEPTHMAPX_MAJOR_VERSION 0 +#define DEPTHMAPX_MINOR_VERSION 7 +#define DEPTHMAPX_REVISION_VERSION 0 + #define DEPTHMAP_MODULE_VERSION 10.04 // leave these alone - C Preprocessor magic to get stuff to the right format #define STRINGIFY(v) #v -#define DEPTHMAPX_MINOR_VERSION_FORMAT(minor) STRINGIFY(minor) -#define DEPTHMAPX_MINOR_VERSION DEPTHMAPX_MINOR_VERSION_FORMAT(DEPTHMAPX_MINOR_VERSION_RAW) -#define TITLE_BASE_FORMAT(version, minor) "depthmapX " STRINGIFY(version) STRINGIFY(minor) -#define TITLE_BASE TITLE_BASE_FORMAT(DEPTHMAPX_VERSION, DEPTHMAPX_MINOR_VERSION_RAW) +#define TITLE_BASE_FORMAT(version, minor, revision) "depthmapX " STRINGIFY(version) "." STRINGIFY(minor) "." STRINGIFY(revision) +#define TITLE_BASE TITLE_BASE_FORMAT(DEPTHMAPX_MAJOR_VERSION, DEPTHMAPX_MINOR_VERSION, DEPTHMAPX_REVISION_VERSION) #endif // VERSION_H diff --git a/version_defs.h.in b/version_defs.h.in new file mode 100644 index 00000000..e62197e7 --- /dev/null +++ b/version_defs.h.in @@ -0,0 +1,29 @@ +// Copyright (C) 2018 Christian Sailer +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// This file is autogenerated - do not modify it directly! + +#pragma once + +#ifndef APP_DATE +#define APP_DATE "@APP_DATE@" +#endif + +#ifndef APP_GIT_BRANCH +#define APP_GIT_BRANCH "@APP_BRANCH@" +#endif + +#ifndef APP_GIT_COMMIT +#define APP_GIT_COMMIT "@APP_COMMIT@" +#endif