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