Issue/2121 : SessionRecording wildcard and syntax improvements

This commit is contained in:
Gene Payne
2022-06-23 17:47:54 -06:00
committed by GitHub
parent 16073c77c0
commit 4f5b2fdb0d
5 changed files with 138 additions and 54 deletions

View File

@@ -604,7 +604,7 @@ protected:
Timestamps t3stamps;
};
double _timestampRecordStarted = 0.0;
Timestamps _timestamps3RecordStarted;
Timestamps _timestamps3RecordStarted{ 0.0, 0.0, 0.0 };
double _timestampPlaybackStarted_application = 0.0;
double _timestampPlaybackStarted_simulation = 0.0;
double _timestampApplicationStarted_simulation = 0.0;
@@ -696,10 +696,12 @@ protected:
std::string& version, DataMode& mode);
void populateListofLoadedSceneGraphNodes();
bool checkIfScriptUsesScenegraphNode(std::string s);
void checkForScenegraphNodeAccess_Scene(std::string& s, std::string& result);
void checkForScenegraphNodeAccess_Nav(std::string& s, std::string& result);
void checkIfScriptUsesScenegraphNode(std::string s);
bool checkForScenegraphNodeAccessScene(std::string& s);
bool checkForScenegraphNodeAccessNav(std::string& navTerm);
std::string extractScenegraphNodeFromScene(std::string& s);
bool checkIfInitialFocusNodeIsLoaded(unsigned int firstCamIndex);
std::string isolateTermFromQuotes(std::string s);
void eraseSpacesFromString(std::string& s);
std::string getNameFromSurroundingQuotes(std::string& s);
@@ -733,11 +735,11 @@ protected:
bool _saveRenderingDuringPlayback = false;
double _saveRenderingDeltaTime = 1.0 / 30.0;
double _saveRenderingCurrentRecordedTime;
double _saveRenderingCurrentRecordedTime = 0.0;
std::chrono::steady_clock::duration _saveRenderingDeltaTime_interpolation_usec;
std::chrono::steady_clock::time_point _saveRenderingCurrentRecordedTime_interpolation;
double _saveRenderingCurrentApplicationTime_interpolation;
long long _saveRenderingClockInterpolation_countsPerSec;
double _saveRenderingCurrentApplicationTime_interpolation = 0.0;
long long _saveRenderingClockInterpolation_countsPerSec = 1;
bool _saveRendering_isFirstFrame = true;
unsigned char _keyframeBuffer[_saveBufferMaxSize_bytes];

View File

