mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-02-25 14:29:03 -06:00
Merge branch 'master' into feature/imgui-touchhandling
# Conflicts: # modules/touch/src/touchinteraction.cpp
This commit is contained in:
@@ -36,6 +36,7 @@
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
#include <openspace/properties/scalar/doubleproperty.h>
|
||||
#include <openspace/properties/triggerproperty.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
@@ -143,8 +144,8 @@ private:
|
||||
properties::FloatProperty _followAnchorNodeRotationDistance;
|
||||
properties::FloatProperty _minimumAllowedDistance;
|
||||
properties::FloatProperty _flightDestinationDistance;
|
||||
properties::DoubleProperty _flightDestinationFactor;
|
||||
properties::BoolProperty _applyLinearFlight;
|
||||
|
||||
|
||||
properties::FloatProperty _velocitySensitivity;
|
||||
properties::FloatProperty _mouseSensitivity;
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
|
||||
namespace openspace {
|
||||
|
||||
// The TouchInput represents a single finger/device-input at a specific point in time.
|
||||
// the fingerId and touchDeviceId coupled with the timestamp allows this to be compared
|
||||
// with other TouchInputs in order to calculate gesture-like behaviour.
|
||||
struct TouchInput {
|
||||
TouchInput(size_t touchDeviceId, size_t fingerId, float x, float y, double timestamp);
|
||||
glm::vec2 screenCoordinates(glm::vec2 resolution) const;
|
||||
@@ -46,19 +49,25 @@ struct TouchInput {
|
||||
float y;
|
||||
float dx = 0.f; // movement in x direction since last touch input
|
||||
float dy = 0.f; // movement in y direction since last touch input
|
||||
double timestamp; // timestamp in seconds from global touch initialization
|
||||
double timestamp; // timestamp in seconds from global touch initialization
|
||||
};
|
||||
|
||||
// The TouchInputHolder holds one or many TouchInputs, in order to track the history of
|
||||
// the finger/input device
|
||||
class TouchInputHolder {
|
||||
public:
|
||||
TouchInputHolder(TouchInput input);
|
||||
|
||||
// tryAddInput:
|
||||
// Succeeds upon a different input than last.
|
||||
// Fails upon a too similar input as last.
|
||||
// Updates time for the last input if same position.
|
||||
bool tryAddInput(TouchInput input);
|
||||
|
||||
void clearInputs();
|
||||
|
||||
// Checks whether or not this Holder actually holds a specific input (based on IDs)
|
||||
// Succeeds when `input` is held by this Holder
|
||||
// Fails if `input` is not held by this Holder
|
||||
bool holdsInput(const TouchInput &input) const;
|
||||
|
||||
size_t touchDeviceId() const;
|
||||
@@ -72,12 +81,14 @@ public:
|
||||
double gestureTime() const;
|
||||
|
||||
size_t numInputs() const;
|
||||
const TouchInput& firstInput() const;
|
||||
const TouchInput& latestInput() const;
|
||||
const std::deque<TouchInput>& peekInputs() const;
|
||||
|
||||
private:
|
||||
//A deque of recorded inputs. Adding newer points to the front of the queue
|
||||
std::deque<TouchInput> _inputs;
|
||||
TouchInput _firstInput;
|
||||
|
||||
size_t _touchDeviceId;
|
||||
size_t _fingerId;
|
||||
|
||||
@@ -784,4 +784,22 @@ float RenderableLabels::unit(int unit) const {
|
||||
}
|
||||
}
|
||||
|
||||
std::string RenderableLabels::toString(int unit) const {
|
||||
switch (static_cast<Unit>(unit)) {
|
||||
case Meter: return MeterUnit;
|
||||
case Kilometer: return KilometerUnit;
|
||||
case Megameter: return MegameterUnit;
|
||||
case Gigameter: return GigameterUnit;
|
||||
case AU: return AstronomicalUnit;
|
||||
case Terameter: return TerameterUnit;
|
||||
case Petameter: return PetameterUnit;
|
||||
case Parsec: return ParsecUnit;
|
||||
case Kiloparsec: return KiloparsecUnit;
|
||||
case Megaparsec: return MegaparsecUnit;
|
||||
case Gigaparsec: return GigaparsecUnit;
|
||||
case GigalightYears: return GigalightyearUnit;
|
||||
default: throw std::logic_error("Missing case label");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -74,6 +74,8 @@ protected:
|
||||
|
||||
float unit(int unit) const;
|
||||
|
||||
std::string toString(int unit) const;
|
||||
|
||||
// Data may require some type of transformation prior the spice transformation being
|
||||
// applied.
|
||||
glm::dmat4 _transformationMatrix = glm::dmat4(1.0);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/properties/vector/ivec2property.h>
|
||||
#include <openspace/properties/vector/vec4property.h>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
@@ -94,7 +95,7 @@ public:
|
||||
std::vector<TouchInput>& lastProcessed);
|
||||
|
||||
// Calculates the new camera state with velocities and time since last frame
|
||||
void step(double dt);
|
||||
void step(double dt, bool directTouch = false);
|
||||
|
||||
// Called each frame we have no new input, used to reset data
|
||||
void resetAfterInput();
|
||||
@@ -159,6 +160,7 @@ private:
|
||||
properties::IntProperty _deceleratesPerSecond;
|
||||
properties::FloatProperty _touchScreenSize;
|
||||
properties::FloatProperty _tapZoomFactor;
|
||||
properties::FloatProperty _pinchZoomFactor;
|
||||
properties::FloatProperty _nodeRadiusThreshold;
|
||||
properties::FloatProperty _rollAngleThreshold;
|
||||
properties::FloatProperty _orbitSpeedThreshold;
|
||||
@@ -193,7 +195,7 @@ private:
|
||||
double pinchConsecZoomFactor = 0;
|
||||
//int stepVelUpdate = 0;
|
||||
#endif
|
||||
|
||||
std::array<TouchInputHolder, 2> _pinchInputs;
|
||||
// Class variables
|
||||
VelocityStates _vel;
|
||||
VelocityStates _lastVel;
|
||||
|
||||
@@ -116,6 +116,13 @@ namespace {
|
||||
"" // @TODO Missing documentation
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo PinchZoomFactorInfo = {
|
||||
"PinchZoomFactor",
|
||||
"Scaling distance travelled on pinch",
|
||||
"This value is used to reduce the amount of pinching needed. A linear kind of "
|
||||
"sensitivity that will alter the pinch-zoom speed."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo DirectManipulationInfo = {
|
||||
"DirectManipulationRadius",
|
||||
"Radius a planet has to have to activate direct-manipulation",
|
||||
@@ -257,6 +264,7 @@ TouchInteraction::TouchInteraction()
|
||||
, _deceleratesPerSecond(DecelatesPerSecondInfo, 240, 60, 300)
|
||||
, _touchScreenSize(TouchScreenSizeInfo, 55.0f, 5.5f, 150.0f)
|
||||
, _tapZoomFactor(TapZoomFactorInfo, 0.2f, 0.f, 0.5f)
|
||||
, _pinchZoomFactor(PinchZoomFactorInfo, 0.01f, 0.f, 0.2f)
|
||||
, _nodeRadiusThreshold(DirectManipulationInfo, 0.2f, 0.0f, 1.0f)
|
||||
, _rollAngleThreshold(RollThresholdInfo, 0.025f, 0.f, 0.05f)
|
||||
, _orbitSpeedThreshold(OrbitSpinningThreshold, 0.005f, 0.f, 0.01f)
|
||||
@@ -270,7 +278,12 @@ TouchInteraction::TouchInteraction()
|
||||
0.25f
|
||||
)
|
||||
, _zoomBoundarySphereMultiplier(ZoomBoundarySphereMultiplierInfo, 1.001f, 1.f, 1.01f)
|
||||
, _zoomOutLimit(ZoomOutLimitInfo, std::numeric_limits<double>::max(), 1000.0, std::numeric_limits<double>::max())
|
||||
, _zoomOutLimit(
|
||||
ZoomOutLimitInfo,
|
||||
std::numeric_limits<double>::max(),
|
||||
1000.0,
|
||||
std::numeric_limits<double>::max()
|
||||
)
|
||||
, _zoomInLimit(ZoomInLimitInfo, -1.0, 0.0, std::numeric_limits<double>::max())
|
||||
, _inputStillThreshold(InputSensitivityInfo, 0.0005f, 0.f, 0.001f)
|
||||
// used to void wrongly interpreted roll interactions
|
||||
@@ -290,8 +303,9 @@ TouchInteraction::TouchInteraction()
|
||||
0.f,
|
||||
1.f
|
||||
)
|
||||
, _pinchInputs({ TouchInput(0, 0, 0.0, 0.0, 0.0), TouchInput(0, 0, 0.0, 0.0, 0.0) })
|
||||
, _vel{ glm::dvec2(0.0), 0.0, 0.0, glm::dvec2(0.0) }
|
||||
, _sensitivity{ glm::dvec2(0.08, 0.045), 12.0 /*4.0*/, 2.75, glm::dvec2(0.08, 0.045) }
|
||||
, _sensitivity{ glm::dvec2(0.08, 0.045), 12.0, 2.75, glm::dvec2(0.08, 0.045) }
|
||||
, _constTimeDecay_secs(ConstantTimeDecaySecsInfo, 1.75f, 0.1f, 4.0f)
|
||||
// calculated with two vectors with known diff in length, then
|
||||
// projDiffLength/diffLength.
|
||||
@@ -303,6 +317,7 @@ TouchInteraction::TouchInteraction()
|
||||
addProperty(_deceleratesPerSecond);
|
||||
addProperty(_touchScreenSize);
|
||||
addProperty(_tapZoomFactor);
|
||||
addProperty(_pinchZoomFactor);
|
||||
addProperty(_nodeRadiusThreshold);
|
||||
addProperty(_rollAngleThreshold);
|
||||
addProperty(_orbitSpeedThreshold);
|
||||
@@ -442,7 +457,7 @@ void TouchInteraction::directControl(const std::vector<TouchInputHolder>& list)
|
||||
_vel.pan = glm::dvec2(par.at(4), par.at(5));
|
||||
}
|
||||
}
|
||||
step(1.0);
|
||||
step(1.0, true);
|
||||
|
||||
// Reset velocities after setting new camera state
|
||||
_lastVel = _vel;
|
||||
@@ -720,6 +735,15 @@ int TouchInteraction::interpretInteraction(const std::vector<TouchInputHolder>&
|
||||
return ROLL;
|
||||
}
|
||||
else {
|
||||
const bool sameInput0 = _pinchInputs[0].holdsInput(list[0].latestInput());
|
||||
const bool sameInput1 = _pinchInputs[1].holdsInput(list[1].latestInput());
|
||||
if (sameInput0 && sameInput1) {
|
||||
_pinchInputs[0].tryAddInput(list[0].latestInput());
|
||||
_pinchInputs[1].tryAddInput(list[1].latestInput());
|
||||
} else {
|
||||
_pinchInputs[0] = TouchInputHolder(list[0].latestInput());
|
||||
_pinchInputs[1] = TouchInputHolder(list[1].latestInput());
|
||||
}
|
||||
return PINCH;
|
||||
}
|
||||
}
|
||||
@@ -759,6 +783,9 @@ void TouchInteraction::computeVelocities(const std::vector<TouchInputHolder>& li
|
||||
#endif
|
||||
|
||||
const TouchInputHolder& inputHolder = list.at(0);
|
||||
const glm::ivec2 windowSize = global::windowDelegate.currentWindowSize();
|
||||
const float aspectRatio =
|
||||
static_cast<float>(windowSize.x) / static_cast<float>(windowSize.y);
|
||||
switch (action) {
|
||||
case ROT: { // add rotation velocity
|
||||
_vel.orbit += glm::dvec2(inputHolder.speedX() *
|
||||
@@ -772,54 +799,31 @@ void TouchInteraction::computeVelocities(const std::vector<TouchInputHolder>& li
|
||||
}
|
||||
case PINCH: {
|
||||
// add zooming velocity - dependant on distance difference between contact
|
||||
// points this/last frame
|
||||
double distance = std::accumulate(
|
||||
list.begin(),
|
||||
list.end(),
|
||||
0.0,
|
||||
[&](double d, const TouchInputHolder& c) {
|
||||
const glm::vec2 currPos = { c.latestInput().x, c.latestInput().y };
|
||||
return d + glm::distance(currPos, _centroid);
|
||||
}
|
||||
) / list.size();
|
||||
double lastDistance = std::accumulate(
|
||||
lastProcessed.begin(),
|
||||
lastProcessed.end(),
|
||||
0.f,
|
||||
[&](float d, const TouchInput& p) {
|
||||
const glm::vec2 lastPos = { p.x, p.y };
|
||||
return d + glm::distance(lastPos, _centroid);
|
||||
}
|
||||
) / lastProcessed.size();
|
||||
// points this/first frame
|
||||
using namespace glm;
|
||||
const TouchInput& startFinger0 = _pinchInputs[0].firstInput();
|
||||
const TouchInput& startFinger1 = _pinchInputs[1].firstInput();
|
||||
const dvec2 startVec0 = dvec2(startFinger0.x * aspectRatio, startFinger0.y);
|
||||
const dvec2 startVec1 = dvec2(startFinger1.x * aspectRatio, startFinger1.y);
|
||||
double distToCentroidStart = length(startVec0 - startVec1) / 2.0;
|
||||
|
||||
glm::dvec3 camPos = _camera->positionVec3();
|
||||
glm::dvec3 centerPos = anchor->worldPosition();
|
||||
glm::dvec3 currDistanceToFocusNode = camPos - centerPos;
|
||||
const TouchInput& endFinger0 = _pinchInputs[0].latestInput();
|
||||
const TouchInput& endFinger1 = _pinchInputs[1].latestInput();
|
||||
const dvec2 endVec0 = dvec2(endFinger0.x * aspectRatio, endFinger0.y);
|
||||
const dvec2 endVec1 = dvec2(endFinger1.x * aspectRatio, endFinger1.y);
|
||||
double distToCentroidEnd = length(endVec0 - endVec1) / 2.0;
|
||||
|
||||
const double distanceFromFocusSurface =
|
||||
length(currDistanceToFocusNode) - anchor->boundingSphere();
|
||||
double zoomFactor = (distance - lastDistance);
|
||||
double zoomFactor = distToCentroidEnd - distToCentroidStart;
|
||||
#ifdef TOUCH_DEBUG_PROPERTIES
|
||||
pinchConsecCt++;
|
||||
pinchConsecZoomFactor += zoomFactor;
|
||||
#endif
|
||||
|
||||
_constTimeDecayCoeff.zoom = computeConstTimeDecayCoefficient(_vel.zoom);
|
||||
if (distanceFromFocusSurface > 0.1) {
|
||||
const double ratioOfDistanceToNodeVsSurface =
|
||||
length(currDistanceToFocusNode) / distanceFromFocusSurface;
|
||||
if (ratioOfDistanceToNodeVsSurface > _zoomSensitivityDistanceThreshold) {
|
||||
zoomFactor *= pow(
|
||||
std::abs(distanceFromFocusSurface),
|
||||
static_cast<float>(_zoomSensitivityExponential)
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
zoomFactor = 1.0;
|
||||
}
|
||||
_vel.zoom = zoomFactor * _zoomSensitivityProportionalDist *
|
||||
std::max(_touchScreenSize.value() * 0.1, 1.0);
|
||||
_constTimeDecayCoeff.zoom = 1.0;
|
||||
_vel.zoom = zoomFactor *
|
||||
_pinchZoomFactor *
|
||||
_zoomSensitivityProportionalDist *
|
||||
std::max(_touchScreenSize.value() * 0.1, 1.0);
|
||||
break;
|
||||
}
|
||||
case ROLL: {
|
||||
@@ -860,7 +864,7 @@ void TouchInteraction::computeVelocities(const std::vector<TouchInputHolder>& li
|
||||
break;
|
||||
}
|
||||
case PAN: {
|
||||
// add local rotation velocity
|
||||
// add local rotation velocity
|
||||
_vel.pan += glm::dvec2(inputHolder.speedX() *
|
||||
_sensitivity.pan.x, inputHolder.speedY() * _sensitivity.pan.y);
|
||||
double panVelocityAvg = glm::distance(_vel.pan.x, _vel.pan.y);
|
||||
@@ -868,7 +872,7 @@ void TouchInteraction::computeVelocities(const std::vector<TouchInputHolder>& li
|
||||
break;
|
||||
}
|
||||
case PICK: {
|
||||
// pick something in the scene as focus node
|
||||
// pick something in the scene as focus node
|
||||
if (_pickingSelected) {
|
||||
setFocusNode(_pickingSelected);
|
||||
|
||||
@@ -935,7 +939,7 @@ double TouchInteraction::computeTapZoomDistance(double zoomGain) {
|
||||
|
||||
// Main update call, calculates the new orientation and position for the camera depending
|
||||
// on _vel and dt. Called every frame
|
||||
void TouchInteraction::step(double dt) {
|
||||
void TouchInteraction::step(double dt, bool directTouch) {
|
||||
using namespace glm;
|
||||
|
||||
const SceneGraphNode* anchor =
|
||||
@@ -1046,22 +1050,45 @@ void TouchInteraction::step(double dt) {
|
||||
_loggerCat, _zoomOutLimit.value()
|
||||
));
|
||||
}
|
||||
const double currentPosDistance = length(centerToCamera);
|
||||
|
||||
//Apply the velocity to update camera position
|
||||
glm::dvec3 zoomDistanceIncrement = directionToCenter * _vel.zoom * dt;
|
||||
double zoomVelocity = _vel.zoom;
|
||||
if (!directTouch) {
|
||||
const double distanceFromSurface =
|
||||
length(currentPosDistance) - anchor->boundingSphere();
|
||||
if (distanceFromSurface > 0.1) {
|
||||
const double ratioOfDistanceToNodeVsSurface =
|
||||
length(currentPosDistance) / distanceFromSurface;
|
||||
if (ratioOfDistanceToNodeVsSurface > _zoomSensitivityDistanceThreshold) {
|
||||
zoomVelocity *= pow(
|
||||
std::abs(distanceFromSurface),
|
||||
static_cast<float>(_zoomSensitivityExponential)
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
zoomVelocity = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
const glm::dvec3 zoomDistanceIncrement = directionToCenter * zoomVelocity * dt;
|
||||
const double newPosDistance = length(centerToCamera + zoomDistanceIncrement);
|
||||
const double currentPosDistance = length(centerToCamera);
|
||||
|
||||
// Possible with other navigations performed outside touch interaction
|
||||
const bool currentPosViolatingZoomOutLimit =
|
||||
(currentPosDistance >= _zoomOutLimit.value());
|
||||
(currentPosDistance >= _zoomOutLimit);
|
||||
const bool willNewPositionViolateZoomOutLimit =
|
||||
(newPosDistance >= _zoomOutLimit.value());
|
||||
(newPosDistance >= _zoomOutLimit);
|
||||
bool willNewPositionViolateZoomInLimit =
|
||||
(newPosDistance < zoomInBounds);
|
||||
bool willNewPositionViolateDirection =
|
||||
(currentPosDistance <= length(zoomDistanceIncrement));
|
||||
|
||||
if (!willNewPositionViolateZoomInLimit
|
||||
&& !willNewPositionViolateZoomOutLimit) {
|
||||
if (!willNewPositionViolateZoomInLimit &&
|
||||
!willNewPositionViolateDirection &&
|
||||
!willNewPositionViolateZoomOutLimit)
|
||||
{
|
||||
camPos += zoomDistanceIncrement;
|
||||
}
|
||||
else if (currentPosViolatingZoomOutLimit) {
|
||||
@@ -1148,6 +1175,20 @@ void TouchInteraction::resetAfterInput() {
|
||||
}
|
||||
}
|
||||
|
||||
// Reset emulated mouse values
|
||||
ImGUIModule& module = *(global::moduleEngine.module<ImGUIModule>());
|
||||
if (_guiON) {
|
||||
bool activeLastFrame = module.touchInput.action;
|
||||
module.touchInput.active = false;
|
||||
if (activeLastFrame) {
|
||||
module.touchInput.active = true;
|
||||
module.touchInput.action = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
module.touchInput.active = false;
|
||||
module.touchInput.action = 0;
|
||||
}
|
||||
_lmSuccess = true;
|
||||
|
||||
// Reset variables
|
||||
@@ -1155,6 +1196,11 @@ void TouchInteraction::resetAfterInput() {
|
||||
_lastVel.zoom = 0.0;
|
||||
_lastVel.roll = 0.0;
|
||||
_lastVel.pan = glm::dvec2(0.0);
|
||||
|
||||
_constTimeDecayCoeff.zoom = computeConstTimeDecayCoefficient(_vel.zoom);
|
||||
_pinchInputs[0].clearInputs();
|
||||
_pinchInputs[1].clearInputs();
|
||||
|
||||
_selected.clear();
|
||||
_pickingSelected = nullptr;
|
||||
}
|
||||
@@ -1167,6 +1213,7 @@ void TouchInteraction::resetToDefault() {
|
||||
_deceleratesPerSecond.set(240);
|
||||
_touchScreenSize.set(55.0f);
|
||||
_tapZoomFactor.set(0.2f);
|
||||
_pinchZoomFactor.set(0.01f);
|
||||
_nodeRadiusThreshold.set(0.2f);
|
||||
_rollAngleThreshold.set(0.025f);
|
||||
_orbitSpeedThreshold.set(0.005f);
|
||||
|
||||
@@ -40,12 +40,18 @@
|
||||
#define ENABLE_DIRECTMSG
|
||||
|
||||
namespace {
|
||||
using namespace std::chrono;
|
||||
constexpr const char* _loggerCat = "win32_touch";
|
||||
HHOOK gTouchHook = nullptr;
|
||||
std::thread* gMouseHookThread;
|
||||
HHOOK gMouseHook = nullptr;
|
||||
bool gStarted = false;
|
||||
std::chrono::microseconds gStartTime = std::chrono::microseconds(0);
|
||||
microseconds gStartTime = microseconds(0);
|
||||
const long long gFrequency = []() -> long long {
|
||||
LARGE_INTEGER frequency;
|
||||
QueryPerformanceFrequency(&frequency);
|
||||
return frequency.QuadPart;
|
||||
}();
|
||||
std::unordered_map<
|
||||
UINT32,
|
||||
std::unique_ptr<openspace::TouchInputHolder>
|
||||
@@ -79,10 +85,14 @@ LRESULT CALLBACK HookCallback(int nCode, WPARAM wParam, LPARAM lParam) {
|
||||
break;
|
||||
}
|
||||
|
||||
using namespace std::chrono;
|
||||
const microseconds timestamp = duration_cast<microseconds>(
|
||||
high_resolution_clock::now().time_since_epoch()
|
||||
) - gStartTime;
|
||||
//Implementation from microsoft STL of high_resolution_clock(steady_clock):
|
||||
const long long freq = gFrequency;
|
||||
const long long whole = (info.PerformanceCount / freq) * std::micro::den;
|
||||
const long long part = (info.PerformanceCount % freq) *
|
||||
std::micro::den / freq;
|
||||
const microseconds timestamp =
|
||||
duration<UINT64, std::micro>(whole + part) - gStartTime;
|
||||
|
||||
RECT rect;
|
||||
GetClientRect(pStruct->hwnd, reinterpret_cast<LPRECT>(&rect));
|
||||
|
||||
@@ -100,7 +110,7 @@ LRESULT CALLBACK HookCallback(int nCode, WPARAM wParam, LPARAM lParam) {
|
||||
static_cast<size_t>(info.pointerId),
|
||||
xPos,
|
||||
yPos,
|
||||
static_cast<double>(timestamp.count())/1'000'000.0
|
||||
static_cast<double>(timestamp.count()) / 1'000'000.0
|
||||
);
|
||||
|
||||
if (info.pointerFlags & POINTER_FLAG_DOWN) {
|
||||
@@ -213,9 +223,8 @@ Win32TouchHook::Win32TouchHook(void* nativeWindow)
|
||||
|
||||
if (!gStarted) {
|
||||
gStarted = true;
|
||||
gStartTime = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::high_resolution_clock::now().time_since_epoch()
|
||||
);
|
||||
gStartTime =
|
||||
duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch());
|
||||
#ifdef ENABLE_TUIOMESSAGES
|
||||
gTuioServer = new TUIO::TuioServer("localhost", 3333);
|
||||
TUIO::TuioTime::initSession();
|
||||
|
||||
@@ -221,7 +221,7 @@ void TouchModule::internalInitialize(const ghoul::Dictionary& /*dictionary*/){
|
||||
global::callback::touchUpdated.push_back(
|
||||
[this](TouchInput i) {
|
||||
updateOrAddTouchInput(i);
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -42,6 +42,20 @@ namespace {
|
||||
"Property to track a nodeline. When tracking the label text will be updating the "
|
||||
"distance from the nodeline start and end."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo DistanceUnitInfo = {
|
||||
"DistanceUnit",
|
||||
"Distance Unit",
|
||||
"Property to define the unit in which the distance should be displayed."
|
||||
"Defaults to 'km' if not specified."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo CustomUnitDescriptorInfo = {
|
||||
"CustomUnitDescriptor",
|
||||
"Custom Unit Descriptor",
|
||||
"Property to define a custom unit descriptor to use to describe the distance value."
|
||||
"Defaults to the units SI descriptor if not specified."
|
||||
};
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
@@ -58,6 +72,18 @@ documentation::Documentation RenderableDistanceLabel::Documentation() {
|
||||
Optional::No,
|
||||
NodeLineInfo.description
|
||||
},
|
||||
{
|
||||
DistanceUnitInfo.identifier,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
DistanceUnitInfo.description
|
||||
},
|
||||
{
|
||||
CustomUnitDescriptorInfo.identifier,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
CustomUnitDescriptorInfo.description
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -65,6 +91,8 @@ documentation::Documentation RenderableDistanceLabel::Documentation() {
|
||||
RenderableDistanceLabel::RenderableDistanceLabel(const ghoul::Dictionary& dictionary)
|
||||
: RenderableLabels(dictionary)
|
||||
, _nodelineId(NodeLineInfo)
|
||||
, _distanceUnit(DistanceUnitInfo, 1, 0, 11)
|
||||
, _customUnitDescriptor(CustomUnitDescriptorInfo)
|
||||
{
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
@@ -76,6 +104,16 @@ RenderableDistanceLabel::RenderableDistanceLabel(const ghoul::Dictionary& dictio
|
||||
_nodelineId = dictionary.value<std::string>(NodeLineInfo.identifier);
|
||||
addProperty(_nodelineId);
|
||||
}
|
||||
if (dictionary.hasKey(DistanceUnitInfo.identifier)) {
|
||||
_distanceUnit = static_cast<int>(
|
||||
dictionary.value<double>(DistanceUnitInfo.identifier)
|
||||
);
|
||||
addProperty(_distanceUnit);
|
||||
}
|
||||
if (dictionary.hasKey(CustomUnitDescriptorInfo.identifier)) {
|
||||
_customUnitDescriptor = dictionary.value<std::string>(CustomUnitDescriptorInfo.identifier);
|
||||
addProperty(_customUnitDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderableDistanceLabel::update(const UpdateData&) {
|
||||
@@ -87,7 +125,6 @@ void RenderableDistanceLabel::update(const UpdateData&) {
|
||||
|
||||
SceneGraphNode* nodelineNode = RE.scene()->sceneGraphNode(_nodelineId);
|
||||
if (nodelineNode) {
|
||||
// Calculate distance
|
||||
RenderableNodeLine* nodeline = dynamic_cast<RenderableNodeLine*>(
|
||||
nodelineNode->renderable()
|
||||
);
|
||||
@@ -97,15 +134,23 @@ void RenderableDistanceLabel::update(const UpdateData&) {
|
||||
return;
|
||||
}
|
||||
|
||||
double myDistance = nodeline->distance();
|
||||
// Get used unit scale
|
||||
const float scale = unit(_distanceUnit);
|
||||
|
||||
// Format string
|
||||
float scale = unit(Kilometer);
|
||||
std::string distanceText = std::to_string(std::round(myDistance / scale));
|
||||
// Get unit descriptor text
|
||||
std::string unitDescriptor = toString(_distanceUnit);
|
||||
if (!_customUnitDescriptor.value().empty()) {
|
||||
unitDescriptor = _customUnitDescriptor.value();
|
||||
}
|
||||
|
||||
// Get distance as string and remove fractional part
|
||||
std::string distanceText = std::to_string(std::round(nodeline->distance() / scale));
|
||||
int pos = static_cast<int>(distanceText.find("."));
|
||||
std::string subStr = distanceText.substr(pos);
|
||||
distanceText.erase(pos, subStr.size());
|
||||
std::string finalText = distanceText + " Km";
|
||||
|
||||
// Create final label text and set it
|
||||
const std::string finalText = distanceText + " " + unitDescriptor;
|
||||
setLabelText(finalText);
|
||||
|
||||
// Update placement of label with transformation matrix
|
||||
|
||||
@@ -40,6 +40,8 @@ public:
|
||||
private:
|
||||
|
||||
properties::StringProperty _nodelineId;
|
||||
properties::IntProperty _distanceUnit;
|
||||
properties::StringProperty _customUnitDescriptor;
|
||||
bool _errorThrown = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -84,10 +84,9 @@ public:
|
||||
void draw();
|
||||
void close(bool force = false);
|
||||
|
||||
void sendTouchPressEvent(const CefMouseEvent & event,
|
||||
CefBrowserHost::MouseButtonType button, const int clickCount);
|
||||
void sendResleasePressEvent(const CefMouseEvent & event,
|
||||
CefBrowserHost::MouseButtonType button, const int clickCount);
|
||||
#ifdef WIN32
|
||||
void sendTouchEvent(const CefTouchEvent& event) const;
|
||||
#endif
|
||||
|
||||
bool sendKeyEvent(const CefKeyEvent& event);
|
||||
bool sendMouseClickEvent(const CefMouseEvent& event,
|
||||
|
||||
@@ -84,6 +84,19 @@ private:
|
||||
*/
|
||||
CefMouseEvent mouseEvent(KeyModifier mods = KeyModifier::NoModifier);
|
||||
|
||||
#ifdef WIN32
|
||||
/**
|
||||
* Build a CEF touch event based on our internal structure
|
||||
*
|
||||
* Note: as of 02/21/2020 we are using an older version of CEF on OSX
|
||||
* than WIN32.
|
||||
* This version does not handle the CefTouchEvent type and does
|
||||
* not have any internal touch handling.
|
||||
*/
|
||||
CefTouchEvent touchEvent(const TouchInput& input,
|
||||
const cef_touch_event_type_t eventType) const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Find the CEF key event to use for a given action.
|
||||
*
|
||||
|
||||
@@ -149,19 +149,11 @@ bool BrowserInstance::sendMouseClickEvent(const CefMouseEvent& event,
|
||||
return hasContent(event.x, event.y);
|
||||
}
|
||||
|
||||
void BrowserInstance::sendTouchPressEvent(const CefMouseEvent& event,
|
||||
CefBrowserHost::MouseButtonType button,
|
||||
const int clickCount)
|
||||
{
|
||||
_browser->GetHost()->SendMouseClickEvent(event, button, false, clickCount);
|
||||
}
|
||||
|
||||
void BrowserInstance::sendResleasePressEvent(const CefMouseEvent& event,
|
||||
CefBrowserHost::MouseButtonType button,
|
||||
const int clickCount)
|
||||
{
|
||||
_browser->GetHost()->SendMouseClickEvent(event, button, true, clickCount);
|
||||
#ifdef WIN32
|
||||
void BrowserInstance::sendTouchEvent(const CefTouchEvent& event) const{
|
||||
_browser->GetHost()->SendTouchEvent(event);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool BrowserInstance::sendMouseMoveEvent(const CefMouseEvent& event) {
|
||||
constexpr const bool DidNotLeaveWindow = false;
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include <openspace/engine/globalscallbacks.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/interaction/inputstate.h>
|
||||
#include <openspace/interaction/interactionmonitor.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <fmt/format.h>
|
||||
@@ -208,6 +210,13 @@ void EventHandler::initialize() {
|
||||
}
|
||||
|
||||
if (_validTouchStates.empty()) {
|
||||
#ifdef WIN32
|
||||
CefTouchEvent event = touchEvent(
|
||||
input,
|
||||
cef_touch_event_type_t::CEF_TET_PRESSED
|
||||
);
|
||||
_browserInstance->sendTouchEvent(event);
|
||||
#else
|
||||
_mousePosition.x = windowPos.x;
|
||||
_mousePosition.y = windowPos.y;
|
||||
_leftButton.down = true;
|
||||
@@ -217,6 +226,7 @@ void EventHandler::initialize() {
|
||||
false,
|
||||
BrowserInstance::SingleClick
|
||||
);
|
||||
#endif
|
||||
_validTouchStates.emplace_back(input);
|
||||
}
|
||||
else {
|
||||
@@ -245,11 +255,20 @@ void EventHandler::initialize() {
|
||||
);
|
||||
|
||||
if (it == _validTouchStates.cbegin()) {
|
||||
#ifdef WIN32
|
||||
|
||||
CefTouchEvent event = touchEvent(
|
||||
input,
|
||||
cef_touch_event_type_t::CEF_TET_MOVED
|
||||
);
|
||||
_browserInstance->sendTouchEvent(event);
|
||||
#else
|
||||
glm::vec2 windowPos = input.currentWindowCoordinates();
|
||||
_mousePosition.x = windowPos.x;
|
||||
_mousePosition.y = windowPos.y;
|
||||
_leftButton.down = true;
|
||||
_browserInstance->sendMouseMoveEvent(mouseEvent());
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
else if (it != _validTouchStates.cend()){
|
||||
@@ -280,8 +299,15 @@ void EventHandler::initialize() {
|
||||
if (found == _validTouchStates.cend()) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
CefTouchEvent event = touchEvent(
|
||||
input,
|
||||
cef_touch_event_type_t::CEF_TET_RELEASED
|
||||
);
|
||||
_browserInstance->sendTouchEvent(event);
|
||||
#endif
|
||||
_validTouchStates.erase(found);
|
||||
#ifndef WIN32
|
||||
if (_validTouchStates.empty()) {
|
||||
glm::vec2 windowPos = input.currentWindowCoordinates();
|
||||
_mousePosition.x = windowPos.x;
|
||||
@@ -294,6 +320,7 @@ void EventHandler::initialize() {
|
||||
BrowserInstance::SingleClick
|
||||
);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -337,7 +364,7 @@ bool EventHandler::mouseButtonCallback(MouseButton button, MouseAction action,
|
||||
bool EventHandler::isDoubleClick(const MouseButtonState& button) const {
|
||||
// check time
|
||||
using namespace std::chrono;
|
||||
|
||||
|
||||
auto now = high_resolution_clock::now();
|
||||
milliseconds maxTimeDifference(doubleClickTime());
|
||||
auto requiredTime = button.lastClickTime + maxTimeDifference;
|
||||
@@ -438,6 +465,27 @@ CefMouseEvent EventHandler::mouseEvent(KeyModifier mods) {
|
||||
return event;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
CefTouchEvent EventHandler::touchEvent(const TouchInput& input,
|
||||
const cef_touch_event_type_t eventType) const
|
||||
{
|
||||
const glm::vec2 windowPos = input.currentWindowCoordinates();
|
||||
CefTouchEvent event = {};
|
||||
event.id = static_cast<int>(input.fingerId);
|
||||
event.x = windowPos.x;
|
||||
event.y = windowPos.y;
|
||||
event.type = eventType;
|
||||
const std::vector<std::pair<Key, KeyModifier>> &keyModVec =
|
||||
global::navigationHandler.inputState().pressedKeys();
|
||||
for (auto keyModPair : keyModVec) {
|
||||
const KeyModifier mods = keyModVec[0].second;
|
||||
event.modifiers |= static_cast<uint32_t>(mapToCefModifiers(mods));
|
||||
}
|
||||
event.pointer_type = cef_pointer_type_t::CEF_POINTER_TYPE_TOUCH;
|
||||
return event;
|
||||
}
|
||||
#endif
|
||||
|
||||
void EventHandler::setBrowserInstance(BrowserInstance* browserInstance) {
|
||||
LDEBUG("Setting browser instance.");
|
||||
_browserInstance = browserInstance;
|
||||
|
||||
@@ -34,7 +34,6 @@ namespace {
|
||||
|
||||
constexpr const double AngleEpsilon = 1E-7;
|
||||
constexpr const double DistanceRatioAimThreshold = 1E-4;
|
||||
constexpr const double FlightDestinationFactor = 1E-4;
|
||||
|
||||
constexpr const openspace::properties::Property::PropertyInfo AnchorInfo = {
|
||||
"Anchor",
|
||||
@@ -155,6 +154,12 @@ namespace {
|
||||
"The final distance we want to fly to, with regards to the anchor node."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo FlightDestinationFactorInfo = {
|
||||
"FlightDestinationFactor",
|
||||
"Flight Destination Factor",
|
||||
"The minimal distance factor that we need to reach to end linear flight."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo
|
||||
StereoInterpolationTimeInfo = {
|
||||
"StereoInterpolationTime",
|
||||
@@ -232,6 +237,7 @@ OrbitalNavigator::OrbitalNavigator()
|
||||
, _velocitySensitivity(VelocityZoomControlInfo, 0.02f, 0.01f, 0.15f)
|
||||
, _applyLinearFlight(ApplyLinearFlightInfo, false)
|
||||
, _flightDestinationDistance(FlightDestinationDistanceInfo, 2e8f, 0.0f, 1e10f)
|
||||
, _flightDestinationFactor(FlightDestinationFactorInfo, 1E-4, 1E-6, 0.5)
|
||||
, _mouseSensitivity(MouseSensitivityInfo, 15.0f, 1.0f, 50.f)
|
||||
, _joystickSensitivity(JoystickSensitivityInfo, 10.0f, 1.0f, 50.f)
|
||||
, _websocketSensitivity(WebsocketSensitivityInfo, 10.0f, 1.0f, 50.f)
|
||||
@@ -362,6 +368,7 @@ OrbitalNavigator::OrbitalNavigator()
|
||||
addProperty(_minimumAllowedDistance);
|
||||
addProperty(_velocitySensitivity);
|
||||
addProperty(_flightDestinationDistance);
|
||||
addProperty(_flightDestinationFactor);
|
||||
addProperty(_applyLinearFlight);
|
||||
|
||||
addProperty(_useAdaptiveStereoscopicDepth);
|
||||
@@ -440,7 +447,7 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) {
|
||||
double distFromCameraToFocus = glm::distance(prevCameraPosition, anchorPos) - nodeRadius;
|
||||
|
||||
// Make the approximation delta size depending on the flight distance
|
||||
double arrivalThreshold = _flightDestinationDistance.value() * FlightDestinationFactor;
|
||||
double arrivalThreshold = _flightDestinationDistance.value() * _flightDestinationFactor;
|
||||
|
||||
// Fly towards the flight destination distance. When getting closer than arrivalThreshold terminate the flight
|
||||
if (abs(distFromCameraToFocus - _flightDestinationDistance.value()) > arrivalThreshold) {
|
||||
|
||||
@@ -73,32 +73,41 @@ float TouchInput::angleToPos(float otherX, float otherY) const {
|
||||
|
||||
TouchInputHolder::TouchInputHolder(TouchInput input)
|
||||
: _inputs{ input }
|
||||
, _firstInput(input)
|
||||
, _touchDeviceId(input.touchDeviceId)
|
||||
, _fingerId(input.fingerId)
|
||||
{}
|
||||
|
||||
bool TouchInputHolder::tryAddInput(TouchInput input) {
|
||||
if(_inputs.empty()) {
|
||||
_inputs.emplace_front(input);
|
||||
return true;
|
||||
}
|
||||
constexpr const double ONE_MS = 0.001;
|
||||
const TouchInput& lastInput = latestInput();
|
||||
input.dx = input.x - lastInput.x;
|
||||
input.dy = input.y - lastInput.y;
|
||||
|
||||
const bool sameTimeAsLastInput = (input.timestamp - lastInput.timestamp) > ONE_MS;
|
||||
bool wasInserted = false;
|
||||
if (isMoving()) {
|
||||
const bool sameTimeAsLastInput = (input.timestamp - lastInput.timestamp) < ONE_MS;
|
||||
bool successful = false;
|
||||
if (!sameTimeAsLastInput && isMoving()) {
|
||||
_inputs.emplace_front(input);
|
||||
wasInserted = true;
|
||||
successful = true;
|
||||
}
|
||||
else if (sameTimeAsLastInput && input.isMoving()) {
|
||||
else if (!sameTimeAsLastInput && input.isMoving()) {
|
||||
_inputs.emplace_front(input);
|
||||
wasInserted = true;
|
||||
successful = true;
|
||||
}
|
||||
else if (!sameTimeAsLastInput){
|
||||
_inputs.front().timestamp = input.timestamp;
|
||||
successful = true;
|
||||
}
|
||||
|
||||
constexpr const int MaxInputs = 128;
|
||||
if (_inputs.size() > MaxInputs) {
|
||||
_inputs.pop_back();
|
||||
}
|
||||
return wasInserted;
|
||||
return successful;
|
||||
}
|
||||
|
||||
void TouchInputHolder::clearInputs() {
|
||||
@@ -142,8 +151,7 @@ bool TouchInputHolder::isMoving() const {
|
||||
if (_inputs.size() <= 1) {
|
||||
return false;
|
||||
}
|
||||
const TouchInput& currentInput = _inputs[0];
|
||||
return currentInput.dx != 0.f || currentInput.dy != 0.f;
|
||||
return latestInput().isMoving();
|
||||
}
|
||||
|
||||
float TouchInputHolder::gestureDistance() const {
|
||||
@@ -174,6 +182,10 @@ size_t TouchInputHolder::numInputs() const {
|
||||
return _inputs.size();
|
||||
}
|
||||
|
||||
const TouchInput& TouchInputHolder::firstInput() const {
|
||||
return _firstInput;
|
||||
}
|
||||
|
||||
const TouchInput& TouchInputHolder::latestInput() const {
|
||||
return _inputs.front();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user