1#include "DepthAxisSystem.h"
5#include "Systems/Core/CameraSystem.h"
6#include "Systems/Core/TransformSystem.h"
8#include "Utilities/Math.h"
9#include "Math/LinePlaneIntersection.h"
11#include "Components/Core/MeshComponent.h"
12#include "Components/Core/TextComponent.h"
13#include "Components/Core/SubMeshRenderComponent.h"
14#include "Components/Data/TrajectoryComponent.h"
15#include "../Components/AnnotationAxisComponent.h"
17#include "Resources/MeshManager.h"
18#include "Resources/MaterialManager.h"
19#include "Resources/FontManager.h"
20#include "Resources/DefaultMaterial.h"
22#include "Foundation/ComponentModel/Entity.h"
23#include "Foundation/Geometry/BoundingBox.hpp"
24#include "Foundation/Geometry/SampleListGenerator.hpp"
25#include "Foundation/Geometry/PathGenerator.hpp"
35 glm::vec3 project(
const CameraData & data,
const glm::vec3 & in)
37 auto projected = data.viewProjection * glm::vec4(in, 1);
39 projected /= projected.w != 0.0f ? projected.w : 1.0f;
41 return glm::vec3(projected);
44 float getWorldToScreenScale(Context * ,
const CameraData & cameraData,
const glm::vec3 & worldCenter,
float normRadius)
48 const auto screenCenter = project(cameraData, worldCenter) + glm::vec3(normRadius, 0, 0);
50 const auto projectionPoint = glm::vec3(cameraData.inverseViewMatrix * glm::vec4(0, 0, 0, 1));
51 const auto reverseProjectedW = cameraData.inverseViewProjectionMatrix * glm::vec4(screenCenter.x, screenCenter.y, -1, 1);
53 const auto reverseProjected = glm::vec3(reverseProjectedW / reverseProjectedW.w);
55 const auto centerToCamera = worldCenter - projectionPoint;
57 if (!glm::length(centerToCamera))
return 1;
59 const float planeDistance = glm::dot(glm::normalize(centerToCamera), worldCenter);
61 glm::vec3 intersection;
62 Cogs::Geometry::intersect(glm::normalize(centerToCamera), planeDistance, projectionPoint, glm::normalize(reverseProjected - projectionPoint), intersection);
64 return glm::length(intersection - worldCenter);
71 const auto cameraComponent =
context->cameraSystem->getMainCamera();
72 const auto & cameraData =
context->cameraSystem->getData(cameraComponent);
74 for (
auto & component :
pool) {
75 if (!component.isActive() || !component.trajectory ||
83 annotationComponent->strings.clear();
84 annotationComponent->positions.clear();
93 auto & data = getData(&component);
95 if (component.hasChanged() || trajectory->hasChanged()) {
96 data.majorTickDepths.clear();
97 data.minorTickDepths.clear();
98 data.currentAxis = glm::vec3();
100 getAnnotationTicks(component, trajectory, data.majorTickDepths, data.minorTickDepths);
102 data.majorPositions.resize(data.majorTickDepths.size());
103 data.majorDirections.resize(data.majorTickDepths.size());
105 Cogs::Geometry::PathGenerator::generateLinearPath(data.majorTickDepths.data(),
106 static_cast<int>(data.majorTickDepths.size()),
107 trajectory->indexes.data(),
108 trajectory->positions.data(),
109 static_cast<int>(trajectory->positions.size()),
110 data.majorPositions.data(),
111 data.majorDirections.data());
113 if (data.minorTickDepths.size()) {
114 data.minorPositions.resize(data.minorTickDepths.size());
115 data.minorDirections.resize(data.minorTickDepths.size());
117 Cogs::Geometry::PathGenerator::generateLinearPath(data.minorTickDepths.data(),
118 static_cast<int>(data.minorTickDepths.size()),
119 trajectory->indexes.data(),
120 trajectory->positions.data(),
121 static_cast<int>(trajectory->positions.size()),
122 data.minorPositions.data(),
123 data.minorDirections.data());
126 if (data.majorTickDepths.size()) {
127 data.majorTexts.resize(data.majorTickDepths.size());
129 addText(component, data.majorTexts.data(), data.majorTickDepths.size(), data.majorTickDepths.data());
131 if (component.enableMinorText && data.minorTickDepths.size()) {
132 data.minorTexts.resize(data.minorTickDepths.size());
134 if (data.minorTexts.size()) {
135 addText(component, data.minorTexts.data(), data.minorTickDepths.size(), data.minorTickDepths.data());
139 if (component.axis.x > 0) {
145 auto meshComponent = component.getComponent<
MeshComponent>();
153 if (renderComponent->materials.size() != 2) {
156 auto majorMaterial =
context->materialInstanceManager->createMaterialInstance(
context->materialManager->getDefaultMaterial());
157 auto minorMaterial =
context->materialInstanceManager->createMaterialInstance(
context->materialManager->getDefaultMaterial());
159 majorMaterial->setPermutation(
"Line");
160 minorMaterial->setPermutation(
"Line");
162 majorMaterial->setVariant(
"EnableLighting",
false);
163 minorMaterial->setVariant(
"EnableLighting",
false);
165 majorMaterial->setBoolProperty(DefaultMaterial::EnableLighting,
false);
166 minorMaterial->setBoolProperty(DefaultMaterial::EnableLighting,
false);
168 majorMaterial->setVec4Property(DefaultMaterial::DiffuseColor, component.diffuseColor);
169 minorMaterial->setVec4Property(DefaultMaterial::DiffuseColor, glm::vec4(component.diffuseColor.r, component.diffuseColor.g, component.diffuseColor.b, component.diffuseColor.a * 0.5f));
171 renderComponent->materials[0] = majorMaterial;
172 renderComponent->materials[1] = minorMaterial;
174 auto majorMaterial = renderComponent->materials[0];
175 auto minorMaterial = renderComponent->materials[1];
177 majorMaterial->setVec4Property(DefaultMaterial::DiffuseColor, component.diffuseColor);
178 minorMaterial->setVec4Property(DefaultMaterial::DiffuseColor, glm::vec4(component.diffuseColor.r, component.diffuseColor.g, component.diffuseColor.b, component.diffuseColor.a * 0.5f));
181 textComponent->color = component.diffuseColor;
183 textComponent->fontHandle =
context->fontManager->getHandle(
context->fontManager->DefaultRegularFont);
188 glm::vec3 axis = glm::vec3(cameraData.inverseViewMatrix * glm::vec4(component.axis, 0));
190 if (!glm::all(glm::epsilonEqual(data.currentAxis, axis, 0.02f))) {
191 data.currentAxis = glm::normalize(axis);
193 glm::vec3 trajectoryAxis = data.majorDirections.size() ? data.majorDirections[0] : glm::vec3(0, 0, -1);
195 if (component.enableMaxSize) {
196 std::vector<float> majorScales(data.majorTickDepths.size());
197 std::vector<float> minorScales(data.minorTickDepths.size());
199 const float distance = component.majorDistance;
200 const float invertedDistance = 1.0f / distance;
202 const float projectedSize = component.maxSize;
203 const float nsize = projectedSize /
static_cast<float>(cameraComponent->viewportSize.x);
206 std::vector<glm::vec3> positions(data.majorTickDepths.size());
208 for (
size_t j = 0; j < data.majorTickDepths.size(); ++j) {
209 positions[j] = Cogs::Geometry::transform(data.majorPositions[j], modelMatrix);
212 for (
size_t i = 0; i < data.majorTickDepths.size(); ++i) {
213 auto scale = getWorldToScreenScale(
context, cameraData, positions[i], nsize) * invertedDistance;
215 majorScales[i] = scale;
217 if (majorScales[i] > 1 || majorScales[i] != majorScales[i]) majorScales[i] = 1;
220 positions.resize(data.minorTickDepths.size());
222 for (
size_t j = 0; j < data.minorTickDepths.size(); ++j) {
223 positions[j] = Cogs::Geometry::transform(data.minorPositions[j], modelMatrix);
226 for (
size_t i = 0; i < data.minorTickDepths.size(); ++i) {
227 minorScales[i] = getWorldToScreenScale(
context, cameraData, positions[i], nsize) * invertedDistance;
229 if (minorScales[i] > 1 || minorScales[i] != minorScales[i]) minorScales[i] = 1;
232 std::vector<glm::vec3> vertexes;
233 std::vector<uint32_t> majorIndexes;
234 std::vector<uint32_t> minorIndexes;
236 addTicks(component, vertexes, majorIndexes, data.majorPositions, data.majorDirections, axis, trajectoryAxis, component.majorDistance, majorScales);
237 addTicks(component, vertexes, minorIndexes, data.minorPositions, data.minorDirections, axis, trajectoryAxis, component.minorDistance, minorScales);
239 auto meshComponent = component.getComponent<
MeshComponent>();
243 mesh->setIndexes(std::vector<uint32_t>());
244 mesh->setPositions(std::move(vertexes));
248 annotation->strings.clear();
251 addAnnotations(component, annotation, data.majorPositions, data.majorDirections, data.majorTexts, axis, trajectoryAxis, component.majorDistance, majorScales);
253 if (component.enableMinorText) {
254 addAnnotations(component, annotation, data.minorPositions, data.minorDirections, data.minorTexts, axis, trajectoryAxis, component.minorDistance, minorScales,
true);
257 std::vector<glm::vec3> vertexes;
258 std::vector<uint32_t> majorIndexes;
259 std::vector<uint32_t> minorIndexes;
261 addTicks(component, vertexes, majorIndexes, data.majorPositions, data.majorDirections, axis, trajectoryAxis, component.majorDistance, std::vector<float>());
262 addTicks(component, vertexes, minorIndexes, data.minorPositions, data.minorDirections, axis, trajectoryAxis, component.minorDistance, std::vector<float>());
264 auto meshComponent = component.getComponent<
MeshComponent>();
268 mesh->setIndexes(std::vector<uint32_t>());
269 mesh->setPositions(std::move(vertexes));
273 annotation->strings.clear();
276 addAnnotations(component, annotation, data.majorPositions, data.majorDirections, data.majorTexts, axis, trajectoryAxis, component.majorDistance, std::vector<float>());
278 if (component.enableMinorText) {
279 addAnnotations(component, annotation, data.minorPositions, data.minorDirections, data.minorTexts, axis, trajectoryAxis, component.minorDistance, std::vector<float>());
288 namespace Calculation
290 template<
class TReal,
bool ShiftStartToNearestIntervalSize>
291 void calculateIntervals(TReal start, TReal end, TReal interval, std::vector<TReal> & majorIntervals)
293 if ((end - start) <= 0) {
297 if (ShiftStartToNearestIntervalSize) {
298 float startFloor = std::floor(start / interval);
299 float truncatedStart = startFloor * interval;
301 if (truncatedStart < start) {
302 truncatedStart += interval;
305 start = truncatedStart;
310 while (value <= end) {
311 majorIntervals.push_back(value);
316 template<
class TReal>
317 void calculateIntermediateIntervals(TReal start, TReal end, TReal interval,
const std::vector<TReal> & majorIntervals, std::vector<TReal> & intervals,
float epsilon = FLT_EPSILON)
319 if (!majorIntervals.size())
return;
321 float value = majorIntervals[0] - interval;
323 while (value >= start) {
324 intervals.push_back(value);
328 for (
size_t i = 0; i < majorIntervals.size() - 1; ++i) {
329 value = majorIntervals[i] + interval;
331 while (value < majorIntervals[i + 1] - epsilon) {
332 intervals.push_back(value);
337 value = majorIntervals[majorIntervals.size() - 1] + interval;
339 while (value <= end) {
340 intervals.push_back(value);
347void Cogs::Core::DepthAxisSystem::getAnnotationTicks(DepthAxisComponent & component,
const TrajectoryComponent * trajectory, std::vector<float> & majorTicks, std::vector<float> & minorTicks)
349 const float scaledMajorInterval = component.majorInterval / component.unitScale;
350 const float scaledMinorInterval = component.minorInterval / component.unitScale;
352 const bool endpointsInclusive = component.endpointsInclusive;
353 const bool endpointsOnly =
false;
355 const float startDepth = std::max(component.startMeasuredDepth, trajectory->indexes[0]);
356 const float endDepth = std::min(component.endMeasuredDepth, trajectory->indexes[trajectory->indexes.size() - 1]);
358 if (endpointsInclusive && (fmod(startDepth, scaledMajorInterval) != 0 || endpointsOnly)) {
359 majorTicks.push_back(startDepth);
362 if (!endpointsOnly) {
363 Cogs::Calculation::calculateIntervals<float, true>(startDepth, endDepth, scaledMajorInterval, majorTicks);
366 if (endpointsInclusive) {
367 majorTicks.push_back(endDepth);
370 if (!endpointsOnly) {
371 Cogs::Calculation::calculateIntermediateIntervals(startDepth, endDepth, scaledMinorInterval, majorTicks, minorTicks, scaledMinorInterval / 2);
375void Cogs::Core::DepthAxisSystem::addText(DepthAxisComponent & component, std::string * texts,
const size_t count,
const float * depths)
377 const std::string & unit = component.unitOfMeasurement;
378 const float unitScale = component.unitScale;
380 for (
size_t i = 0; i < count; ++i) {
381 const float depth = depths[i] * unitScale;
382 const float remainder = depth - std::floor(depth + 0.5f);
384 std::stringstream ss;
386 if (fabs(remainder) > 0.01f) {
387 ss << std::fixed << std::setprecision(2) << depth << unit;
390 ss << std::fixed << std::setprecision(0) << depth << unit;
396void Cogs::Core::DepthAxisSystem::addTicks(DepthAxisComponent & component, std::vector<glm::vec3> & vertexes, std::vector<uint32_t> & indexes,
const std::vector<glm::vec3> & positions,
const std::vector<glm::vec3> & directions,
const glm::vec3 & axis,
const glm::vec3 & principalAxis,
const float extent,
const std::vector<float> & scales)
398 const size_t offset = vertexes.size();
400 vertexes.resize(offset + positions.size() * 2);
401 indexes.resize(positions.size() * 2);
403 float radius = component.radius;
404 bool useTrajectoryOrientedAxis = component.useTrajectoryOrientedAxis;
406 for (
size_t i = 0; i < positions.size(); ++i) {
409 glm::quat rotation = Cogs::Core::getRotation(principalAxis, directions[i]);
410 base = glm::normalize(rotation * axis);
412 glm::vec3 start = positions[i] + (base * radius);
414 float scale = extent;
420 vertexes[offset + i * 2] = start;
421 vertexes[offset + i * 2 + 1] = start + (useTrajectoryOrientedAxis ? base : axis) * 0.9f * scale;
426 for (
size_t i = 0; i < positions.size(); i++) {
427 indexes[idx++] =
static_cast<uint32_t
>(offset + i * 2);
428 indexes[idx++] =
static_cast<uint32_t
>(offset + i * 2 + 1);
432void Cogs::Core::DepthAxisSystem::addAnnotations(DepthAxisComponent & component, AnnotationAxisComponent * annotationAxis,
const std::vector<glm::vec3> & positions,
const std::vector<glm::vec3> & directions,
const std::vector<std::string> & texts,
const glm::vec3 & axis,
const glm::vec3 & principalAxis,
const float extent,
const std::vector<float> & scales,
bool removeDistantAnnotations )
434 const size_t numAnnotations = positions.size();
435 const size_t offset = annotationAxis->strings.size();
438 annotationAxis->strings.resize(offset + numAnnotations);
439 annotationAxis->positions.resize(offset + numAnnotations);
441 float radius = component.radius;
442 float scaleThreshold = component.minorScaleThreshold;
443 bool useTrajectoryOrientedAxis = component.useTrajectoryOrientedAxis;
445 size_t index = offset;
447 for (
size_t i = 0; i < numAnnotations; ++i) {
448 float distance = extent;
451 float scale = scales[i];
454 if (removeDistantAnnotations && scale > scaleThreshold) {
463 glm::quat rotation = Cogs::Core::getRotation(principalAxis, directions[i]);
464 base = rotation * axis;
466 glm::vec3 start = positions[i] + (base * radius);
468 annotationAxis->strings[index] = texts[i];
469 annotationAxis->positions[index++] = start + (useTrajectoryOrientedAxis ? base : axis) * distance;
473 annotationAxis->strings.resize(index);
474 annotationAxis->positions.resize(index);
476 annotationAxis->setChanged();
ComponentType * getComponent() const
Context * context
Pointer to the Context instance the system lives in.
void update()
Updates the system state to that of the current frame.
ComponentPool< ComponentType > pool
Pool of components managed by the system.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Contains a handle to a Mesh resource to use when rendering using the MeshRenderComponent.
MeshHandle meshHandle
Handle to a Mesh resource to use when rendering.
Renders a mesh with flexible submesh usage.
std::vector< MaterialInstanceHandle > materials
Materials used to render individual sub-meshes.
Renders the given text(s) by generating sprites.
std::vector< glm::vec3 > positions
Offset positions for each of the strings in texts.
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
@ Right
The rightmost character is placed to the left of the screen position.
@ Left
The leftmost character is placed to the right of the screen position.
Contains all Cogs related functionality.
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.
ResourceType * resolve() const
Resolve the handle, returning a pointer to the actual resource.
Data component defining a 3D trajectory, for example a Well trajectory.
std::vector< glm::vec3 > positions
Trajectory positions. For wells the Z component is a measurement of True Vertical Depth (TVD)....