@@ -253,6 +253,17 @@ public:
*/
void setPropertiesFromProfile(const Profile& p);
/**
* Searches for any properties that match the regex propertyString, and returns
* the results in a vector.
*
* \param propertyString the regex string that is intended to match one or more
* properties in the currently-available properties
* \return Vector of Property objs containing property names that matched the regex
*/
std::vector<properties::Property*> propertiesMatchingRegex(
std::string propertyString);
private:
/**
* Accepts string version of a property value from a profile, converts it to the

View File

@@ -271,7 +271,7 @@ void SessionRecording::stopRecording() {
if (_state == SessionState::Recording) {
// Add all property baseline scripts to the beginning of the recording file
datamessagestructures::ScriptMessage smTmp;
for (TimelineEntry initPropScripts : _keyframesSavePropertiesBaseline_timeline) {
for (TimelineEntry& initPropScripts : _keyframesSavePropertiesBaseline_timeline) {
if (initPropScripts.keyframeType == RecordedType::Script) {
smTmp._script = _keyframesSavePropertiesBaseline_scripts
[initPropScripts.idxIntoKeyframeTypeArray];
@@ -1514,7 +1514,7 @@ bool SessionRecording::playbackScript() {
_playbackLineNum
);
success &= checkIfScriptUsesScenegraphNode(kf._script);
checkIfScriptUsesScenegraphNode(kf._script);
if (success) {
success = addKeyframe(
@@ -1534,61 +1534,100 @@ void SessionRecording::populateListofLoadedSceneGraphNodes() {
}
}
bool SessionRecording::checkIfScriptUsesScenegraphNode(std::string s) {
void SessionRecording::checkIfScriptUsesScenegraphNode(std::string s) {
if (s.rfind(scriptReturnPrefix, 0) == 0) {
s.erase(0, scriptReturnPrefix.length());
}
// This works for both setPropertyValue and setPropertyValueSingle
if (s.rfind("openspace.setPropertyValue", 0) == 0) {
std::string found;
if (s.find("(\"") != std::string::npos) {
std::string subj = s.substr(s.find("(\"") + 2);
checkForScenegraphNodeAccess_Scene(subj, found);
checkForScenegraphNodeAccess_Nav(subj, found);
if (found.length() > 0) {
auto it = std::find(_loadedNodes.begin(), _loadedNodes.end(), found);
bool containsSetPropertyVal = (s.rfind("openspace.setPropertyValue", 0) == 0);
bool containsParensStart = (s.find("(") != std::string::npos);
if (containsSetPropertyVal && containsParensStart) {
std::string subjectOfSetProp = isolateTermFromQuotes(s.substr(s.find("(") + 1));
if (checkForScenegraphNodeAccessNav(subjectOfSetProp)) {
size_t commaPos = s.find(",");
std::string navNode = isolateTermFromQuotes(s.substr(commaPos + 1));
if (navNode != "nil") {
std::vector<std::string>::iterator it =
std::find(_loadedNodes.begin(), _loadedNodes.end(), navNode);
if (it == _loadedNodes.end()) {
LERROR(fmt::format(
"Playback file requires scenegraph node '{}', which is "
"not currently loaded", found
LWARNING(fmt::format(
"Playback file contains a property setting of navigation using"
" scenegraph node '{}', which is not currently loaded", navNode
));
}
}
}
else if (checkForScenegraphNodeAccessScene(subjectOfSetProp)) {
std::string found = extractScenegraphNodeFromScene(subjectOfSetProp);
if (!found.empty()) {
std::vector<properties::Property*> matchHits =
global::renderEngine->scene()->propertiesMatchingRegex(
subjectOfSetProp
);
if (matchHits.empty()) {
LWARNING(fmt::format(
"Playback file contains a property setting of scenegraph"
" node '{}', which is not currently loaded", found
));
return false;
}
}
}
}
return true;
}
void SessionRecording::checkForScenegraphNodeAccess_Scene(std::string& s,
std::string& result)
{
bool SessionRecording::checkForScenegraphNodeAccessScene(std::string& s) {
const std::string scene = "Scene.";
auto posScene = s.find(scene);
return (s.find(scene) != std::string::npos);
}
std::string SessionRecording::extractScenegraphNodeFromScene(std::string& s) {
const std::string scene = "Scene.";
std::string extracted;
size_t posScene = s.find(scene);
if (posScene != std::string::npos) {
auto posDot = s.find(".", posScene + scene.length() + 1);
size_t posDot = s.find(".", posScene + scene.length() + 1);
if (posDot > posScene && posDot != std::string::npos) {
result = s.substr(posScene + scene.length(), posDot
- (posScene + scene.length()));
extracted = s.substr(posScene + scene.length(), posDot -
(posScene + scene.length()));
}
}
return extracted;
}
void SessionRecording::checkForScenegraphNodeAccess_Nav(std::string& s,
std::string& result)
{
bool SessionRecording::checkForScenegraphNodeAccessNav(std::string& navTerm) {
const std::string nextTerm = "NavigationHandler.OrbitalNavigator.";
auto posNav = s.find(nextTerm);
size_t posNav = navTerm.find(nextTerm);
if (posNav != std::string::npos) {
for (std::string accessName : _navScriptsUsingNodes) {
if (s.substr(posNav + nextTerm.length()).rfind(accessName) == 0) {
std::string postName = s.substr(posNav + nextTerm.length()
+ accessName.length() + 2);
eraseSpacesFromString(postName);
result = getNameFromSurroundingQuotes(postName);
}
if (navTerm.find(accessName) != std::string::npos) {
return true;
}
}
}
return false;
}
std::string SessionRecording::isolateTermFromQuotes(std::string s) {
//Remove any leading spaces
while (s.front() == ' ') {
s.erase(0, 1);
}
const std::string possibleQuotes = "\'\"[]";
while (possibleQuotes.find(s.front()) != std::string::npos) {
s.erase(0, 1);
}
for (char q : possibleQuotes) {
if (s.find(q) != std::string::npos) {
s = s.substr(0, s.find(q));
return s;
}
}
//If no quotes found, remove other possible characters from end
std::string unwantedChars = " );";
while (unwantedChars.find(s.back()) != std::string::npos) {
s.pop_back();
}
return s;
}
void SessionRecording::eraseSpacesFromString(std::string& s) {

View File

@@ -812,6 +812,12 @@ PropertyValueType Scene::propertyValueType(const std::string& value) {
}
}
std::vector<properties::Property*> Scene::propertiesMatchingRegex(
std::string propertyString)
{
return findMatchesInAllProperties(propertyString, allProperties(), "");
}
scripting::LuaLibrary Scene::luaLibrary() {
return {
"",

View File

@@ -81,21 +81,17 @@ openspace::properties::PropertyOwner* findPropertyOwnerWithMatchingGroupTag(T* p
return tagMatchOwner;
}
void applyRegularExpression(lua_State* L, const std::string& regex,
const std::vector<openspace::properties::Property*>& properties,
double interpolationDuration,
const std::string& groupName,
ghoul::EasingFunction easingFunction)
std::vector<openspace::properties::Property*> findMatchesInAllProperties(
const std::string& regex,
const std::vector<openspace::properties::Property*>& properties,
const std::string& groupName)
{
using namespace openspace;
using ghoul::lua::errorLocation;
using ghoul::lua::luaTypeToString;
std::vector<properties::Property*> matches;
const bool isGroupMode = !groupName.empty();
bool isLiteral = false;
const int type = lua_type(L, -1);
// Extract the property and node name to be searched for from regex
std::string propertyName;
std::string nodeName;
@@ -107,25 +103,25 @@ void applyRegularExpression(lua_State* L, const std::string& regex,
// If none then malformed regular expression
if (propertyName.empty() && nodeName.empty()) {
LERRORC(
"applyRegularExpression",
"findMatchesInAllProperties",
fmt::format(
"Malformed regular expression: '{}': Empty both before and after '*'",
regex
)
);
return;
return matches;
}
// Currently do not support several wildcards
if (regex.find_first_of("*", wildPos + 1) != std::string::npos) {
LERRORC(
"applyRegularExpression",
"findMatchesInAllProperties",
fmt::format(
"Malformed regular expression: '{}': Currently only one '*' is "
"supported", regex
)
);
return;
return matches;
}
}
// Literal or tag
@@ -146,7 +142,7 @@ void applyRegularExpression(lua_State* L, const std::string& regex,
if (isLiteral && id != propertyName) {
continue;
}
else if (!propertyName.empty()){
else if (!propertyName.empty()) {
size_t propertyPos = id.find(propertyName);
if (propertyPos != std::string::npos) {
// Check that the propertyName fully matches the property in id
@@ -192,6 +188,36 @@ void applyRegularExpression(lua_State* L, const std::string& regex,
continue;
}
}
matches.push_back(prop);
}
return matches;
}
void applyRegularExpression(lua_State* L, const std::string& regex,
const std::vector<openspace::properties::Property*>& properties,
double interpolationDuration,
const std::string& groupName,
ghoul::EasingFunction easingFunction)
{
using namespace openspace;
using ghoul::lua::errorLocation;
using ghoul::lua::luaTypeToString;
const bool isGroupMode = !groupName.empty();
bool isLiteral = false;
const int type = lua_type(L, -1);
std::vector<properties::Property*> matchingProps = findMatchesInAllProperties(
regex,
properties,
groupName
);
// Stores whether we found at least one matching property. If this is false at the
// end of the loop, the property name regex was probably misspelled.
bool foundMatching = false;
for (properties::Property* prop : matchingProps) {
// Check that the types match
if (type != prop->typeLua()) {