mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-05-04 18:11:01 -05:00
Merge branch 'thesis/2018/dsn' of github.com:OpenSpace/OpenSpace into thesis/2018/dsn
This commit is contained in:
@@ -4,8 +4,13 @@ local spacecrafts = asset.require('scene/solarsystem/dsn/spacecrafts')
|
||||
--------------------------------------------------
|
||||
--------------------- Labels --------------------
|
||||
--------------------------------------------------
|
||||
|
||||
local CassiniLabel = {
|
||||
LabelText = ".Cassini",
|
||||
TimeFrame = {
|
||||
Start = "2014-002T18:00:00",
|
||||
End = "2017-258T14:00:00"
|
||||
},
|
||||
ObjectIdentifier = spacecrafts.CassiniAsset.spacecraftID
|
||||
}
|
||||
local ChandraXrayLabel = {
|
||||
@@ -14,22 +19,42 @@ local ChandraXrayLabel = {
|
||||
}
|
||||
local DawnLabel = {
|
||||
LabelText = ".Dawn",
|
||||
TimeFrame = {
|
||||
Start = "2014-003T16:00:00",
|
||||
End = "2018-257T01:00:00"
|
||||
},
|
||||
ObjectIdentifier = spacecrafts.DawnAsset.spacecraftID
|
||||
}
|
||||
local GaiaLabel = {
|
||||
LabelText = ".Gaia",
|
||||
TimeFrame = {
|
||||
Start = "2018-100T15:00:00",
|
||||
End = "2018-154T06:00:00"
|
||||
},
|
||||
ObjectIdentifier = spacecrafts.GaiaAsset.spacecraftID
|
||||
}
|
||||
local GenesisLabel = {
|
||||
LabelText = ".Genesis",
|
||||
TimeFrame = {
|
||||
Start = "2015-254T21:00:00",
|
||||
End = "2015-254T22:00:00"
|
||||
},
|
||||
ObjectIdentifier = spacecrafts.GenesisAsset.spacecraftID
|
||||
}
|
||||
local Hayabusa2Label = {
|
||||
LabelText = ".Hayabusa 2",
|
||||
TimeFrame = {
|
||||
Start = "2014-337T06:00:00",
|
||||
End = "2018-363T13:00:00"
|
||||
},
|
||||
ObjectIdentifier = spacecrafts.Hayabusa2Asset.spacecraftID
|
||||
}
|
||||
local IceLabel = {
|
||||
LabelText = ".Ice",
|
||||
TimeFrame = {
|
||||
Start = "2014-169T20:00:00",
|
||||
End = "2014-192T16:00:00"
|
||||
},
|
||||
ObjectIdentifier = spacecrafts.IceAsset.spacecraftID
|
||||
}
|
||||
local JunoLabel = {
|
||||
@@ -45,11 +70,15 @@ local MarsRecOrbLabel = {
|
||||
ObjectIdentifier = spacecrafts.MarsRecOrbAsset.spacecraftID
|
||||
}
|
||||
local MarsOdysseyLabel = {
|
||||
LabelText = ".Mars Odyssey",
|
||||
LabelText= ".Mars Odyssey",
|
||||
ObjectIdentifier = spacecrafts.MarsOdysseyAsset.spacecraftID
|
||||
}
|
||||
local MessengerLabel = {
|
||||
LabelText = ".Messenger",
|
||||
TimeFrame = {
|
||||
Start = "2014-002T01:00:00",
|
||||
End = "2015-121T05:00:00"
|
||||
},
|
||||
ObjectIdentifier = spacecrafts.MessengerAsset.spacecraftID
|
||||
}
|
||||
local NewHorizonsLabel = {
|
||||
@@ -57,7 +86,7 @@ local NewHorizonsLabel = {
|
||||
ObjectIdentifier = spacecrafts.NewHorizonsAsset.spacecraftID
|
||||
}
|
||||
local SohoLabel = {
|
||||
LabelText = ".Solar & Heliospheric Observatory",
|
||||
LabelText = ".Soho",
|
||||
ObjectIdentifier = spacecrafts.SohoAsset.spacecraftID
|
||||
}
|
||||
local SpitzerLabel = {
|
||||
@@ -70,10 +99,19 @@ local StereoALabel = {
|
||||
}
|
||||
local StereoBLabel = {
|
||||
LabelText = ".Stereo B",
|
||||
TimeFrame = {
|
||||
Start = "2014-001T00:00:00",
|
||||
End = "2018-290T09:00:00"
|
||||
},
|
||||
ObjectIdentifier = spacecrafts.StereoBAsset.spacecraftID
|
||||
}
|
||||
--Transit exoplanet Survey Satellite
|
||||
local TessLabel = {
|
||||
LabelText = ".Transit Exoplanet Survey Satellite",
|
||||
LabelText = ".Tess",
|
||||
TimeFrame = {
|
||||
Start = "2018-108T23:00:00",
|
||||
End = "2019-001T01:00:00"
|
||||
},
|
||||
ObjectIdentifier = spacecrafts.TessAsset.spacecraftID
|
||||
}
|
||||
local ThemisBLabel = {
|
||||
@@ -86,6 +124,10 @@ local ThemisCLabel = {
|
||||
}
|
||||
local TraceGasOrbiterLabel = {
|
||||
LabelText = ".Trace Gas Orbiter",
|
||||
TimeFrame = {
|
||||
Start = "2016-012T12:00:00",
|
||||
End = "2018-364T23:00:00"
|
||||
},
|
||||
ObjectIdentifier = spacecrafts.TraceGasOrbiterAsset.spacecraftID
|
||||
}
|
||||
local Voyager1Label = {
|
||||
@@ -101,6 +143,7 @@ local WindLabel = {
|
||||
ObjectIdentifier = spacecrafts.WindAsset.spacecraftID
|
||||
}
|
||||
|
||||
|
||||
--------------------------------------------------
|
||||
----------------- Cluster Labels ----------------
|
||||
--------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
---------------------------------------------------------------------------------------------------
|
||||
----- The maps in this file are used to keep the SceneGraphNode identifiers for each spacecraft ---
|
||||
----- up to date with the labels and dsn signal data among other things ---
|
||||
---------------------------------------------------------------------------------------------------
|
||||
local SpaceCrafts = asset.require('scene/solarsystem/dsn/spacecrafts')
|
||||
|
||||
-------------------- dsn signal data map --------------------
|
||||
local signalDataIdMap = {
|
||||
CAS = SpaceCrafts.CassiniAsset.spacecraftID,
|
||||
GAIA = SpaceCrafts.GaiaAsset.spacecraftID,
|
||||
GNS = SpaceCrafts.GenesisAsset.spacecraftID,
|
||||
HYB2 = SpaceCrafts.Hayabusa2Asset.spacecraftID,
|
||||
ICE = SpaceCrafts.IceAsset.spacecraftID,
|
||||
CHDR = SpaceCrafts.ChandraXrayAsset.spacecraftID,
|
||||
DAWN = SpaceCrafts.DawnAsset.spacecraftID,
|
||||
JNO = SpaceCrafts.JunoAsset.spacecraftID,
|
||||
KEPL = SpaceCrafts.KeplerAsset.spacecraftID,
|
||||
MRO = SpaceCrafts.MarsRecOrbAsset.spacecraftID,
|
||||
M010 = SpaceCrafts.MarsOdysseyAsset.spacecraftID,
|
||||
MSGR = SpaceCrafts.MessengerAsset.spacecraftID,
|
||||
NHPC = SpaceCrafts.NewHorizonsAsset.spacecraftID,
|
||||
SOHO = SpaceCrafts.SohoAsset.spacecraftID,
|
||||
STF = SpaceCrafts.SpitzerAsset.spacecraftID,
|
||||
STA = SpaceCrafts.StereoAAsset.spacecraftID,
|
||||
STB = SpaceCrafts.StereoBAsset.spacecraftID,
|
||||
TESS = SpaceCrafts.TessAsset.spacecraftID,
|
||||
THB = SpaceCrafts.ThemisBAsset.spacecraftID,
|
||||
THC = SpaceCrafts.ThemisCAsset.spacecraftID,
|
||||
TGO = SpaceCrafts.TraceGasOrbiterAsset.spacecraftID,
|
||||
VGR1 = SpaceCrafts.Voyager1Asset.spacecraftID,
|
||||
VGR2 = SpaceCrafts.Voyager2Asset.spacecraftID,
|
||||
WIND = SpaceCrafts.WindAsset.spacecraftID
|
||||
|
||||
}
|
||||
|
||||
------------------------ spacecraft labels -----------------------
|
||||
|
||||
local CassiniLabel = {
|
||||
LabelText = ".Cassini",
|
||||
TimeFrame = {
|
||||
Start = "2014-002T18:00:00",
|
||||
End = "2017-258T14:00:00"
|
||||
},
|
||||
ObjectIdentifier = SpaceCrafts.CassiniAsset.spacecraftID
|
||||
}
|
||||
local ChandraXrayLabel = {
|
||||
LabelText = ".Chandra Xray",
|
||||
ObjectIdentifier = SpaceCrafts.ChandraXrayAsset.spacecraftID
|
||||
}
|
||||
local DawnLabel = {
|
||||
LabelText = ".Dawn",
|
||||
TimeFrame = {
|
||||
Start = "2014-003T16:00:00",
|
||||
End = "2018-257T01:00:00"
|
||||
},
|
||||
ObjectIdentifier = SpaceCrafts.DawnAsset.spacecraftID
|
||||
}
|
||||
local GaiaLabel = {
|
||||
LabelText = ".Gaia",
|
||||
TimeFrame = {
|
||||
Start = "2018-100T15:00:00",
|
||||
End = "2018-154T06:00:00"
|
||||
},
|
||||
ObjectIdentifier = SpaceCrafts.GaiaAsset.spacecraftID
|
||||
}
|
||||
local GenesisLabel = {
|
||||
LabelText = ".Genesis",
|
||||
TimeFrame = {
|
||||
Start = "2015-254T21:00:00",
|
||||
End = "2015-254T22:00:00"
|
||||
},
|
||||
ObjectIdentifier = SpaceCrafts.GenesisAsset.spacecraftID
|
||||
}
|
||||
local Hayabusa2Label = {
|
||||
LabelText = ".Hayabusa 2",
|
||||
TimeFrame = {
|
||||
Start = "2014-337T06:00:00",
|
||||
End = "2018-363T13:00:00"
|
||||
},
|
||||
ObjectIdentifier = SpaceCrafts.Hayabusa2Asset.spacecraftID
|
||||
}
|
||||
local IceLabel = {
|
||||
LabelText = ".Ice",
|
||||
TimeFrame = {
|
||||
Start = "2014-169T20:00:00",
|
||||
End = "2014-192T16:00:00"
|
||||
},
|
||||
ObjectIdentifier = SpaceCrafts.IceAsset.spacecraftID
|
||||
}
|
||||
local JunoLabel = {
|
||||
LabelText = ".Juno",
|
||||
ObjectIdentifier = SpaceCrafts.JunoAsset.spacecraftID
|
||||
}
|
||||
local KeplerLabel = {
|
||||
LabelText = ".Kepler",
|
||||
ObjectIdentifier = SpaceCrafts.KeplerAsset.spacecraftID
|
||||
}
|
||||
local MarsRecOrbLabel = {
|
||||
LabelText = ".Mars Recon Orbiter",
|
||||
ObjectIdentifier = SpaceCrafts.MarsRecOrbAsset.spacecraftID
|
||||
}
|
||||
local MarsOdysseyLabel = {
|
||||
LabelText= ".Mars Odyssey",
|
||||
ObjectIdentifier = SpaceCrafts.MarsOdysseyAsset.spacecraftID
|
||||
}
|
||||
local MessengerLabel = {
|
||||
LabelText = ".Messenger",
|
||||
TimeFrame = {
|
||||
Start = "2014-002T01:00:00",
|
||||
End = "2015-121T05:00:00"
|
||||
},
|
||||
ObjectIdentifier = SpaceCrafts.MessengerAsset.spacecraftID
|
||||
}
|
||||
local NewHorizonsLabel = {
|
||||
LabelText = ".New Horizons",
|
||||
ObjectIdentifier = SpaceCrafts.NewHorizonsAsset.spacecraftID
|
||||
}
|
||||
local SohoLabel = {
|
||||
LabelText = ".Soho",
|
||||
ObjectIdentifier = SpaceCrafts.SohoAsset.spacecraftID
|
||||
}
|
||||
local SpitzerLabel = {
|
||||
LabelText = ".Spitzer",
|
||||
ObjectIdentifier = SpaceCrafts.SpitzerAsset.spacecraftID
|
||||
}
|
||||
local StereoALabel = {
|
||||
LabelText = ".Stereo A",
|
||||
ObjectIdentifier = SpaceCrafts.StereoAAsset.spacecraftID
|
||||
}
|
||||
local StereoBLabel = {
|
||||
LabelText = ".Stereo B",
|
||||
TimeFrame = {
|
||||
Start = "2014-001T00:00:00",
|
||||
End = "2018-290T09:00:00"
|
||||
},
|
||||
ObjectIdentifier = SpaceCrafts.StereoBAsset.spacecraftID
|
||||
}
|
||||
--Transit exoplanet Survey Satellite
|
||||
local TessLabel = {
|
||||
LabelText = ".Tess",
|
||||
TimeFrame = {
|
||||
Start = "2018-108T23:00:00",
|
||||
End = "2019-001T01:00:00"
|
||||
},
|
||||
ObjectIdentifier = SpaceCrafts.TessAsset.spacecraftID
|
||||
}
|
||||
local ThemisBLabel = {
|
||||
LabelText = ".Themis B",
|
||||
ObjectIdentifier = SpaceCrafts.ThemisBAsset.spacecraftID
|
||||
}
|
||||
local ThemisCLabel = {
|
||||
LabelText = ".Themis C",
|
||||
ObjectIdentifier = SpaceCrafts.ThemisCAsset.spacecraftID
|
||||
}
|
||||
local TraceGasOrbiterLabel = {
|
||||
LabelText = ".Trace Gas Orbiter",
|
||||
TimeFrame = {
|
||||
Start = "2016-012T12:00:00",
|
||||
End = "2018-364T23:00:00"
|
||||
},
|
||||
ObjectIdentifier = SpaceCrafts.TraceGasOrbiterAsset.spacecraftID
|
||||
}
|
||||
local Voyager1Label = {
|
||||
LabelText = ".Voyager 1",
|
||||
ObjectIdentifier = SpaceCrafts.Voyager1Asset.spacecraftID
|
||||
}
|
||||
local Voyager2Label = {
|
||||
LabelText = ".Voyager 2",
|
||||
ObjectIdentifier = SpaceCrafts.Voyager2Asset.spacecraftID
|
||||
}
|
||||
local WindLabel = {
|
||||
LabelText = ".Wind",
|
||||
ObjectIdentifier = SpaceCrafts.WindAsset.spacecraftID
|
||||
}
|
||||
|
||||
------------------------ cluster labels -----------------------
|
||||
|
||||
local MarsClusterLabel = {
|
||||
LabelText = ".MarsOdyssey,\nMars Recon Orbiter ",
|
||||
ObjectIdentifier = "Mars"
|
||||
}
|
||||
|
||||
-------------------- label id maps --------------------
|
||||
local labelMapMarsMissions = {
|
||||
Label1 = MarsRecOrbLabel,
|
||||
Label2 = MarsOdysseyLabel
|
||||
|
||||
}
|
||||
|
||||
local labelMapOuterSpace = {
|
||||
Label1 = Voyager1Label,
|
||||
Label2 = Voyager2Label,
|
||||
label3 = NewHorizonsLabel
|
||||
|
||||
}
|
||||
|
||||
local labelMapInnerSpace = {
|
||||
Label1 = StereoALabel,
|
||||
Label2 = StereoBLabel,
|
||||
Label3 = JunoLabel,
|
||||
Label4 = CassiniLabel,
|
||||
Label5 = KeplerLabel,
|
||||
label6 = DawnLabel,
|
||||
label7 = SpitzerLabel,
|
||||
label8 = GenesisLabel,
|
||||
label9 = Hayabusa2Label,
|
||||
label10 = MessengerLabel,
|
||||
label11 = TraceGasOrbiterLabel
|
||||
|
||||
}
|
||||
|
||||
local labelMapNearEarth = {
|
||||
Label1 = GaiaLabel,
|
||||
Label2 = ChandraXrayLabel,
|
||||
label3 = ThemisBLabel,
|
||||
label4 = ThemisCLabel,
|
||||
label5 = WindLabel,
|
||||
label6 = SohoLabel,
|
||||
label7 = IceLabel,
|
||||
label8 = TessLabel
|
||||
|
||||
}
|
||||
local labelMapClusters = {
|
||||
Label1 = MarsClusterLabel
|
||||
}
|
||||
|
||||
------------------------ export -------------------------
|
||||
asset.export("signalDataIdMap", signalDataIdMap)
|
||||
asset.export("labelMapMarsMissions", labelMapMarsMissions)
|
||||
asset.export("labelMapOuterSpace", labelMapOuterSpace)
|
||||
asset.export("labelMapInnerSpace", labelMapInnerSpace)
|
||||
asset.export("labelMapNearEarth", labelMapNearEarth)
|
||||
asset.export("labelMapClusters", labelMapClusters)
|
||||
@@ -46,6 +46,7 @@ namespace {
|
||||
constexpr const char* KeyObjectIdentifier = "ObjectIdentifier";
|
||||
constexpr const char* KeyLabelText = "LabelText";
|
||||
constexpr const char* KeyTextColor = "TextColor";
|
||||
constexpr const char* keyTimeFrame = "TimeFrame";
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo LabelIdentifierMapInfo = {
|
||||
"LabelIdentifierMap",
|
||||
@@ -268,6 +269,18 @@ namespace openspace {
|
||||
ghoul::Dictionary labelInfoDictionary = tempLabelIdMap.value<ghoul::Dictionary>(labels.at(i));
|
||||
LabelInfo labelInfo;
|
||||
labelInfo.text = labelInfoDictionary.value<std::string>(KeyLabelText);
|
||||
|
||||
if (labelInfoDictionary.hasKey(keyTimeFrame)) {
|
||||
ghoul::Dictionary timeFrameDictionary = labelInfoDictionary.value<ghoul::Dictionary>(keyTimeFrame);
|
||||
|
||||
std::string startTime = timeFrameDictionary.value <std::string>("Start");
|
||||
std::string endTime = timeFrameDictionary.value <std::string>("End");
|
||||
|
||||
labelInfo.startTime = Time::convertTime(startTime);
|
||||
labelInfo.endTime = Time::convertTime(endTime);
|
||||
|
||||
labelInfo.hasKeyTimeFrame = true;
|
||||
}
|
||||
|
||||
if (labelInfoDictionary.hasKey(KeyTextColor)) {
|
||||
labelInfo.textColor = labelInfoDictionary.value<glm::vec4>(KeyTextColor);
|
||||
@@ -375,7 +388,7 @@ namespace openspace {
|
||||
}
|
||||
|
||||
void RenderableDsnLabels::initialize() {
|
||||
bool success = loadData();
|
||||
bool success = loadData(0);
|
||||
if (!success) {
|
||||
throw ghoul::RuntimeError("Error with identifiers for labels");
|
||||
}
|
||||
@@ -407,7 +420,7 @@ namespace openspace {
|
||||
|
||||
if (_hasLabelIdMap) {
|
||||
_labelData.clear();
|
||||
loadLabelDataFromId();
|
||||
loadLabelDataFromId(data.time);
|
||||
}
|
||||
for (const std::tuple<glm::dvec3, std::string, glm::vec4>& label : _labelData) {
|
||||
|
||||
@@ -415,7 +428,7 @@ namespace openspace {
|
||||
glm::dvec3 nodePos = std::get<0>(label);
|
||||
std::string labelText = std::get<1>(label);
|
||||
glm::vec4 labelTextColor = std::get<2>(label);
|
||||
|
||||
|
||||
glm::vec4 textColor = labelTextColor;
|
||||
|
||||
// The distance from the camera to the SceneGraphNode of the label
|
||||
@@ -530,37 +543,38 @@ namespace openspace {
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderableDsnLabels::loadData() {
|
||||
bool RenderableDsnLabels::loadData(const Time& time) {
|
||||
bool success = true;
|
||||
|
||||
if (_hasLabelIdMap) {
|
||||
|
||||
success &= loadLabelDataFromId();
|
||||
|
||||
success &= loadLabelDataFromId(time);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool RenderableDsnLabels::loadLabelDataFromId() {
|
||||
|
||||
bool RenderableDsnLabels::loadLabelDataFromId(const Time& time) {
|
||||
for (int i = 0; i < labelDataInfo.size(); i++) {
|
||||
LabelInfo labelinfo = labelDataInfo.at(i);
|
||||
|
||||
if (global::renderEngine.scene()->sceneGraphNode(labelinfo.attachedId)) {
|
||||
|
||||
glm::dvec3 position = global::renderEngine.scene()->sceneGraphNode(labelinfo.attachedId)->worldPosition();
|
||||
|
||||
glm::dvec3 transformedPos = glm::dvec3(
|
||||
_transformationMatrix * glm::dvec4(position, 1.0)
|
||||
);
|
||||
_labelData.emplace_back(std::make_tuple(transformedPos, labelinfo.text, labelinfo.textColor));
|
||||
|
||||
}
|
||||
else {
|
||||
LERROR(fmt::format("No SceneGraphNode found with identifier {}", labelinfo.attachedId));
|
||||
return false;
|
||||
}
|
||||
double currentTime = time.j2000Seconds();
|
||||
|
||||
bool inTimeFrame = (currentTime > labelinfo.startTime && currentTime < labelinfo.endTime);
|
||||
if ( (labelinfo.hasKeyTimeFrame == true && inTimeFrame) || labelinfo.hasKeyTimeFrame == false) {
|
||||
|
||||
if (global::renderEngine.scene()->sceneGraphNode(labelinfo.attachedId)) {
|
||||
|
||||
glm::dvec3 position = global::renderEngine.scene()->sceneGraphNode(labelinfo.attachedId)->worldPosition();
|
||||
|
||||
glm::dvec3 transformedPos = glm::dvec3(
|
||||
_transformationMatrix * glm::dvec4(position, 1.0)
|
||||
);
|
||||
_labelData.emplace_back(std::make_tuple(transformedPos, labelinfo.text, labelinfo.textColor));
|
||||
}
|
||||
else {
|
||||
LERROR(fmt::format("No SceneGraphNode found with identifier {}", labelinfo.attachedId));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <openspace/properties/vector/vec2property.h>
|
||||
#include <openspace/properties/vector/vec3property.h>
|
||||
#include <openspace/properties/vector/vec4property.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
|
||||
namespace ghoul::fontrendering { class Font; }
|
||||
|
||||
@@ -54,7 +55,6 @@ namespace openspace {
|
||||
void render(const RenderData& data, RendererTasks& rendererTask) override;
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
private:
|
||||
|
||||
double _fadeInDistanceUnit = 1E10;
|
||||
@@ -65,14 +65,16 @@ namespace openspace {
|
||||
const glm::dvec3& orthoRight, const glm::dvec3& orthoUp);
|
||||
void updateTextColor();
|
||||
|
||||
bool loadData();
|
||||
bool loadLabelDataFromId();
|
||||
bool loadData(const Time& time);
|
||||
bool loadLabelDataFromId(const Time& time);
|
||||
|
||||
bool _hasStaticLabelSize = false;
|
||||
bool _dataIsDirty = true;
|
||||
bool _textColorIsDirty = true;
|
||||
bool _hasLabel = false;
|
||||
bool _hasLabelIdMap = false;
|
||||
|
||||
|
||||
double maxMinNormalize(double value, glm::dvec2 newRange, glm::dvec2 oldRange);
|
||||
|
||||
properties::FloatProperty _scaleFactor;
|
||||
@@ -94,6 +96,9 @@ namespace openspace {
|
||||
std::string text;
|
||||
glm::vec4 textColor;
|
||||
std::string attachedId;
|
||||
double startTime;
|
||||
double endTime;
|
||||
bool hasKeyTimeFrame = false;
|
||||
bool hasIndividualColor = false;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user