diff --git a/FsTrack.jucer b/FsTrack.jucer index c122d35..9172452 100644 --- a/FsTrack.jucer +++ b/FsTrack.jucer @@ -8,6 +8,10 @@ + + + + diff --git a/Source/HttpServer.cpp b/Source/HttpServer.cpp index 1378dcc..32e1970 100644 --- a/Source/HttpServer.cpp +++ b/Source/HttpServer.cpp @@ -1,6 +1,5 @@ #include "HttpServer.hpp" - HttpServer::HttpServer(int port, const char *pDocDir) : Thread("Http") , m_port(port) @@ -23,36 +22,46 @@ void HttpServer::addListener(IHttpListener *pListener) const char* HttpServer::getDocName(char *buffer, int buflen) { static char docBuffer[1024]; - char *pDocname; + char *pDoc = docBuffer; + char *pBuf; + bool hasQuery = false; strcpy(docBuffer, m_docDir); - pDocname = &docBuffer[strlen(docBuffer)]; - *pDocname = '\\'; - pDocname++; - - int i, off; + pDoc = &docBuffer[strlen(docBuffer)]; + *pDoc = '\\'; + pDoc++; if (!stricmp(buffer, "GET")) { return nullptr; } - off = 0; - while(buffer[3+off] == 0x20) - off++; + pBuf = buffer + 3; + while(*pBuf == 0x20) + pBuf++; - while(buffer[3+off] == '/') - off++; + while(*pBuf == '/') + pBuf++; - i = 0; - while(buffer[3+off+i] != 0x20) + int len = 0; + while(*pBuf != 0x20) { - pDocname[i] = buffer[3+off+i]; - i++; + if (*pBuf == '?') + { + hasQuery = true; + break; + } + *pDoc++ = *pBuf++; + len++; } - pDocname[i] = 0; + *pDoc = 0; - if (i==0) + if (hasQuery) + { + m_viewFormat.parse(pBuf); + } + + if (len==0) return nullptr; return docBuffer; @@ -85,7 +94,7 @@ void HttpServer::run() } else { - m_listeners.call(&IHttpListener::onUpdate, pDoc); + m_listeners.call(&IHttpListener::onUpdate, pDoc, m_viewFormat); } } diff --git a/Source/HttpServer.hpp b/Source/HttpServer.hpp index 1a3f09c..2aa4365 100644 --- a/Source/HttpServer.hpp +++ b/Source/HttpServer.hpp @@ -1,7 +1,8 @@ -#ifndef HTTPSERVER -#define HTTPSERVER +#ifndef HTTPSERVER_HPP +#define HTTPSERVER_HPP #include "../JuceLibraryCode/JuceHeader.h" +#include "ViewFormat.hpp" #include "IHttp.hpp" class HttpServer : public juce::Thread @@ -15,6 +16,7 @@ private: int m_port; const char *m_docDir; ListenerList m_listeners; + ViewFormat m_viewFormat; const char* getDocName(char *buffer, int buflen); void run(); diff --git a/Source/IHttp.hpp b/Source/IHttp.hpp index 6a1af6d..73c2a1b 100644 --- a/Source/IHttp.hpp +++ b/Source/IHttp.hpp @@ -8,12 +8,14 @@ #ifndef IHTTP_HPP #define IHTTP_HPP +#include "ViewFormat.hpp" + struct IHttpListener { IHttpListener() {} virtual ~IHttpListener() {} - virtual void onUpdate(const char *pPath) = 0; + virtual void onUpdate(const char *pPath, ViewFormat const &viewFormat) = 0; }; #endif /* IHTTP_HPP */ diff --git a/Source/Kml.cpp b/Source/Kml.cpp index 8278d08..dd2ec72 100644 --- a/Source/Kml.cpp +++ b/Source/Kml.cpp @@ -12,6 +12,10 @@ Kml::Kml(const char *pDocRoot) , m_docRoot(pDocRoot) , m_altitudeModeString("absolute") , m_pathColorString("0xff00ffff") +, m_cameraAlt(1000) +, m_cameraTilt(0) +, m_cameraAutoHeading(false) +, m_cameraAutoRoll(false) { memset(m_path, 0, sizeof(m_path)); } @@ -49,6 +53,7 @@ void Kml::create() // Create an outer XML element.. kml->setAttribute("xmlns", "http://www.opengis.net/kml/2.2"); + kml->setAttribute("xmlns:gx", "http://www.google.com/kml/ext/2.2"); sprintf(m_path, "%s\\flight_%4.4d%2.2d%2.2d_%2.2d%2.2d%2.2d.kml", m_docRoot, 1900+time_now->tm_year, time_now->tm_mon+1, time_now->tm_mday, time_now->tm_hour, time_now->tm_min, time_now->tm_sec); pFile->addTextElement(m_path); pSnippet->setAttribute("maxLines", "2"); @@ -57,13 +62,13 @@ void Kml::create() pSnippet->addTextElement(time_str); // Camera - pCamera->createNewChildElement("longitude")->addTextElement(""); - pCamera->createNewChildElement("latitude")->addTextElement(""); - pCamera->createNewChildElement("altitude")->addTextElement(""); - pCamera->createNewChildElement("heading")->addTextElement(""); - pCamera->createNewChildElement("tilt")->addTextElement(""); - pCamera->createNewChildElement("altitudeMode")->addTextElement(""); - + pCamera->createNewChildElement("longitude")->addTextElement("0"); + pCamera->createNewChildElement("latitude")->addTextElement("0"); + pCamera->createNewChildElement("altitude")->addTextElement("0"); + pCamera->createNewChildElement("heading")->addTextElement("0"); + pCamera->createNewChildElement("tilt")->addTextElement("0"); + pCamera->createNewChildElement("roll")->addTextElement("0"); + pCamera->createNewChildElement("altitudeMode")->addTextElement(m_altitudeModeString); } @@ -103,6 +108,16 @@ void Kml::setPathColor(String const &colorString) } +void Kml::setCameraAltitude(float alt_meters) +{ + m_cameraAlt = alt_meters; +} + +void Kml::setCameraTilt(float tilt_deg) +{ + m_cameraTilt = tilt_deg; +} + void Kml::update(FlightData const &flightData) { const ScopedLock sl (m_lock); @@ -110,6 +125,16 @@ void Kml::update(FlightData const &flightData) updatePath(flightData); } +void Kml::setCameraAutoHeading(bool enable) +{ + m_cameraAutoHeading = enable; +} + +void Kml::setCameraAutoRoll(bool enable) +{ + m_cameraAutoRoll = enable; +} + void Kml::updatePlane(FlightData const &flightData) { char temp_str[1024]; @@ -133,7 +158,6 @@ void Kml::updatePlane(FlightData const &flightData) XmlElement *pCoords; XmlElement *pCamera; - XmlElement *pLookAt; if(pPlacemark == NULL) { @@ -212,13 +236,20 @@ void Kml::updatePlane(FlightData const &flightData) pCoords = pPlacemark->getChildByName("Point")->getChildByName("coordinates"); pCoords->getFirstChildElement()->setText(temp_str); - // Camera pCamera = kml->getChildByName("NetworkLinkControl")->getChildByName("Camera"); + pCamera->getChildByName("longitude")->getFirstChildElement()->setText(String(flightData.lon)); pCamera->getChildByName("latitude")->getFirstChildElement()->setText(String(flightData.lat)); - pCamera->getChildByName("altitude")->getFirstChildElement()->setText(String(flightData.alt_meter)); - pCamera->getChildByName("heading")->getFirstChildElement()->setText(String(flightData.hdgTrue_deg)); - pCamera->getChildByName("tilt")->getFirstChildElement()->setText("90"); + pCamera->getChildByName("altitude")->getFirstChildElement()->setText(String(flightData.alt_meter+m_cameraAlt)); + + if (m_cameraAutoHeading) + pCamera->getChildByName("heading")->getFirstChildElement()->setText(String(flightData.hdgTrue_deg)); + + pCamera->getChildByName("tilt")->getFirstChildElement()->setText(String(m_cameraTilt)); + + if (m_cameraAutoRoll) + pCamera->getChildByName("roll")->getFirstChildElement()->setText(String(flightData.bank_deg)); + pCamera->getChildByName("altitudeMode")->getFirstChildElement()->setText(m_altitudeModeString); } @@ -323,8 +354,30 @@ void Kml::exportKmz(const char *pPath) } } -void Kml::onUpdate(const char *pPath) +void Kml::onUpdate(const char *pPath, ViewFormat const &viewFormat) { + if (kml == nullptr) + return; + + // LookAt + XmlElement *pCamera; + + pCamera = kml->getChildByName("NetworkLinkControl")->getChildByName("Camera"); + + if (viewFormat.has_camera) + { +// pCamera->getChildByName("longitude")->getFirstChildElement()->setText(String(viewFormat.camera.lookatLon)); +// pCamera->getChildByName("latitude")->getFirstChildElement()->setText(String(viewFormat.camera.lookatLat)); +// pCamera->getChildByName("altitude")->getFirstChildElement()->setText(String(viewFormat.camera.lookatRange)); +// pCamera->getChildByName("heading")->getFirstChildElement()->setText(String(viewFormat.camera.lookatHeading)); +// pCamera->getChildByName("heading")->getFirstChildElement()->setText(String(0)); +// pCamera->getChildByName("tilt")->getFirstChildElement()->setText(String(viewFormat.camera.lookatTilt)); +// pCamera->getChildByName("tilt")->getFirstChildElement()->setText(String(0)); +// pCamera->getChildByName("range")->getFirstChildElement()->setText(String(viewFormat.camera.lookatRange)); +// pCamera->getChildByName("range")->getFirstChildElement()->setText(String("10000")); +// pCamera->getChildByName("altitudeMode")->getFirstChildElement()->setText(m_altitudeModeString); + } + exportKmz(pPath); } diff --git a/Source/Kml.hpp b/Source/Kml.hpp index 63bcf21..c7293be 100644 --- a/Source/Kml.hpp +++ b/Source/Kml.hpp @@ -13,6 +13,10 @@ public: void setAltitudeMode(String const &modeString); void setPathColor(String const &colorString); + void setCameraAltitude(float alt_meters); + void setCameraTilt(float tilt_deg); + void setCameraAutoHeading(bool enable); + void setCameraAutoRoll(bool enable); private: CriticalSection m_lock; @@ -23,7 +27,10 @@ private: const char *m_docRoot; String m_altitudeModeString; String m_pathColorString; - + float m_cameraAlt; + float m_cameraTilt; + bool m_cameraAutoHeading; + bool m_cameraAutoRoll; void create(); void destroy(); const char* getPath(); @@ -32,7 +39,7 @@ private: void exportKmz(const char *pPath); void updatePlane(FlightData const &flightData); void updatePath(FlightData const &flightData); - void onUpdate(const char *pPath); + void onUpdate(const char *pPath, ViewFormat const &viewFormat); }; #endif // !KML_HPP diff --git a/Source/MainComponent.cpp b/Source/MainComponent.cpp index 60bdc3b..6e67423 100644 --- a/Source/MainComponent.cpp +++ b/Source/MainComponent.cpp @@ -69,6 +69,28 @@ MainComponent::MainComponent (String const &homeDir) m_altitudeMode->addSeparator(); m_altitudeMode->addListener (this); + addAndMakeVisible (m_cameraAltitude = new Slider ("Camera Altitude")); + m_cameraAltitude->setTooltip (TRANS("Camera Altitude")); + m_cameraAltitude->setRange (0, 100000, 100); + m_cameraAltitude->setSliderStyle (Slider::LinearHorizontal); + m_cameraAltitude->setTextBoxStyle (Slider::TextBoxLeft, false, 80, 20); + m_cameraAltitude->addListener (this); + + addAndMakeVisible (m_CameraTilt = new Slider ("Camera Tilt")); + m_CameraTilt->setTooltip (TRANS("Camera Tilt")); + m_CameraTilt->setRange (0, 90, 5); + m_CameraTilt->setSliderStyle (Slider::LinearHorizontal); + m_CameraTilt->setTextBoxStyle (Slider::TextBoxLeft, false, 80, 20); + m_CameraTilt->addListener (this); + + addAndMakeVisible (m_cameraAutoHeadingEnable = new ToggleButton ("Camera Auto Heading")); + m_cameraAutoHeadingEnable->setTooltip (TRANS("Camera Auto Heading")); + m_cameraAutoHeadingEnable->addListener (this); + + addAndMakeVisible (m_cameraAutoRollEnable = new ToggleButton ("Camera Auto Roll")); + m_cameraAutoRollEnable->setTooltip (TRANS("Camera Auto Roll")); + m_cameraAutoRollEnable->addListener (this); + //[UserPreSize] //[/UserPreSize] @@ -99,6 +121,8 @@ MainComponent::MainComponent (String const &homeDir) m_colorSelector->setCurrentColour(juce::Colours::yellow); m_altitudeMode->setSelectedId(1, juce::NotificationType::sendNotification); + m_cameraAltitude->setValue(10000, juce::NotificationType::sendNotification); + m_CameraTilt->setValue(0, juce::NotificationType::sendNotification); //[/Constructor] } @@ -116,6 +140,10 @@ MainComponent::~MainComponent() m_kmlUpdInterval_s = nullptr; m_colorSelector = nullptr; m_altitudeMode = nullptr; + m_cameraAltitude = nullptr; + m_CameraTilt = nullptr; + m_cameraAutoHeadingEnable = nullptr; + m_cameraAutoRollEnable = nullptr; //[Destructor]. You can add your own custom destruction code here.. @@ -138,9 +166,13 @@ void MainComponent::resized() { m_fsuipcStatus->setBounds (16, 264, 150, 24); m_flightStatus->setBounds (216, 264, 150, 24); - m_kmlUpdInterval_s->setBounds (16, 232, 184, 24); + m_kmlUpdInterval_s->setBounds (24, 232, 160, 24); m_colorSelector->setBounds (24, 24, 168, 192); m_altitudeMode->setBounds (216, 32, 160, 24); + m_cameraAltitude->setBounds (216, 80, 160, 24); + m_CameraTilt->setBounds (216, 120, 160, 24); + m_cameraAutoHeadingEnable->setBounds (216, 160, 150, 24); + m_cameraAutoRollEnable->setBounds (216, 192, 150, 24); //[UserResized] Add your own custom resize handling here.. //[/UserResized] } @@ -156,6 +188,18 @@ void MainComponent::sliderValueChanged (Slider* sliderThatWasMoved) m_fsLink->setUpdateInterval(sliderThatWasMoved->getValue()); //[/UserSliderCode_m_kmlUpdInterval_s] } + else if (sliderThatWasMoved == m_cameraAltitude) + { + //[UserSliderCode_m_cameraAltitude] -- add your slider handling code here.. + m_kml->setCameraAltitude(sliderThatWasMoved->getValue()); + //[/UserSliderCode_m_cameraAltitude] + } + else if (sliderThatWasMoved == m_CameraTilt) + { + //[UserSliderCode_m_CameraTilt] -- add your slider handling code here.. + m_kml->setCameraTilt(sliderThatWasMoved->getValue()); + //[/UserSliderCode_m_CameraTilt] + } //[UsersliderValueChanged_Post] //[/UsersliderValueChanged_Post] @@ -177,6 +221,28 @@ void MainComponent::comboBoxChanged (ComboBox* comboBoxThatHasChanged) //[/UsercomboBoxChanged_Post] } +void MainComponent::buttonClicked (Button* buttonThatWasClicked) +{ + //[UserbuttonClicked_Pre] + //[/UserbuttonClicked_Pre] + + if (buttonThatWasClicked == m_cameraAutoHeadingEnable) + { + //[UserButtonCode_m_cameraAutoHeadingEnable] -- add your button handler code here.. + m_kml->setCameraAutoHeading(buttonThatWasClicked->getToggleState()); + //[/UserButtonCode_m_cameraAutoHeadingEnable] + } + else if (buttonThatWasClicked == m_cameraAutoRollEnable) + { + //[UserButtonCode_m_cameraAutoRollEnable] -- add your button handler code here.. + m_kml->setCameraAutoRoll(buttonThatWasClicked->getToggleState()); + //[/UserButtonCode_m_cameraAutoRollEnable] + } + + //[UserbuttonClicked_Post] + //[/UserbuttonClicked_Post] +} + //[MiscUserCode] You can add your own definitions of your custom methods or any other code here... @@ -229,7 +295,7 @@ BEGIN_JUCER_METADATA editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font" fontsize="15" bold="0" italic="0" justification="33"/> @@ -240,6 +306,22 @@ BEGIN_JUCER_METADATA virtualName="" explicitFocusOrder="0" pos="216 32 160 24" tooltip="Altitude Mode" editable="0" layout="33" items="absolute relativeToGround clampToGround " textWhenNonSelected="" textWhenNoItems="(no choices)"/> + + + + END_JUCER_METADATA diff --git a/Source/MainComponent.h b/Source/MainComponent.h index 7a13ef0..eec778c 100644 --- a/Source/MainComponent.h +++ b/Source/MainComponent.h @@ -41,7 +41,8 @@ class MainComponent : public Component, public IFsLinkListener, public ChangeListener, public SliderListener, - public ComboBoxListener + public ComboBoxListener, + public ButtonListener { public: //============================================================================== @@ -56,6 +57,7 @@ public: void resized(); void sliderValueChanged (Slider* sliderThatWasMoved); void comboBoxChanged (ComboBox* comboBoxThatHasChanged); + void buttonClicked (Button* buttonThatWasClicked); @@ -77,6 +79,10 @@ private: ScopedPointer m_kmlUpdInterval_s; ScopedPointer m_colorSelector; ScopedPointer m_altitudeMode; + ScopedPointer m_cameraAltitude; + ScopedPointer m_CameraTilt; + ScopedPointer m_cameraAutoHeadingEnable; + ScopedPointer m_cameraAutoRollEnable; //============================================================================== diff --git a/Source/ViewFormat.hpp b/Source/ViewFormat.hpp new file mode 100644 index 0000000..befb51f --- /dev/null +++ b/Source/ViewFormat.hpp @@ -0,0 +1,158 @@ +#ifndef VIEWFORMAT_HPP +#define VIEWFORMAT_HPP + +#include "../JuceLibraryCode/JuceHeader.h" + +class AParser +{ +public: + virtual void parse(char **ppStream) + { + printf("%s\n", extractField(ppStream)); + } + +protected: + AParser() {} + ~AParser() {} + + struct Field + { + Field(const char *_name, AParser &_member, bool &hasTag) + : name(_name) + , member(_member) + , m_hasTag(hasTag) + { + m_hasTag = false; + } + const char *name; + AParser &member; + bool &m_hasTag; + }; + + char *extractField(char **ppStream) + { + static char field[256]; + char *pStream = *ppStream; + char *pField = field; + + skip(&pStream); + + for (size_t i=0; i < sizeof(field); i++) + { + if (*pStream == ',') + break; + + if (*pStream == ';') + break; + + if (*pStream == '=') + break; + + *(pField++) = *(pStream++); + } + *pField = 0; + *ppStream = pStream; + + return field; + } + +private: + void skip(char **ppStream) + { + while ((**ppStream == '\\') || (**ppStream == '?') || (**ppStream == ',') || (**ppStream == ';') || (**ppStream == '=') || (**ppStream <= 0x20)) + { + (*ppStream)++; + }; + + } +}; + +// ?BBOX=1.0, 2.0, 3.0, 4.0?CAMERA/Pos=1.0, 2.0, 3.0 +class ViewFormat : private AParser +{ +private: + struct Bbox : public AParser + { + float n, e, s, w; + + void parse(char **ppStream) + { + n = String(extractField(ppStream)).getFloatValue(); + e = String(extractField(ppStream)).getFloatValue(); + s = String(extractField(ppStream)).getFloatValue(); + w = String(extractField(ppStream)).getFloatValue(); + } + }; + + struct Camera : public AParser + { + float lookatLon, lookatLat, lookatRange, lookatTilt, lookatHeading; + + void parse(char **ppStream) + { + lookatLon = String(extractField(ppStream)).getFloatValue(); + lookatLat = String(extractField(ppStream)).getFloatValue(); + lookatRange = String(extractField(ppStream)).getFloatValue(); + lookatTilt = String(extractField(ppStream)).getFloatValue(); + lookatHeading = String(extractField(ppStream)).getFloatValue(); + } + }; + + struct View : public AParser + { + float horizFov, vertFov, horizPixels, vertPixels, terrainEnabled; + + void parse(char **ppStream) + { + horizFov = String(extractField(ppStream)).getFloatValue(); + vertFov = String(extractField(ppStream)).getFloatValue(); + horizPixels = String(extractField(ppStream)).getFloatValue(); + vertPixels = String(extractField(ppStream)).getFloatValue(); + terrainEnabled = String(extractField(ppStream)).getFloatValue(); + } + }; + + AParser::Field fieldBbox; + AParser::Field fieldCamera; + AParser::Field fieldView; + AParser::Field *fields[3]; + +public: + bool has_bbox; + Bbox bbox; + + bool has_camera; + Camera camera; + + bool has_view; + View view; + + ViewFormat() + : fieldBbox(AParser::Field("BBox", bbox, has_bbox)) + , fieldCamera(AParser::Field("Camera", camera, has_camera)) + , fieldView(AParser::Field("View", view, has_view)) + { + fields[0] = &fieldBbox; + fields[1] = &fieldCamera; + fields[2] = &fieldView; + } + ~ViewFormat() {} + + void parse(const char *pStream) + { + char *pSubStream = (char*)pStream; + + for (unsigned i=0; i < sizeof(fields)/sizeof(*fields); i++) + { + char *pField = extractField(&pSubStream); + if (!stricmp(pField, fields[i]->name)) + { + fields[i]->member.parse(&pSubStream); + fields[i]->m_hasTag = true; + } + } + } + +}; + +#endif // VIEWFORMAT_HPP