dewalls-1.0.0/000077500000000000000000000000001263712165300131515ustar00rootroot00000000000000dewalls-1.0.0/.gitignore000066400000000000000000000004441263712165300151430ustar00rootroot00000000000000# C++ objects and libs *.slo *.lo *.o *.a *.la *.lai *.so *.dll *.dylib # Qt-es /.qmake.cache /.qmake.stash *.pro.user *.pro.user.* *.qbs.user *.qbs.user.* *.moc moc_*.cpp qrc_*.cpp ui_*.h Makefile* *-build-* # QtCreator *.autosave #QtCtreator Qml *.qmlproject.user *.qmlproject.user.* dewalls-1.0.0/LICENSE000066400000000000000000000020701263712165300141550ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015 Andy Edwards Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. dewalls-1.0.0/README.md000066400000000000000000000014141263712165300144300ustar00rootroot00000000000000# dewalls A C++/Qt parser for Walls .wpj and .srv cave survey data format I'm on a crusade to liberate survey data from the Walls format so it can be used in modern 3D cave survey viewers like [Cavewhere](https://github.com/Cavewhere/cavewhere) and [Breakout](https://github.com/jedwards1211/breakout). Right now this is just a parsing library to be embedded in other programs. Maybe someday I'll use it to make command-line converters from Walls to other formats. I've been careful to write very clean and precise code for this parser, but the documentation is...pretty much nonexistent :) If you're interested in using this for your own program, let me know and I'll write up documentation and help you get started. ## Building Just open `dewalls.qbs` in Qt and hit run. dewalls-1.0.0/dewalls.qbs000066400000000000000000000053001263712165300153110ustar00rootroot00000000000000import qbs 1.0 Project { name: "dewalls" DynamicLibrary { name: "dewalls" Depends { name: "cpp" } Depends { name: "Qt"; submodules: ["core"] } cpp.includePaths: ["src"] Export { Depends { name: "cpp" } cpp.includePaths: ["src"] } Group { fileTagsFilter: ["dynamiclibrary"] qbs.installDir: (qbs.targetOS.contains("darwin") ? product.name + ".framework/Versions/A" : "") qbs.install: true } Group { fileTagsFilter: ["bundle"] qbs.install: true } cpp.installNamePrefix: qbs.installRoot Properties { condition: qbs.targetOS.contains("windows") cpp.defines: ["DEWALLS_LIB"] } Properties { condition: qbs.targetOS.contains("osx") cpp.cxxFlags: [ "-stdlib=libc++", "-std=c++11", //For c++11 support "-Werror" //Treat warnings as errors ] cpp.dynamicLibraries: [ "c++" ] cpp.linkerFlags: [ "-stdlib=libc++" ] } Properties { condition: qbs.targetOS.contains("linux") cpp.cxxFlags: [ "-std=c++11", //For c++11 support "-Werror" //Treat warnings as errors ] } files: [ "src/*.cpp", "src/*.h" ] } CppApplication { name: "dewalls-test" consoleApplication: true type: "application" Depends { name: "cpp" } Depends { name: "Qt"; submodules: ["core"] } Depends { name: "dewalls" } cpp.includePaths: ["src"] Properties { condition: qbs.targetOS.contains("osx") cpp.cxxFlags: [ "-stdlib=libc++", "-std=c++11", //For c++11 support "-Werror" //Treat warnings as errors ] cpp.dynamicLibraries: [ "c++" ] cpp.linkerFlags: [ "-stdlib=libc++" ] } Properties { condition: qbs.targetOS.contains("linux") cpp.cxxFlags: [ "-std=c++11", //For c++11 support "-Werror" //Treat warnings as errors ] cpp.dynamicLibraries: [ "c++" ] } files: [ "test/*.cpp", "test/*.h", "test/dewalls-test.qrc", ] } } dewalls-1.0.0/lib/000077500000000000000000000000001263712165300137175ustar00rootroot00000000000000dewalls-1.0.0/main.cpp000066400000000000000000000260561263712165300146120ustar00rootroot00000000000000#include #include "unit.h" #include "unittype.h" #include "length.h" #include "angle.h" #include "defaultunit.h" #include "unitizeddouble.h" #include "unitizedmath.h" #include #include "segment.h" #include #include #include #include #include #include "lineparser.h" #include "varianceoverride.h" #include "wallsvisitor.h" #include "cardinaldirection.h" #include "wallssurveyparser.h" using namespace std; using namespace dewalls; template void func(T t) { std::cout << t << std::endl ; } template void func(T t, Args... args) // recursive variadic function { std::cout << t <(110.0, Angle::Degrees)) << endl; } void parseLine(WallsSurveyParser& parser, QString line) { static int lineNumber = 1; std::cout << std::endl << std::endl << line.toStdString() << std::endl; parser.reset(Segment(line, "fakefile.txt", lineNumber++, 0)); try { parser.parseLine(); } catch (const SegmentParseExpectedException& ex) { cout << ex.message().toStdString() << endl; } catch (const SegmentParseException& ex) { cout << ex.message().toStdString() << endl; } } QString toString(QHash h) { QString result('['); foreach(QString key, h.keys()) { if (result.length() > 1) { result += ", "; } result += QString("%1 => %2").arg(key, h[key]); } return result + ']'; } int main(int argc, char *argv[]) { Length::init(); Angle::init(); if (argc < 2) { cout << "Usage: dewalls <.srv file>" << endl; return 0; } QString filename = QString::fromLatin1(argv[1]); cout << "Parsing file: " << filename.toStdString() << endl; QFile file(filename); file.open(QFile::ReadOnly); WallsSurveyParser parser2; PrintingWallsVisitor printingVisitor; parser2.setVisitor(&printingVisitor); int lineNumber = 0; while (!file.atEnd()) { QString line = file.readLine(); if (file.error() != QFile::NoError) { cerr << QString("Error reading from file %1 at line %2: %3") .arg(filename) .arg(lineNumber) .arg(file.errorString()).toStdString() << endl; return 1; } parser2.reset(Segment(line, filename, lineNumber, 0)); try { parser2.parseLine(); } catch (const SegmentParseExpectedException& ex) { cerr << ex.message().toStdString() << endl; return 2; } catch (const SegmentParseException& ex) { cerr << ex.message().toStdString() << endl; return 2; } lineNumber++; } file.close(); if (3 > 2) { return 0; } typedef UnitizedDouble ULength; typedef UnitizedDouble UAngle; auto ft = Length::Feet; auto m = Length::Meters; auto deg = Angle::Degrees; auto percent = Angle::PercentGrade; cout << UAngle(45, deg).get(percent) << endl; auto a = ULength(3, ft); auto b = ULength(5, m); auto c = a - b; auto d = new ULength(4, m); cout << -c << endl; cout << a + b + b << endl; cout << a * 3 << endl; cout << 3 * a << endl; cout << a / 3 << endl; cout << 3 / a << endl; cout << a.in(m) * 3 + b / 2 << endl; cout << 3 / *d << endl; Segment segment("test\r\none", "", 5, 3); cout << segment.endLine() << endl; cout << segment.endCol() << endl; Segment segment2("test\r\n\none\r\n\n\r", "", 5, 3); cout << segment2.endLine() << endl; cout << segment2.endCol() << endl; Segment segment3 = Segment("hello\r\nworld", "", 5, 3).mid(2, 4); cout << segment3.startLine() << endl; cout << segment3.startCol() << endl; cout << segment3.endLine() << endl; cout << segment3.endCol() << endl; QList segs = Segment("this is a test", "", 5, 3).split("\\s+"); for (auto iter = segs.begin(); iter < segs.end(); iter++) { cout << *iter << endl; } cout << Segment(" \r this should be trimmed \t\n ", "", 5, 3).trimmed() << endl; cout << Segment("hello\nweird\nworld", "", 2, 0).mid(3, 10).underlineInContext().toStdString() << endl; QRegExp rx("he(llo\nwei)rd"); Segment segment4("hello\nweird\nworld", "", 2, 0); indexIn(rx, segment4); cout << cap(rx, segment4, 1).underlineInContext().toStdString() << endl; WallsSurveyParser parser(Segment("hello weird world", "fakefile.txt", 2, 0)); try { parser.expect("hello "); parser.oneOf([&]() { parser.expect("test"); }, [&]() { parser.expect("blah"); }); } catch (const SegmentParseException& ex) { cout << ex.message().toStdString() << endl; } typedef QSharedPointer VarianceOverridePtr; VarianceOverridePtr v = VarianceOverridePtr(new RMSError(ULength(4, m))); cout << v->toString().toStdString() << endl; v.clear(); v = VarianceOverride::FLOATED_TRAVERSE; cout << v->toString().toStdString() << endl; quadrantTest(); parser = WallsSurveyParser(Segment("123.456 -123.456m -123i14.5", "fakefile.txt", 2, 0)); try { cout << parser.length(Length::Feet) << endl; parser.expect(' '); cout << parser.length(Length::Feet) << endl; parser.expect(' '); cout << parser.length(Length::Feet) << endl; } catch (const SegmentParseException& ex) { cout << ex.message().toStdString() << endl; } PrintingWallsVisitor visitor; parser.setVisitor(&visitor); parseLine(parser, "#units ct feet save lrud=fb:lurd incab=2.3h"); parseLine(parser, "A*1 B1 350i4 41 +25/-6 *2, --, 4,5,C*#Seg /some/really/cool segment;4, 5>"); parseLine(parser, "A*1 B1 350 N200mW +25 (*) *2, 3, 4,5,C*#Seg blah;4, 5>"); parseLine(parser, "#u tape=it"); parseLine(parser, "A1 B1 350 41 +25 15 16 (3, 5) <2, 3,4,5 >#Seg blah;4, 5>"); parseLine( parser , "A*1 B1 350i4 41 +25/-6 *2, --, 4,5,C*#Seg /some/really/cool segment;4, 5>" ); parseLine( parser , "A*1 B1 350 41 +25 *2, 3, 4,5,C*#Q /some/really/cool segment;4, 5>" ); parseLine( parser , "A*1 B1 350 41 +25 *2, 3 4,5,C*;4, 5>" ); parseLine( parser , "A*1 B1 350 41 +25 *2 3 4 5 C*;4, 5>" ); parseLine( parser , "A*1 B1 350 41 +25 *2, 3, 4,5,C*#Seg blah;4, 5>" ); parseLine( parser , "A*1 B1 350 41:20 +25 (?,) *2, 3, 4,5,C*#Seg blah;4, 5>" ); parseLine( parser , "A*1 *2,3,4,5*" ); parseLine( parser , "A*1 B1 350 N41gW +25 (*) *2, 3, 4,5,C*#Seg blah;4, 5>" ); parseLine( parser , "A*1 B1 350 N41gW +25 ;(*) *2, 3, 4,5,C*#Seg blah;4, 5>" ); parseLine( parser , "A*1 B1 350 N41gW +25 (*) *2, 3, 4m,3f,50g,C*#Seg blah;4, 5>" ); parseLine( parser , "A*1 B1 350 N200gW +25 (*) *2, 3, 4,5,C*#Seg blah;4, 5>" ); parseLine( parser , "A*1 B1 350 N200mS +25 (*) *2, 3, 4,5,C*#Seg blah;4, 5>" ); parseLine( parser , "A*1 *2,3,4,*" ); parseLine( parser , "A1, " ); parseLine( parser , "A1 " ); parseLine( parser , "A1 b" ); parseLine( parser , "A1 B1 350 41 +25 (3, 5) <2, 3, 4,5> okay>< weird #Seg blah;4, 5>" ); parseLine( parser , "A1 B1 350 41 +25 <2, 3, 4,5>#Seg blah;4, 5>" ); parseLine( parser , "A1 B1 350 41 +25 (3, 5) <2, 3,4,5 >#Seg blah;4, 5>" ); parseLine( parser , "A1 B1 350 41 +25 (3;, 5) <2, 3,4,5 >#Seg blah;4, 5>" ); parseLine( parser , "A1 B1 350 41 +25 (3, 5) <2, 3,4,5 *#Seg blah;4, 5>" ); parseLine( parser , "A1 B1 350 41 +25 (3, 5) hello <2, 3,4,5 *#Seg blah;4, 5>" ); parseLine( parser , "#u tape=it" ); parseLine( parser , "A1 B1 350 41 +25 15 16 (3, 5) <2, 3,4,5 >#Seg blah;4, 5>" ); parseLine( parser , "A1 B1 350 41 +25 15 16 17 (3, 5) <2, 3,4,5 >#Seg blah;4, 5>" ); parseLine( parser , " #flag /This is a test" ); parseLine( parser , " #flag AB30 /This is a test" ); parseLine( parser , " #f" ); parseLine( parser , " #f AB30 CY5 /This is a test" ); //parseLine( parser , " #u prefix1=A prefix2=CR case=lower" ); parseLine( parser , " #u prefix1=A case=lower" ); parseLine( parser , " #prefix2 CR ;test" ); parseLine( parser , " #symbol aslkjb;lkj aslkjasdf a; asdflaksjdf" ); parseLine( parser , " #sym ; asdlkfjasldf" ); parseLine( parser , " \tA1 B:B1 350 41 +25 15 16 (3, 5) <2, 3,4,5 >#Seg blah;4, 5>" ); parseLine( parser , " FR::A1 B:B1 350 41 +25 15 16 (3, 5) <2, 3,4,5 >#Seg blah;4, 5>" ); parseLine( parser , " #seg /hello/world blah;comment" ); parseLine( parser , " #note FR::A1 blah\\n\" hello\\n hello;comment" ); parseLine( parser , "#date 2015-01-16" ); parseLine( parser , "#date 01-16-2005" ); parseLine( parser , "#date 01-16-05" ); parseLine( parser , "#date 01/16/05" ); parseLine( parser , "#date 01/16/1905" ); parseLine( parser , " #[ this is a test" ); parseLine( parser , " blah" ); parseLine( parser , " blah" ); parseLine( parser , " #segment /hello/world" ); parseLine( parser , " ;#]" ); parseLine( parser , " #segment /hello/world" ); parseLine( parser , " #]" ); parseLine( parser , " FR::A1 B:B1 350 41 +25 15 16 (3, 5) <2, 3,4,5 >#Seg blah;4, 5>" ); parseLine( parser , " #fox" ); parseLine( parser , " #fix GPS9 620765 3461243 123 (R5,?) /Bat Cave Entrance" ); parseLine( parser , " #FIX A1 W97:43:52.5 N31:16:45 323f /Entrance #s /hello/world;dms with ft elevations" ); parseLine( parser , "#uNits $hello=\"er=vad order=NUE\"" ); parseLine( parser , "#u ord$(hello)" ); // System.out.println( parser.units.ctOrder ); // System.out.println( parser.units.rectOrder ); parseLine( parser , "#u ord$(hel lo)" ); parseLine( parser , "#u ord$(hello" ); parseLine( parser , "#u o=dav" ); parseLine( parser , "a - 350 20 +5 *1,2,3,4*" ); parseLine( parser , "- a 350 20 +5 *1,2,3,4*" ); ULength la(2, Length::Meters); ULength lb; cout << (la + lb) << endl; WallsUnits units; units.typeab_corrected = true; units.typevb_corrected = true; units.inch = ULength(1, Length::Inches); units.incv = UAngle(30, Angle::Degrees); units.incd = ULength(1, Length::Feet); ULength dist(20, Length::Feet); UAngle fsInc(35, Angle::Degrees); UAngle bsInc(33, Angle::Degrees); units.applyHeightCorrections(dist, fsInc, bsInc, ULength(-5, Length::Inches), ULength()); cout << "dist: " << dist << endl; cout << "fsInc: " << fsInc << endl; cout << "bsInc: " << bsInc << endl; } dewalls-1.0.0/src/000077500000000000000000000000001263712165300137405ustar00rootroot00000000000000dewalls-1.0.0/src/angle.cpp000066400000000000000000000034501263712165300155340ustar00rootroot00000000000000#include "angle.h" #include namespace dewalls { const long double PI = acosl(-1.0L); const long double DegreesToRadians = PI / 180.0L; const long double GradiansToRadians = PI / 200.0L; const long double MilsNATOToRadians = PI / 3200.0L; const long double RadiansToDegrees = 180.0L / PI; const long double RadiansToGradians = 200.0L / PI; const long double RadiansToMilsNATO = 3200.0L / PI; QString Angle::Name("angle"); QString Angle::symbolFor(Unit unit) { switch (unit) { case Radians: return "rad"; case Degrees: return "deg"; case Gradians: return "grad"; case MilsNATO: return "mil"; case PercentGrade: return "%"; default: return ""; } } long double Angle::toBase(long double quantity, Unit fromUnit) { switch (fromUnit) { case Radians: return quantity; case Degrees: return quantity * DegreesToRadians; case Gradians: return quantity * GradiansToRadians; case MilsNATO: return quantity * MilsNATOToRadians; case PercentGrade: return atan(quantity * 0.01L); default: return NAN; } } long double Angle::fromBase(long double quantity, Unit toUnit) { switch (toUnit) { case Radians: return quantity; case Degrees: return quantity * RadiansToDegrees; case Gradians: return quantity * RadiansToGradians; case MilsNATO: return quantity * RadiansToMilsNATO; case PercentGrade: return 100.0L * tan(quantity); default: return NAN; } } long double Angle::convert(long double quantity, Unit fromUnit, Unit toUnit) { return fromBase(toBase(quantity, fromUnit), toUnit); } } // namespace dewalls dewalls-1.0.0/src/angle.h000066400000000000000000000013071263712165300152000ustar00rootroot00000000000000#ifndef DEWALLS_ANGLE_H #define DEWALLS_ANGLE_H #include #include #include "dewallsexport.h" namespace dewalls { class DEWALLS_LIB_EXPORT Angle { public: enum Unit { Invalid = 0, Radians = 1, Degrees = 2, Gradians = 3, MilsNATO = 4, PercentGrade = 5 }; static QString Name; static long double toBase(long double quantity, Unit fromUnit); static long double fromBase(long double quantity, Unit toUnit); static long double convert(long double quantity, Unit fromUnit, Unit toUnit); static QString symbolFor(Unit unit); }; } // namespace dewalls #endif // DEWALLS_ANGLE_H dewalls-1.0.0/src/cardinaldirection.cpp000066400000000000000000000023371263712165300201270ustar00rootroot00000000000000#include "cardinaldirection.h" namespace dewalls { typedef UnitizedDouble UAngle; const CardinalDirection CardinalDirection::North(0); const CardinalDirection CardinalDirection::East(1); const CardinalDirection CardinalDirection::South(2); const CardinalDirection CardinalDirection::West(3); const QString CardinalDirection::names[4] = {"North", "East", "South", "West"}; const UAngle CardinalDirection::angles[4] = { UAngle(0, Angle::Degrees), UAngle(90, Angle::Degrees), UAngle(180, Angle::Degrees), UAngle(270, Angle::Degrees) }; UAngle CardinalDirection::nonnorm_quadrant(CardinalDirection to, UAngle rotation) const { if (to._ordinal == (_ordinal + 1) % 4) { return angle() + rotation; } else if (_ordinal == (to._ordinal + 1) % 4) { return angle() - rotation; } throw std::invalid_argument("invalid from/to combination"); } UAngle CardinalDirection::quadrant(CardinalDirection to, UAngle rotation) const { UAngle result = nonnorm_quadrant(to, rotation) % UAngle(360.0, Angle::Degrees); if (result < North.angle()) { result += UAngle(360.0, Angle::Degrees); } return result; } } // namespace dewalls dewalls-1.0.0/src/cardinaldirection.h000066400000000000000000000026051263712165300175720ustar00rootroot00000000000000#ifndef DEWALLS_CARDINALDIRECTION_H #define DEWALLS_CARDINALDIRECTION_H #include "angle.h" #include "unitizeddouble.h" #include "dewallsexport.h" namespace dewalls { class DEWALLS_LIB_EXPORT CardinalDirection { public: typedef UnitizedDouble UAngle; inline CardinalDirection() : _ordinal(0) {} inline QString name() const { return names[_ordinal]; } inline int ordinal() const { return _ordinal; } inline UAngle angle() const { return angles[_ordinal]; } inline CardinalDirection opposite() const { return CardinalDirection((_ordinal + 2) % 4); } UAngle quadrant(CardinalDirection to, UAngle angle) const; static const CardinalDirection North; static const CardinalDirection East; static const CardinalDirection South; static const CardinalDirection West; inline bool operator ==(const CardinalDirection& rhs) const { return _ordinal == rhs._ordinal; } inline CardinalDirection& operator =(CardinalDirection rhs) { this->_ordinal = rhs._ordinal; return *this; } private: inline CardinalDirection(int ordinal) : _ordinal(ordinal) {} UAngle nonnorm_quadrant(CardinalDirection to, UAngle angle) const; static const QString names[4]; static const UAngle angles[4]; int _ordinal; }; } // namespace dewalls #endif // DEWALLS_CARDINALDIRECTION_H dewalls-1.0.0/src/dewallsexport.h000066400000000000000000000006061263712165300170100ustar00rootroot00000000000000#ifndef DEWALLSEXPORT_H #define DEWALLSEXPORT_H #include /** These are required defines for exporting symbols in the cavewhere lib for windows. These do nothing on other platforms like mac and linux */ #if defined(DEWALLS_LIB) # define DEWALLS_LIB_EXPORT Q_DECL_EXPORT #else # define DEWALLS_LIB_EXPORT Q_DECL_IMPORT #endif #endif // DEWALLSEXPORT_H dewalls-1.0.0/src/fixstation.h000066400000000000000000000062571263712165300163130ustar00rootroot00000000000000#ifndef DEWALLS_FIXSTATION_H #define DEWALLS_FIXSTATION_H #include "unitizeddouble.h" #include "length.h" #include "angle.h" #include "varianceoverride.h" #include #include #include #include #include #include "wallsunits.h" #include "dewallsexport.h" namespace dewalls { class FixStationData : public QSharedData { public: typedef UnitizedDouble ULength; typedef UnitizedDouble UAngle; typedef QSharedPointer VarianceOverridePtr; inline FixStationData() : QSharedData(), name(), north(), east(), rectUp(), latitude(), longitude(), horizVariance(), vertVariance(), note(), segment(), comment(), date(), units() { } QString name; ULength north; ULength east; ULength rectUp; UAngle latitude; UAngle longitude; VarianceOverridePtr horizVariance; VarianceOverridePtr vertVariance; QString note; QStringList segment; QString comment; QDate date; WallsUnits units; }; class DEWALLS_LIB_EXPORT FixStation { public: typedef UnitizedDouble ULength; typedef UnitizedDouble UAngle; typedef QSharedPointer VarianceOverridePtr; inline FixStation() { d = new FixStationData; } inline FixStation(const FixStation& other) : d(other.d) { } inline QString name() { return d->name; } inline ULength north() { return d->north; } inline ULength east() { return d->east; } inline ULength rectUp() { return d->rectUp; } inline UAngle latitude() { return d->latitude; } inline UAngle longitude() { return d->longitude; } inline VarianceOverridePtr horizVariance() { return d->horizVariance; } inline VarianceOverridePtr vertVariance() { return d->vertVariance; } inline QString note() { return d->note; } inline QStringList segment() { return d->segment; } inline QString comment() { return d->comment; } inline QDate date() const { return d->date; } inline WallsUnits units() const { return d->units; } inline void setName(QString name) { d->name = name; } inline void setNorth(ULength north) { d->north = north; } inline void setEast(ULength east) { d->east = east; } inline void setRectUp(ULength rectUp) { d->rectUp = rectUp; } inline void setLatitude(UAngle latitude) { d->latitude = latitude; } inline void setLongitude(UAngle longitude) { d->longitude = longitude; } inline void setHorizVariance(VarianceOverridePtr horizVariance) { d->horizVariance = horizVariance; } inline void setVertVariance(VarianceOverridePtr vertVariance) { d->vertVariance = vertVariance; } inline void setNote(QString note) { d->note = note; } inline void setSegment(QStringList segment) { d->segment = segment; } inline void setComment(QString comment) { d->comment = comment; } inline void setDate(QDate date) { d->date = date; } inline void setUnits(WallsUnits units) { d->units = units; } private: QSharedDataPointer d; }; } // namespace dewalls #endif // DEWALLS_FIXSTATION_H dewalls-1.0.0/src/length.cpp000066400000000000000000000035661263712165300157370ustar00rootroot00000000000000#include "length.h" #include namespace dewalls { QString Length::Name("length"); const long double FeetToMeters = 0.3048L; const long double YardsToMeters = 3.0L * FeetToMeters; const long double InchesToMeters = FeetToMeters / 12.0L; const long double MetersToFeet = 1.0L / FeetToMeters; const long double MetersToYards = 1.0L / YardsToMeters; const long double MetersToInches = 1.0L / InchesToMeters; QString Length::symbolFor(Unit unit) { switch (unit) { case Meters: return "m"; case Centimeters: return "cm"; case Kilometers: return "km"; case Feet: return "ft"; case Yards: return "yd"; case Inches: return "in"; default: return ""; } } long double Length::toBase(long double quantity, Unit fromUnit) { switch (fromUnit) { case Meters: return quantity; case Centimeters: return quantity * 0.01L; case Kilometers: return quantity * 1000.0L; case Feet: return quantity * FeetToMeters; case Yards: return quantity * YardsToMeters; case Inches: return quantity * InchesToMeters; default: return NAN; } } long double Length::fromBase(long double quantity, Unit toUnit) { switch (toUnit) { case Meters: return quantity; case Centimeters: return quantity * 100.0L; case Kilometers: return quantity * 0.001L; case Feet: return quantity * MetersToFeet; case Yards: return quantity * MetersToYards; case Inches: return quantity * MetersToInches; default: return NAN; } } long double Length::convert(long double quantity, Unit fromUnit, Unit toUnit) { return fromBase(toBase(quantity, fromUnit), toUnit); } } // namespace dewalls dewalls-1.0.0/src/length.h000066400000000000000000000013321263712165300153710ustar00rootroot00000000000000#ifndef DEWALLS_LENGTH_H #define DEWALLS_LENGTH_H #include #include #include "dewallsexport.h" namespace dewalls { class DEWALLS_LIB_EXPORT Length { public: enum Unit { Invalid = 0, Meters = 1, Centimeters = 2, Kilometers = 3, Feet = 4, Yards = 5, Inches = 6 }; static QString Name; static long double toBase(long double quantity, Unit fromUnit); static long double fromBase(long double quantity, Unit toUnit); static long double convert(long double quantity, Unit fromUnit, Unit toUnit); static QString symbolFor(Unit unit); }; } // namespace dewalls #endif // DEWALLS_LENGTH_H dewalls-1.0.0/src/lineparser.cpp000066400000000000000000000134771263712165300166240ustar00rootroot00000000000000#include "lineparser.h" namespace dewalls { const QRegExp LineParser::whitespaceRx("\\s+"); const QRegExp LineParser::nonwhitespaceRx("\\S+"); LineParser::LineParser() : LineParser(Segment(QString(), QString(), 0, 0)) { } LineParser::LineParser(Segment line) : _line(line), _i(0), _expectedIndex(0), _expectedItems(QStringList()) { } void LineParser::reset(QString newLine) { _line = Segment(newLine); _i = 0; _expectedIndex = 0; _expectedItems.clear(); } void LineParser::reset(Segment newLine) { _line = newLine; _i = 0; _expectedIndex = 0; _expectedItems.clear(); } bool LineParser::isAtEnd() const { return _i == _line.length(); } void LineParser::addExpected(const SegmentParseExpectedException& expected) { int index = std::max(expected.segment().sourceIndex(), 0) - std::max(_line.sourceIndex(), 0); if (index > _expectedIndex) { _expectedItems.clear(); _expectedIndex = index; } if (index == _expectedIndex) { _expectedItems << expected.expectedItems(); } } SegmentParseExpectedException LineParser::allExpected() { if (!_expectedItems.isEmpty()) { return SegmentParseExpectedException( _line.atAsSegment(_i), _expectedItems); } return SegmentParseExpectedException( _line.atAsSegment(_i), ""); } void LineParser::throwAllExpected() { if (!_expectedItems.isEmpty()) { throw SegmentParseExpectedException( _line.atAsSegment(_expectedIndex), _expectedItems); } } void LineParser::throwAllExpected(const SegmentParseExpectedException& finalEx) { addExpected(finalEx); throwAllExpected(); } void LineParser::expect(const QChar &c, Qt::CaseSensitivity cs) { if (_i < _line.length()) { QChar lhs = c; QChar rhs = _line.at(_i); if (cs == Qt::CaseInsensitive) { lhs = lhs.toLower(); rhs = rhs.toLower(); } if (lhs == rhs) { _i++; return; } } throw SegmentParseExpectedException(_line.atAsSegment(_i), QString(c)); } void LineParser::expect(const QString &c, Qt::CaseSensitivity cs) { if (_i + c.length() <= _line.length()) { QString lhs = c; QString rhs = _line.mid(_i, c.length()).value(); if (cs == Qt::CaseInsensitive) { lhs = lhs.toLower(); rhs = rhs.toLower(); } if (lhs == rhs) { _i += c.length(); return; } } throw SegmentParseExpectedException(_line.atAsSegment(_i), c); } Segment LineParser::expect(const QRegExp &rx, std::initializer_list expectedItems) { QRegExp rxcopy = rx; int index = indexIn(rxcopy, _line, _i); if (index != _i) { throw SegmentParseExpectedException(_line.atAsSegment(_i), expectedItems); } int start = _i; _i += rxcopy.matchedLength(); return _line.mid(start, rxcopy.matchedLength()); } Segment LineParser::expect(QRegExp &rx, std::initializer_list expectedItems) { int index = indexIn(rx, _line, _i); if (index != _i) { throw SegmentParseExpectedException(_line.atAsSegment(_i), expectedItems); } int start = _i; _i += rx.matchedLength(); return _line.mid(start, rx.matchedLength()); } Segment LineParser::expect(QRegExp &rx, QList expectedItems) { int index = indexIn(rx, _line, _i); if (index != _i) { throw SegmentParseExpectedException(_line.atAsSegment(_i), expectedItems); } int start = _i; _i += rx.matchedLength(); return _line.mid(start, rx.matchedLength()); } Segment LineParser::whitespace() { return expect(whitespaceRx, {""}); } bool LineParser::maybeWhitespace() { return maybe([&]() { whitespace(); } ); } Segment LineParser::nonwhitespace() { return expect(nonwhitespaceRx, {""}); } const QRegExp LineParser::unsignedIntLiteralRx("\\d+"); uint LineParser::unsignedIntLiteral() { return expect(unsignedIntLiteralRx, {""}).value().toUInt(); } QHash createIntSignSignums() { QHash intSignSignums; intSignSignums['-'] = -1; intSignSignums['+'] = 1; return intSignSignums; } const QHash LineParser::intSignSignums = createIntSignSignums(); int LineParser::intLiteral() { int signum; if (!maybe(signum, [this]() { return this->oneOfMap(intSignSignums); } )) { signum = 1; } return signum * unsignedIntLiteral(); } const QRegExp LineParser::unsignedDoubleLiteralRx("\\d+(\\.\\d*)?|\\.\\d+"); double LineParser::unsignedDoubleLiteral() { return expect(unsignedDoubleLiteralRx, {""}).value().toDouble(); } QHash createSignSignums() { QHash signSignums; signSignums['-'] = -1.0; signSignums['+'] = 1.0; return signSignums; } const QHash LineParser::signSignums = createSignSignums(); double LineParser::doubleLiteral() { double signum; if (!maybe(signum, [this]() { return this->oneOfMap(signSignums); } )) { signum = 1.0; } return signum * unsignedDoubleLiteral(); } void LineParser::endOfLine() { if (_i != _line.length()) { throw SegmentParseExpectedException(_line.atAsSegment(_i), ""); } } Segment LineParser::remaining() { Segment result = _line.mid(_i); _i = _line.length(); return result; } bool LineParser::maybeChar(QChar c) { return maybe([&]() { this->expect(c); }); } } // namespace dewalls dewalls-1.0.0/src/lineparser.h000066400000000000000000000207751263712165300162700ustar00rootroot00000000000000#ifndef DEWALLS_LINEPARSER_H #define DEWALLS_LINEPARSER_H #include #include "segment.h" #include #include #include #include #include #include #include #include "segmentparseexpectedexception.h" #include #include #include "dewallsexport.h" #include namespace dewalls { class DEWALLS_LIB_EXPORT LineParser { public: LineParser(); LineParser(Segment line); virtual void reset(QString newLine); virtual void reset(Segment newLine); bool isAtEnd() const; void addExpected(const SegmentParseExpectedException& ex); SegmentParseExpectedException allExpected(); void throwAllExpected(); void throwAllExpected(const SegmentParseExpectedException& finalEx); void expect(const QChar& c, Qt::CaseSensitivity cs = Qt::CaseSensitive); void expect(const QString& c, Qt::CaseSensitivity cs = Qt::CaseSensitive); Segment expect(const QRegExp& rx, std::initializer_list expectedItems); Segment expect(QRegExp& rx, std::initializer_list expectedItems); Segment expect(QRegExp &rx, QList expectedItems); template QChar expectChar(F charPredicate, std::initializer_list expectedItems); Segment whitespace(); Segment nonwhitespace(); bool maybeWhitespace(); static const QRegExp unsignedIntLiteralRx; uint unsignedIntLiteral(); static const QHash intSignSignums; int intLiteral(); static const QRegExp unsignedDoubleLiteralRx; double unsignedDoubleLiteral(); static const QHash signSignums; double doubleLiteral(); template V oneOfMap(QHash map); template V oneOfMap(QHash map, V elseValue); template V oneOfMapLowercase(const QRegExp& rx, QHash map); template V oneOfMapLowercase(QRegExp& rx, QHash map); template void throwAllExpected(F production); template void oneOf(F production); template void oneOf(F production, Args... args); template void oneOfR(R& result, F production); template void oneOfR(R& result, F production, Args... args); template void oneOfWithLookahead(F production); template void oneOfWithLookahead(F production, Args... args); template bool maybe(F production); template bool maybeWithLookahead(F production); template bool maybe(R& result, F production); bool maybeChar(QChar c); void endOfLine(); Segment remaining(); static const QRegExp whitespaceRx; static const QRegExp nonwhitespaceRx; protected: Segment _line; int _i; int _expectedIndex; QStringList _expectedItems; }; template void LineParser::throwAllExpected(F production) { try { production(); } catch (const SegmentParseExpectedException& ex) { throwAllExpected(ex); } } template void LineParser::oneOf(F production) { try { production(); } catch (const SegmentParseExpectedException& ex) { throwAllExpected(ex); } } template void LineParser::oneOf(F production, Args... args) { int start = _i; try { production(); } catch (const SegmentParseExpectedException& ex) { if (_i > start) { throwAllExpected(ex); } addExpected(ex); oneOf(args...); } } template void LineParser::oneOfR(R& result, F production) { try { result = production(); } catch (const SegmentParseExpectedException& ex) { throwAllExpected(ex); } } template void LineParser::oneOfR(R& result, F production, Args... args) { int start = _i; try { result = production(); } catch (const SegmentParseExpectedException& ex) { if (_i > start) { throwAllExpected(ex); } addExpected(ex); oneOfR(result, args...); } } //template //void oneOfOwnR(R& result, R (O::*production)()) //{ // try // { // return (this->*production)(); // } // catch (const SegmentParseExpectedException& ex) // { // throwAllExpected(ex); // } //} //template //void oneOfOwnR(R& result, R (O::*production)(), Args... args) //{ // int start = _i; // try // { // return (this->*production)(); // } // catch (const SegmentParseExpectedException& ex) // { // if (_i > start) // { // throwAllExpected(ex); // } // addExpected(ex); // oneOfOwnR(result, args...); // } //} template void LineParser::oneOfWithLookahead(F production) { try { production(); } catch (const SegmentParseExpectedException& ex) { // std::cout << ex.message().toStdString() << std::endl; throwAllExpected(ex); } } template void LineParser::oneOfWithLookahead(F production, Args... args) { int start = _i; try { production(); } catch (const SegmentParseExpectedException& ex) { // std::cout << ex.message().toStdString() << std::endl; addExpected(ex); _i = start; oneOfWithLookahead(args...); } } template V LineParser::oneOfMap(QHash map) { QChar c; if (_i >= _line.length() || !map.contains(c = _line.at(_i))) { QList expectedItems; for (QChar exp : map.keys()) { expectedItems << QString(exp); } throw SegmentParseExpectedException(_line.atAsSegment(_i), expectedItems); } _i++; return map[c]; } template V LineParser::oneOfMap(QHash map, V elseValue) { try { return oneOfMap(map); } catch (const SegmentParseExpectedException& ex) { addExpected(ex); return elseValue; } } template V LineParser::oneOfMapLowercase(const QRegExp& rx, QHash map) { QRegExp rxCopy = rx; return oneOfMapLowercase(rxCopy, map); } template V LineParser::oneOfMapLowercase(QRegExp& rx, QHash map) { int start = _i; Segment seg = expect(rx, map.keys()); QString str = seg.toLower(); if (!map.contains(str)) { _i = start; throw SegmentParseExpectedException(seg, map.keys()); } return map[str]; } template bool LineParser::maybe(F production) { int start = _i; try { production(); return true; } catch (const SegmentParseExpectedException& ex) { if (_i > start) { throwAllExpected(ex); } addExpected(ex); return false; } } template bool LineParser::maybeWithLookahead(F production) { int start = _i; try { production(); return true; } catch (const SegmentParseExpectedException& ex) { addExpected(ex); _i = start; return false; } } template bool LineParser::maybe(R& result, F production) { int start = _i; try { result = production(); return true; } catch (const SegmentParseExpectedException& ex) { if (_i > start) { throwAllExpected(ex); } addExpected(ex); return false; } } template QChar LineParser::expectChar(F charPredicate, std::initializer_list expectedItems) { QChar c; if (_i >= _line.length() || !charPredicate(c = _line.at(_i))) { throw SegmentParseExpectedException(_line.atAsSegment(_i), expectedItems); } _i++; return c; } } // namespace dewalls #endif // DEWALLS_LINEPARSER_H dewalls-1.0.0/src/segment.cpp000066400000000000000000000133401263712165300161070ustar00rootroot00000000000000#include "segment.h" #include #include namespace dewalls { SegmentImpl::SegmentImpl(SegmentPtr sourceSegment, int sourceIndex, QString value, QString source, int startLine, int startCol, int endLine, int endCol) : _sourceSegment(sourceSegment), _sourceIndex(sourceIndex), _value(value), _source(source), _startLine(startLine), _startCol(startCol), _endLine(endLine), _endCol(endCol) { } SegmentImpl::SegmentImpl(SegmentPtr sourceSegment, int sourceIndex, QString value, QString source, int startLine, int startCol) : _sourceSegment(sourceSegment), _sourceIndex(sourceIndex), _value(value), _source(source), _startLine(startLine), _startCol(startCol), _endLine(startLine), _endCol(startCol + value.length() - 1) { QRegExp LINE_BREAK("\r\n|\r|\n"); int pos = 0; while ((pos = LINE_BREAK.indexIn(value, pos)) != -1) { int end = pos + LINE_BREAK.matchedLength(); if (end >= value.length()) { break; } _endLine++; _endCol = value.length() - end - 1; pos = end; } } SegmentImpl::SegmentImpl(QString value, QString source, int startLine, int startCol) : SegmentImpl(SegmentPtr(), -1, value, source, startLine, startCol) { } SegmentImpl::SegmentImpl(QString value) : SegmentImpl(SegmentPtr(), -1, value, QString(), 0, 0) { } Segment::Segment(SegmentPtr impl) : _impl(impl) { } Segment::Segment(QString value) : Segment(SegmentPtr(new SegmentImpl(value))) { } Segment::Segment(QString value, QString source, int startLine, int startCol) : Segment(SegmentPtr(new SegmentImpl(value, source, startLine, startCol))) { } Segment Segment::mid(int position, int n) const { if (n < 0) { n = length(); } if (startLine() == endLine()) { return Segment(SegmentPtr(new SegmentImpl( _impl->_sourceSegment.isNull() ? _impl : _impl->_sourceSegment, sourceIndex() >= 0 ? sourceIndex() + position : position, value().mid(position, n), source(), startLine(), startCol() + position, startLine(), startCol() + position + n - 1))); } int newStartLine = startLine(); int newStartCol = startCol() + position; int toIndex = position; if (toIndex < value().length() && toIndex > 0 && value().at(toIndex) == '\n' && value().at(toIndex - 1) == '\r') { toIndex--; } QRegExp LINE_BREAK("\r\n|\r|\n"); int pos = 0; while ((pos = LINE_BREAK.indexIn(value(), pos)) >= 0) { if (pos >= toIndex) { break; } newStartLine++; pos += LINE_BREAK.matchedLength(); newStartCol = position - pos; } return Segment(SegmentPtr(new SegmentImpl( _impl->_sourceSegment.isNull() ? _impl : _impl->_sourceSegment, sourceIndex() >= 0 ? sourceIndex() + position : position, value().mid(position, n), source(), newStartLine, newStartCol))); } QList Segment::split(const QRegExp &re, QString::SplitBehavior behavior) const { QList matchList; QRegExp matcher = re; int partStart = 0; int matchStart = 0; while ((matchStart = matcher.indexIn(value(), partStart)) >= 0) { if (behavior == QString::SplitBehavior::KeepEmptyParts || matchStart > partStart) { matchList << mid(partStart, matchStart - partStart); } partStart = matchStart + matcher.matchedLength(); } if (behavior == QString::SplitBehavior::KeepEmptyParts || partStart < length()) { matchList << mid(partStart); } return matchList; } QList Segment::split(const QString &pattern, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const { return split(QRegExp(pattern, cs), behavior); } QString Segment::underlineInContext() const { QString result; QList lines = _impl->_sourceSegment.isNull() ? split("\r\n|\r|\n") : Segment(_impl->_sourceSegment).split("\r\n|\r|\n"); for (auto line = lines.cbegin(); line < lines.cend(); line++) { if (line->startLine() < startLine() || line->startLine() > endLine()) { continue; } result.append(line->value()).append('\n'); int k = 0; if (startLine() == line->startLine()) { result.append(line->value().mid(k, startCol() - k).replace(QRegExp("[^\t]"), " ")); //result.append(QString(startCol() - k, ' ')); k = startCol(); } if (line->startLine() < endLine()) { // result.append(QString(line->length() - k, '^')); result.append(line->value().right(k).replace(QRegExp("[^\t]"), "^")); k = line->length(); } else if (endLine() == line->startLine()) { if (endCol() < startCol()) { result.append('^'); } else { // result.append(QString(endCol() + 1 - k, '^')); result.append(line->value().mid(k, endCol() + 1 - k).replace(QRegExp("[^\t]"), "^")); k = endCol() + 1; } } if (line->startLine() < endLine()) { result.append('\n'); } } return result; } } // namespace dewalls dewalls-1.0.0/src/segment.h000066400000000000000000000223671263712165300155650ustar00rootroot00000000000000#ifndef DEWALLS_SEGMENT_H #define DEWALLS_SEGMENT_H #include #include #include #include #include #include "dewallsexport.h" namespace dewalls { class SegmentImpl; class Segment; typedef QSharedPointer SegmentPtr; /** * @brief The data that's implicitly shared by Segment instances */ class SegmentImpl { public: friend class Segment; SegmentImpl(QString value, QString source, int startLine, int startCol); SegmentImpl(QString value); protected: SegmentImpl(SegmentPtr sourceSegment, int sourceIndex, QString value, QString source, int startLine, int startCol); SegmentImpl(SegmentPtr sourceSegment, int sourceIndex, QString value, QString source, int startLine, int startCol, int endLine, int endCol); private: SegmentImpl() = delete; SegmentImpl(SegmentImpl& other) = delete; SegmentImpl& operator=(SegmentImpl& other) = delete; SegmentPtr _sourceSegment; int _sourceIndex; QString _value; QString _source; int _startLine; int _startCol; int _endLine; int _endCol; }; /** * @brief A wrapper for a QString that maintains information about where it's located in * some source file. Subsegments of this Segment created with mid(), split(), trimmed(), etc. * will also contain proper location information. This way, if a parser encounters a * syntax error in any subsegment of a file or line it's operating on, it can underline the * error in context using cout << segment.mid(errorStart, errorLen).underlineInContext().toStdString(). * * Not to be confused with Walls #segment directives. * * Many methods simply delegate to the wrapped QString. Others have an analogous signature but * return Segment or QList instead of QString or QStringList. * * Segment uses implicit sharing like many Qt classes. */ class DEWALLS_LIB_EXPORT Segment { public: Segment(); Segment(QString value); Segment(QString value, QString source, int startLine, int startCol); Segment(Segment&& other); Segment(const Segment& other) = default; Segment sourceSegment() const; int sourceIndex() const; QString value() const; QString source() const; int startLine() const; int startCol() const; int endLine() const; int endCol() const; int length() const; bool isEmpty() const; const QChar at(int index) const; Segment atAsSegment(int index) const; Segment mid(int position, int n = -1) const; Segment left(int n) const; Segment right(int n) const; QList split(const QRegExp& re, QString::SplitBehavior behavior = QString::KeepEmptyParts) const; QList split(const QString& pattern, QString::SplitBehavior behavior = QString::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; int compare(const QString& other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; int compare(const QStringRef& other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; bool contains(const QString& str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; bool contains(const QStringRef& str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; bool contains(const QRegExp& rx) const; bool contains(QRegExp& rx) const; bool endsWith(const QString& str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; bool endsWith(const QStringRef& str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; int indexOf(const QString& str, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; int indexOf(const QStringRef& str, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; int lastIndexOf(const QString& str, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; int lastIndexOf(const QStringRef& str, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; std::string toStdString() const; std::wstring toStdWString() const; Segment trimmed() const; QString toUpper() const; QString toLower() const; QString::const_iterator begin() const; QString::const_iterator end() const; const QChar operator[](int position) const; const QChar operator[](uint position) const; QString underlineInContext() const; inline friend void swap(Segment& first, Segment& second) { using std::swap; swap(first._impl, second._impl); } Segment& operator =(Segment other); friend std::ostream& operator<<(std::ostream& os, const Segment& obj) { return os << obj.value().toStdString(); } protected: Segment(SegmentPtr impl); private: SegmentPtr _impl; }; inline bool exactMatch(QRegExp& rx, const Segment& segment) { return rx.exactMatch(segment.value()); } inline int indexIn(QRegExp& rx, const Segment& segment, int offset = 0, QRegExp::CaretMode caretMode = QRegExp::CaretAtZero) { return rx.indexIn(segment.value(), offset, caretMode); } inline int lastIndexIn(QRegExp& rx, const Segment& segment, int offset = -1, QRegExp::CaretMode caretMode = QRegExp::CaretAtZero) { return rx.lastIndexIn(segment.value(), offset, caretMode); } inline Segment cap(QRegExp& rx, const Segment& segment, int nth = 0) { return segment.mid(rx.pos(nth), rx.cap(nth).length()); } inline Segment::Segment() : Segment(QString(), QString(), 0, 0) { } inline Segment::Segment(Segment&& other) { swap(*this, other); } inline Segment& Segment::operator =(Segment other) { swap(*this, other); return *this; } inline Segment Segment::sourceSegment() const { return Segment(_impl->_sourceSegment); } inline int Segment::sourceIndex() const { return _impl->_sourceIndex; } inline QString Segment::value() const { return _impl->_value; } inline QString Segment::source() const { return _impl->_source; } inline int Segment::startLine() const { return _impl->_startLine; } inline int Segment::startCol() const { return _impl->_startCol; } inline int Segment::endLine() const { return _impl->_endLine; } inline int Segment::endCol() const { return _impl->_endCol; } inline int Segment::length() const { return _impl->_value.length(); } inline bool Segment::isEmpty() const { return _impl->_value.isEmpty(); } inline const QChar Segment::at(int i) const { return _impl->_value.at(i); } inline Segment Segment::atAsSegment(int i) const { return mid(i, i == length() ? 0 : 1); } inline Segment Segment::left(int n) const { return mid(0, n); } inline Segment Segment::right(int n) const { return mid(length() - n, n); } inline int Segment::compare(const QString& other, Qt::CaseSensitivity cs) const { return value().compare(other, cs); } inline int Segment::compare(const QStringRef& other, Qt::CaseSensitivity cs) const { return value().compare(other, cs); } inline bool Segment::contains(const QString& str, Qt::CaseSensitivity cs) const { return value().contains(str, cs); } inline bool Segment::contains(const QStringRef& str, Qt::CaseSensitivity cs) const { return value().contains(str, cs); } inline bool Segment::contains(const QRegExp& rx) const { return value().contains(rx); } inline bool Segment::contains(QRegExp& rx) const { return value().contains(rx); } inline bool Segment::endsWith(const QString& str, Qt::CaseSensitivity cs) const { return value().endsWith(str, cs); } inline bool Segment::endsWith(const QStringRef& str, Qt::CaseSensitivity cs) const { return value().endsWith(str, cs); } inline int Segment::indexOf(const QString& str, int from, Qt::CaseSensitivity cs) const { return value().indexOf(str, from, cs); } inline int Segment::indexOf(const QStringRef& str, int from, Qt::CaseSensitivity cs) const { return value().indexOf(str, from, cs); } inline int Segment::lastIndexOf(const QString& str, int from, Qt::CaseSensitivity cs) const { return value().lastIndexOf(str, from, cs); } inline int Segment::lastIndexOf(const QStringRef& str, int from, Qt::CaseSensitivity cs) const { return value().lastIndexOf(str, from, cs); } inline std::string Segment::toStdString() const { return value().toStdString(); } inline std::wstring Segment::toStdWString() const { return value().toStdWString(); } inline Segment Segment::trimmed() const { QString val = value(); auto start = val.begin(); auto end = val.end(); while (start < end && start->isSpace()) start++; while (end > start && (end - 1)->isSpace()) end--; return mid(start - val.begin(), end - start); } inline QString Segment::toUpper() const { return value().toUpper(); } inline QString Segment::toLower() const { return value().toLower(); } inline QString::const_iterator Segment::begin() const { return value().begin(); } inline QString::const_iterator Segment::end() const { return value().end(); } inline const QChar Segment::operator [](int position) const { return value()[position]; } inline const QChar Segment::operator [](uint position) const { return value()[position]; } } // namespace dewalls #endif // DEWALLS_SEGMENT_H dewalls-1.0.0/src/segmentparseexception.cpp000066400000000000000000000003261263712165300210610ustar00rootroot00000000000000#include "segmentparseexception.h" #include "wallsmessage.h" namespace dewalls { QString SegmentParseException::message() const { return WallsMessage(*this).toString(); } } // namespace dewalls dewalls-1.0.0/src/segmentparseexception.h000066400000000000000000000023301263712165300205230ustar00rootroot00000000000000#ifndef DEWALLS_SEGMENTPARSEEXCEPTION_H #define DEWALLS_SEGMENTPARSEEXCEPTION_H #include #include "segment.h" #include "dewallsexport.h" namespace dewalls { class DEWALLS_LIB_EXPORT SegmentParseException : public QException { public: SegmentParseException(Segment segment); SegmentParseException(Segment segment, QString detailMessage); Segment segment() const; virtual QString detailMessage() const; virtual QString message() const; virtual void raise() const { throw *this; } virtual SegmentParseException *clone() const { return new SegmentParseException(*this); } private: Segment _segment; QString _detailMessage; }; inline SegmentParseException::SegmentParseException(Segment segment, QString detailMessage) : _segment(segment), _detailMessage(detailMessage) { } inline SegmentParseException::SegmentParseException(Segment segment) : SegmentParseException(segment, "") { } inline Segment SegmentParseException::segment() const { return _segment; } inline QString SegmentParseException::detailMessage() const { return _detailMessage; } } // namespace dewalls #endif // DEWALLS_SEGMENTPARSEEXCEPTION_H dewalls-1.0.0/src/segmentparseexpectedexception.cpp000066400000000000000000000022611263712165300226030ustar00rootroot00000000000000#include "segmentparseexpectedexception.h" #include namespace dewalls { SegmentParseExpectedException::SegmentParseExpectedException(Segment segment, QList expectedItems) : SegmentParseException(segment), _expectedItems(expectedItems) { } SegmentParseExpectedException::SegmentParseExpectedException(Segment segment, QString expectedItem) : SegmentParseExpectedException(segment, QList({expectedItem})) { } SegmentParseExpectedException::SegmentParseExpectedException(Segment segment, std::initializer_list expectedItems) : SegmentParseExpectedException(segment, QList(expectedItems)) { } QString SegmentParseExpectedException::detailMessage() const { QSet uniq; QStringList uniqList; foreach (QString item, _expectedItems) { if (!uniq.contains(item)) { uniq << item; uniqList << item; } } if (uniqList.size() == 1) { return QString("Expected \"%1\"\n").arg(uniqList.first()); } return QString("Expected one of:\n %1\n").arg(uniqList.join("\n ")); } } // namespace dewalls dewalls-1.0.0/src/segmentparseexpectedexception.h000066400000000000000000000021011263712165300222410ustar00rootroot00000000000000#ifndef DEWALLS_SEGMENTPARSEEXPECTEDEXCEPTION_H #define DEWALLS_SEGMENTPARSEEXPECTEDEXCEPTION_H #include #include #include "segmentparseexception.h" #include #include "dewallsexport.h" namespace dewalls { class DEWALLS_LIB_EXPORT SegmentParseExpectedException : public SegmentParseException { public: SegmentParseExpectedException(Segment segment, QString expectedItem); SegmentParseExpectedException(Segment segment, QList expectedItems); SegmentParseExpectedException(Segment segment, std::initializer_list expectedItems); QList expectedItems() const; virtual QString detailMessage() const; virtual void raise() const { throw *this; } virtual SegmentParseException *clone() const { return new SegmentParseExpectedException(*this); } private: QList _expectedItems; }; inline QList SegmentParseExpectedException::expectedItems() const { return _expectedItems; } } // namespace dewalls #endif // DEWALLS_SEGMENTPARSEEXPECTEDEXCEPTION_H dewalls-1.0.0/src/signum.h000066400000000000000000000002141263712165300154100ustar00rootroot00000000000000#ifndef SIGNUM_H #define SIGNUM_H template int signum(T val) { return (T(0) < val) - (val < T(0)); } #endif // SIGNUM_H dewalls-1.0.0/src/unitizeddouble.h000066400000000000000000000152541263712165300171460ustar00rootroot00000000000000#ifndef DEWALLS_UNITIZEDDOUBLE_H #define DEWALLS_UNITIZEDDOUBLE_H #include #include #include #include "dewallsexport.h" #include "length.h" #include "angle.h" namespace dewalls { template class UnitizedDouble { public: typedef typename T::Unit Unit; UnitizedDouble(); UnitizedDouble(double quantity, Unit unit); UnitizedDouble(UnitizedDouble&& other); UnitizedDouble(const UnitizedDouble& other) = default; Unit unit() const; double get(Unit toUnit) const; UnitizedDouble in(Unit unit) const; inline bool isValid() const { return _unit != T::Invalid; } inline void clear() { _unit = T::Invalid; } inline bool isZero() const { return _unit && _quantity == 0.0; } inline bool isNonzero() const { return _unit && _quantity != 0.0; } inline bool isNegative() const { return _unit && _quantity < 0.0; } inline bool isPositive() const { return _unit && _quantity > 0.0; } double signum() const; friend void swap(UnitizedDouble& first, UnitizedDouble& second) { using std::swap; swap(first._quantity, second._quantity); swap(first._unit, second._unit); } UnitizedDouble& operator =(UnitizedDouble other); UnitizedDouble& operator +=(const UnitizedDouble& rhs); UnitizedDouble operator -(); UnitizedDouble& operator -=(const UnitizedDouble& rhs); UnitizedDouble& operator *=(const double& rhs); UnitizedDouble& operator /=(const double& rhs); UnitizedDouble& operator %=(const UnitizedDouble& rhs); QString toString() const; friend std::ostream& operator<<(std::ostream& os, const UnitizedDouble& obj) { return os << obj.toString().toStdString(); } private: Unit _unit; double _quantity; }; template class DEWALLS_LIB_EXPORT UnitizedDouble; template class DEWALLS_LIB_EXPORT UnitizedDouble; template inline UnitizedDouble::UnitizedDouble() : _unit(T::Invalid) { } template inline UnitizedDouble::UnitizedDouble(UnitizedDouble&& other) : UnitizedDouble() { swap(*this, other); } template inline double UnitizedDouble::signum() const { if (_unit) { return _quantity > 0.0 ? 1.0 : _quantity == 0.0 ? 0.0 : -1.0; } return NAN; } template inline UnitizedDouble& UnitizedDouble::operator =(UnitizedDouble other) { swap(*this, other); return *this; } template inline UnitizedDouble& UnitizedDouble::operator +=(const UnitizedDouble& rhs) { if (!rhs._unit) _unit = T::Invalid; else if (_unit) _quantity += rhs.get(_unit); return *this; } template inline UnitizedDouble UnitizedDouble::operator -() { return UnitizedDouble(-_quantity, _unit); } template inline UnitizedDouble& UnitizedDouble::operator -=(const UnitizedDouble& rhs) { if (!rhs._unit) _unit = T::Invalid; else if (_unit) _quantity -= rhs.get(_unit); return *this; } template inline UnitizedDouble& UnitizedDouble::operator *=(const double& rhs) { _quantity *= rhs; return *this; } template inline UnitizedDouble& UnitizedDouble::operator /=(const double& rhs) { _quantity /= rhs; return *this; } template inline UnitizedDouble& UnitizedDouble::operator %=(const UnitizedDouble& rhs) { if (!rhs._unit) _unit = T::Invalid; else if (_unit) _quantity = fmod(_quantity, rhs.get(_unit)); return *this; } template inline bool operator ==(const UnitizedDouble& lhs, const UnitizedDouble& rhs) { return lhs.unit() ? rhs.unit() && lhs.get(lhs.unit()) == rhs.get(lhs.unit()) : !rhs.unit(); } template inline bool operator !=(const UnitizedDouble& lhs, const UnitizedDouble& rhs) { return !operator ==(lhs, rhs); } template inline bool operator < (const UnitizedDouble& lhs, const UnitizedDouble& rhs) { return lhs.unit() && lhs.get(lhs.unit()) < rhs.get(lhs.unit()); } template inline bool operator > (const UnitizedDouble& lhs, const UnitizedDouble& rhs) { return operator < (rhs, lhs); } template inline bool operator <=(const UnitizedDouble& lhs, const UnitizedDouble& rhs) { return !operator > (rhs, lhs); } template inline bool operator >=(const UnitizedDouble& lhs, const UnitizedDouble& rhs) { return !operator < (rhs, lhs); } template inline UnitizedDouble operator +(UnitizedDouble lhs, const UnitizedDouble& rhs) { lhs += rhs; return lhs; } template inline UnitizedDouble operator -(UnitizedDouble lhs, const UnitizedDouble& rhs) { lhs -= rhs; return lhs; } template inline UnitizedDouble operator *(UnitizedDouble lhs, const double& rhs) { lhs *= rhs; return lhs; } template inline UnitizedDouble operator *(double lhs, const UnitizedDouble& rhs) { return rhs * lhs; } template inline UnitizedDouble operator /(UnitizedDouble lhs, const double& rhs) { lhs /= rhs; return lhs; } template inline UnitizedDouble operator /(double lhs, const UnitizedDouble& rhs) { return rhs.unit() ? UnitizedDouble(lhs / rhs.get(rhs.unit()), rhs.unit()) : UnitizedDouble(); } template inline double operator / (const UnitizedDouble& lhs, const UnitizedDouble& rhs) { return lhs.unit() && rhs.unit() ? lhs.get(lhs.unit()) / rhs.get(lhs.unit()) : NAN; } template inline UnitizedDouble operator %(UnitizedDouble lhs, const UnitizedDouble& rhs) { lhs %= rhs; return lhs; } template inline UnitizedDouble::UnitizedDouble(double quantity, Unit unit): _unit(unit), _quantity(quantity) { } template inline typename T::Unit UnitizedDouble::unit() const { return _unit; } template inline double UnitizedDouble::get(Unit toUnit) const { return T::convert(_quantity, _unit, toUnit); } template inline UnitizedDouble UnitizedDouble::in(typename T::Unit unit) const { return UnitizedDouble(get(unit), unit); } template inline QString UnitizedDouble::toString() const { if (!_unit) return ""; return QString("%1 %2").arg(_quantity).arg(T::symbolFor(_unit)); } } // namespace dewalls #endif // DEWALLS_UNITIZEDDOUBLE_H dewalls-1.0.0/src/unitizedmath.h000066400000000000000000000034471263712165300166260ustar00rootroot00000000000000#ifndef UNITIZEDMATH_H #define UNITIZEDMATH_H #include "angle.h" #include "unitizeddouble.h" #include namespace dewalls { inline double usin(UnitizedDouble u) { return sin(u.get(Angle::Radians)); } inline UnitizedDouble uasin(double value) { return UnitizedDouble(asin(value), Angle::Radians); } inline double ucos(UnitizedDouble u) { return cos(u.get(Angle::Radians)); } inline UnitizedDouble uacos(double value) { return UnitizedDouble(acos(value), Angle::Radians); } inline double utan(UnitizedDouble u) { return tan(u.get(Angle::Radians)); } inline UnitizedDouble uatan(double value) { return UnitizedDouble(atan(value), Angle::Radians); } inline UnitizedDouble uatan2(double y, double x) { return UnitizedDouble(atan2(y, x), Angle::Radians); } template inline UnitizedDouble uatan2(UnitizedDouble y, UnitizedDouble x) { return UnitizedDouble(atan2(y.get(y.unit()), x.get(y.unit())), Angle::Radians); } template inline UnitizedDouble usq(UnitizedDouble x) { double val = x.get(x.unit()); return UnitizedDouble(val * val, x.unit()); } template inline UnitizedDouble umul(UnitizedDouble a, UnitizedDouble b) { if (!a.isValid() || !b.isValid()) return UnitizedDouble(); return UnitizedDouble(a.get(a.unit()) * b.get(a.unit()), a.unit()); } template inline UnitizedDouble usqrt(UnitizedDouble x) { return UnitizedDouble(sqrt(x.get(x.unit())), x.unit()); } template inline UnitizedDouble uabs(UnitizedDouble x) { return UnitizedDouble(fabs(x.get(x.unit())), x.unit()); } } #endif // UNITIZEDMATH_H dewalls-1.0.0/src/varianceoverride.cpp000066400000000000000000000004511263712165300177740ustar00rootroot00000000000000#include "varianceoverride.h" namespace dewalls { const QSharedPointer VarianceOverride::FLOATED(new FloatedVarianceOverride()); const QSharedPointer VarianceOverride::FLOATED_TRAVERSE(new FloatedTraverseVarianceOverride()); } // namespace dewalls dewalls-1.0.0/src/varianceoverride.h000066400000000000000000000054741263712165300174530ustar00rootroot00000000000000#ifndef DEWALLS_VARIANCEOVERRIDE_H #define DEWALLS_VARIANCEOVERRIDE_H #include #include #include "unitizeddouble.h" #include "length.h" #include "dewallsexport.h" namespace dewalls { class FloatedVarianceOverride; class FloatedTraverseVarianceOverride; class DEWALLS_LIB_EXPORT VarianceOverride { public: enum class Type { FLOATED = 0, FLOATED_TRAVERSE = 1, LENGTH_OVERRIDE = 2, RMS_ERROR = 3 }; virtual ~VarianceOverride() {} virtual Type type() const = 0; virtual QString toString() const = 0; static const QSharedPointer FLOATED; static const QSharedPointer FLOATED_TRAVERSE; protected: inline VarianceOverride() { } }; class DEWALLS_LIB_EXPORT FloatedVarianceOverride : public VarianceOverride { public: inline FloatedVarianceOverride() : VarianceOverride() { } inline virtual Type type() const { return Type::FLOATED; } inline virtual QString toString() const { return "?"; } }; class DEWALLS_LIB_EXPORT FloatedTraverseVarianceOverride : public VarianceOverride { public: inline FloatedTraverseVarianceOverride() : VarianceOverride() { } inline virtual Type type() const { return Type::FLOATED_TRAVERSE; } inline virtual QString toString() const { return "*"; } }; class DEWALLS_LIB_EXPORT LengthOverride : public VarianceOverride { public: inline LengthOverride(UnitizedDouble lengthOverride) : VarianceOverride(), _lengthOverride(lengthOverride) { } inline virtual Type type() const { return Type::LENGTH_OVERRIDE; } inline virtual QString toString() const { return _lengthOverride.toString(); } inline UnitizedDouble lengthOverride() const { return _lengthOverride; } private: LengthOverride() = delete; LengthOverride(const LengthOverride& that) = delete; UnitizedDouble _lengthOverride; }; class DEWALLS_LIB_EXPORT RMSError : public VarianceOverride { public: inline RMSError(UnitizedDouble error) : VarianceOverride(), _error(error) { } inline virtual Type type() const { return Type::RMS_ERROR; } inline virtual QString toString() const { return "R" + _error.toString(); } inline UnitizedDouble error() const { return _error; } private: RMSError() = delete; RMSError(const RMSError& that) = delete; UnitizedDouble _error; }; } // namespace dewalls #endif // DEWALLS_VARIANCEOVERRIDE_H dewalls-1.0.0/src/vector.cpp000066400000000000000000000140341263712165300157500ustar00rootroot00000000000000#include "vector.h" #include "unitizedmath.h" #include "segmentparseexception.h" #include namespace dewalls { void Vector::deriveCtFromRect() { ULength ne2 = usq(north()) + usq(east()); ULength ne = usqrt(ne2); // horizontal offset ULength up = rectUp(); if (!up.isValid()) up = ULength(0, Length::Meters); setDistance(usqrt(ne2 + usq(up)).in(units().dUnit()) - units().incd()); UAngle azm = uatan2(east(), north()).in(units().aUnit()) - units().inca(); if (azm < UAngle(0, Angle::Degrees)) { azm += UAngle(360.0, Angle::Degrees); } setFrontAzimuth(azm); setFrontInclination(uatan2(up, ne).in(units().vUnit()) - units().incv()); } bool Vector::isVertical() { return units().isVertical(frontInclination(), frontAzimuth()); } bool Vector::applyHeightCorrections() { if (!isVertical() && (units().inch().isNonzero() || instHeight().isNonzero() || targetHeight().isNonzero())) { // get corrected average inclination (default to zero) UAngle inc = units().avgInc(frontInclination() + units().incv(), backInclination() + units().incvb()); // get corrected distance ULength tapeDist = distance() + units().incd(); // get corrected instrument and target heights (default to zero) ULength _instHeight = instHeight() + units().incs(); if (!_instHeight.isValid()) _instHeight = ULength(0, tapeDist.unit()); ULength _targetHeight = targetHeight() + units().incs(); if (!_targetHeight.isValid()) _targetHeight = ULength(0, tapeDist.unit()); ULength stationToStationDist; UAngle stationToStationInc; if (units().tape()[0] == TapingMethodMeasurement::Station && units().tape()[1] == TapingMethodMeasurement::Station && (!inc.isValid() || inc.isZero())) { // this is a dive-style shot stationToStationDist = tapeDist; ULength heightOffset = _instHeight - _targetHeight; if (uabs(heightOffset) > tapeDist * (1 + 1e-6)) { throw SegmentParseException(sourceSegment(), "instrument and target height difference is greater than tape distance; this is impossible"); } if (uabs(uabs(heightOffset) - tapeDist) < tapeDist * 1e-8) { // vertical shot stationToStationInc = heightOffset.isPositive() ? UAngle(90.0, Angle::Degrees) : UAngle(-90.0, Angle::Degrees); stationToStationDist = uabs(heightOffset + units().inch()); } else { if (units().inch().isNonzero()) { ULength horizDistance = usqrt(usq(tapeDist) - usq(heightOffset)); ULength totalHeightOffset = heightOffset + units().inch(); stationToStationDist = usqrt(usq(horizDistance) + usq(totalHeightOffset)); stationToStationInc = uatan2(totalHeightOffset, horizDistance); } else { stationToStationInc = uasin(heightOffset / tapeDist); } } } if (!stationToStationInc.isValid()){ if (!inc.isValid()) inc = UAngle(0, Angle::Degrees); // compute height of tape ends above stations ULength tapeFromHeight = units().tape()[0] == TapingMethodMeasurement::Station ? ULength(0, tapeDist.unit()) : _instHeight; ULength tapeToHeight = units().tape()[1] == TapingMethodMeasurement::Station ? ULength(0, tapeDist.unit()) : _targetHeight; // compute height of instrument and target above tape ends ULength instHeightAboveTape = _instHeight - tapeFromHeight; ULength targetHeightAboveTape = _targetHeight - tapeToHeight; // height change between tape vector and instrument to target vector ULength delta = instHeightAboveTape - targetHeightAboveTape; if (uabs(delta) > tapeDist) { throw SegmentParseException(sourceSegment(), "vector is ambiguous because abs(instrument height above tape - target height above tape) > distance. In this case, there are two possible vectors that fulfill the constraints imposed by the measurements. Split this shot into two shots (one vertical) to make it unambiguous."); } // compute instrument to target distance // it's difficult to justify this equation in pure text, it requires a geometric proof ULength instToTargetDist = usqrt(usq(tapeDist) - usq(delta * ucos(inc))) - delta * usin(inc); // height change between inst to target vector and final corrected vector ULength totalDelta = _instHeight - _targetHeight + units().inch(); // compute station to station distance and inclination stationToStationDist = usqrt(usq(instToTargetDist * usin(inc) + totalDelta) + usq(instToTargetDist * ucos(inc))); stationToStationInc = uatan2(instToTargetDist * usin(inc) + totalDelta, instToTargetDist * ucos(inc)); } // make sure to subtract corrections so that when they are applied later, // they will produce the same vector calculated here setDistance(stationToStationDist - units().incd()); if (!frontInclination().isValid() && !backInclination().isValid()) { setFrontInclination(stationToStationInc - units().incv()); } else { UAngle dInc = stationToStationInc - inc; // since we are moving the original vectors by the difference, we don't need to subtract the // correction factors -- they're already present setFrontInclination(frontInclination() + dInc); setBackInclination (backInclination () + dInc); } // clear out the instrument and target heights, since the vector is now fully determined by the // distance and inclination setInstHeight(ULength()); setTargetHeight(ULength()); return true; } return false; } } // namespace dewalls dewalls-1.0.0/src/vector.h000066400000000000000000000137651263712165300154270ustar00rootroot00000000000000#ifndef DEWALLS_VECTOR_H #define DEWALLS_VECTOR_H #include "unitizeddouble.h" #include "segment.h" #include "length.h" #include "angle.h" #include "varianceoverride.h" #include #include #include #include #include #include "wallsunits.h" #include "dewallsexport.h" namespace dewalls { class VectorData : public QSharedData { public: typedef UnitizedDouble ULength; typedef UnitizedDouble UAngle; typedef QSharedPointer VarianceOverridePtr; inline VectorData() : QSharedData(), sourceSegment(), from(), to(), distance(), frontAzimuth(), backAzimuth(), frontInclination(), backInclination(), instHeight(), targetHeight(), north(), east(), rectUp(), horizVariance(), vertVariance(), left(), right(), up(), down(), lrudAngle(), cFlag(false), segment(), comment(), date(), units() { } Segment sourceSegment; QString from; QString to; ULength distance; UAngle frontAzimuth; UAngle backAzimuth; UAngle frontInclination; UAngle backInclination; ULength instHeight; ULength targetHeight; ULength north; ULength east; ULength rectUp; VarianceOverridePtr horizVariance; VarianceOverridePtr vertVariance; ULength left; ULength right; ULength up; ULength down; UAngle lrudAngle; bool cFlag; QStringList segment; QString comment; QDate date; WallsUnits units; }; class DEWALLS_LIB_EXPORT Vector { public: typedef UnitizedDouble ULength; typedef UnitizedDouble UAngle; typedef QSharedPointer VarianceOverridePtr; inline Vector() { d = new VectorData; } inline Vector(const Vector& other) : d(other.d) { } inline Segment sourceSegment() const { return d->sourceSegment; } inline QString from() const { return d->from; } inline QString to() const { return d->to; } inline ULength distance() const { return d->distance; } inline UAngle frontAzimuth() const { return d->frontAzimuth; } inline UAngle backAzimuth() const { return d->backAzimuth; } inline UAngle frontInclination() const { return d->frontInclination; } inline UAngle backInclination() const { return d->backInclination; } inline ULength instHeight() const { return d->instHeight; } inline ULength targetHeight() const { return d->targetHeight; } inline ULength north() const { return d->north; } inline ULength east() const { return d->east; } inline ULength rectUp() const { return d->rectUp; } inline VarianceOverridePtr horizVariance() const { return d->horizVariance; } inline VarianceOverridePtr vertVariance() const { return d->vertVariance; } inline ULength left() const { return d->left; } inline ULength right() const { return d->right; } inline ULength up() const { return d->up; } inline ULength down() const { return d->down; } inline UAngle lrudAngle() const { return d->lrudAngle; } inline bool cFlag() const { return d->cFlag; } inline QStringList segment() const { return d->segment; } inline QString comment() const { return d->comment; } inline QDate date() const { return d->date; } inline WallsUnits units() const { return d->units; } inline void setSourceSegment(Segment sourceSegment) { d->sourceSegment = sourceSegment; } inline void setFrom(QString from) { d->from = from; } inline void setTo(QString to) { d->to = to; } inline void setDistance(ULength distance) { d->distance = distance; } inline void setFrontAzimuth(UAngle frontAzimuth) { d->frontAzimuth = frontAzimuth; } inline void setBackAzimuth(UAngle backAzimuth) { d->backAzimuth = backAzimuth; } inline void setFrontInclination(UAngle frontInclination) { d->frontInclination = frontInclination; } inline void setBackInclination(UAngle backInclination) { d->backInclination = backInclination; } inline void setInstHeight(ULength instHeight) { d->instHeight = instHeight; } inline void setTargetHeight(ULength targetHeight) { d->targetHeight = targetHeight; } inline void setNorth(ULength north) { d->north = north; } inline void setEast(ULength east) { d->east = east; } inline void setRectUp(ULength rectUp) { d->rectUp = rectUp; } inline void setHorizVariance(VarianceOverridePtr horizVariance) { d->horizVariance = horizVariance; } inline void setVertVariance(VarianceOverridePtr vertVariance) { d->vertVariance = vertVariance; } inline void setLeft(ULength left) { d->left = left; } inline void setRight(ULength right) { d->right = right; } inline void setUp(ULength up) { d->up = up; } inline void setDown(ULength down) { d->down = down; } inline void setLrudAngle(UAngle lrudAngle) { d->lrudAngle = lrudAngle; } inline void setCFlag(bool cFlag) { d->cFlag = cFlag; } inline void setSegment(QStringList segment) { d->segment = segment; } inline void setComment(QString comment) { d->comment = comment; } inline void setDate(QDate date) { d->date = date; } inline void setUnits(WallsUnits units) { d->units = units; } /// /// \brief derives compass-and-tape measurements from the rect measurements. /// void deriveCtFromRect(); /// /// \brief calculates the vector offset including instrument and target heights and Walls INCH /// correction, rederives the distance and inclinations from that offset, and clears the instrument /// and target heights. This is for programs that don't store instrument and target heights or /// something like INCH internally. /// \return true iff height corrections were applied /// bool applyHeightCorrections(); bool isVertical(); private: QSharedDataPointer d; }; } // namespace dewalls //Q_DECLARE_METATYPE(dewalls::Vector) #endif // DEWALLS_VECTOR_H dewalls-1.0.0/src/wallsmessage.cpp000066400000000000000000000031351263712165300171350ustar00rootroot00000000000000#include "wallsmessage.h" namespace dewalls { WallsMessage::WallsMessage(QString severity, QString message, QString source, int startLine, int startColumn, int endLine, int endColumn, QString context) : Severity(severity), Message(message), Source(source), StartLine(startLine), StartColumn(startColumn), EndLine(endLine), EndColumn(endColumn), Context(context) { } WallsMessage::WallsMessage(QString severity, QString message, Segment segment) : Severity(severity), Message(message), Source(segment.source()), StartLine(segment.startLine()), StartColumn(segment.startCol()), EndLine(segment.endLine()), EndColumn(segment.endCol()), Context(segment.underlineInContext()) { } WallsMessage::WallsMessage(const SegmentParseException& ex) : Severity("error"), Message(ex.detailMessage()), Source(ex.segment().source()), StartLine(ex.segment().startLine()), StartColumn(ex.segment().startCol()), EndLine(ex.segment().endLine()), EndColumn(ex.segment().endCol()), Context(ex.segment().underlineInContext()) { } QString WallsMessage::toString() { QString result = QString("%1: %2").arg(Severity, Message); if (!Context.isNull()) { result += "\n" + Context; } if (!Source.isNull()) { result += "\n(" + Source; if (StartLine >= 0) { result += QString(", line %1").arg(StartLine + 1); if (StartColumn >= 0) { result += QString(", column %1").arg(StartColumn + 1); } } result += ")"; } return result; } } // namespace dewalls dewalls-1.0.0/src/wallsmessage.h000066400000000000000000000025331263712165300166030ustar00rootroot00000000000000#ifndef DEWALLS_WALLSMESSAGE_H #define DEWALLS_WALLSMESSAGE_H #include #include "segmentparseexception.h" #include "dewallsexport.h" namespace dewalls { /// /// \brief a message emitted by WallsSurveyParser or WallsProjectParser, usually an error or a /// warning /// class DEWALLS_LIB_EXPORT WallsMessage { public: WallsMessage(QString severity, QString message, QString source = QString(), int startLine = -1, int startColumn = -1, int endLine = -1, int endColumn = -1, QString context = QString()); WallsMessage(QString severity, QString message, Segment segment); WallsMessage(const SegmentParseException& ex); inline QString severity() const { return Severity; } inline QString message() const { return Message; } inline QString source() const { return Source; } inline QString context() const { return Context; } inline int startLine() const { return StartLine; } inline int startColumn() const { return StartColumn; } inline int endLine() const { return EndLine; } inline int endColumn() const { return EndColumn; } QString toString(); private: QString Severity; QString Message; QString Source; int StartLine; int StartColumn; int EndLine; int EndColumn; QString Context; }; } // namespace dewalls #endif // DEWALLS_WALLSMESSAGE_H dewalls-1.0.0/src/wallsprojectparser.cpp000066400000000000000000000274241263712165300204030ustar00rootroot00000000000000#include "wallsprojectparser.h" #include #include #include #include "signum.h" #include "segment.h" #include "segmentparseexception.h" namespace dewalls { typedef UnitizedDouble ULength; typedef UnitizedDouble UAngle; // STATUS BITS // 2^0 : Type = Book // 2^1 : ? // 2^2 : ? // 2^3 : Name defines segment // 2^4 : 1 = Feet, 0 = Meters // 2^5 : ? // 2^6 : reference unspecified // 2^7 : ? // Derive decl from date: // 2^8 : 1 = no // 2^9 : 1 = yes // UTM/GPS Grid-relative: // 2^10: 1 = no // 2^11: 1 = yes // Preserve vertical shot orientation: // 2^12: 1 = no // 2^13: 1 = yes // Preserve vertical shot length: // 2^14: 1 = no // 2^15: 1 = yes // Other type // 2^16: 1 = type is other // 2^17: edit on launch // 2^18: open on launch // Default view after compilation (bits 21-19): // 1: North or East // 10: North or West // 11: North // 100: East // 101: West // REFERENCE FIELDS // northing easting zn conv el ? d m s lat d m s long index/name // .REF 2308552.729 324501.432 16 -0.601 27 6 20 52 14.229 88 41 13.085 0 "Adindan" WallsProjectParser::WallsProjectParser(QObject* parent) : QObject(parent), LineParser() { } WpjEntry::WpjEntry(WpjBookPtr parent, QString title) : Parent(parent), Title(title), Name(), Path(), Status(0), Options(), Reference() { } WpjBook::WpjBook(WpjBookPtr parent, QString title) : WpjEntry(parent, title) { } const int WpjEntry::NameDefinesSegmentBit = 1 << 3; const int WpjEntry::FeetBit = 1 << 4; const int WpjEntry::ReferenceUnspecifiedBit = 1 << 6; const int WpjEntry::DontDeriveDeclBit = 1 << 8; const int WpjEntry::DeriveDeclBit = 1 << 9; const int WpjEntry::NotGridRelativeBit = 1 << 10; const int WpjEntry::GridRelativeBit = 1 << 11; const int WpjEntry::DontPreserveVertShotOrientationBit = 1 << 12; const int WpjEntry::PreserveVertShotOrientationBit = 1 << 13; const int WpjEntry::DontPreserveVertShotLengthBit = 1 << 14; const int WpjEntry::PreserveVertShotLengthBit = 1 << 15; const int WpjEntry::OtherTypeBit = 1 << 16; const int WpjEntry::EditOnLaunchBit = 1 << 17; const int WpjEntry::OpenOnLaunchBit = 1 << 18; const int WpjEntry::DefaultViewAfterCompilationMask = 7 << 19; const int WpjEntry::NorthOrEastViewBits = 1 << 19; const int WpjEntry::NorthOrWestViewBits = 2 << 19; const int WpjEntry::NorthViewBits = 3 << 19; const int WpjEntry::EastViewBits = 4 << 19; const int WpjEntry::WestViewBits = 5 << 19; bool WpjEntry::isOther() const { return Status & OtherTypeBit; } bool WpjEntry::isSurvey() const { return !isBook() && !isOther(); } bool WpjEntry::nameDefinesSegment() const { return Status & NameDefinesSegmentBit; } GeoReferencePtr WpjEntry::reference() const { if (Status & ReferenceUnspecifiedBit) { return GeoReferencePtr(); } if (!Reference.isNull()) { return Reference; } if (!Parent.isNull()) { return Parent->reference(); } return GeoReferencePtr(); } WpjEntry::ReviewUnits WpjEntry::reviewUnits() const { return Status & FeetBit ? Feet : Meters; } bool WpjEntry::deriveDeclFromDate() const { if (Status & DontDeriveDeclBit) { return false; } if (Status & DeriveDeclBit) { return true; } if (!Parent.isNull()) { return Parent->deriveDeclFromDate(); } return false; } bool WpjEntry::gridRelative() const { if (Status & NotGridRelativeBit) { return false; } if (Status & GridRelativeBit) { return true; } if (!Parent.isNull()) { return Parent->gridRelative(); } return false; } bool WpjEntry::preserveVertShotOrientation() const { if (Status & DontPreserveVertShotOrientationBit) { return false; } if (Status & PreserveVertShotOrientationBit) { return true; } if (!Parent.isNull()) { return Parent->preserveVertShotOrientation(); } return false; } bool WpjEntry::preserveVertShotLength() const { if (Status & DontPreserveVertShotLengthBit) { return false; } if (Status & PreserveVertShotLengthBit) { return true; } if (!Parent.isNull()) { return Parent->preserveVertShotLength(); } return false; } WpjEntry::LaunchOptions WpjEntry::launchOptions() const { if (Status & EditOnLaunchBit) { return Edit; } if (Status & OpenOnLaunchBit) { return Open; } return Properties; } WpjEntry::View WpjEntry::defaultViewAfterCompilation() const { switch (Status & DefaultViewAfterCompilationMask) { case NorthOrEastViewBits: return NorthOrEast; case NorthOrWestViewBits: return NorthOrWest; case NorthViewBits: return North; case EastViewBits: return East; case WestViewBits: return West; default: if (!Parent.isNull()) { return Parent->defaultViewAfterCompilation(); } return NorthOrEast; } } QDir WpjEntry::dir() const { if (Parent.isNull() || QDir::isAbsolutePath(Path)) { return QDir(Path); } if (!Path.isNull()) { return QDir(QDir::cleanPath(Parent->dir().path() + '/' + Path)); } return Parent->dir(); } QString WpjEntry::absolutePath() const { if (isBook()) { return QDir::cleanPath(dir().absolutePath()); } else { QString name = Name.value(); if (name.isEmpty()) { return QString(); } if (isSurvey() && !name.endsWith(".SRV", Qt::CaseInsensitive)) { if (QFileInfo(QDir::cleanPath(dir().absoluteFilePath(name + ".SRV"))).exists()) { name += ".SRV"; } else if (QFileInfo(QDir::cleanPath(dir().absoluteFilePath(name + ".srv"))).exists()) { name += ".srv"; } else { name += ".SRV"; } } return QDir::cleanPath(dir().absoluteFilePath(name)); } } QList WpjEntry::allOptions() const { QList options; if (!Parent.isNull()) { options = Parent->allOptions(); } if (!Options.isEmpty()) { options << Options; } return options; } QStringList WpjEntry::segment() const { QStringList result; if (!Parent.isNull()) { result = Parent->segment(); } if (nameDefinesSegment() && !Name.isEmpty()) { result << Name.value(); } return result; } void WallsProjectParser::parseLine(QString line) { parseLine(Segment(line)); } void WallsProjectParser::parseLine(Segment line) { reset(line); maybeWhitespace(); if (ProjectRoot.isNull()) { oneOf([&]() { this->bookLine(); }, [&]() { this->commentLine(); }, [&]() { this->emptyLine(); }); } else if (CurrentEntry.isNull()) { oneOf([&]() { this->commentLine(); }, [&]() { this->emptyLine(); }); } else { oneOf([&]() { this->bookLine(); }, [&]() { this->endbookLine(); }, [&]() { this->surveyLine(); }, [&]() { this->nameLine(); }, [&]() { this->pathLine(); }, [&]() { this->refLine(); }, [&]() { this->optionsLine(); }, [&]() { this->statusLine(); }, [&]() { this->commentLine(); }, [&]() { this->emptyLine(); }); } } void WallsProjectParser::emptyLine() { maybeWhitespace(); endOfLine(); } void WallsProjectParser::bookLine() { expect(".BOOK", Qt::CaseInsensitive); whitespace(); QString title = remaining().value(); WpjBookPtr parent = currentBook(); WpjBookPtr newEntry(new WpjBook(parent, title)); if (!parent.isNull()) { parent->Children << newEntry; } else { ProjectRoot = newEntry; } CurrentEntry = newEntry; } void WallsProjectParser::endbookLine() { expect(".ENDBOOK", Qt::CaseInsensitive); maybeWhitespace(); endOfLine(); CurrentEntry = currentBook()->Parent; } void WallsProjectParser::nameLine() { expect(".NAME", Qt::CaseInsensitive); whitespace(); CurrentEntry->Name = remaining(); } void WallsProjectParser::pathLine() { expect(".PATH", Qt::CaseInsensitive); whitespace(); CurrentEntry->Path = remaining().value(); } void WallsProjectParser::surveyLine() { expect(".SURVEY", Qt::CaseInsensitive); whitespace(); QString title = remaining().value(); WpjBookPtr book = currentBook(); WpjEntryPtr newEntry(new WpjEntry(book, title)); book->Children << newEntry; CurrentEntry = newEntry; } void WallsProjectParser::statusLine() { expect(".STATUS", Qt::CaseInsensitive); whitespace(); CurrentEntry->Status = unsignedIntLiteral(); } void WallsProjectParser::optionsLine() { expect(".OPTIONS", Qt::CaseInsensitive); whitespace(); CurrentEntry->Options = remaining(); } void WallsProjectParser::commentLine() { expect(";"); remaining(); } void WallsProjectParser::refLine() { expect(".REF", Qt::CaseInsensitive); whitespace(); GeoReference ref; ref.northing = ULength(doubleLiteral(), Length::Meters); whitespace(); ref.easting = ULength(doubleLiteral(), Length::Meters); whitespace(); ref.zone = intLiteral(); whitespace(); ref.gridConvergence = UAngle(doubleLiteral(), Angle::Degrees); whitespace(); ref.elevation = ULength(doubleLiteral(), Length::Meters); whitespace(); doubleLiteral(); // don't know what this field represents whitespace(); double degrees, minutes, seconds; degrees = intLiteral(); whitespace(); minutes = unsignedIntLiteral(); whitespace(); seconds = unsignedDoubleLiteral(); whitespace(); ref.latitude = UAngle(degrees + ((minutes + seconds / 60.0) / 60.0) * signum(degrees), Angle::Degrees); degrees = intLiteral(); whitespace(); minutes = unsignedIntLiteral(); whitespace(); seconds = unsignedDoubleLiteral(); whitespace(); ref.longitude = UAngle(degrees + ((minutes + seconds / 60.0) / 60.0) * signum(degrees), Angle::Degrees); ref.wallsDatumIndex = unsignedIntLiteral(); whitespace(); expect('"'); ref.datumName = expect(QRegExp("[^\"]+"), {""}).value(); expect('"'); maybeWhitespace(); endOfLine(); CurrentEntry->Reference = GeoReferencePtr(new GeoReference); *(CurrentEntry->Reference) = ref; } WpjBookPtr WallsProjectParser::parseFile(QString fileName) { QFile file(fileName); if (!file.open(QFile::ReadOnly)) { QString msg = QString("I couldn't open %1").arg(fileName); emit message(WallsMessage("error", msg)); return WpjBookPtr(); } int lineNumber = 0; while (!file.atEnd() && (ProjectRoot.isNull() || !CurrentEntry.isNull())) { QString line = file.readLine(); line = line.trimmed(); if (file.error() != QFile::NoError) { emit message(WallsMessage("error", QString("failed to read from file: %1").arg(file.errorString()), fileName, lineNumber)); file.close(); return WpjBookPtr(); } try { parseLine(Segment(line, fileName, lineNumber, 0)); } catch (const SegmentParseException& ex) { emit message(WallsMessage(ex)); file.close(); return WpjBookPtr(); } lineNumber++; } file.close(); // not enough .ENDBOOKs at end? if (!CurrentEntry.isNull()) { emit message(WallsMessage("error", QString("unexpected end of file: %1").arg(fileName), fileName, lineNumber)); return WpjBookPtr(); } if (!ProjectRoot.isNull()) { ProjectRoot->Path = QFileInfo(fileName).dir().canonicalPath(); } return ProjectRoot; } } // namespace dewalls dewalls-1.0.0/src/wallsprojectparser.h000066400000000000000000000121641263712165300200430ustar00rootroot00000000000000#ifndef DEWALLS_WALLSPROJECTPARSER_H #define DEWALLS_WALLSPROJECTPARSER_H #include #include #include #include #include #include #include #include "unitizeddouble.h" #include "dewallsexport.h" #include "angle.h" #include "length.h" #include "wallsmessage.h" #include "lineparser.h" namespace dewalls { class Segment; struct DEWALLS_LIB_EXPORT GeoReference { typedef UnitizedDouble ULength; typedef UnitizedDouble UAngle; // positive for north, negative for south int zone; ULength northing; ULength easting; UAngle gridConvergence; ULength elevation; UAngle latitude; UAngle longitude; int wallsDatumIndex; QString datumName; }; typedef QSharedPointer GeoReferencePtr; class WpjEntry; class WpjBook; typedef QSharedPointer WpjEntryPtr; typedef QSharedPointer WpjBookPtr; /// /// \brief an item in a Walls project tree (a book, survey, or other file) /// class DEWALLS_LIB_EXPORT WpjEntry { public: enum ReviewUnits { Meters = 0, Feet = 1 }; enum LaunchOptions { Properties = 0, Edit = 1, Open = 2 }; enum View { NorthOrEast = 0, NorthOrWest = 1, North = 2, East = 3, West = 4 }; WpjEntry(WpjBookPtr parent, QString title); virtual ~WpjEntry() {} const WpjBookPtr Parent; // display name const QString Title; // the file name (relative to path if given) Segment Name; // the path of the directory in which the file is found relative to the parent QString Path; int Status; // extra #units options Segment Options; GeoReferencePtr Reference; bool referenceInherited() const; GeoReferencePtr reference() const; virtual bool isBook() const { return false; } bool isOther() const; bool isSurvey() const; bool nameDefinesSegment() const; ReviewUnits reviewUnits() const; bool deriveDeclFromDate() const; bool gridRelative() const; bool preserveVertShotOrientation() const; bool preserveVertShotLength() const; LaunchOptions launchOptions() const; View defaultViewAfterCompilation() const; /** * @return the directory where this entry's file (or this book's subentries' files) * is located */ QDir dir() const; /** * @return the absolute path to this entry's file (or this book's directory) */ QString absolutePath() const; /** * @return the inherited and own #units options for this entry (or this book's subentries) */ QList allOptions() const; /** * @return the starting segment for this entry */ QStringList segment() const; static const int BookTypeBit; static const int NameDefinesSegmentBit; static const int FeetBit; static const int ReferenceUnspecifiedBit; static const int DontDeriveDeclBit; static const int DeriveDeclBit; static const int NotGridRelativeBit; static const int GridRelativeBit; static const int DontPreserveVertShotOrientationBit; static const int PreserveVertShotOrientationBit; static const int DontPreserveVertShotLengthBit; static const int PreserveVertShotLengthBit; static const int OtherTypeBit; static const int EditOnLaunchBit; static const int OpenOnLaunchBit; static const int DefaultViewAfterCompilationMask; static const int NorthOrEastViewBits; static const int NorthOrWestViewBits; static const int NorthViewBits; static const int EastViewBits; static const int WestViewBits; }; /// /// \brief a book in a Walls project tree (data between .BOOK and .ENDBOOK lines) /// class DEWALLS_LIB_EXPORT WpjBook : public WpjEntry { public: WpjBook(WpjBookPtr parent, QString title); virtual ~WpjBook() {} virtual bool isBook() const { return true; } QList Children; }; /// /// \brief parses a Walls project file (.WPJ). You may either pass in a file /// to parseFile() and get back a project tree, or call parseLine() yourself /// on the lines of the file and get the project tree from result(). /// class DEWALLS_LIB_EXPORT WallsProjectParser : public QObject, public LineParser { Q_OBJECT public: WallsProjectParser(QObject* parent = 0); void parseLine(QString line); void parseLine(Segment line); WpjBookPtr parseFile(QString file); void emptyLine(); void bookLine(); void endbookLine(); void surveyLine(); void nameLine(); void refLine(); void optionsLine(); void statusLine(); void pathLine(); void commentLine(); inline WpjBookPtr result() const { return ProjectRoot; } inline WpjBookPtr currentBook() const { if (CurrentEntry.isNull()) { return WpjBookPtr(); } if (CurrentEntry->isBook()) { return CurrentEntry.dynamicCast(); } return CurrentEntry->Parent; } signals: void message(WallsMessage message); private: WpjEntryPtr CurrentEntry; WpjBookPtr ProjectRoot; }; } // namespace dewalls #endif // DEWALLS_WALLSPROJECTPARSER_H dewalls-1.0.0/src/wallssurveyparser.cpp000066400000000000000000001504421263712165300202670ustar00rootroot00000000000000#include "wallssurveyparser.h" #include "unitizedmath.h" namespace dewalls { typedef UnitizedDouble ULength; typedef UnitizedDouble UAngle; typedef QSharedPointer VarianceOverridePtr; typedef void (WallsSurveyParser::*OwnProduction)(); QHash WallsSurveyParser::createLengthUnits() { QHash result; result["meters"] = result["meter"] = result["m"] = Length::Meters; result["feet"] = result["foot"] = result["ft"] = result["f"] = Length::Feet; return result; } QHash WallsSurveyParser::createAzmUnits() { QHash result; result["degree"] = result["degree"] = result["deg"] = result["d"] = Angle::Degrees; result["mills"] = result["mils"] = result["mil"] = result["m"] = Angle::MilsNATO; result["grads"] = result["grad"] = result["g"] = Angle::Gradians; return result; } QHash WallsSurveyParser::createIncUnits() { QHash result; result["degrees"] = result["degree"] = result["deg"] = result["d"] = Angle::Degrees; result["mills"] = result["mils"] = result["mil"] = result["m"] = Angle::MilsNATO; result["grads"] = result["grad"] = result["g"] = Angle::Gradians; result["percent"] = result["p"] = Angle::PercentGrade; return result; } QHash WallsSurveyParser::createLengthUnitSuffixes() { QHash result; result['m'] = result['M'] = Length::Meters; result['f'] = result['F'] = Length::Feet; result['i'] = result['I'] = Length::Inches; return result; } QHash WallsSurveyParser::createAzmUnitSuffixes() { QHash result; result['d'] = result['D'] = Angle::Degrees; result['g'] = result['G'] = Angle::Gradians; result['m'] = result['M'] = Angle::MilsNATO; return result; } QHash WallsSurveyParser::createIncUnitSuffixes() { QHash result; result['d'] = result['D'] = Angle::Degrees; result['g'] = result['G'] = Angle::Gradians; result['m'] = result['M'] = Angle::MilsNATO; result['p'] = result['P'] = Angle::PercentGrade; return result; } QHash WallsSurveyParser::createCardinalDirections() { QHash result; result['n'] = result['N'] = CardinalDirection::North; result['s'] = result['S'] = CardinalDirection::South; result['e'] = result['E'] = CardinalDirection::East; result['w'] = result['W'] = CardinalDirection::West; return result; } QHash WallsSurveyParser::createNorthSouth() { QHash result; result['n'] = result['N'] = CardinalDirection::North; result['s'] = result['S'] = CardinalDirection::South; return result; } QHash WallsSurveyParser::createEastWest() { QHash result; result['e'] = result['E'] = CardinalDirection::East; result['w'] = result['W'] = CardinalDirection::West; return result; } QHash WallsSurveyParser::createEscapedChars() { QHash result; result['r'] = 'r'; result['n'] = 'n'; result['f'] = 'f'; result['t'] = 't'; result['"'] = '"'; result['\\'] = '\\'; return result; } QHash WallsSurveyParser::createCtElements() { QHash result; result['d'] = result['D'] = CtMeasurement::D; result['a'] = result['A'] = CtMeasurement::A; result['v'] = result['V'] = CtMeasurement::V; return result; } QHash WallsSurveyParser::createRectElements() { QHash result; result['e'] = result['E'] = RectMeasurement::E; result['n'] = result['N'] = RectMeasurement::N; result['u'] = result['U'] = RectMeasurement::U; return result; } QHash WallsSurveyParser::createLrudElements() { QHash result; result['l'] = result['L'] = LrudMeasurement::L; result['r'] = result['R'] = LrudMeasurement::R; result['u'] = result['U'] = LrudMeasurement::U; result['d'] = result['D'] = LrudMeasurement::D; return result; } QHash WallsSurveyParser::createCorrectedValues() { QHash result; result["corrected"] = result["c"] = true; result["normal"] = result["n"] = false; return result; } QHash WallsSurveyParser::createCaseTypes() { QHash result; result["upper"] = result["u"] = CaseType::Upper; result["lower"] = result["l"] = CaseType::Lower; result["mixed"] = result["m"] = CaseType::Mixed; return result; } QHash WallsSurveyParser::createLrudTypes() { QHash result; result["from"] = result["f"] = LrudType::From; result["fb"] = LrudType::FB; result["to"] = result["t"] = LrudType::To; result["tb"] = LrudType::TB; return result; } QHash> WallsSurveyParser::createTapingMethods() { typedef QList Method; QHash> result; result["it"] = Method({TapingMethodMeasurement::InstrumentHeight, TapingMethodMeasurement::TargetHeight}); result["is"] = Method({TapingMethodMeasurement::InstrumentHeight, TapingMethodMeasurement::Station}); result["st"] = Method({TapingMethodMeasurement::Station, TapingMethodMeasurement::TargetHeight}); result["ss"] = Method({TapingMethodMeasurement::Station, TapingMethodMeasurement::Station}); return result; } QHash WallsSurveyParser::createPrefixDirectives() { QHash result; result["#prefix1"] = result["#prefix"] = 0; result["#prefix2"] = 1; result["#prefix3"] = 2; return result; } QHash WallsSurveyParser::createUnitsOptionMap() { QHash result; result["save"] = &WallsSurveyParser::save; result["restore"] = &WallsSurveyParser::restore; result["reset"] = &WallsSurveyParser::reset_; result["m"] = &WallsSurveyParser::meters; result["meters"] = &WallsSurveyParser::meters; result["f"] = &WallsSurveyParser::feet; result["feet"] = &WallsSurveyParser::feet; result["ct"] = &WallsSurveyParser::ct; result["d"] = &WallsSurveyParser::d; result["s"] = &WallsSurveyParser::s; result["a"] = &WallsSurveyParser::a; result["ab"] = &WallsSurveyParser::ab; result["a/ab"] = &WallsSurveyParser::a_ab; result["v"] = &WallsSurveyParser::v; result["vb"] = &WallsSurveyParser::vb; result["v/vb"] = &WallsSurveyParser::v_vb; result["o"] = &WallsSurveyParser::order; result["order"] = &WallsSurveyParser::order; result["decl"] = &WallsSurveyParser::decl; result["grid"] = &WallsSurveyParser::grid; result["rect"] = &WallsSurveyParser::rect; result["incd"] = &WallsSurveyParser::incd; result["inch"] = &WallsSurveyParser::inch; result["incs"] = &WallsSurveyParser::incs; result["inca"] = &WallsSurveyParser::inca; result["incab"] = &WallsSurveyParser::incab; result["incv"] = &WallsSurveyParser::incv; result["incvb"] = &WallsSurveyParser::incvb; result["typeab"] = &WallsSurveyParser::typeab; result["typevb"] = &WallsSurveyParser::typevb; result["case"] = &WallsSurveyParser::case_; result["lrud"] = &WallsSurveyParser::lrud; result["tape"] = &WallsSurveyParser::tape; result["prefix"] = &WallsSurveyParser::prefix1; result["prefix1"] = &WallsSurveyParser::prefix1; result["prefix2"] = &WallsSurveyParser::prefix2; result["prefix3"] = &WallsSurveyParser::prefix3; result["uvh"] = &WallsSurveyParser::uvh; result["uvv"] = &WallsSurveyParser::uvv; result["uv"] = &WallsSurveyParser::uv; result["flag"] = &WallsSurveyParser::flag; return result; } QHash WallsSurveyParser::createDirectivesMap() { QHash result; result["#units"] = result["#u"] = &WallsSurveyParser::unitsLine; result["#flag"] = result["#f"] = &WallsSurveyParser::flagLine; result["#fix"] = &WallsSurveyParser::fixLine; result["#note"] = &WallsSurveyParser::noteLine; result["#symbol"] = result["#sym"] = &WallsSurveyParser::symbolLine; result["#segment"] = result["#seg"] = result["#s"] = &WallsSurveyParser::segmentLine; result["#date"] = &WallsSurveyParser::dateLine; result["#["] = &WallsSurveyParser::beginBlockCommentLine; result["#]"] = &WallsSurveyParser::endBlockCommentLine; result["#prefix1"] = result["#prefix2"] = result["#prefix3"] = result["#prefix"] = &WallsSurveyParser::prefixLine; return result; } double WallsSurveyParser::approx(double val) { return floor(val * 1e6) * 1e-6; } const QHash WallsSurveyParser::lengthUnits = WallsSurveyParser::createLengthUnits(); const QHash WallsSurveyParser::azmUnits = WallsSurveyParser::createAzmUnits(); const QHash WallsSurveyParser::incUnits = WallsSurveyParser::createIncUnits(); const QHash WallsSurveyParser::lengthUnitSuffixes = WallsSurveyParser::createLengthUnitSuffixes(); const QHash WallsSurveyParser::azmUnitSuffixes = WallsSurveyParser::createAzmUnitSuffixes(); const QHash WallsSurveyParser::incUnitSuffixes = WallsSurveyParser::createIncUnitSuffixes(); const QHash WallsSurveyParser::cardinalDirections = WallsSurveyParser::createCardinalDirections(); const QHash WallsSurveyParser::northSouth = WallsSurveyParser::createNorthSouth(); const QHash WallsSurveyParser::eastWest = WallsSurveyParser::createEastWest(); const QHash WallsSurveyParser::escapedChars = WallsSurveyParser::createEscapedChars(); const QHash WallsSurveyParser::ctElements = WallsSurveyParser::createCtElements(); const QSet WallsSurveyParser::requiredCtElements({CtMeasurement::D, CtMeasurement::A}); const QHash WallsSurveyParser::rectElements = WallsSurveyParser::createRectElements(); const QSet WallsSurveyParser::requiredRectElements({RectMeasurement::E, RectMeasurement::N}); const QHash WallsSurveyParser::lrudElements = WallsSurveyParser::createLrudElements(); const QSet WallsSurveyParser::requiredLrudElements({LrudMeasurement::L, LrudMeasurement::R, LrudMeasurement::U, LrudMeasurement::D}); const QHash WallsSurveyParser::correctedValues = WallsSurveyParser::createCorrectedValues(); const QHash WallsSurveyParser::caseTypes = WallsSurveyParser::createCaseTypes(); const QHash WallsSurveyParser::lrudTypes = WallsSurveyParser::createLrudTypes(); const QHash> WallsSurveyParser::tapingMethods = WallsSurveyParser::createTapingMethods(); const QHash WallsSurveyParser::prefixDirectives = WallsSurveyParser::createPrefixDirectives(); const QRegExp WallsSurveyParser::wordRx("\\w+"); const QRegExp WallsSurveyParser::notSemicolonRx("[^;]+"); const QRegExp WallsSurveyParser::unitsOptionRx("[a-zA-Z_0-9/]*"); const QRegExp WallsSurveyParser::directiveRx("#([][]|[a-zA-Z0-9]+)"); const QRegExp WallsSurveyParser::macroNameRx("[^()=,,# \t]*"); const QRegExp WallsSurveyParser::stationRx("([^:;,,#/ \t]*:){0,3}[^:;,,#/ \t]{1,8}"); const QRegExp WallsSurveyParser::prefixRx("[^:;,,#/ \t]*"); const QRegExp WallsSurveyParser::optionalRx("-+"); const QRegExp WallsSurveyParser::optionalStationRx("-+"); const QRegExp WallsSurveyParser::isoDateRx("\\d{4}-\\d{2}-\\d{2}"); const QRegExp WallsSurveyParser::usDateRx1("\\d{2}-\\d{2}-\\d{2,4}"); const QRegExp WallsSurveyParser::usDateRx2("\\d{2}/\\d{2}/\\d{2,4}"); const QRegExp WallsSurveyParser::usDateRx3("\\d{4}-\\d{1,2}-\\d{1,2}"); const QRegExp WallsSurveyParser::segmentPartRx("[^./\\;][^/\\;]+"); const QHash WallsSurveyParser::unitsOptionMap = WallsSurveyParser::createUnitsOptionMap(); const QHash WallsSurveyParser::directivesMap = WallsSurveyParser::createDirectivesMap(); const UAngle WallsSurveyParser::oneEighty = UAngle(180.0, Angle::Degrees); WallsSurveyParser::WallsSurveyParser() : WallsSurveyParser(Segment()) { } WallsSurveyParser::WallsSurveyParser(QString line) : WallsSurveyParser(Segment(line)) { } WallsSurveyParser::WallsSurveyParser(Segment segment) : LineParser(segment), _inBlockComment(false), _units(), _stack(), _macros(), _segment(), _date(), _fromStationSegment(), _toStationSegment(), _azmSegment(), _incSegment(), _vector(), _fixStation() { } ULength WallsSurveyParser::unsignedLengthInches() { expect('i', Qt::CaseInsensitive); double inches = unsignedDoubleLiteral(); return ULength(inches, Length::Inches); } ULength WallsSurveyParser::unsignedLengthNonInches(Length::Unit defaultUnit) { double value = unsignedDoubleLiteral(); Length::Unit unit = oneOfMap(lengthUnitSuffixes, defaultUnit); if (unit == Length::Inches) { double inches = unsignedDoubleLiteral(); return ULength(value * 12 + inches, Length::Inches); } return ULength(value, unit); } ULength WallsSurveyParser::unsignedLength(Length::Unit defaultUnit) { ULength result; oneOfR(result, [&]() { return unsignedLengthNonInches(defaultUnit); }, [&]() { return unsignedLengthInches(); }); return result; } ULength WallsSurveyParser::length(Length::Unit defaultUnit) { bool negate = maybe( [&]() { return expect('-'); } ); ULength length = unsignedLength(defaultUnit); return negate ? -length : length; } UAngle WallsSurveyParser::unsignedAngle(QHash unitSuffixes, Angle::Unit defaultUnit) { auto expectColon = [&]() { expect(':'); }; auto _unsignedDoubleLiteral = [&]{ return unsignedDoubleLiteral(); }; double value; bool hasValue = maybe(value, _unsignedDoubleLiteral); if (maybe(expectColon)) { double minutes, seconds; bool hasMinutes = maybe(minutes, _unsignedDoubleLiteral); bool hasSeconds = false; if (maybe(expectColon)) { hasSeconds = maybe(seconds, _unsignedDoubleLiteral); } if (!(hasValue || hasMinutes || hasSeconds)) { throwAllExpected(); } return UAngle((hasValue ? value : 0) + (hasMinutes ? minutes / 60.0 : 0) + (hasSeconds ? seconds / 3600.0 : 0), Angle::Degrees); } else if (!hasValue) { throwAllExpected(); } return UAngle(value, oneOfMap(unitSuffixes, defaultUnit)); } UAngle WallsSurveyParser::unsignedDmsAngle() { auto expectColon = [&]() { expect(':'); }; auto _unsignedDoubleLiteral = [&]{ return unsignedDoubleLiteral(); }; double degrees, minutes, seconds; bool hasDegrees = maybe(degrees, _unsignedDoubleLiteral); expect(':'); bool hasMinutes = maybe(minutes, _unsignedDoubleLiteral); bool hasSeconds = false; if (maybe(expectColon)) { hasSeconds = maybe(seconds, _unsignedDoubleLiteral); } if (!(hasDegrees || hasMinutes || hasSeconds)) { throwAllExpected(); } return UAngle((hasDegrees ? degrees : 0) + (hasMinutes ? minutes / 60.0 : 0) + (hasSeconds ? seconds / 3600.0 : 0), Angle::Degrees); } UAngle WallsSurveyParser::latitude() { int start = _i; CardinalDirection side = oneOfMap(northSouth); UAngle latitude = unsignedDmsAngle(); if (approx(latitude.get(Angle::Degrees)) > 90.0) { throw SegmentParseException(_line.mid(start, _i), "latitude out of range"); } if (side == CardinalDirection::South) { return -latitude; } return latitude; } UAngle WallsSurveyParser::longitude() { int start = _i; CardinalDirection side = oneOfMap(eastWest); UAngle longitude = unsignedDmsAngle(); if (approx(longitude.get(Angle::Degrees)) > 180.0) { throw SegmentParseException(_line.mid(start, _i), "longitude out of range"); } if (side == CardinalDirection::West) { return -longitude; } return longitude; } UAngle WallsSurveyParser::nonQuadrantAzimuth(Angle::Unit defaultUnit) { int start = _i; UAngle result = unsignedAngle(azmUnitSuffixes, defaultUnit); if (approx(result.get(Angle::Degrees)) >= 360.0) { throw SegmentParseException(_line.mid(start, _i), "azimuth out of range"); } return result; } UAngle WallsSurveyParser::quadrantAzimuth() { CardinalDirection from = oneOfMap(cardinalDirections); int start = _i; UAngle angle; if (maybe(angle, [&]() { return nonQuadrantAzimuth(Angle::Degrees); })) { if (approx(angle.get(Angle::Degrees)) >= 90.0) { throw SegmentParseException(_line.mid(start, _i), "azimuth out of range"); } CardinalDirection to = oneOfMap( from == CardinalDirection::North || from == CardinalDirection::South ? eastWest : northSouth); return from.quadrant(to, angle); } return from.angle(); } UAngle WallsSurveyParser::azimuth(Angle::Unit defaultUnit) { UAngle result; oneOfR(result, [&]() { return quadrantAzimuth(); }, [&]() { return nonQuadrantAzimuth(defaultUnit); }); return result; } UAngle WallsSurveyParser::azimuthOffset(Angle::Unit defaultUnit) { double signum; if (!maybe(signum, [this]() { return oneOfMap(signSignums); } )) { signum = 1.0; } return nonQuadrantAzimuth(defaultUnit) * signum; } UAngle WallsSurveyParser::unsignedInclination(Angle::Unit defaultUnit) { int start = _i; UAngle result = unsignedAngle(incUnitSuffixes, defaultUnit); if (approx(result.get(Angle::Degrees)) > 90.0) { throw SegmentParseException(_line.mid(start, _i), "inclination out of range"); } return result; } UAngle WallsSurveyParser::inclination(Angle::Unit defaultUnit) { int start = _i; double signum; bool hasSignum = maybe(signum, [this]() { return oneOfMap(signSignums); } ); UAngle angle = unsignedInclination(defaultUnit); if (hasSignum) { if (angle.get(angle.unit()) == 0.0) { throw SegmentParseException(_line.mid(start, _i), "zero inclinations must not be preceded by a sign"); } return angle * signum; } return angle; } VarianceOverridePtr WallsSurveyParser::varianceOverride(Length::Unit defaultUnit) { VarianceOverridePtr result; oneOfR(result, [&]() { return floatedVectorVarianceOverride(); }, [&]() { return floatedTraverseVarianceOverride(); }, [&]() { return lengthVarianceOverride(defaultUnit); }, [&]() { return rmsErrorVarianceOverride(defaultUnit); }, [&]() { return VarianceOverridePtr(NULL); }); return result; } VarianceOverridePtr WallsSurveyParser::floatedVectorVarianceOverride() { expect('?'); return VarianceOverride::FLOATED; } VarianceOverridePtr WallsSurveyParser::floatedTraverseVarianceOverride() { expect('*'); return VarianceOverride::FLOATED_TRAVERSE; } VarianceOverridePtr WallsSurveyParser::lengthVarianceOverride(Length::Unit defaultUnit) { return VarianceOverridePtr(new LengthOverride(unsignedLength(defaultUnit))); } VarianceOverridePtr WallsSurveyParser::rmsErrorVarianceOverride(Length::Unit defaultUnit) { expect('r', Qt::CaseInsensitive); return VarianceOverridePtr(new RMSError(unsignedLength(defaultUnit))); } QString WallsSurveyParser::quotedTextOrNonwhitespace() { QString result; oneOfR(result, [&]() { return quotedText(); }, [&]() { return nonwhitespace().value(); }); return result; } QString WallsSurveyParser::quotedText() { expect('"'); QString result = escapedText([](QChar c) { return c != '"'; }, {""}); expect('"'); return result; } QString WallsSurveyParser::movePastEndQuote() { int start = _i++; while (_i < _line.length()) { QChar c = _line.at(_i++); if (c == '\\') { if (_i < _line.length()) _i++; } else if (c == '"') { break; } } return _line.value().mid(start, _i - start); } void WallsSurveyParser::parseLine(QString line) { reset(line); parseLine(); } void WallsSurveyParser::parseLine(Segment line) { reset(line); parseLine(); } void WallsSurveyParser::parseLine() { _parsedSegmentDirective = false; maybeWhitespace(); if (isAtEnd()) { return; } if (_inBlockComment) { throwAllExpected([&]() { oneOfWithLookahead([&]() { endBlockCommentLine(); }, [&]() { insideBlockCommentLine(); }); }); } else { throwAllExpected([&]() { oneOf([&]() { comment(); }, [&]() { directiveLine(); }, [&]() { vectorLine(); }); }); } } void WallsSurveyParser::directiveLine() { int start = _i; OwnProduction directive = oneOfMapLowercase(directiveRx, directivesMap); _i = start; if (directive != &WallsSurveyParser::fixLine) replaceMacros(); (this->*directive)(); } QString WallsSurveyParser::replaceMacro() { _i += 2; int start = _i; while (_i < _line.length()) { QChar c = _line.at(_i++); if (c == ')') { Segment macroName = _line.mid(start, _i - 1 - start); if (!_macros.contains(macroName.value())) { throw SegmentParseException(macroName, "macro not defined"); } return _macros[macroName.value()]; } else if (c.isSpace()) { throw SegmentParseExpectedException(_line.atAsSegment(_i - 1), ""); } } throw SegmentParseExpectedException(_line.atAsSegment(_i), std::initializer_list{"", ")"}); } void WallsSurveyParser::replaceMacros() { QString newLine; bool replaced = false; while (_i < _line.length()) { QChar c = _line.at(_i); switch(c.toLatin1()) { case '"': newLine += movePastEndQuote(); break; case '$': if (_i + 1 < _line.length() && _line.at(_i + 1) == '(') { replaced = true; newLine += replaceMacro(); break; } default: newLine += c; _i++; break; } } _i = 0; if (replaced) { _line = Segment(newLine, _line.source(), _line.startLine(), _line.startCol()); } } void WallsSurveyParser::beginBlockCommentLine() { maybeWhitespace(); expect("#["); _inBlockComment = true; } void WallsSurveyParser::endBlockCommentLine() { maybeWhitespace(); expect("#]"); remaining(); _inBlockComment = false; } void WallsSurveyParser::insideBlockCommentLine() { emit parsedComment(remaining().value()); } Segment WallsSurveyParser::untilComment(std::initializer_list expectedItems) { return expect(notSemicolonRx, expectedItems); } void WallsSurveyParser::segmentLine() { maybeWhitespace(); _segment = segmentDirective(); maybeWhitespace(); inlineCommentOrEndOfLine(); } void WallsSurveyParser::segmentSeparator() { oneOf([&]() { expect("/"); }, [&]() { expect("\\"); }); } QString WallsSurveyParser::initialSegmentPart() { QString result; oneOfR(result, [&]() { expect("."); return "."; }, [&]() { expect(".."); return ".."; }); return result; } QString WallsSurveyParser::nonInitialSegmentPart() { return expect(segmentPartRx, {""}).value(); } QStringList WallsSurveyParser::segmentPath() { QStringList path; oneOf([&]() { segmentSeparator(); path = _rootSegment; }, [&]() { path = _segment; while (maybe([&] { if (initialSegmentPart() == ".." && !path.isEmpty()) { path.removeLast(); } })); }); int lastAddedIndex = -1; while (maybe([&] { path << nonInitialSegmentPart(); lastAddedIndex = path.size() - 1; })); if (lastAddedIndex >= 0) { QString lastPart = path[lastAddedIndex]; lastPart.truncate(QRegExp("\\s*$").indexIn(lastPart)); path[lastAddedIndex] = lastPart; } return path; } QStringList WallsSurveyParser::segmentDirective() { oneOf([&]() { expect("#segment", Qt::CaseInsensitive); }, [&]() { expect("#seg", Qt::CaseInsensitive); }, [&]() { expect("#s", Qt::CaseInsensitive); } ); _parsedSegmentDirective = true; QStringList result = _segment; if (maybeWhitespace()) { maybe(result, [&]() { return segmentPath(); }); } return result; } void WallsSurveyParser::prefixLine() { maybeWhitespace(); prefixDirective(); maybeWhitespace(); inlineCommentOrEndOfLine(); } void WallsSurveyParser::prefixDirective() { int prefixIndex = oneOfMapLowercase(nonwhitespaceRx, prefixDirectives); if (maybeWhitespace()) { _units.setPrefix(prefixIndex, expect(prefixRx, {""}).value()); } } void WallsSurveyParser::noteLine() { maybeWhitespace(); noteDirective(); maybeWhitespace(); inlineCommentOrEndOfLine(); } void WallsSurveyParser::noteDirective() { oneOf([&]() { expect("#note", Qt::CaseInsensitive); }, [&]() { expect("#n", Qt::CaseInsensitive); }); whitespace(); QString _station = station().value(); whitespace(); QString _note = escapedText([](QChar c) { return c != ';'; }, {""}); emit parsedNote(_station, _note); } void WallsSurveyParser::flagLine() { maybeWhitespace(); flagDirective(); maybeWhitespace(); inlineCommentOrEndOfLine(); } void WallsSurveyParser::flagDirective() { oneOf([&]() { expect("#flag", Qt::CaseInsensitive); }, [&]() { expect("#f", Qt::CaseInsensitive); }); QStringList stations; maybeWhitespace(); do { QString _station; if (!maybe(_station, [&]() { return station().value(); })) { break; } stations << _station; } while(maybe([&]() { oneOf([&]() { whitespace(); }, [&]() { expect(','); }); })); QString _flag; bool hasFlag = maybe(_flag, [&]() { return slashPrefixedFlag(); }); maybeWhitespace(); if (stations.isEmpty()) { _units.flag() = _flag; } else { if (!hasFlag) { throwAllExpected(); } emit parsedFlag(stations, _flag); } inlineCommentOrEndOfLine(); } QString WallsSurveyParser::slashPrefixedFlag() { expect('/'); return expect(notSemicolonRx, {""}).value(); } void WallsSurveyParser::symbolLine() { maybeWhitespace(); oneOf([&]() { expect("#symbol", Qt::CaseInsensitive); }, [&]() { expect("#sym", Qt::CaseInsensitive); }); // ignore the rest for now remaining(); } void WallsSurveyParser::dateLine() { maybeWhitespace(); emit parsedDate(dateDirective()); maybeWhitespace(); inlineCommentOrEndOfLine(); } QDate WallsSurveyParser::dateDirective() { expect("#date", Qt::CaseInsensitive); whitespace(); oneOfR(_date, [&]() { return isoDate(); }, [&]() { return usDate1(); }, [&]() { return usDate2(); }, [&]() { return usDate3(); }); return _date; } QDate WallsSurveyParser::isoDate() { Segment dateSegment = expect(isoDateRx, {""}); return QDate::fromString(dateSegment.value(), Qt::ISODate); } QDate WallsSurveyParser::usDate1() { QString str = expect(usDateRx1, {""}).value(); return QDate::fromString(str, str.length() > 8 ? "MM-dd-yyyy" : "MM-dd-yy"); } QDate WallsSurveyParser::usDate2() { QString str = expect(usDateRx2, {""}).value(); return QDate::fromString(str, str.length() > 8 ? "MM/dd/yyyy" : "MM/dd/yy"); } QDate WallsSurveyParser::usDate3() { QString str = expect(usDateRx3, {""}).value(); return QDate::fromString(str, "yyyy-MM-dd"); } void WallsSurveyParser::unitsLine() { maybeWhitespace(); oneOf([&]() { expect("#units", Qt::CaseInsensitive); }, [&]() { expect("#u", Qt::CaseInsensitive); }); emit willParseUnits(); if (maybeWhitespace()) { unitsOptions(); emit parsedUnits(); } } void WallsSurveyParser::parseUnitsOptions(Segment options) { reset(options); unitsOptions(); emit parsedUnits(); } void WallsSurveyParser::unitsOptions() { bool gotOne = false; while(!maybe([&]() { inlineCommentOrEndOfLine(); } )) { if (gotOne) { whitespace(); } else { gotOne = true; } maybe([&]() { oneOf( [&]() { unitsOption(); }, [&]() { macroOption(); } ); }); } } void WallsSurveyParser::unitsOption() { void (WallsSurveyParser::*option)() = oneOfMapLowercase(unitsOptionRx, unitsOptionMap); (this->*option)(); } void WallsSurveyParser::macroOption() { expect('$'); QString macroName = expect(macroNameRx, {""}).value(); QString macroValue; if (maybeChar('=')) { macroValue = quotedTextOrNonwhitespace(); } _macros[macroName] = macroValue; } void WallsSurveyParser::save() { if (_stack.size() >= 10) { throw SegmentParseException(_line.mid(_i - 4, _i), "units stack is full"); } _stack.push(_units); } void WallsSurveyParser::restore() { if (_stack.isEmpty()) { throw SegmentParseException(_line.mid(_i - 7, _i), "units stack is empty"); } _units = _stack.pop(); } void WallsSurveyParser::reset_() { _units = WallsUnits(); } void WallsSurveyParser::meters() { _units.setDUnit(Length::Meters); _units.setSUnit(Length::Meters); } void WallsSurveyParser::feet() { _units.setDUnit(Length::Feet); _units.setSUnit(Length::Feet); } void WallsSurveyParser::ct() { _units.setVectorType(VectorType::CT); } void WallsSurveyParser::d() { expect('='); _units.setDUnit(oneOfMapLowercase(nonwhitespaceRx, lengthUnits)); } void WallsSurveyParser::s() { expect('='); _units.setSUnit(oneOfMapLowercase(nonwhitespaceRx, lengthUnits)); } void WallsSurveyParser::a() { expect('='); _units.setAUnit(oneOfMapLowercase(nonwhitespaceRx, azmUnits)); } void WallsSurveyParser::ab() { expect('='); _units.setAbUnit(oneOfMapLowercase(nonwhitespaceRx, azmUnits)); } void WallsSurveyParser::a_ab() { expect('='); Angle::Unit unit = oneOfMapLowercase(nonwhitespaceRx, azmUnits); _units.setAUnit(unit); _units.setAbUnit(unit); } void WallsSurveyParser::v() { expect('='); _units.setVUnit(oneOfMapLowercase(nonwhitespaceRx, incUnits)); } void WallsSurveyParser::vb() { expect('='); _units.setVbUnit(oneOfMapLowercase(nonwhitespaceRx, incUnits)); } void WallsSurveyParser::v_vb() { expect('='); Angle::Unit unit = oneOfMapLowercase(nonwhitespaceRx, incUnits); _units.setVUnit(unit); _units.setVbUnit(unit); } void WallsSurveyParser::order() { expect('='); oneOf([&]() { ctOrder(); }, [&]() { rectOrder(); }); } void WallsSurveyParser::ctOrder() { _units.setCtOrder(elementChars(ctElements, requiredCtElements)); } void WallsSurveyParser::rectOrder() { _units.setRectOrder(elementChars(rectElements, requiredRectElements)); } void WallsSurveyParser::decl() { expect('='); _units.setDecl(azimuthOffset(_units.aUnit())); } void WallsSurveyParser::grid() { expect('='); _units.setGrid(azimuthOffset(_units.aUnit())); } void WallsSurveyParser::rect() { if (maybeChar('=')) { _units.setRect(azimuthOffset(_units.aUnit())); } else { _units.setVectorType(VectorType::RECT); } } void WallsSurveyParser::incd() { expect('='); _units.setIncd(length(_units.dUnit())); } void WallsSurveyParser::inch() { expect('='); _units.setInch(length(_units.sUnit())); } void WallsSurveyParser::incs() { expect('='); _units.setIncs(length(_units.sUnit())); } void WallsSurveyParser::inca() { expect('='); _units.setInca(azimuthOffset(_units.aUnit())); } void WallsSurveyParser::incab() { expect('='); _units.setIncab(azimuthOffset(_units.abUnit())); } void WallsSurveyParser::incv() { expect('='); _units.setIncv(inclination(_units.vUnit())); } void WallsSurveyParser::incvb() { expect('='); _units.setIncvb(inclination(_units.vbUnit())); } void WallsSurveyParser::typeab() { expect('='); _units.setTypeabCorrected(oneOfMapLowercase(wordRx, correctedValues)); if (maybeChar(',')) { _units.setTypeabTolerance(UAngle(unsignedDoubleLiteral(), Angle::Degrees)); if (maybeChar(',')) { expect('x', Qt::CaseInsensitive); _units.setTypeabNoAverage(true); } else { _units.setTypeabNoAverage(false); } } else { _units.setTypeabTolerance(UAngle(2.0, Angle::Degrees)); } } void WallsSurveyParser::typevb() { expect('='); _units.setTypevbCorrected(oneOfMapLowercase(wordRx, correctedValues)); if (maybeChar(',')) { _units.setTypevbTolerance(UAngle(unsignedDoubleLiteral(), Angle::Degrees)); if (maybeChar(',')) { expect('x', Qt::CaseInsensitive); _units.setTypevbNoAverage(true); } else { _units.setTypevbNoAverage(false); } } else { _units.setTypevbTolerance(UAngle(2.0, Angle::Degrees)); } } void WallsSurveyParser::case_() { expect('='); _units.setCase(oneOfMapLowercase(nonwhitespaceRx, caseTypes)); } void WallsSurveyParser::lrud() { expect('='); _units.setLrud(oneOfMapLowercase(wordRx, lrudTypes)); if (maybeChar(':')) { lrudOrder(); } else { _units.setLrudOrder(QList({LrudMeasurement::L, LrudMeasurement::R, LrudMeasurement::U, LrudMeasurement::D})); } } void WallsSurveyParser::lrudOrder() { _units.setLrudOrder(elementChars(lrudElements, requiredLrudElements)); } void WallsSurveyParser::prefix1() { prefix(0); } void WallsSurveyParser::prefix2() { prefix(1); } void WallsSurveyParser::prefix3() { prefix(2); } void WallsSurveyParser::prefix(int index) { QString prefix; if (maybeChar('=')) { prefix = expect(prefixRx, {""}).value(); } _units.setPrefix(index, prefix); } void WallsSurveyParser::tape() { expect('='); _units.setTape(oneOfMapLowercase(nonwhitespaceRx, tapingMethods)); } void WallsSurveyParser::uvh() { expect('='); _units.setUvh(unsignedDoubleLiteral()); } void WallsSurveyParser::uvv() { expect('='); _units.setUvv(unsignedDoubleLiteral()); } void WallsSurveyParser::uv() { expect('='); double value = unsignedDoubleLiteral(); _units.setUvv(value); _units.setUvh(value); } void WallsSurveyParser::flag() { QString flag; if (maybeChar('=')) { flag = quotedTextOrNonwhitespace(); } _units.setFlag(flag); } void WallsSurveyParser::vectorLine() { maybeWhitespace(); fromStation(); _parsedSegmentDirective = false; whitespace(); afterFromStation(); maybeWhitespace(); endOfLine(); if (_parsedSegmentDirective) { _vector.setSegment(_segment); } _vector.setDate(_date); _vector.setUnits(_units); emit parsedVector(_vector); } Segment WallsSurveyParser::station() { return expect(stationRx, {""}); } void WallsSurveyParser::fromStation() { _fromStationSegment = station(); QString from = _fromStationSegment.value(); if (optionalStationRx.exactMatch(from)) { from.clear(); } _vector = Vector(); _vector.setSourceSegment(_line); _vector.setFrom(from); } void WallsSurveyParser::afterFromStation() { oneOfWithLookahead([&]() { toStation(); whitespace(); afterToStation(); }, [&]() { // clear all measurements QString from = _vector.from(); _vector = Vector(); _vector.setSourceSegment(_line); _vector.setFrom(from); lruds(); afterLruds(); }); } void WallsSurveyParser::toStation() { _toStationSegment = station(); QString to = _toStationSegment.value(); if (optionalStationRx.exactMatch(to)) { to.clear(); } if (_vector.from().isEmpty() && to.isEmpty()) { throw SegmentParseException(_toStationSegment, "from and to station can't both be omitted"); } _vector.setTo(to); } void WallsSurveyParser::afterToStation() { int k = 0; if (_units.vectorType() == VectorType::RECT) { foreach(RectMeasurement elem, _units.rectOrder()) { if (k++ > 0) { whitespace(); } rectMeasurement(elem); } } else { foreach(CtMeasurement elem, _units.ctOrder()) { if (k++ > 0) { whitespace(); } ctMeasurement(elem); } } using namespace std; if (_units.vectorType() == VectorType::CT) { if (!_vector.frontAzimuth().isValid() && !_vector.backAzimuth().isValid() && !WallsUnits::isVertical(_vector.frontInclination(), _vector.backInclination())) { throw SegmentParseException(_azmSegment, "azimuth can only be omitted for vertical shots"); } maybeWithLookahead([&]() { whitespace(); instrumentHeight(); }); maybeWithLookahead([&]() { whitespace(); targetHeight(); }); } afterVectorMeasurements(); } void WallsSurveyParser::rectMeasurement(RectMeasurement elem) { switch(elem) { case RectMeasurement::E: east(); break; case RectMeasurement::N: north(); break; case RectMeasurement::U: rectUp(); break; } } void WallsSurveyParser::east() { _vector.setEast(length(_units.dUnit())); } void WallsSurveyParser::north() { _vector.setNorth(length(_units.dUnit())); } void WallsSurveyParser::rectUp() { _vector.setRectUp(length(_units.dUnit())); } void WallsSurveyParser::ctMeasurement(CtMeasurement elem) { switch(elem) { case CtMeasurement::D: distance(); break; case CtMeasurement::A: azimuth(); break; case CtMeasurement::V: inclination(); break; } } void WallsSurveyParser::checkCorrectedSign(int segStart, ULength measurement, ULength correction) { if (measurement.isNonzero() && correction.isNonzero() && measurement.signum() != (measurement + correction).signum()) { throw SegmentParseException(_line.mid(segStart, _i - segStart), "correction changes sign of measurement"); } } void WallsSurveyParser::distance() { int start = _i; ULength dist = unsignedLength(_units.dUnit()); checkCorrectedSign(start, dist, _units.incd()); _vector.setDistance(dist); } UAngle WallsSurveyParser::azmDifference(UAngle fs, UAngle bs) { if (!_units.typeabCorrected()) { if (bs < oneEighty) { bs += oneEighty; } else { bs -= oneEighty; } } UAngle diff = uabs(fs - bs); return diff > oneEighty ? UAngle(360.0, Angle::Degrees) - diff : diff; } void WallsSurveyParser::azimuth() { int start = _i; UAngle azmFs; UAngle azmBs; oneOf([&]() { optional(azmFs, [&]() { return azimuth(_units.aUnit()); }); maybe([&]() { expect('/'); optional(azmBs, [&]() { return azimuth(_units.abUnit()); }); }); }, [&]() { expect('/'); optional(azmBs, [&]() { return azimuth(_units.abUnit()); }); }); _vector.setFrontAzimuth(azmFs); _vector.setBackAzimuth(azmBs); _azmSegment = _line.mid(start, _i - start); if (azmFs.isValid() && azmBs.isValid()) { UAngle diff = azmDifference(azmFs, azmBs); if (diff > _units.typeabTolerance() * (1 + 1e-6)) { emit message(WallsMessage("warning", QString("azimuth fs/bs difference (%1) exceeds tolerance (%2)") .arg(diff.toString()) .arg(_units.typeabTolerance().toString()), _azmSegment)); } } } UAngle WallsSurveyParser::incDifference(UAngle fs, UAngle bs) { return _units.typevbCorrected() ? uabs(fs - bs) : uabs(fs + bs); } void WallsSurveyParser::inclination() { int start = _i; UAngle incFs; UAngle incBs; oneOf([&]() { optional(incFs, [&]() { return inclination(_units.vUnit()); }); maybe([&]() { expect('/'); optional(incBs, [&]() { return inclination(_units.vbUnit()); }); }); }, [&]() { expect('/'); optional(incBs, [&]() { return inclination(_units.vbUnit()); }); }); _incSegment = _line.mid(start, _i - start); if (!incFs.isValid() && !incBs.isValid()) { incFs = UAngle(0, _units.vUnit()); } else if (incFs.isValid() && incBs.isValid()) { UAngle diff = incDifference(incFs, incBs); if (diff > _units.typevbTolerance() * (1 + 1e-6)) { emit message(WallsMessage("warning", QString("inclination fs/bs difference (%1) exceeds tolerance (%2)") .arg(diff.toString()) .arg(_units.typevbTolerance().toString()), _incSegment)); } } _vector.setFrontInclination(incFs); _vector.setBackInclination(incBs); } void WallsSurveyParser::instrumentHeight() { int start = _i; ULength ih; if (optional(ih, [&]() { return length(_units.sUnit()); })) { checkCorrectedSign(start, ih, _units.incs()); _vector.setInstHeight(ih); } } void WallsSurveyParser::targetHeight() { int start = _i; ULength th; if (optional(th, [&]() { return length(_units.sUnit()); })) { checkCorrectedSign(start, th, _units.incs()); _vector.setTargetHeight(th); } } void WallsSurveyParser::lrudMeasurement(LrudMeasurement elem) { switch(elem) { case LrudMeasurement::L: left(); break; case LrudMeasurement::R: right(); break; case LrudMeasurement::U: up(); break; case LrudMeasurement::D: down(); break; } } template void WallsSurveyParser::warnIfNegative(UnitizedDouble measurement, int start, QString name) { if (measurement.isValid() && measurement.get(measurement.unit()) < 0) { emit message(WallsMessage("warning", QString("negative %1 measurement").arg(name), _line.mid(_i, start - _i))); } } void WallsSurveyParser::left() { int start = _i; ULength left; if (optionalWithLookahead(left, [&]() { return length(_units.sUnit()); })) { warnIfNegative(left, start, "LRUD"); checkCorrectedSign(start, left, _units.incs()); _vector.setLeft(left); } } void WallsSurveyParser::right() { int start = _i; ULength right; if (optionalWithLookahead(right, [&]() { return length(_units.sUnit()); })) { warnIfNegative(right, start, "LRUD"); checkCorrectedSign(start, right, _units.incs()); _vector.setRight(right); } } void WallsSurveyParser::up() { int start = _i; ULength up; if (optionalWithLookahead(up, [&]() { return length(_units.sUnit()); })) { warnIfNegative(up, start, "LRUD"); checkCorrectedSign(start, up, _units.incs()); _vector.setUp(up); } } void WallsSurveyParser::down() { int start = _i; ULength down; if (optionalWithLookahead(down, [&]() { return length(_units.sUnit()); })) { warnIfNegative(down, start, "LRUD"); checkCorrectedSign(start, down, _units.incs()); _vector.setDown(down); } } void WallsSurveyParser::afterVectorMeasurements() { maybeWithLookahead([&]() { whitespace(); varianceOverrides(_vector); }); afterVectorVarianceOverrides(); } template void WallsSurveyParser::varianceOverrides(T& target) { expect('('); maybeWhitespace(); VarianceOverridePtr horizontal = varianceOverride(_units.dUnit()); target.setHorizVariance(horizontal); maybeWhitespace(); if (maybeChar(',')) { maybeWhitespace(); VarianceOverridePtr vertical = varianceOverride(_units.dUnit()); if (horizontal.isNull() && vertical.isNull()) { throw allExpected(); } target.setVertVariance(vertical); } else if (!horizontal.isNull()) { target.setVertVariance(horizontal); } expect(')'); } void WallsSurveyParser::afterVectorVarianceOverrides() { maybeWithLookahead([&]() { whitespace(); lruds(); }); afterLruds(); } void WallsSurveyParser::lruds() { oneOfWithLookahead([&]() { expect('<'); try { lrudContent(); } catch (const SegmentParseExpectedException& ex) { if (!ex.segment().value().startsWith(">")) { throw; } emit message(WallsMessage("warning", "missing LRUD measurment; use -- to indicate omitted measurements", ex.segment())); } expect('>'); }, [&]() { expect('*'); try { lrudContent(); } catch (const SegmentParseExpectedException& ex) { if (!ex.segment().value().startsWith("*")) { throw; } emit message(WallsMessage("warning", "missing LRUD measurement; use -- to indicate omitted measurements", ex.segment())); } expect('*'); }); } void WallsSurveyParser::lrudContent() { maybeWhitespace(); int m = 0; foreach(LrudMeasurement elem, _units.lrudOrder()) { if (m++ > 0) { oneOfWithLookahead([&]() { maybeWhitespace(); expect(','); maybeWhitespace(); }, [&]() { whitespace(); }); } if (!maybe([&]() { lrudMeasurement(elem); })) { emit message(WallsMessage("warning", "missing LRUD measurement; use -- to indicate omitted measurements", _line.mid(_i))); } } maybeWhitespace(); afterRequiredLrudMeasurements(); } void WallsSurveyParser::afterRequiredLrudMeasurements() { if (maybeChar(',')) { maybeWhitespace(); } maybe([&]() { oneOf([&]() { lrudFacingAngle(); maybeWhitespace(); if (maybeChar(',')) { maybeWhitespace(); } lrudCFlag(); }, [&]() { lrudCFlag(); }); }); } void WallsSurveyParser::lrudFacingAngle() { _vector.setLrudAngle(azimuth(_units.aUnit())); } void WallsSurveyParser::lrudCFlag() { expect('c', Qt::CaseInsensitive); _vector.setCFlag(true); } void WallsSurveyParser::afterLruds() { maybeWhitespace(); if (maybe([&]() { inlineDirective(); })) { maybeWhitespace(); } inlineCommentOrEndOfLine(); } void WallsSurveyParser::inlineDirective() { // currently this is the only directive that can be on a vector line inlineSegmentDirective(_vector); } void WallsSurveyParser::inlineFixDirective() { // currently this is the only directive that can be on a fix station line inlineSegmentDirective(_fixStation); } template void WallsSurveyParser::inlineSegmentDirective(T& target) { target.setSegment(segmentDirective()); } void WallsSurveyParser::fixLine() { maybeWhitespace(); expect("#fix", Qt::CaseInsensitive); whitespace(); fixedStation(); whitespace(); _parsedSegmentDirective = false; afterFixedStation(); maybeWhitespace(); endOfLine(); if (!_parsedSegmentDirective) { _fixStation.setSegment(_segment); } _fixStation.setDate(_date); _fixStation.setUnits(_units); emit parsedFixStation(_fixStation); } void WallsSurveyParser::fixedStation() { QString fixed = station().value(); _fixStation = FixStation(); _fixStation.setName(fixed); } void WallsSurveyParser::afterFixedStation() { int k = 0; foreach(RectMeasurement elem, _units.rectOrder()) { if (k++ > 0) { whitespace(); } fixRectMeasurement(elem); } maybeWhitespace(); afterFixMeasurements(); } void WallsSurveyParser::fixRectMeasurement(RectMeasurement elem) { switch(elem) { case RectMeasurement::E: fixEast(); break; case RectMeasurement::N: fixNorth(); break; case RectMeasurement::U: fixUp(); break; } } void WallsSurveyParser::fixEast() { oneOf([&]() { _fixStation.setEast(length(_units.dUnit())); }, [&]() { _fixStation.setLongitude(longitude()); }); } void WallsSurveyParser::fixNorth() { oneOf([&]() { _fixStation.setNorth(length(_units.dUnit())); }, [&]() { _fixStation.setLatitude(latitude()); }); } void WallsSurveyParser::fixUp() { _fixStation.setRectUp(length(_units.dUnit())); } void WallsSurveyParser::afterFixMeasurements() { if (maybe([&]() { varianceOverrides(_fixStation); })) { maybeWhitespace(); } afterFixVarianceOverrides(); } void WallsSurveyParser::afterFixVarianceOverrides() { if (maybe([&]() { inlineNote(_fixStation); })) { maybeWhitespace(); } afterInlineFixNote(); } template void WallsSurveyParser::inlineNote(T& target) { expect('/'); target.setNote(escapedText([](QChar c) { return c != ';' && c != '#'; }, {""}).trimmed()); } void WallsSurveyParser::afterInlineFixNote() { if (maybe([&]() { inlineFixDirective(); })) { maybeWhitespace(); } inlineCommentOrEndOfLine(_fixStation); } void WallsSurveyParser::inlineCommentOrEndOfLine() { oneOf([&]() { inlineComment(); }, [&]() { endOfLine(); }); } template void WallsSurveyParser::inlineCommentOrEndOfLine(T& target) { oneOf([&]() { inlineComment(target); }, [&]() { endOfLine(); }); } void WallsSurveyParser::comment() { expect(';'); emit parsedComment(remaining().value()); } void WallsSurveyParser::inlineComment() { expect(';'); emit parsedComment(remaining().value()); } template void WallsSurveyParser::inlineComment(T& target) { expect(';'); target.setComment(remaining().value()); } } // namespace dewalls dewalls-1.0.0/src/wallssurveyparser.h000066400000000000000000000350311263712165300177300ustar00rootroot00000000000000#ifndef DEWALLS_WALLSPARSER_H #define DEWALLS_WALLSPARSER_H #include #include #include #include #include #include "lineparser.h" #include "unitizeddouble.h" #include "length.h" #include "angle.h" #include "cardinaldirection.h" #include "varianceoverride.h" #include "wallstypes.h" #include "wallsunits.h" #include "vector.h" #include "fixstation.h" #include "wallsmessage.h" #include "dewallsexport.h" namespace dewalls { /// /// \brief parses Walls .SRV files /// You pass in lines frme the .SRV file to parse to parseLine(), and the parser will emit /// signals for the various types of data it parses. The parsed data must be interpreted /// in the context of the current units(), date(), and segment(). /// class DEWALLS_LIB_EXPORT WallsSurveyParser : public QObject, public LineParser { Q_OBJECT public: typedef UnitizedDouble ULength; typedef UnitizedDouble UAngle; typedef QSharedPointer VarianceOverridePtr; typedef void (WallsSurveyParser::*OwnProduction)(); WallsSurveyParser(); WallsSurveyParser(QString line); WallsSurveyParser(Segment segment); /// /// \brief parses the current line (which must be set by calling reset(line)) /// void parseLine(); /// /// \brief parses a line from a .SRV file. This method is designed for testing /// and doesn't allow you to pass in the source file and line number; prefer /// using parseLine(Segment) instead. /// void parseLine(QString line); /// /// \brief this is the ideal method to call to parse a line of a .SRV file. /// void parseLine(Segment line); /// /// \brief parses units options that come after "#units" /// this can be used to parse options given by a .OPTIONS line in /// a .WPJ file /// void parseUnitsOptions(Segment options); /// /// \return the current Walls units (from #units directives) /// WallsUnits units() const; /// /// \return the current date associated with the data (from #date directives) /// QDate date() const; /// /// \return the current segment associated with the data (from #segment directives) /// QStringList segment() const; /// /// \return the segment that a #segment path starting with \ or / will switch back to /// QStringList rootSegment() const; QHash macros() const; /// /// \brief sets the walls #segment. Used for passing in name-defined segments from /// project files. /// void setSegment(QStringList segment); /// /// \brief sets the root #segment, which should be set to a name-defined segment /// from a project file. /// void setRootSegment(QStringList rootSegment); ULength unsignedLengthInches(); ULength unsignedLengthNonInches(Length::Unit defaultUnit); ULength unsignedLength(Length::Unit defaultUnit); ULength length(Length::Unit defaultUnit); UAngle unsignedAngle(QHash unitSuffixes, Angle::Unit defaultUnit); UAngle unsignedDmsAngle(); UAngle latitude(); UAngle longitude(); UAngle nonQuadrantAzimuth(Angle::Unit defaultUnit); UAngle quadrantAzimuth(); UAngle azimuth(Angle::Unit defaultUnit); UAngle azimuthOffset(Angle::Unit defaultUnit); UAngle unsignedInclination(Angle::Unit defaultUnit); UAngle inclination(Angle::Unit defaultUnit); VarianceOverridePtr varianceOverride(Length::Unit defaultUnit); VarianceOverridePtr floatedVectorVarianceOverride(); VarianceOverridePtr floatedTraverseVarianceOverride(); VarianceOverridePtr lengthVarianceOverride(Length::Unit defaultUnit); VarianceOverridePtr rmsErrorVarianceOverride(Length::Unit defaultUnit); template QChar escapedChar(F charPredicate, std::initializer_list expectedItems); template QString escapedText(F charPredicate, std::initializer_list expectedItems); QString quotedTextOrNonwhitespace(); QString quotedText(); template bool optional(R& result, F production); template bool optionalWithLookahead(R& result, F production); template QList elementChars(QHash elements, QSet requiredElements); void beginBlockCommentLine(); void endBlockCommentLine(); void insideBlockCommentLine(); void directiveLine(); void segmentLine(); void prefixLine(); void noteLine(); void flagLine(); void symbolLine(); void dateLine(); void unitsLine(); void vectorLine(); signals: void parsedVector(Vector parsedVector); void parsedFixStation(FixStation station); void parsedComment(QString parsedComment); void parsedNote(QString station, QString parsedNote); void parsedDate(QDate date); void parsedFlag(QStringList stations, QString flag); void willParseUnits(); void parsedUnits(); void parsedSegment(QString segment); void message(WallsMessage message); private: static double approx(double val); static QHash createLengthUnits(); static QHash createAzmUnits(); static QHash createIncUnits(); static QHash createLengthUnitSuffixes(); static QHash createAzmUnitSuffixes(); static QHash createIncUnitSuffixes(); static QHash createCardinalDirections(); static QHash createNorthSouth(); static QHash createEastWest(); static QHash createEscapedChars(); static QHash createCtElements(); static QHash createRectElements(); static QHash createLrudElements(); static QHash createCorrectedValues(); static QHash createCaseTypes(); static QHash createLrudTypes(); static QHash> createTapingMethods(); static QHash createPrefixDirectives(); static QHash createUnitsOptionMap(); static QHash createDirectivesMap(); static const QHash lengthUnits; static const QHash azmUnits; static const QHash incUnits; static const QHash lengthUnitSuffixes; static const QHash azmUnitSuffixes; static const QHash incUnitSuffixes; static const QHash cardinalDirections; static const QHash northSouth; static const QHash eastWest; static const QHash escapedChars; static const QHash ctElements; static const QSet requiredCtElements; static const QHash rectElements; static const QSet requiredRectElements; static const QHash lrudElements; static const QSet requiredLrudElements; static const QHash correctedValues; static const QHash caseTypes; static const QHash lrudTypes; static const QHash> tapingMethods; static const QHash prefixDirectives; static const QRegExp wordRx; static const QRegExp notSemicolonRx; static const QRegExp unitsOptionRx; static const QRegExp directiveRx; static const QRegExp macroNameRx; static const QRegExp stationRx; static const QRegExp prefixRx; static const QRegExp optionalRx; static const QRegExp optionalStationRx; static const QRegExp isoDateRx; static const QRegExp usDateRx1; static const QRegExp usDateRx2; static const QRegExp usDateRx3; static const QRegExp segmentPartRx; static const QHash unitsOptionMap; static const QHash directivesMap; static const UAngle oneEighty; UAngle azmDifference(UAngle fs, UAngle bs); UAngle incDifference(UAngle fs, UAngle bs); void replaceMacros(); QString movePastEndQuote(); QString replaceMacro(); Segment untilComment(std::initializer_list expectedItems); void segmentSeparator(); QString initialSegmentPart(); QString nonInitialSegmentPart(); QStringList segmentPath(); QStringList segmentDirective(); void prefixDirective(); void noteDirective(); void flagDirective(); QString slashPrefixedFlag(); QDate dateDirective(); QDate isoDate(); QDate usDate1(); QDate usDate2(); QDate usDate3(); void unitsOptions(); void unitsOption(); void macroOption(); void save(); void restore(); void reset_(); void meters(); void feet(); void ct(); void d(); void s(); void a(); void ab(); void a_ab(); void v(); void vb(); void v_vb(); void order(); void ctOrder(); void rectOrder(); void decl(); void grid(); void rect(); void incd(); void inch(); void incs(); void inca(); void incab(); void incv(); void incvb(); void typeab(); void typevb(); void case_(); void lrud(); void lrudOrder(); void prefix1(); void prefix2(); void prefix3(); void prefix(int index); void tape(); void uvh(); void uvv(); void uv(); void flag(); void checkCorrectedSign(int segStart, ULength measurement, ULength correction); Segment station(); void fromStation(); void afterFromStation(); void toStation(); void afterToStation(); void rectMeasurement(RectMeasurement elem); void east(); void north(); void rectUp(); void ctMeasurement(CtMeasurement elem); void distance(); void azimuth(); void inclination(); void instrumentHeight(); void targetHeight(); void lrudMeasurement(LrudMeasurement elem); void left(); void right(); void up(); void down(); template void warnIfNegative(UnitizedDouble measurement, int start, QString name); void afterVectorMeasurements(); template void varianceOverrides(T& target); void afterVectorVarianceOverrides(); void lruds(); void lrudContent(); void afterRequiredLrudMeasurements(); void lrudFacingAngle(); void lrudCFlag(); void afterLruds(); void inlineDirective(); template void inlineNote(T& target); template void inlineSegmentDirective(T& target); template void inlineCommentOrEndOfLine(T& target); template void inlineComment(T& target); void inlineCommentOrEndOfLine(); void inlineComment(); void fixLine(); void fixedStation(); void afterFixedStation(); void fixRectMeasurement(RectMeasurement elem); void fixEast(); void fixNorth(); void fixUp(); void afterFixMeasurements(); void afterFixVarianceOverrides(); void afterInlineFixNote(); void inlineFixDirective(); void comment(); bool _inBlockComment; WallsUnits _units; QStack _stack; QHash _macros; QStringList _segment; QStringList _rootSegment; QDate _date; bool _parsedSegmentDirective; Segment _fromStationSegment; Segment _toStationSegment; Segment _azmSegment; Segment _incSegment; Vector _vector; FixStation _fixStation; }; inline WallsUnits WallsSurveyParser::units() const { return _units; } inline QHash WallsSurveyParser::macros() const { return _macros; } inline QDate WallsSurveyParser::date() const { return _date; } inline QStringList WallsSurveyParser::rootSegment() const { return _rootSegment; } inline void WallsSurveyParser::setRootSegment(QStringList rootSegment) { _rootSegment = rootSegment; } inline QStringList WallsSurveyParser::segment() const { return _segment; } inline void WallsSurveyParser::setSegment(QStringList segment) { _segment = segment; } template QChar WallsSurveyParser::escapedChar(F charPredicate, std::initializer_list expectedItems) { QChar c = expectChar(charPredicate, expectedItems); return c == '\\' ? oneOfMap(escapedChars) : c; } template QString WallsSurveyParser::escapedText(F charPredicate, std::initializer_list expectedItems) { QString result; while (maybe([&]() { result.append(escapedChar(charPredicate, expectedItems)); } )); return result; } template bool WallsSurveyParser::optional(R& result, F production) { try { result = production(); } catch (const SegmentParseExpectedException& ex) { if (maybe([&]() { return expect(optionalRx, {"-", "--"}); })) { return false; } throw; } return true; } template bool WallsSurveyParser::optionalWithLookahead(R& result, F production) { int start = _i; try { result = production(); } catch (const SegmentParseExpectedException& ex) { _i = start; if (maybe([&]() { return expect(optionalRx, {"-", "--"}); })) { return false; } throw; } return true; } template QList WallsSurveyParser::elementChars(QHash elements, QSet requiredElements) { QList result; while (!elements.isEmpty()) { T element; if (requiredElements.isEmpty()) { if (!maybe(element, [&]() { return oneOfMap(elements); })) { break; } } else { element = oneOfMap(elements); } result += element; QChar c = _line.at(_i - 1); elements.remove(c.toLower()); elements.remove(c.toUpper()); requiredElements -= element; } return result; } } // namespace dewalls #endif // DEWALLS_WALLSPARSER_H dewalls-1.0.0/src/wallstypes.cpp000066400000000000000000000004401263712165300166510ustar00rootroot00000000000000#include "wallstypes.h" namespace dewalls { QString applyCaseType(CaseType type, const QString& s) { switch (type) { case Lower: return s.toLower(); case Upper: return s.toUpper(); default: break; } return s; } } dewalls-1.0.0/src/wallstypes.h000066400000000000000000000041731263712165300163250ustar00rootroot00000000000000#ifndef WALLSTYPES_H #define WALLSTYPES_H #include #include #include "dewallsexport.h" namespace dewalls { /// /// \brief station name case transforms /// enum CaseType { /// convert to upper case Upper = 0, /// convert to lower case Lower = 1, /// leave in original case Mixed = 2 }; QString applyCaseType(CaseType, const QString& s); /// /// \brief a type of measurement for compass-and-tape vectors /// enum class CtMeasurement { /// distance D = 'D', /// azimuth A = 'A', /// inclination V = 'V' }; inline uint qHash(CtMeasurement key, uint seed = 0) { return uint(static_cast(key)) ^ seed; } /// /// \brief a type of measurement for LRUDs /// enum class LrudMeasurement { /// left L = 'L', /// right R = 'R', /// up U = 'U', /// down D = 'D' }; inline uint qHash(const LrudMeasurement& key, uint seed = 0) { return uint(static_cast(key)) ^ seed; } /// /// \brief the types of LRUD station associations/orientations /// enum class DEWALLS_LIB_EXPORT LrudType { /// at from station, perpendicular to vector From = 0, /// at to station, perpendicular to vector To = 1, /// at from station, bisecting vectors FB = 2, /// at to station, bisecting vectors TB = 3 }; /// /// \brief a type of measurement for RECT vectors /// enum class RectMeasurement { /// east offset E = 'E', /// north offset N = 'N', /// up offset U = 'U' }; inline uint qHash(const RectMeasurement& key, uint seed = 0) { return uint(static_cast(key)) ^ seed; } /// /// \brief instrument/target height measurement types /// enum class TapingMethodMeasurement { Station = 0, InstrumentHeight = 1, TargetHeight = 2 }; /// /// \brief how a vector is measured (compass and tape or cartesian component vectors) /// enum class DEWALLS_LIB_EXPORT VectorType { /// compass and tape CT = 0, /// rectangular (north, east, up) RECT = 1 }; } #endif // WALLSTYPES_H dewalls-1.0.0/src/wallsunits.cpp000066400000000000000000000071141263712165300166540ustar00rootroot00000000000000#include "wallsunits.h" #include "unitizedmath.h" namespace dewalls { typedef UnitizedDouble ULength; typedef UnitizedDouble UAngle; WallsUnitsData::WallsUnitsData() : QSharedData(), vectorType(VectorType::CT), ctOrder(QList({CtMeasurement::D, CtMeasurement::A, CtMeasurement::V})), rectOrder(QList({RectMeasurement::E, RectMeasurement::N, RectMeasurement::U})), dUnit(Length::Meters), sUnit(Length::Meters), aUnit(Angle::Degrees), abUnit(Angle::Degrees), vUnit(Angle::Degrees), vbUnit(Angle::Degrees), decl(UAngle(0.0, Angle::Degrees)), grid(UAngle(0.0, Angle::Degrees)), rect(UAngle(0.0, Angle::Degrees)), incd(ULength(0.0, Length::Meters)), inca(UAngle(0.0, Angle::Degrees)), incab(UAngle(0.0, Angle::Degrees)), incv(UAngle(0.0, Angle::Degrees)), incvb(UAngle(0.0, Angle::Degrees)), incs(ULength(0.0, Length::Meters)), inch(ULength(0.0, Length::Meters)), typeabCorrected(false), typeabTolerance(UAngle(2, Angle::Degrees)), typeabNoAverage(false), typevbCorrected(false), typevbTolerance(UAngle(2, Angle::Degrees)), typevbNoAverage(false), case_(CaseType::Mixed), lrud(LrudType::From), lrudOrder(QList({LrudMeasurement::L, LrudMeasurement::R, LrudMeasurement::U, LrudMeasurement::D})), tape(QList({TapingMethodMeasurement::InstrumentHeight, TapingMethodMeasurement::TargetHeight})), flag(QString()), prefix(QStringList()), uvh(1.0), uvv(1.0) { } WallsUnits::WallsUnits() { d = new WallsUnitsData; } void WallsUnits::setPrefix(int index, QString newPrefix) { if (index < 0 || index > 2) { throw std::invalid_argument("prefix index out of range"); } d.detach(); while (d->prefix.size() <= index) { d->prefix << QString(); } d->prefix[index] = newPrefix; while (!d->prefix.isEmpty() && d->prefix.last().isNull()) { d->prefix.removeLast(); } } QString WallsUnits::processStationName(QString name) const { if (name.isNull()) { return QString(); } name = applyCaseType(d->case_, name); int explicitPrefixCount = name.count(':'); for (int i = explicitPrefixCount; i < d->prefix.size(); i++) { name.prepend(':').prepend(d->prefix[i]); } return name.replace(QRegExp("^:+"), ""); } ULength WallsUnits::correctLength(ULength length, ULength correction) { return length.isNonzero() && correction.isNonzero() ? length + correction : length; } UAngle WallsUnits::avgInc(UAngle fsInc, UAngle bsInc) const { if (!typevbCorrected()) { bsInc = -bsInc; } if (!fsInc.isValid()) { return bsInc; } else if (!bsInc.isValid()) { return fsInc; } return (fsInc + bsInc) * 0.5; } bool WallsUnits::isVertical(UAngle angle) { return fabs(fabs(angle.get(Angle::Degrees)) - 90.0) < 1e-6; } bool WallsUnits::isVertical(UAngle fsInc, UAngle bsInc) { if (fsInc.isValid() && !isVertical(fsInc)) { return false; } if (bsInc.isValid() && !isVertical(bsInc)) { return false; } return fsInc.isValid() || bsInc.isValid(); } QString WallsUnits::lrudOrderString() const { QString result; foreach(LrudMeasurement elem, lrudOrder()) { result += char(elem); } return result; } } // namespace dewalls dewalls-1.0.0/src/wallsunits.h000066400000000000000000000230451263712165300163220ustar00rootroot00000000000000#ifndef DEWALLS_WALLSUNITS_H #define DEWALLS_WALLSUNITS_H #include #include #include #include #include #include #include "unitizeddouble.h" #include "length.h" #include "angle.h" #include "wallstypes.h" #include "math.h" #include "dewallsexport.h" namespace dewalls { class WallsUnitsData : public QSharedData { public: typedef UnitizedDouble ULength; typedef UnitizedDouble UAngle; WallsUnitsData(); VectorType vectorType; QList ctOrder; QList rectOrder; Length::Unit dUnit; Length::Unit sUnit; Angle::Unit aUnit; Angle::Unit abUnit; Angle::Unit vUnit; Angle::Unit vbUnit; UAngle decl; UAngle grid; UAngle rect; ULength incd; UAngle inca; UAngle incab; UAngle incv; UAngle incvb; ULength incs; ULength inch; bool typeabCorrected; UAngle typeabTolerance; bool typeabNoAverage; bool typevbCorrected; UAngle typevbTolerance; bool typevbNoAverage; CaseType case_; LrudType lrud; QList lrudOrder; QList tape; QString flag; QStringList prefix; double uvh; double uvv; }; /// /// \brief Variables that are controlled through the #units directive (except for those /// that aren't affected by #units save/restore/reset, like macros). /// class DEWALLS_LIB_EXPORT WallsUnits { public: typedef UnitizedDouble ULength; typedef UnitizedDouble UAngle; WallsUnits(); /// /// \brief the current vector type - CT (compass and tape) or RECT /// inline VectorType vectorType() const { return d->vectorType; } /// /// \brief the order of measurements for CT (compass and tape) vectors. /// inline QList ctOrder() const { return d->ctOrder; } /// /// \brief the order of measurements for RECT vectors. /// inline QList rectOrder() const { return d->rectOrder; } /// /// \brief the unit for distances /// inline Length::Unit dUnit() const { return d->dUnit; } /// /// \brief the unit for short distances like LRUDs, inst/target heights /// inline Length::Unit sUnit() const { return d->sUnit; } /// /// \brief the frontsight azimuth unit /// inline Angle::Unit aUnit() const { return d->aUnit; } /// /// \brief the backsight azimuth unit /// inline Angle::Unit abUnit() const { return d->abUnit; } /// /// \brief the frontsight inclination unit /// inline Angle::Unit vUnit() const { return d->vUnit; } /// /// \brief the backsight inclination unit /// inline Angle::Unit vbUnit() const { return d->vbUnit; } /// /// \brief magnetic declination /// inline UAngle decl() const { return d->decl; } /// /// \brief grid correction (true north minus magnetic north) /// inline UAngle grid() const { return d->grid; } /// /// \brief rect correction (true north minus RECT north) /// inline UAngle rect() const { return d->rect; } /// /// \brief distance correction /// inline ULength incd() const { return d->incd; } /// /// \brief frontsight azimuth correction /// inline UAngle inca() const { return d->inca; } /// /// \brief backsight azimuth correction /// inline UAngle incab() const { return d->incab; } /// /// \brief frontsight inclination correction /// inline UAngle incv() const { return d->incv; } /// /// \brief backsight inclination correction /// inline UAngle incvb() const { return d->incvb; } /// /// \brief short distance corretion (e.g. LRUDs, inst/target heights) /// inline ULength incs() const { return d->incs; } /// /// \brief height correction (added to vertical offset of vectors) /// inline ULength inch() const { return d->inch; } /// /// \brief whether backsight azimuth is corrected /// inline bool typeabCorrected() const { return d->typeabCorrected; } /// /// \brief warning threshold for frontsight/backsight azimuth discrepancy /// inline UAngle typeabTolerance() const { return d->typeabTolerance; } /// /// \brief if true, use frontsight azimuth only in calculations /// inline bool typeabNoAverage() const { return d->typeabNoAverage; } /// /// \brief whether backsight inclination is corrected /// inline bool typevbCorrected() const { return d->typevbCorrected; } /// /// \brief warning threshold for frontsight/backsight inclination discrepancy /// inline UAngle typevbTolerance() const { return d->typevbTolerance; } /// /// \brief if true, use frontsight inclination only in calculations /// inline bool typevbNoAverage() const { return d->typevbNoAverage; } /// /// \brief station name case modification /// inline CaseType case_() const { return d->case_; } /// /// \brief LRUD station association/orientation /// inline LrudType lrud() const { return d->lrud; } /// /// \brief order of LRUD measurements /// inline QList lrudOrder() const { return d->lrudOrder; } /// /// \brief whether instrument and target heights may be present after dist/azm/inc /// inline QList tape() const { return d->tape; } /// /// \brief walls station flag /// inline QString flag() const { return d->flag; } /// /// \brief prefixes to prepend to station, joined by colons /// inline QStringList prefix() const { return d->prefix; } /// /// \brief assumed horizontal variance of all vectors /// inline double uvh() const { return d->uvh; } /// /// \brief assumed vertical variance of all vectors /// inline double uvv() const { return d->uvv; } inline void setVectorType(VectorType vectorType) { d->vectorType = vectorType; } inline void setCtOrder(QList ctOrder) { d->ctOrder = ctOrder; } inline void setRectOrder(QList rectOrder) { d->rectOrder = rectOrder; } inline void setDUnit(Length::Unit dUnit) { d->dUnit = dUnit; } inline void setSUnit(Length::Unit sUnit) { d->sUnit = sUnit; } inline void setAUnit(Angle::Unit aUnit) { d->aUnit = aUnit; } inline void setAbUnit(Angle::Unit abUnit) { d->abUnit = abUnit; } inline void setVUnit(Angle::Unit vUnit) { d->vUnit = vUnit; } inline void setVbUnit(Angle::Unit vbUnit) { d->vbUnit = vbUnit; } inline void setDecl(UAngle decl) { d->decl = decl; } inline void setGrid(UAngle grid) { d->grid = grid; } inline void setRect(UAngle rect) { d->rect = rect; } inline void setIncd(ULength incd) { d->incd = incd; } inline void setInca(UAngle inca) { d->inca = inca; } inline void setIncab(UAngle incab) { d->incab = incab; } inline void setIncv(UAngle incv) { d->incv = incv; } inline void setIncvb(UAngle incvb) { d->incvb = incvb; } inline void setIncs(ULength incs) { d->incs = incs; } inline void setInch(ULength inch) { d->inch = inch; } inline void setTypeabCorrected(bool typeabCorrected) { d->typeabCorrected = typeabCorrected; } inline void setTypeabTolerance(UAngle typeabTolerance) { d->typeabTolerance = typeabTolerance; } inline void setTypeabNoAverage(bool typeabNoAverage) { d->typeabNoAverage = typeabNoAverage; } inline void setTypevbCorrected(bool typevbCorrected) { d->typevbCorrected = typevbCorrected; } inline void setTypevbTolerance(UAngle typevbTolerance) { d->typevbTolerance = typevbTolerance; } inline void setTypevbNoAverage(bool typevbNoAverage) { d->typevbNoAverage = typevbNoAverage; } inline void setCase(CaseType case_) { d->case_ = case_; } inline void setLrud(LrudType lrud) { d->lrud = lrud; } inline void setLrudOrder(QList lrudOrder) { d->lrudOrder = lrudOrder; } inline void setTape(QList tape) { d->tape = tape; } inline void setFlag(QString flag) { d->flag = flag; } inline void setPrefix(QStringList prefix) { d->prefix = prefix; } inline void setUvh(double uvh) { d->uvh = uvh; } inline void setUvv(double uvv) { d->uvv = uvv; } /// /// \brief sets the prefix at the given index [1-3] /// void setPrefix(int index, QString newPrefix); /// /// \brief applies case modification and prefixes to a station name /// QString processStationName(QString name) const; /// /// \return QString representation of LRUD order /// QString lrudOrderString() const; /// /// \brief corrects a length measurement if it's nonzero by adding the given correction /// static ULength correctLength(ULength dist, ULength correction); /// /// \brief gets the average inclination of the given frontsight/backsight, which may be invalid /// UAngle avgInc(UAngle fsInc, UAngle bsInc) const; /// /// \brief determines if the given inclination is almost vertical /// static bool isVertical(UAngle angle); /// /// \brief determines if the given frontsight/backsight inclination are almost vertical /// static bool isVertical(UAngle fsInc, UAngle bsInc); private: QSharedDataPointer d; }; } // namespace dewalls #endif // DEWALLS_WALLSUNITS_H dewalls-1.0.0/test/000077500000000000000000000000001263712165300141305ustar00rootroot00000000000000dewalls-1.0.0/test/Kaua North Maze.wpj000066400000000000000000000064411263712165300174700ustar00rootroot00000000000000;WALLS Project file .BOOK Actun Kaua - North Maze .NAME KAUA-NM .STATUS 2563 .REF 2308521.655 324341.706 16 -0.602 27 6 20 52 11.202 88 41 18.631 13 "NAD27 Alaska" .SURVEY SVG Map Info - Please Read First! .NAME SVGINFO.TXT .STATUS 196618 .SURVEY Flags and Notes .NAME NOTES .BOOK SVG Sources .STATUS 9 .SURVEY KAUA-NM_w2d_mrg.svg .NAME KAUA-NM_w2d_mrg.svg .STATUS 196616 .ENDBOOK .BOOK Fixed Points .STATUS 9 .SURVEY Fixed Reference at Station 5 .NAME ENT-ZERO .STATUS 8 .SURVEY 2nd Fix that Moves W2 10m North .NAME WARPTEST .STATUS 10 .ENDBOOK .BOOK North Maze Surveys .NAME NORTH .STATUS 9 .BOOK Dec30-Jan11 2003 Surveys .NAME ALL2003 .STATUS 24 .SURVEY Jan 09 D-Survey .NAME DSURV09 .STATUS 24 .SURVEY Jan 08 D-Survey .NAME DSURV08 .STATUS 24 .SURVEY Jan 07 D-Survey .NAME DSURV07 .STATUS 24 .SURVEY Jan 05 D-Survey .NAME DSURV05 .STATUS 24 .SURVEY Jan 04 D-Survey .NAME DSURV04 .STATUS 24 .SURVEY Jan 02 D-Survey .NAME DSURV02 .STATUS 24 .SURVEY Jan 01 D-Survey .NAME DSURV01 .STATUS 8 .SURVEY Dec 31 D-Survey .NAME DSURV31 .STATUS 8 .SURVEY Dec 30 D-Survey .NAME D-SURVEY .STATUS 8 .ENDBOOK .BOOK Dec 2001 Surveys .NAME DEC2001A .STATUS 24 .SURVEY Floated Shots for SVG Export .NAME NM-FLOAT .STATUS 8 .BOOK N Surveys .NAME NSURVEYS .STATUS 8 .SURVEY Jan 10 2002 N Survey .NAME 020110N .STATUS 8 .SURVEY Jan 9 2002 N Survey .NAME 020109N .STATUS 8 .SURVEY Jan 8 2002 N Survey .NAME 020108-N .STATUS 24 .SURVEY Jan 6 2002 N Survey .NAME 020105-N .STATUS 24 .SURVEY Jan 3 2002 N Survey .NAME 020103N .STATUS 24 .SURVEY Jan 2, 2002 Survey .NAME 020102N .STATUS 24 .SURVEY Jan 1 2002 N Survey .NAME 020101N .STATUS 24 .SURVEY Dec 30 2001 N Survey .NAME 011230-N .STATUS 24 .ENDBOOK .BOOK F Surveys .NAME FSURVEYS .OPTIONS incV=-0.5 .STATUS 8 .SURVEY Jan 10 2002 F-Survey .NAME 020110-F .STATUS 8 .SURVEY Jan 8 2002 F-Survey .NAME 020108-F .STATUS 24 .SURVEY Jan 7 2002 F-Survey .NAME 020107-F .STATUS 8 .SURVEY Jan 06 2002 F-Survey .NAME 020106F .STATUS 8 .SURVEY Jan 02 2002 F-Survey .NAME 020102F .STATUS 8 .SURVEY Jan 01 2002 F-Survey .NAME 020101F .STATUS 24 .SURVEY Dec 30 2001 F-Survey .NAME 011230F .STATUS 8 .SURVEY Dec 29 Survey .NAME 01-12-29 .STATUS 8 .SURVEY Dec 26 Survey .NAME 01-12-26 .STATUS 8 .ENDBOOK .ENDBOOK .BOOK 1994 Additions .NAME K1994ADD .STATUS 8 .SURVEY A Survey .NAME KASURVEY .OPTIONS IncA=-2 .STATUS 8 .ENDBOOK .BOOK 1974 Surveys .NAME NMAZE74 .STATUS 8 .BOOK Entance Maze (1974) .NAME EMAZE74 .STATUS 8 .SURVEY Entrance Maze to Well 1 .NAME NMAZEN .STATUS 24 .SURVEY *R:1-18 - Ent Maze & North Edge (9 Oct 74) .NAME K741009 .STATUS 8 .SURVEY *R:19-22 - Ent Maze and South Edge (10 Oct 1974) .NAME K741010 .STATUS 24 .SURVEY C:1-22 Ent Maze and South Maze (21 Oct 74) .NAME K741021 .STATUS 24 .ENDBOOK .SURVEY Q:1-5 W3-W2 Well Connection (8 Oct 74?) .NAME NMAZEN2 .STATUS 24 .SURVEY W:1-9 Right Wall to W2 (8 Oct 74?) .NAME RTWALL .STATUS 24 .SURVEY *B:1-38 North Maze: X-Surv (8-9 Dec 74) .NAME K741208 .STATUS 24 .SURVEY A:1-18 North Maze: J-Surv (9 Nov 74) .NAME K741109 .STATUS 24 .SURVEY A:19-38 North Maze: T,J Surv (19 Nov 74) .NAME K741119 .STATUS 24 .SURVEY A:39-65 North Maze: J,X Surv (20 Nov 74) .NAME K741120 .STATUS 24 .ENDBOOK .BOOK Left Wall Passage .NAME WEST .STATUS 24 .SURVEY Left Wall (19 July 75) .NAME K750719 .STATUS 24 .SURVEY Left Wall (20 July 75) .NAME K750720 .STATUS 24 .ENDBOOK .ENDBOOK .ENDBOOK dewalls-1.0.0/test/applyheightcorrectionstest.cpp000066400000000000000000000151041263712165300223260ustar00rootroot00000000000000#include "../lib/catch.hpp" #include "vector.h" #include "wallstypes.h" #include "unitizedmath.h" #include using namespace dewalls; typedef UnitizedDouble ULength; typedef UnitizedDouble UAngle; void testInstance(ULength instY, ULength targetY, ULength fromY, ULength toY, ULength horizDist, ULength inch, QList tape) { WallsUnits units; units.setInch(inch); units.setIncd(ULength(1, Length::Inches)); units.setIncs(ULength(1, Length::Inches)); units.setIncv(UAngle(2, Angle::Degrees)); units.setTape(tape); std::cout << "===============================" << std::endl; std::cout << " instY: " << instY << std::endl; std::cout << " targetY: " << targetY << std::endl; std::cout << " fromY: " << fromY << std::endl; std::cout << " toY: " << toY << std::endl; std::cout << " horizDist: " << horizDist << std::endl; std::cout << " inch: " << inch << std::endl; ULength tapeFromY = tape[0] == TapingMethodMeasurement::InstrumentHeight ? instY : fromY; ULength tapeToY = tape[1] == TapingMethodMeasurement::TargetHeight ? targetY : toY; Vector vector; vector.setDistance(usqrt(usq(horizDist) + usq(tapeToY - tapeFromY)) - units.incd()); vector.setFrontAzimuth(UAngle(0, Angle::Degrees) - units.inca()); if (horizDist.isNonzero() && targetY != instY) { vector.setFrontInclination(uatan((targetY - instY) / horizDist) - units.incv()); } vector.setInstHeight(instY - fromY - units.incs()); vector.setTargetHeight(targetY - toY - units.incs()); vector.setUnits(units); ULength expectedDist = usqrt(usq(toY + inch - fromY) + usq(horizDist)); UAngle expectedInc = uatan2((toY + inch - fromY), horizDist); ULength instHeightAboveTape = instY - tapeFromY; ULength targetHeightAboveTape = targetY - tapeToY; bool isDiveShot = tape[0] == TapingMethodMeasurement::Station && tape[1] == TapingMethodMeasurement::Station && (!vector.frontInclination().isValid() || vector.frontInclination().isZero()); if (!isDiveShot && uabs(instHeightAboveTape - targetHeightAboveTape) > vector.distance()) { CHECK_THROWS( vector.applyHeightCorrections() ); } else { vector.applyHeightCorrections(); CHECK( (vector.distance() + units.incd()).get(Length::Meters) == Approx( expectedDist.get(Length::Meters) ) ); CHECK( (vector.frontInclination() + units.incv()).get(Angle::Degrees) == Approx( expectedInc.get(Angle::Degrees) ) ); } } QList IT({TapingMethodMeasurement::InstrumentHeight, TapingMethodMeasurement::TargetHeight}); QList IS({TapingMethodMeasurement::InstrumentHeight, TapingMethodMeasurement::Station}); QList ST({TapingMethodMeasurement::Station, TapingMethodMeasurement::TargetHeight}); QList SS({TapingMethodMeasurement::Station, TapingMethodMeasurement::Station}); void testInstance(ULength instY, ULength targetY, ULength fromY, ULength toY, ULength horizDist, ULength inch) { if (horizDist.isNonzero()) { testInstance(instY, targetY, fromY, toY, horizDist, inch, IT); testInstance(instY, targetY, fromY, toY, horizDist, inch, IS); testInstance(instY, targetY, fromY, toY, horizDist, inch, ST); } testInstance(instY, targetY, fromY, toY, horizDist, inch, SS); } TEST_CASE( "applyHeightCorrections", "[dewalls]" ) { SECTION( "vertical dive shots without inch" ) { testInstance(ULength(0, Length::Meters), ULength(0, Length::Meters), ULength(-8, Length::Meters), ULength(-3, Length::Meters), ULength(0, Length::Meters), ULength(0, Length::Meters)); testInstance(ULength(0, Length::Meters), ULength(0, Length::Meters), ULength(-3, Length::Meters), ULength(-8, Length::Meters), ULength(0, Length::Meters), ULength(0, Length::Meters)); } SECTION( "vertical dive shots with inch" ) { testInstance(ULength(0, Length::Meters), ULength(0, Length::Meters), ULength(-8, Length::Meters), ULength(-3, Length::Meters), ULength(0, Length::Meters), ULength(2, Length::Meters)); testInstance(ULength(0, Length::Meters), ULength(0, Length::Meters), ULength(-3, Length::Meters), ULength(-8, Length::Meters), ULength(0, Length::Meters), ULength(2, Length::Meters)); } SECTION( "near-vertical dive shots without inch") { testInstance(ULength(0, Length::Meters), ULength(0, Length::Meters), ULength(-3, Length::Meters), ULength(-18, Length::Meters), ULength(0.5, Length::Meters), ULength(0, Length::Meters), SS); testInstance(ULength(0, Length::Meters), ULength(0, Length::Meters), ULength(-18, Length::Meters), ULength(-3, Length::Meters), ULength(0.5, Length::Meters), ULength(0, Length::Meters), SS); } SECTION( "near-vertical dive shots with inch") { testInstance(ULength(0, Length::Meters), ULength(0, Length::Meters), ULength(-3, Length::Meters), ULength(-18, Length::Meters), ULength(0.5, Length::Meters), ULength(2, Length::Meters), SS); testInstance(ULength(0, Length::Meters), ULength(0, Length::Meters), ULength(-18, Length::Meters), ULength(-3, Length::Meters), ULength(0.5, Length::Meters), ULength(2, Length::Meters), SS); } SECTION( "various shots" ) { testInstance(ULength(3, Length::Meters), ULength(8, Length::Meters), ULength(2, Length::Meters), ULength(4, Length::Meters), ULength(7, Length::Meters), ULength(2, Length::Meters)); testInstance(ULength(3, Length::Meters), ULength(8, Length::Meters), ULength(2, Length::Meters), ULength(9, Length::Meters), ULength(7, Length::Meters), ULength(2, Length::Meters)); testInstance(ULength(3, Length::Meters), ULength(8, Length::Meters), ULength(4, Length::Meters), ULength(7, Length::Meters), ULength(7, Length::Meters), ULength(2, Length::Meters)); testInstance(ULength(3, Length::Meters), ULength(8, Length::Meters), ULength(0, Length::Meters), ULength(0, Length::Meters), ULength(7, Length::Meters), ULength(2, Length::Meters)); } SECTION( "ridiculous shots" ) { testInstance(ULength(3, Length::Meters), ULength(8, Length::Meters), ULength(4, Length::Meters), ULength(68, Length::Meters), ULength(7, Length::Meters), ULength(2, Length::Meters)); testInstance(ULength(3, Length::Meters), ULength(8, Length::Meters), ULength(68, Length::Meters), ULength(68, Length::Meters), ULength(7, Length::Meters), ULength(2, Length::Meters)); testInstance(ULength(3, Length::Meters), ULength(58, Length::Meters), ULength(2, Length::Meters), ULength(-62, Length::Meters), ULength(7, Length::Meters), ULength(2, Length::Meters)); } } dewalls-1.0.0/test/approx.h000066400000000000000000000005201263712165300156070ustar00rootroot00000000000000#ifndef APPROX_H #define APPROX_H namespace dewalls { inline double approx(double val) { return floor(val * 1e6) * 1e-6; } template inline bool approxEquals(UnitizedDouble a, UnitizedDouble b) { return floor(a.get(a.unit()) * 1e6) == floor(b.get(b.unit()) * 1e6); } } #endif // APPROX_H dewalls-1.0.0/test/azimuthparsingtests.cpp000066400000000000000000000107431263712165300207710ustar00rootroot00000000000000#include "../lib/catch.hpp" #include "../src/wallssurveyparser.h" #include "approx.h" using namespace dewalls; typedef UnitizedDouble UAngle; TEST_CASE( "azimuth parsing tests" , "[dewalls, azimuth]" ) { SECTION( "defaultUnit works") { CHECK( WallsSurveyParser("2.5").azimuth(Angle::Degrees) == UAngle(2.5, Angle::Degrees) ); CHECK( WallsSurveyParser("2.5").azimuth(Angle::Gradians) == UAngle(2.5, Angle::Gradians) ); } SECTION( "units suffixes work" ) { CHECK( WallsSurveyParser("2.5g").azimuth(Angle::Degrees) == UAngle(2.5, Angle::Gradians) ); CHECK( WallsSurveyParser("2.5m").azimuth(Angle::Degrees) == UAngle(2.5, Angle::MilsNATO) ); } SECTION( "percentGrade doesn't work" ) { WallsSurveyParser parser("2.5p"); REQUIRE( parser.azimuth(Angle::Degrees) == UAngle(2.5, Angle::Degrees) ); REQUIRE_THROWS( parser.endOfLine() ); } SECTION( "negative numbers work for azimuthOffset" ) { CHECK( WallsSurveyParser("-2.5").azimuthOffset(Angle::Degrees) == UAngle(-2.5, Angle::Degrees) ); } SECTION( "negative numbers throw for azimuth") { CHECK_THROWS( WallsSurveyParser("-2.5").azimuth(Angle::Degrees)); } SECTION( "degrees:minutes:seconds work" ) { CHECK( WallsSurveyParser("5:4:23").azimuth(Angle::Degrees) == UAngle(5 + (4 + 23 / 60.0) / 60.0, Angle::Degrees) ); CHECK( WallsSurveyParser("5:4").azimuth(Angle::Degrees) == UAngle(5 + 4 / 60.0, Angle::Degrees) ); CHECK( WallsSurveyParser("5::23").azimuth(Angle::Degrees) == UAngle(5 + (23 / 60.0) / 60.0, Angle::Degrees) ); CHECK( approxEquals(WallsSurveyParser("::23.5").azimuth(Angle::Degrees), UAngle((23.5 / 60.0) / 60.0, Angle::Degrees)) ); CHECK( WallsSurveyParser(":4").azimuth(Angle::Degrees) == UAngle(4 / 60.0, Angle::Degrees) ); } SECTION( "basic quadrants work" ) { CHECK( WallsSurveyParser("N30E").azimuth(Angle::Gradians) == UAngle(30, Angle::Degrees) ); CHECK( WallsSurveyParser("N30W").azimuth(Angle::Degrees) == UAngle(330, Angle::Degrees) ); CHECK( WallsSurveyParser("E30N").azimuth(Angle::Degrees) == UAngle(60, Angle::Degrees) ); CHECK( WallsSurveyParser("E30S").azimuth(Angle::Degrees) == UAngle(120, Angle::Degrees) ); CHECK( WallsSurveyParser("S30E").azimuth(Angle::Degrees) == UAngle(150, Angle::Degrees) ); CHECK( WallsSurveyParser("S30W").azimuth(Angle::Degrees) == UAngle(210, Angle::Degrees) ); CHECK( WallsSurveyParser("W30S").azimuth(Angle::Degrees) == UAngle(240, Angle::Degrees) ); CHECK( WallsSurveyParser("W30N").azimuth(Angle::Degrees) == UAngle(300, Angle::Degrees) ); } SECTION( "advanced quadrants work" ) { CHECK( WallsSurveyParser("N30.5E").azimuth(Angle::Degrees) == UAngle(30.5, Angle::Degrees) ); CHECK( WallsSurveyParser("N30:30E").azimuth(Angle::Degrees) == UAngle(30.5, Angle::Degrees) ); CHECK( WallsSurveyParser("N30:30:30E").azimuth(Angle::Degrees) == UAngle(30.5 + 30 / 3600.0, Angle::Degrees) ); CHECK( WallsSurveyParser("N30::30E").azimuth(Angle::Degrees) == UAngle(30 + 30 / 3600.0, Angle::Degrees) ); CHECK( approxEquals(WallsSurveyParser("N::30.5E").azimuth(Angle::Degrees), UAngle(30.5 / 3600.0, Angle::Degrees)) ); CHECK( WallsSurveyParser("N:30E").azimuth(Angle::Degrees) == UAngle(.5, Angle::Degrees) ); CHECK( WallsSurveyParser("N30gE").azimuth(Angle::Degrees) == UAngle(30, Angle::Gradians) ); } SECTION( "misc invalid values throw" ) { CHECK_THROWS( WallsSurveyParser("").azimuth(Angle::Degrees) ); CHECK_THROWS( WallsSurveyParser("-").azimuth(Angle::Degrees) ); CHECK_THROWS( WallsSurveyParser("-.").azimuth(Angle::Degrees) ); CHECK_THROWS( WallsSurveyParser(".").azimuth(Angle::Degrees) ); CHECK_THROWS( WallsSurveyParser("+2").azimuth(Angle::Degrees) ); CHECK_THROWS( WallsSurveyParser(" ").azimuth(Angle::Degrees) ); } SECTION( "out of range values throw" ) { CHECK_THROWS( WallsSurveyParser("360").azimuth(Angle::Degrees) ); CHECK_THROWS( WallsSurveyParser("-0.00001").azimuth(Angle::Degrees) ); CHECK_THROWS( WallsSurveyParser("400g").azimuth(Angle::Degrees) ); CHECK_THROWS( WallsSurveyParser("-0.00001g").azimuth(Angle::Degrees) ); CHECK_THROWS( WallsSurveyParser("N90E").azimuth(Angle::Degrees) ); CHECK_THROWS( WallsSurveyParser("N100gE").azimuth(Angle::Degrees) ); } } dewalls-1.0.0/test/dewalls-test.qrc000066400000000000000000000001461263712165300172500ustar00rootroot00000000000000 Kaua North Maze.wpj dewalls-1.0.0/test/dewallstests.cpp000066400000000000000000000003321263712165300173500ustar00rootroot00000000000000#define CATCH_CONFIG_MAIN #include "../lib/catch.hpp" #include "segmentparseexception.h" CATCH_TRANSLATE_EXCEPTION( dewalls::SegmentParseException& ex ) { return ex.message().toLocal8Bit().constData(); } dewalls-1.0.0/test/generaltests.cpp000066400000000000000000001124341263712165300173410ustar00rootroot00000000000000#include "../lib/catch.hpp" #include "../src/wallssurveyparser.h" #include "approx.h" #include "unitizedmath.h" #include "segmentparseexception.h" #include using namespace dewalls; typedef UnitizedDouble ULength; typedef UnitizedDouble UAngle; TEST_CASE( "general tests", "[dewalls]" ) { WallsSurveyParser parser; REQUIRE( parser.units().vectorType() == VectorType::CT ); REQUIRE( parser.units().dUnit() == Length::Meters ); REQUIRE( parser.units().sUnit() == Length::Meters ); REQUIRE( parser.units().aUnit() == Angle::Degrees ); REQUIRE( parser.units().abUnit() == Angle::Degrees ); REQUIRE( parser.units().vUnit() == Angle::Degrees ); REQUIRE( parser.units().vbUnit() == Angle::Degrees ); REQUIRE( parser.units().lrud() == LrudType::From ); REQUIRE( parser.units().prefix().isEmpty() ); REQUIRE( parser.units().typeabCorrected() == false ); REQUIRE( parser.units().typevbTolerance() == UAngle(2.0, Angle::Degrees) ); REQUIRE( parser.units().typevbCorrected() == false ); REQUIRE( parser.units().typevbTolerance() == UAngle(2.0, Angle::Degrees) ); REQUIRE( parser.units().rect().isZero() ); REQUIRE( parser.units().decl().isZero() ); REQUIRE( parser.units().grid().isZero() ); REQUIRE( parser.units().incd().isZero() ); REQUIRE( parser.units().incs().isZero() ); REQUIRE( parser.units().inca().isZero() ); REQUIRE( parser.units().incab().isZero() ); REQUIRE( parser.units().incv().isZero() ); REQUIRE( parser.units().incvb().isZero() ); REQUIRE( parser.units().inch().isZero() ); REQUIRE( parser.units().tape().size() == 2); REQUIRE( parser.units().tape()[0] == TapingMethodMeasurement::InstrumentHeight ); REQUIRE( parser.units().tape()[1] == TapingMethodMeasurement::TargetHeight ); REQUIRE( parser.date().isNull() ); REQUIRE( parser.units().case_() == CaseType::Mixed ); REQUIRE( parser.units().flag().isNull() ); REQUIRE( parser.segment().isEmpty() ); REQUIRE( parser.units().uvh() == 1.0 ); REQUIRE( parser.units().uvv() == 1.0 ); Vector vector; FixStation station; QList messages; QString comment; QObject::connect(&parser, &WallsSurveyParser::parsedVector, [&](Vector v) { vector = v; }); QObject::connect(&parser, &WallsSurveyParser::parsedFixStation, [&](FixStation s) { station = s; }); QObject::connect(&parser, &WallsSurveyParser::message, [&](WallsMessage m) { messages << m; }); QObject::connect(&parser, &WallsSurveyParser::parsedComment, [&](QString c) { comment = c; }); SECTION( "vector line parsing tests" ) { parser.parseLine("A1 A2 2.5 350 2.3"); REQUIRE( vector.from() == "A1" ); REQUIRE( vector.to() == "A2" ); REQUIRE( vector.distance() == ULength(2.5, Length::Meters) ); REQUIRE( vector.frontAzimuth() == UAngle(350, Angle::Degrees) ); REQUIRE( !vector.backAzimuth().isValid() ); REQUIRE( vector.frontInclination() == UAngle(2.3, Angle::Degrees) ); REQUIRE( !vector.backInclination().isValid() ); SECTION( "station prefixes" ) { parser.parseLine(":A1 A2 2.5 350 2.3"); REQUIRE( vector.from() == ":A1" ); parser.parseLine("::A1 A2 2.5 350 2.3"); REQUIRE( vector.from() == "::A1" ); parser.parseLine(":::A1 A2 2.5 350 2.3"); REQUIRE( vector.from() == ":::A1" ); parser.parseLine("q:::A1 A2 2.5 350 2.3"); REQUIRE( vector.from() == "q:::A1" ); parser.parseLine(":q::A1 A2 2.5 350 2.3"); REQUIRE( vector.from() == ":q::A1" ); parser.parseLine("::q:A1 A2 2.5 350 2.3"); REQUIRE( vector.from() == "::q:A1" ); parser.parseLine(":q:q:A1 A2 2.5 350 2.3"); REQUIRE( vector.from() == ":q:q:A1" ); parser.parseLine("q::q:A1 A2 2.5 350 2.3"); REQUIRE( vector.from() == "q::q:A1" ); parser.parseLine("q:q:q:A1 A2 2.5 350 2.3"); REQUIRE( vector.from() == "q:q:q:A1" ); REQUIRE_THROWS( parser.parseLine("::::A1 A2 2.5 350 2.3") ); } SECTION( "backsights" ) { parser.parseLine("A1 A2 2.5 350/349 2.3/2.4"); REQUIRE( vector.from() == "A1" ); REQUIRE( vector.to() == "A2" ); REQUIRE( vector.distance() == ULength(2.5, Length::Meters) ); REQUIRE( vector.frontAzimuth() == UAngle(350, Angle::Degrees) ); REQUIRE( vector.backAzimuth() == UAngle(349, Angle::Degrees) ); REQUIRE( vector.frontInclination() == UAngle(2.3, Angle::Degrees) ); REQUIRE( vector.backInclination() == UAngle(2.4, Angle::Degrees) ); } SECTION( "frontsights/backsights can be omitted" ) { parser.parseLine("A1 A2 2.5 350/-- --/2.4"); REQUIRE( vector.frontAzimuth() == UAngle(350, Angle::Degrees) ); REQUIRE( !vector.backAzimuth().isValid() ); REQUIRE( !vector.frontInclination().isValid() ); REQUIRE( vector.backInclination() == UAngle(2.4, Angle::Degrees) ); } SECTION( "distance" ) { SECTION( "distance can't be omitted" ) { CHECK_THROWS( parser.parseLine("A B -- 350 2.5") ); } SECTION( "can't be negative" ) { CHECK_THROWS( parser.parseLine("A B -0.001 350 4") ); } SECTION( "dUnit affects distance" ) { parser.parseLine("#units d=feet"); parser.parseLine("A B 2.5 350 4"); REQUIRE( vector.distance() == ULength(2.5, Length::Feet) ); } SECTION( "sUnit doesn't affect distance" ) { parser.parseLine("#units s=feet"); parser.parseLine("A B 2.5 350 4"); REQUIRE( vector.distance() == ULength(2.5, Length::Meters) ); } } SECTION( "incd" ) { parser.parseLine("#units incd=-2"); SECTION( "error when incd changes measurement sign" ) { // zero-length shots should not be affected parser.parseLine("A B 0 350 4"); // shots long enough should be OK parser.parseLine("A B 2.1 350 4"); CHECK_THROWS( parser.parseLine("A B 1 350 4") ); } } SECTION( "azimuth" ) { SECTION( "azimuth can be omitted for vertical shots" ) { parser.parseLine("A B 2.5 -- 90"); parser.parseLine("A B 2.5 -- 90/-90"); parser.parseLine("A B 2.5 -- --/90"); parser.parseLine("A B 2.5 -- --/-90"); parser.parseLine("A B 2.5 -- 90/-90"); parser.parseLine("A B 2.5 --/-- 90"); parser.parseLine("A B 2.5 -- -90"); parser.parseLine("A B 2.5 -- 100g"); parser.parseLine("A B 2.5 -- -100g"); } SECTION( "frontsight azimuth can be omitted without dashes" ) { parser.parseLine("A B 2.5 /235 0"); } SECTION( "azimuth can't be omitted for non-vertical shots" ) { CHECK_THROWS( parser.parseLine("A B 2.5 - 45") ); CHECK_THROWS( parser.parseLine("A B 2.5 -/-- 45") ); } SECTION( "aUnit" ) { parser.parseLine("#units a=grads"); parser.parseLine("A B 1 2/3 4"); REQUIRE( vector.frontAzimuth() == UAngle(2, Angle::Gradians) ); REQUIRE( vector.backAzimuth() == UAngle(3, Angle::Degrees) ); } SECTION( "abUnit" ) { parser.parseLine("#units ab=grads"); parser.parseLine("A B 1 2/3 4"); CHECK( vector.frontAzimuth() == UAngle(2, Angle::Degrees) ); CHECK( vector.backAzimuth() == UAngle(3, Angle::Gradians) ); } SECTION( "a/ab unit" ) { parser.parseLine("#units a/ab=grads"); parser.parseLine("A B 1 2/3 4"); CHECK( vector.frontAzimuth() == UAngle(2, Angle::Gradians) ); CHECK( vector.backAzimuth() == UAngle(3, Angle::Gradians) ); } SECTION( "parser warns if fs/bs difference exceeds tolerance" ) { messages.clear(); parser.parseLine("A B 1 1/179 4"); CHECK( messages.size() == 0 ); messages.clear(); parser.parseLine("A B 1 1/183 4"); CHECK( messages.size() == 0 ); messages.clear(); parser.parseLine("A B 1 1/184 4"); REQUIRE( messages.size() == 1 ); CHECK( messages[0].message().contains("exceeds") ); messages.clear(); parser.parseLine("#units typeab=c"); parser.parseLine("A B 1 1/3 4"); CHECK( messages.size() == 0 ); messages.clear(); parser.parseLine("A B 1 1/359 4"); CHECK( messages.size() == 0 ); messages.clear(); parser.parseLine("A B 1 359/1 4"); CHECK( messages.size() == 0 ); messages.clear(); parser.parseLine("#units typeab=c,5"); parser.parseLine("A B 1 1/6 4"); CHECK( messages.size() == 0 ); messages.clear(); parser.parseLine("A B 1 1/7 4"); CHECK( messages.size() == 1 ); } } SECTION( "inclination" ) { SECTION( "vUnit" ) { parser.parseLine("#units v=grads"); parser.parseLine("A B 1 2 3/4"); CHECK( vector.frontInclination() == UAngle(3, Angle::Gradians) ); CHECK( vector.backInclination() == UAngle(4, Angle::Degrees) ); } SECTION( "backsight inclination can be omitted without dashes" ) { parser.parseLine("A B 1 2 /3"); } SECTION( "vbUnit" ) { parser.parseLine("#units vb=grads"); parser.parseLine("A B 1 2 3/4"); CHECK( vector.frontInclination() == UAngle(3, Angle::Degrees) ); CHECK( vector.backInclination() == UAngle(4, Angle::Gradians) ); } SECTION( "v/vb unit" ) { parser.parseLine("#units v/vb=grads"); parser.parseLine("A B 1 2 3/4"); CHECK( vector.frontInclination() == UAngle(3, Angle::Gradians) ); CHECK( vector.backInclination() == UAngle(4, Angle::Gradians) ); } SECTION( "parser warns if fs/bs difference exceeds tolerance" ) { messages.clear(); parser.parseLine("A B 1 2 4/-6"); CHECK( messages.size() == 0 ); messages.clear(); parser.parseLine("A B 1 2 4/-2"); CHECK( messages.size() == 0 ); messages.clear(); parser.parseLine("A B 1 2 4/-7"); REQUIRE( messages.size() == 1 ); REQUIRE( messages[0].message().contains("exceeds") ); messages.clear(); parser.parseLine("#units typevb=c"); parser.parseLine("A B 1 2 1/3"); CHECK( messages.size() == 0 ); messages.clear(); parser.parseLine("A B 1 2 1/-1"); CHECK( messages.size() == 0 ); messages.clear(); parser.parseLine("#units typevb=c,5"); parser.parseLine("A B 1 2 1/6"); CHECK( messages.size() == 0 ); messages.clear(); parser.parseLine("A B 1 2 1/7"); CHECK( messages.size() == 1 ); } } SECTION( "rect data lines" ) { parser.parseLine("#units rect"); parser.parseLine("A B 1 2 3"); REQUIRE( vector.east() == ULength(1, Length::Meters) ); REQUIRE( vector.north() == ULength(2, Length::Meters) ); REQUIRE( vector.rectUp() == ULength(3, Length::Meters) ); REQUIRE_THROWS( parser.parseLine("A B 1 2") ); SECTION( "measurements can be reordered" ) { parser.parseLine("#units order=nue"); parser.parseLine("A B 1 2 3"); REQUIRE( vector.north() == ULength(1, Length::Meters) ); REQUIRE( vector.rectUp() == ULength(2, Length::Meters) ); REQUIRE( vector.east() == ULength(3, Length::Meters) ); } SECTION( "up can be omitted" ) { parser.parseLine("#units order=ne"); parser.parseLine("A B 1 2"); REQUIRE( vector.north() == ULength(1, Length::Meters) ); REQUIRE( vector.east() == ULength(2, Length::Meters) ); } SECTION( "LRUD-only lines can be parsed" ) { parser.parseLine("A *1 2 3 4*"); } SECTION( "LRUD/to station name ambiguity" ) { parser.parseLine("A <1 2 3 4"); CHECK( vector.to() == "<1" ); CHECK( vector.east() == ULength(2, Length::Meters) ); CHECK( vector.north() == ULength(3, Length::Meters) ); CHECK( vector.rectUp() == ULength(4, Length::Meters) ); CHECK( vector.left() == ULength() ); CHECK( vector.right() == ULength() ); CHECK( vector.up() == ULength() ); CHECK( vector.down() == ULength() ); parser.parseLine("A *1 2 3 4 *5,6,7,8*"); CHECK( vector.to() == "*1" ); CHECK( vector.east() == ULength(2, Length::Meters) ); CHECK( vector.north() == ULength(3, Length::Meters) ); CHECK( vector.rectUp() == ULength(4, Length::Meters) ); CHECK( vector.left() == ULength(5, Length::Meters) ); CHECK( vector.right() == ULength(6, Length::Meters) ); CHECK( vector.up() == ULength(7, Length::Meters) ); CHECK( vector.down() == ULength(8, Length::Meters) ); } } SECTION( "splay shots" ) { parser.parseLine("A - 2.5 350 5"); parser.parseLine("- B 2.5 350 5"); REQUIRE_THROWS( parser.parseLine("- - 2.5 350 5") ); } SECTION( "compass/tape measurements can be reordered" ) { parser.parseLine("#units order=avd"); parser.parseLine("A B 1 2 3"); REQUIRE( vector.frontAzimuth() == UAngle(1, Angle::Degrees) ); REQUIRE( vector.frontInclination() == UAngle(2, Angle::Degrees) ); REQUIRE( vector.distance() == ULength(3, Length::Meters) ); } SECTION( "inclination can be omitted from order" ) { parser.parseLine("#units order=da"); parser.parseLine("A B 1 2"); REQUIRE( vector.distance() == ULength(1, Length::Meters) ); REQUIRE( vector.frontAzimuth() == UAngle(2, Angle::Degrees) ); REQUIRE( !vector.frontInclination().isValid() ); } SECTION( "instrument and target heights" ) { parser.parseLine("A B 1 2 3 4 5"); REQUIRE( vector.instHeight() == ULength(4, Length::Meters) ); REQUIRE( vector.targetHeight() == ULength(5, Length::Meters) ); SECTION( "are affected by sUnit" ) { parser.parseLine("#units s=feet"); parser.parseLine("A B 1 2 3 4 5"); REQUIRE( vector.instHeight() == ULength(4, Length::Feet) ); REQUIRE( vector.targetHeight() == ULength(5, Length::Feet) ); } SECTION( "are not affected by dUnit" ) { parser.parseLine("#units d=feet"); parser.parseLine("A B 1 2 3 4 5"); REQUIRE( vector.instHeight() == ULength(4, Length::Meters) ); REQUIRE( vector.targetHeight() == ULength(5, Length::Meters) ); } SECTION( "with inclination omitted" ) { parser.parseLine("A B 1 2 -- 4 5"); REQUIRE( vector.instHeight() == ULength(4, Length::Meters) ); REQUIRE( vector.targetHeight() == ULength(5, Length::Meters) ); } SECTION( "aren't allowed for rect data lines" ) { parser.parseLine("#units rect"); REQUIRE_THROWS( parser.parseLine("A B 1 2 3 4 5") ); } } SECTION( "variance overrides" ) { SECTION( "both can't be omitted" ) { REQUIRE_THROWS( parser.parseLine("A B 1 2 3 (,)") ); } SECTION( "one can be omitted" ) { parser.parseLine("A B 1 2 3 (?,)"); CHECK( vector.horizVariance() == VarianceOverride::FLOATED ); CHECK( vector.vertVariance().isNull() ); parser.parseLine("A B 1 2 3 (,?)"); CHECK( vector.horizVariance().isNull() ); CHECK( vector.vertVariance() == VarianceOverride::FLOATED ); } SECTION( "various types" ) { parser.parseLine("A B 1 2 3 (?,*)"); CHECK( vector.horizVariance() == VarianceOverride::FLOATED ); CHECK( vector.vertVariance() == VarianceOverride::FLOATED_TRAVERSE ); parser.parseLine("A B 1 2 3 (1000f,r4.5f)"); REQUIRE( vector.horizVariance()->type() == VarianceOverride::Type::LENGTH_OVERRIDE ); CHECK( vector.horizVariance().staticCast()->lengthOverride() == ULength(1000, Length::Feet) ); REQUIRE( vector.vertVariance()->type() == VarianceOverride::Type::RMS_ERROR ); CHECK( vector.vertVariance().staticCast()->error() == ULength(4.5, Length::Feet) ); } } SECTION( "lruds" ) { parser.parseLine("A B 1 2 3 *4,5,6,7*"); CHECK( vector.left() == ULength(4, Length::Meters) ); CHECK( vector.right() == ULength(5, Length::Meters) ); CHECK( vector.up() == ULength(6, Length::Meters) ); CHECK( vector.down() == ULength(7, Length::Meters) ); parser.parseLine("A B 1 2 3 *4 5 6 7*"); CHECK( vector.left() == ULength(4, Length::Meters) ); CHECK( vector.right() == ULength(5, Length::Meters) ); CHECK( vector.up() == ULength(6, Length::Meters) ); CHECK( vector.down() == ULength(7, Length::Meters) ); parser.parseLine("A B 1 2 3 <4 5 6 7>"); CHECK( vector.left() == ULength(4, Length::Meters) ); CHECK( vector.right() == ULength(5, Length::Meters) ); CHECK( vector.up() == ULength(6, Length::Meters) ); CHECK( vector.down() == ULength(7, Length::Meters) ); parser.parseLine("A B 1 2 3 <4,5,6,7>"); CHECK( vector.left() == ULength(4, Length::Meters) ); CHECK( vector.right() == ULength(5, Length::Meters) ); CHECK( vector.up() == ULength(6, Length::Meters) ); CHECK( vector.down() == ULength(7, Length::Meters) ); SECTION( "can omit lruds" ) { parser.parseLine("A B 1 2 3 <4,-,6,-->"); CHECK( vector.left() == ULength(4, Length::Meters) ); CHECK( !vector.right().isValid() ); CHECK( vector.up() == ULength(6, Length::Meters) ); CHECK( !vector.down().isValid() ); } SECTION( "negative numbers allowed" ) { messages.clear(); parser.parseLine("A B 1 2 3 *-4,5,-6f,7*"); CHECK( vector.left() == ULength(-4, Length::Meters) ); CHECK( vector.right() == ULength(5, Length::Meters) ); CHECK( vector.up() == ULength(-6, Length::Feet) ); CHECK( vector.down() == ULength(7, Length::Meters) ); CHECK( messages.size() == 2 ); } SECTION( "can unitize individual lruds" ) { parser.parseLine("A B 1 2 3 *4f,5m,6i3,i7*"); CHECK( vector.left() == ULength(4, Length::Feet) ); CHECK( vector.right() == ULength(5, Length::Meters) ); CHECK( vector.up() == ULength(6 * 12 + 3, Length::Inches) ); CHECK( vector.down() == ULength(7, Length::Inches) ); } SECTION( "sUnit affects lruds" ) { parser.parseLine("#units s=feet"); parser.parseLine("A B 1 2 3 *4,5,6,7*"); CHECK( vector.left() == ULength(4, Length::Feet) ); CHECK( vector.right() == ULength(5, Length::Feet) ); CHECK( vector.up() == ULength(6, Length::Feet) ); CHECK( vector.down() == ULength(7, Length::Feet) ); } SECTION( "dUnit doesn't affect lruds" ) { parser.parseLine("#units d=feet"); parser.parseLine("A B 1 2 3 *4,5,6,7*"); CHECK( vector.left() == ULength(4, Length::Meters) ); CHECK( vector.right() == ULength(5, Length::Meters) ); CHECK( vector.up() == ULength(6, Length::Meters) ); CHECK( vector.down() == ULength(7, Length::Meters) ); } SECTION( "malformed lruds" ) { CHECK_THROWS( parser.parseLine("A B 1 2 3 *4,5,6,7>") ); CHECK_THROWS( parser.parseLine("A B 1 2 3 <4,5,6,7*") ); } SECTION( "malformed lruds that Walls accepts in contradition of its documentation" ) { parser.parseLine("A B 1 2 3 *4,5 6,7*"); parser.parseLine("A B 1 2 3 <4,5 6,7>"); messages.clear(); parser.parseLine("A B 1 2 3 <4,5,6,>"); CHECK( !messages.isEmpty() ); messages.clear(); parser.parseLine("A B 1 2 3 <4,5,6>"); CHECK( !messages.isEmpty() ); messages.clear(); parser.parseLine("A B 1 2 3 <1>"); CHECK( !messages.isEmpty() ); messages.clear(); parser.parseLine("A B 1 2 3 <>"); CHECK( !messages.isEmpty() ); messages.clear(); parser.parseLine("A B 1 2 3 < >"); CHECK( !messages.isEmpty() ); messages.clear(); parser.parseLine("A B 1 2 3 <,>"); CHECK( !messages.isEmpty() ); } SECTION( "can change lrud order" ) { parser.parseLine("#units lrud=from:urld"); parser.parseLine("A B 1 2 3 *4,5,6,7*"); REQUIRE( vector.up() == ULength(4, Length::Meters) ); REQUIRE( vector.right() == ULength(5, Length::Meters) ); REQUIRE( vector.left() == ULength(6, Length::Meters) ); REQUIRE( vector.down() == ULength(7, Length::Meters) ); } } SECTION( "lrud/station name ambiguity" ) { parser.parseLine("A *1 2 3 4"); CHECK( vector.to() == "*1" ); CHECK( vector.distance() == ULength(2, Length::Meters) ); CHECK( vector.frontAzimuth() == UAngle(3, Angle::Degrees) ); CHECK( vector.frontInclination() == UAngle(4, Angle::Degrees) ); CHECK( vector.left() == ULength() ); CHECK( vector.right() == ULength() ); CHECK( vector.up() == ULength() ); CHECK( vector.down() == ULength() ); parser.parseLine("A <1 2 3 4"); CHECK( vector.to() == "<1" ); CHECK( vector.distance() == ULength(2, Length::Meters) ); CHECK( vector.frontAzimuth() == UAngle(3, Angle::Degrees) ); CHECK( vector.frontInclination() == UAngle(4, Angle::Degrees) ); CHECK( vector.left() == ULength() ); CHECK( vector.right() == ULength() ); CHECK( vector.up() == ULength() ); CHECK( vector.down() == ULength() ); parser.parseLine("A <1 2 3 4 (?, ?)"); CHECK( vector.to() == "<1" ); CHECK( vector.distance() == ULength(2, Length::Meters) ); CHECK( vector.frontAzimuth() == UAngle(3, Angle::Degrees) ); CHECK( vector.frontInclination() == UAngle(4, Angle::Degrees) ); CHECK( vector.left() == ULength() ); CHECK( vector.right() == ULength() ); CHECK( vector.up() == ULength() ); CHECK( vector.down() == ULength() ); parser.parseLine("A *1 2 3 4 *5,6,7,8*"); CHECK( vector.to() == "*1" ); CHECK( vector.distance() == ULength(2, Length::Meters) ); CHECK( vector.frontAzimuth() == UAngle(3, Angle::Degrees) ); CHECK( vector.frontInclination() == UAngle(4, Angle::Degrees) ); CHECK( vector.left() == ULength(5, Length::Meters) ); CHECK( vector.right() == ULength(6, Length::Meters) ); CHECK( vector.up() == ULength(7, Length::Meters) ); CHECK( vector.down() == ULength(8, Length::Meters) ); parser.parseLine("A *1 2 3 4 4.5 *5,6,7,8*"); CHECK( vector.to() == "*1" ); CHECK( vector.distance() == ULength(2, Length::Meters) ); CHECK( vector.frontAzimuth() == UAngle(3, Angle::Degrees) ); CHECK( vector.frontInclination() == UAngle(4, Angle::Degrees) ); CHECK( vector.instHeight() == ULength(4.5, Length::Meters) ); CHECK( vector.left() == ULength(5, Length::Meters) ); CHECK( vector.right() == ULength(6, Length::Meters) ); CHECK( vector.up() == ULength(7, Length::Meters) ); CHECK( vector.down() == ULength(8, Length::Meters) ); parser.parseLine("A *1 2 3 4 4.5 4.6 *5,6,7,8,9*"); CHECK( vector.to() == "*1" ); CHECK( vector.distance() == ULength(2, Length::Meters) ); CHECK( vector.frontAzimuth() == UAngle(3, Angle::Degrees) ); CHECK( vector.frontInclination() == UAngle(4, Angle::Degrees) ); CHECK( vector.instHeight() == ULength(4.5, Length::Meters) ); CHECK( vector.targetHeight() == ULength(4.6, Length::Meters) ); CHECK( vector.left() == ULength(5, Length::Meters) ); CHECK( vector.right() == ULength(6, Length::Meters) ); CHECK( vector.up() == ULength(7, Length::Meters) ); CHECK( vector.down() == ULength(8, Length::Meters) ); CHECK( vector.lrudAngle() == UAngle(9, Angle::Degrees) ); parser.parseLine("A *1 2 3 4 *"); CHECK( vector.to() == QString() ); CHECK( vector.distance() == ULength() ); CHECK( vector.frontAzimuth() == UAngle() ); CHECK( vector.frontInclination() == UAngle() ); CHECK( vector.left() == ULength(1, Length::Meters) ); CHECK( vector.right() == ULength(2, Length::Meters) ); CHECK( vector.up() == ULength(3, Length::Meters) ); CHECK( vector.down() == ULength(4, Length::Meters) ); parser.parseLine("A *1 2 3 4 5*"); CHECK( vector.to() == QString() ); CHECK( vector.distance() == ULength() ); CHECK( vector.frontAzimuth() == UAngle() ); CHECK( vector.frontInclination() == UAngle() ); CHECK( vector.left() == ULength(1, Length::Meters) ); CHECK( vector.right() == ULength(2, Length::Meters) ); CHECK( vector.up() == ULength(3, Length::Meters) ); CHECK( vector.down() == ULength(4, Length::Meters) ); CHECK( vector.lrudAngle() == UAngle(5, Angle::Degrees) ); parser.parseLine("A *1 2 3 4 5 C*"); CHECK( vector.to() == QString() ); CHECK( vector.distance() == ULength() ); CHECK( vector.frontAzimuth() == UAngle() ); CHECK( vector.frontInclination() == UAngle() ); CHECK( vector.left() == ULength(1, Length::Meters) ); CHECK( vector.right() == ULength(2, Length::Meters) ); CHECK( vector.up() == ULength(3, Length::Meters) ); CHECK( vector.down() == ULength(4, Length::Meters) ); CHECK( vector.lrudAngle() == UAngle(5, Angle::Degrees) ); CHECK( vector.cFlag() ); parser.parseLine("A <1 2 3 4 <5,6,7,8>"); CHECK( vector.to() == "<1" ); CHECK( vector.distance() == ULength(2, Length::Meters) ); CHECK( vector.frontAzimuth() == UAngle(3, Angle::Degrees) ); CHECK( vector.frontInclination() == UAngle(4, Angle::Degrees) ); CHECK( vector.left() == ULength(5, Length::Meters) ); CHECK( vector.right() == ULength(6, Length::Meters) ); CHECK( vector.up() == ULength(7, Length::Meters) ); CHECK( vector.down() == ULength(8, Length::Meters) ); parser.parseLine("A <1 2 3 4 >"); CHECK( vector.to() == QString() ); CHECK( vector.distance() == ULength() ); CHECK( vector.frontAzimuth() == UAngle() ); CHECK( vector.frontInclination() == UAngle() ); CHECK( vector.left() == ULength(1, Length::Meters) ); CHECK( vector.right() == ULength(2, Length::Meters) ); CHECK( vector.up() == ULength(3, Length::Meters) ); CHECK( vector.down() == ULength(4, Length::Meters) ); CHECK_THROWS( parser.parseLine("A *1 2 3 4 *1 2 3 4") ); CHECK_THROWS( parser.parseLine("A *-- -- -- --") ); } } SECTION( "invalid spacing" ) { CHECK_THROWS( parser.parseLine(" A B 1 2 3(?,?)") ); CHECK_THROWS( parser.parseLine(" A B 1 2 3 (?,?)*4,5,6,7*") ); CHECK_THROWS( parser.parseLine(" A B 1 2 3*4,5,6,7*") ); } SECTION( "valid spacing" ) { parser.parseLine(" A B 1 2 3#s blah;test"); parser.parseLine(" A B 1 2 3 *4,5,6,7*#s blah;test"); parser.parseLine(" A B 1 2 3 (?,?)#s blah;test"); parser.parseLine(" A B 1 2 3 (?,?) *4,5,6,7*#s blah;test"); } SECTION( "prefixes" ) { parser.parseLine("#units prefix=a"); CHECK( parser.units().processStationName("b") == "a:b" ); CHECK( parser.units().processStationName("d:b") == "d:b" ); CHECK( parser.units().processStationName(":b") == "b" ); parser.parseLine("#units prefix2=c"); CHECK( parser.units().processStationName("b") == "c:a:b" ); CHECK( parser.units().processStationName(":b") == "c::b" ); CHECK( parser.units().processStationName("d:b") == "c:d:b" ); CHECK( parser.units().processStationName("::b") == "b" ); CHECK( parser.units().processStationName(":::::b") == "b" ); parser.parseLine("#units prefix1"); CHECK( parser.units().processStationName("b") == "c::b" ); } SECTION( "fixed stations" ) { parser.parseLine("#FIX A1 W97:43:52.5 N31:16:45 323f (?,*) /Entrance #s blah ;dms with ft elevations"); REQUIRE( station.name() == "A1" ); REQUIRE( station.longitude() == UAngle(-97 - (43 + 52.5 / 60.0) / 60.0, Angle::Degrees) ); REQUIRE( station.latitude() == UAngle(31 + (16 + 45 / 60.0) / 60.0, Angle::Degrees) ); REQUIRE( station.rectUp() == ULength(323, Length::Feet) ); REQUIRE( station.horizVariance() == VarianceOverride::FLOATED ); REQUIRE( station.vertVariance() == VarianceOverride::FLOATED_TRAVERSE ); REQUIRE( station.note() == "Entrance" ); REQUIRE( station.segment().size() == 1 ); REQUIRE( station.segment()[0] == "blah" ); REQUIRE( station.comment() == "dms with ft elevations"); parser.parseLine("#FIX A4 620775.38 3461050.67 98.45"); REQUIRE( station.name() == "A4" ); REQUIRE( station.east() == ULength(620775.38, Length::Meters) ); REQUIRE( station.north() == ULength(3461050.67, Length::Meters) ); REQUIRE( station.rectUp() == ULength(98.45, Length::Meters) ); SECTION( "measurements can be reordered" ) { parser.parseLine("#units order=nue"); parser.parseLine("#fix a 1 2 3"); REQUIRE( station.north() == ULength(1, Length::Meters) ); REQUIRE( station.rectUp() == ULength(2, Length::Meters) ); REQUIRE( station.east() == ULength(3, Length::Meters) ); } SECTION( "affected by dUnit" ) { parser.parseLine("#units d=feet"); parser.parseLine("#fix a 1 2 3"); REQUIRE( station.east() == ULength(1, Length::Feet) ); REQUIRE( station.north() == ULength(2, Length::Feet) ); REQUIRE( station.rectUp() == ULength(3, Length::Feet) ); } SECTION( "valid spacing" ) { parser.parseLine("#FIX A1 W97:43:52.5 N31:16:45 323f(?,*)/Entrance#s blah;dms with ft elevations"); } } SECTION( "save, restore, and reset" ) { parser.parseLine("#units lrud=from:urld"); parser.parseLine("#units save"); parser.parseLine("#units lrud=from:rldu"); parser.parseLine("#units save"); parser.parseLine("#units reset"); REQUIRE( parser.units().lrudOrderString() == "LRUD" ); parser.parseLine("#units restore"); REQUIRE( parser.units().lrudOrderString() == "RLDU" ); parser.parseLine("#units restore"); REQUIRE( parser.units().lrudOrderString() == "URLD" ); } SECTION( "can't do more than 10 saves" ) { for (int i = 0; i < 10; i++) { parser.parseLine("#units save"); } REQUIRE_THROWS( parser.parseLine("#units save") ); } SECTION( "can't restore more than number of times saved" ) { for (int i = 0; i < 4; i++) { parser.parseLine("#units save"); } for (int i = 0; i < 4; i++) { parser.parseLine("#units restore"); } REQUIRE_THROWS( parser.parseLine("#units restore") ); } SECTION( "Walls' crazy macros" ) { parser.parseLine("#units $hello=\"der=vad pre\" $world=\"fix1=hello feet\""); REQUIRE( parser.macros()["hello"] == "der=vad pre" ); REQUIRE( parser.macros()["world"] == "fix1=hello feet" ); parser.parseLine("#units or$(hello)$(world)"); REQUIRE( parser.units().ctOrder().size() == 3 ); REQUIRE( parser.units().prefix().size() >= 1 ); CHECK( parser.units().ctOrder()[0] == CtMeasurement::V ); CHECK( parser.units().ctOrder()[1] == CtMeasurement::A ); CHECK( parser.units().ctOrder()[2] == CtMeasurement::D ); CHECK( parser.units().prefix()[0] == "hello" ); CHECK( parser.units().dUnit() == Length::Feet ); CHECK( parser.units().sUnit() == Length::Feet ); parser.parseLine("#units $hello $world"); CHECK( parser.macros()["hello"] == "" ); CHECK( parser.macros()["world"] == "" ); CHECK_THROWS( parser.parseLine("#units $(undefined)") ); } SECTION( "Comment lines" ) { parser.parseLine(";#units invalid=hello"); CHECK( comment == "#units invalid=hello" ); vector = Vector(); parser.parseLine(";a b 1 2 3"); CHECK( comment == "a b 1 2 3" ); CHECK( vector.from().isEmpty() ); CHECK( vector.to().isEmpty() ); } SECTION( "Block comments" ) { vector = Vector(); parser.parseLine("#["); parser.parseLine("a b 1 2 3"); CHECK( comment == "a b 1 2 3" ); CHECK( vector.from().isEmpty() ); CHECK( vector.to().isEmpty() ); parser.parseLine("#units f"); CHECK( parser.units().dUnit() == Length::Meters ); parser.parseLine("#]"); parser.parseLine("a b 1 2 3"); CHECK( vector.from() == "a" ); CHECK( vector.to() == "b" ); CHECK( vector.distance() == ULength(1, Length::Meters) ); CHECK( vector.frontAzimuth() == UAngle(2, Angle::Degrees) ); CHECK( vector.frontInclination() == UAngle(3, Angle::Degrees) ); } } TEST_CASE( "WallsUnits tests", "[dewalls]" ) { WallsUnits units; SECTION( "avgInc" ) { units.setTypevbCorrected(true); CHECK( units.avgInc(UAngle(3, Angle::Degrees), UAngle(1, Angle::Degrees)) == UAngle(2, Angle::Degrees) ); CHECK( units.avgInc(UAngle(1, Angle::Degrees), UAngle(3, Angle::Degrees)) == UAngle(2, Angle::Degrees) ); CHECK( units.avgInc(UAngle(3, Angle::Degrees), UAngle()) == UAngle(3, Angle::Degrees) ); CHECK( units.avgInc(UAngle(), UAngle(3, Angle::Degrees)) == UAngle(3, Angle::Degrees) ); units.setTypevbCorrected(false); CHECK( units.avgInc(UAngle(3, Angle::Degrees), UAngle(-1, Angle::Degrees)) == UAngle(2, Angle::Degrees) ); CHECK( units.avgInc(UAngle(1, Angle::Degrees), UAngle(-3, Angle::Degrees)) == UAngle(2, Angle::Degrees) ); CHECK( units.avgInc(UAngle(), UAngle(3, Angle::Degrees)) == UAngle(-3, Angle::Degrees) ); } } dewalls-1.0.0/test/inclinationparsingtests.cpp000066400000000000000000000052631263712165300216200ustar00rootroot00000000000000#include "../lib/catch.hpp" #include "../src/wallssurveyparser.h" #include "approx.h" using namespace dewalls; typedef UnitizedDouble UAngle; TEST_CASE( "inclination parsing tests" , "[dewalls, inclination]" ) { SECTION( "defaultUnit works") { CHECK( WallsSurveyParser("2.5").inclination(Angle::Degrees) == UAngle(2.5, Angle::Degrees) ); CHECK( WallsSurveyParser("2.5").inclination(Angle::Gradians) == UAngle(2.5, Angle::Gradians) ); } SECTION( "units suffixes work" ) { CHECK( WallsSurveyParser("2.5g").inclination(Angle::Degrees) == UAngle(2.5, Angle::Gradians) ); CHECK( WallsSurveyParser("2.5m").inclination(Angle::Degrees) == UAngle(2.5, Angle::MilsNATO) ); CHECK( WallsSurveyParser("2.5p").inclination(Angle::Degrees) == UAngle(2.5, Angle::PercentGrade) ); } SECTION( "negative numbers work" ) { CHECK( WallsSurveyParser("-2.5").inclination(Angle::Degrees) == UAngle(-2.5, Angle::Degrees) ); } SECTION( "degrees:minutes:seconds work" ) { CHECK( WallsSurveyParser("5:4:23").inclination(Angle::Degrees) == UAngle(5 + (4 + 23 / 60.0) / 60.0, Angle::Degrees) ); CHECK( WallsSurveyParser("5:4").inclination(Angle::Degrees) == UAngle(5 + 4 / 60.0, Angle::Degrees) ); CHECK( WallsSurveyParser("-5::23").inclination(Angle::Degrees) == UAngle(-5 - (23 / 60.0) / 60.0, Angle::Degrees) ); CHECK( approxEquals(WallsSurveyParser("::23.5").inclination(Angle::Degrees), UAngle((23.5 / 60.0) / 60.0, Angle::Degrees)) ); CHECK( WallsSurveyParser("-:4").inclination(Angle::Degrees) == UAngle(-4 / 60.0, Angle::Degrees) ); } SECTION( "plus sign works" ) { CHECK( WallsSurveyParser("+::2.5").inclination(Angle::Degrees) == UAngle(2.5 / 3600.0, Angle::Degrees) ); } SECTION( "misc invalid values throw" ) { CHECK_THROWS( WallsSurveyParser("").inclination(Angle::Degrees) ); CHECK_THROWS( WallsSurveyParser("-").inclination(Angle::Degrees) ); CHECK_THROWS( WallsSurveyParser("+").inclination(Angle::Degrees) ); CHECK_THROWS( WallsSurveyParser("-.").inclination(Angle::Degrees) ); CHECK_THROWS( WallsSurveyParser(".").inclination(Angle::Degrees) ); CHECK_THROWS( WallsSurveyParser(" ").inclination(Angle::Degrees) ); } SECTION( "out of range values throw" ) { CHECK_THROWS( WallsSurveyParser("90.0001").inclination(Angle::Degrees) ); CHECK_THROWS( WallsSurveyParser("-90.00001").inclination(Angle::Degrees) ); CHECK_THROWS( WallsSurveyParser("100.0001g").inclination(Angle::Degrees) ); CHECK_THROWS( WallsSurveyParser("-100.00001g").inclination(Angle::Degrees) ); } } dewalls-1.0.0/test/lengthparsingtests.cpp000066400000000000000000000031021263712165300205600ustar00rootroot00000000000000#include "../lib/catch.hpp" #include "../src/wallssurveyparser.h" using namespace dewalls; typedef UnitizedDouble ULength; TEST_CASE( "length parsing tests" , "[dewalls, length]" ) { SECTION( "defaultUnit works") { CHECK( WallsSurveyParser("2.5").length(Length::Meters) == ULength(2.5, Length::Meters) ); CHECK( WallsSurveyParser("2.5").length(Length::Feet) == ULength(2.5, Length::Feet) ); } SECTION( "Units suffixes work" ) { CHECK( WallsSurveyParser("2.5f").length(Length::Meters) == ULength(2.5, Length::Feet) ); CHECK( WallsSurveyParser("i2.5").length(Length::Meters) == ULength(2.5, Length::Inches) ); CHECK( WallsSurveyParser("2.5i4").length(Length::Meters) == ULength(4, Length::Inches) + ULength(2.5, Length::Feet) ); } SECTION( "negative numbers work" ) { CHECK( WallsSurveyParser("-2.5").length(Length::Meters) == ULength(-2.5, Length::Meters) ); } SECTION( "negative numbers throw for unsignedLength") { CHECK_THROWS( WallsSurveyParser("-2.5").unsignedLength(Length::Meters)); } SECTION( "misc invalid values throw" ) { CHECK_THROWS( WallsSurveyParser("").length(Length::Meters) ); CHECK_THROWS( WallsSurveyParser("-").length(Length::Meters) ); CHECK_THROWS( WallsSurveyParser("-.").length(Length::Meters) ); CHECK_THROWS( WallsSurveyParser(".").length(Length::Meters) ); CHECK_THROWS( WallsSurveyParser("+2").length(Length::Meters) ); CHECK_THROWS( WallsSurveyParser(" ").length(Length::Meters) ); } } dewalls-1.0.0/test/tostrings.cpp000066400000000000000000000002351263712165300166700ustar00rootroot00000000000000#include "tostrings.h" //namespace Catch { //template<> std::string toString(QString const& s) { // return s.toLocal8Bit().constData(); //} //} dewalls-1.0.0/test/tostrings.h000066400000000000000000000003401263712165300163320ustar00rootroot00000000000000#ifndef TOSTRINGS_H #define TOSTRINGS_H //#include "../lib/catch.hpp" //#include //#include //namespace Catch { //template<> std::string toString(QString const& s); //} #endif // TOSTRINGS_H dewalls-1.0.0/test/wallsprojectparsertests.cpp000066400000000000000000000123141263712165300216460ustar00rootroot00000000000000#include "../lib/catch.hpp" //#include "tostrings.h" #include "../src/wallsprojectparser.h" using namespace dewalls; typedef UnitizedDouble ULength; typedef UnitizedDouble UAngle; TEST_CASE( "WallsProjectParser parses example file", "[WallsProjectParser]" ) { WallsProjectParser parser; QObject::connect(&parser, &WallsProjectParser::message, [=](WallsMessage message) { std::cout << message.toString().toStdString() << std::endl; }); WpjBookPtr projectRoot; projectRoot = parser.parseFile(":/test/Kaua North Maze.wpj"); REQUIRE( !projectRoot.isNull() ); CHECK( projectRoot->Title == "Actun Kaua - North Maze" ); CHECK( projectRoot->Name.value() == "KAUA-NM" ); CHECK( projectRoot->defaultViewAfterCompilation() == WpjEntry::NorthOrEast); CHECK( !projectRoot->preserveVertShotLength() ); CHECK( !projectRoot->preserveVertShotOrientation() ); CHECK( projectRoot->deriveDeclFromDate() ); CHECK( projectRoot->gridRelative() ); REQUIRE( !projectRoot->reference().isNull() ); CHECK( projectRoot->reference()->northing == ULength(2308521.655, Length::Meters) ); CHECK( projectRoot->reference()->easting == ULength(324341.706, Length::Meters) ); CHECK( projectRoot->reference()->zone == 16 ); CHECK( projectRoot->reference()->gridConvergence == UAngle(-0.602, Angle::Degrees) ); CHECK( projectRoot->reference()->elevation == ULength(27, Length::Meters) ); REQUIRE( projectRoot->Children.size() == 5 ); WpjEntryPtr child0 = projectRoot->Children[0]; CHECK( child0->Title == "SVG Map Info - Please Read First!" ); CHECK( child0->Name.value() == "SVGINFO.TXT" ); CHECK( child0->isOther() ); CHECK( child0->launchOptions() == WpjEntry::Edit ); WpjEntryPtr child1 = projectRoot->Children[1]; CHECK( child1->Title == "Flags and Notes" ); CHECK( child1->Name.value() == "NOTES" ); CHECK( child1->isSurvey() ); WpjEntryPtr child2 = projectRoot->Children[2]; CHECK( child2->Title == "SVG Sources" ); CHECK( child2->Name.value() == QString() ); CHECK( child2->isBook() ); WpjEntryPtr child3 = projectRoot->Children[3]; CHECK( child3->Title == "Fixed Points" ); CHECK( child3->Name.value() == QString() ); CHECK( child3->isBook() ); WpjEntryPtr child4 = projectRoot->Children[4]; CHECK( child4->Title == "North Maze Surveys" ); CHECK( child4->Name.value() == "NORTH" ); CHECK( child4->isBook() ); } namespace dewalls { namespace PathTests { WpjEntryPtr entryAt(WpjBookPtr book, QString titlePath) { QStringList titleParts = titlePath.split("/"); for (int i = 0; i < titleParts.size() && !book.isNull(); i++) { WpjEntryPtr nextChild; foreach(WpjEntryPtr child, book->Children) { if (child->Title == titleParts[i]) { nextChild = child; break; } } if (i == titleParts.size() - 1) { return nextChild; } else if (!nextChild.isNull() && nextChild->isBook()) { book = nextChild.staticCast(); } else { return WpjEntryPtr(); } } return WpjEntryPtr(); } QString absolutePath(WpjEntryPtr entry) { return entry.isNull() ? QString() : entry->absolutePath(); } void checkEntryPath(WpjEntryPtr entry, QString path) { REQUIRE( !entry.isNull() ); CHECK( entry->absolutePath() == QDir::cleanPath(path) ); } } // namespace PathTests } // namespace dewalls TEST_CASE( "WallsProjectParser handles paths correctly", "[WallsProjectParser, .PATH]") { using namespace dewalls::PathTests; WallsProjectParser parser; parser.parseLine(".book root"); parser.parseLine(".path /rootdir"); parser.parseLine(".book a"); parser.parseLine(".book b"); parser.parseLine(".path bdir"); parser.parseLine(".book c"); parser.parseLine(".endbook"); parser.parseLine(".book d"); parser.parseLine(".path ddir"); parser.parseLine(".book e"); parser.parseLine(".endbook"); //e parser.parseLine(".endbook"); //d parser.parseLine(".endbook"); //b parser.parseLine(".book f"); parser.parseLine(".path fdir"); parser.parseLine(".survey g"); parser.parseLine(".name gsurvey"); parser.parseLine(".endbook"); // f parser.parseLine(".book h"); parser.parseLine(".path /hdir"); parser.parseLine(".endbook"); // h parser.parseLine(".survey i"); parser.parseLine(".endbook"); // a parser.parseLine(".endbook"); // root WpjBookPtr root = parser.result(); REQUIRE( !root.isNull() ); CHECK( "/rootdir" == absolutePath(root) ); CHECK( "/rootdir" == absolutePath(entryAt(root, "a")) ); CHECK( "/rootdir/bdir" == absolutePath(entryAt(root, "a/b")) ); CHECK( "/rootdir/bdir" == absolutePath(entryAt(root, "a/b/c")) ); CHECK( "/rootdir/bdir/ddir" == absolutePath(entryAt(root, "a/b/d")) ); CHECK( "/rootdir/bdir/ddir" == absolutePath(entryAt(root, "a/b/d/e")) ); CHECK( "/rootdir/fdir" == absolutePath(entryAt(root, "a/f")) ); CHECK( "/rootdir/fdir/gsurvey.SRV" == absolutePath(entryAt(root, "a/f/g")) ); CHECK( "/hdir" == absolutePath(entryAt(root, "a/h")) ); CHECK( QString() == absolutePath(entryAt(root, "a/i")) ); }