Cogs.Core
PingOutlineComponent.cpp
1#include <sstream>
2#include "PingOutlineComponent.h"
3#include "Context.h"
4#include "EntityStore.h"
5#include "Types.h"
6
7#include "Components/Core/MeshComponent.h"
8#include "Components/Core/MeshRenderComponent.h"
9#include "Components/Core/TransformComponent.h"
10#include "Components/Core/TextComponent.h"
11#include "Components/Appearance/MaterialComponent.h"
12#include "../Extensions/AxisCube/Source/Components/AnnotationAxisComponent.h"
13
14#include "Resources/MeshManager.h"
15#include "Resources/MaterialManager.h"
16#include "Resources/DefaultMaterial.h"
17
18#include "DataSetComponent.h"
19#include "DataRefComponent.h"
20#include "BeamGroupComponent.h"
21#include "../Systems/DataSetSystem.h"
22#include "../BeamUtils.h"
23
24using glm::vec3;
25using glm::angleAxis;
26
27using namespace Cogs::Core;
28using namespace Cogs::Reflection;
29using namespace Cogs::Core;
30
31namespace {
32
33 void setVertexColorMaterial(Cogs::Core::Context* context, Cogs::Core::EntityPtr entity)
34 {
35 auto material = context->materialInstanceManager->createMaterialInstance(context->materialManager->getDefaultMaterial());
36 material->setPermutation("Line");
37 material->setVariant("LightModel", "BaseColor");
38 material->setVariant("EnableLighting", false);
39 material->setVariant("VertexColor", true);
40
41 auto matRndComp = entity->getComponent<MeshRenderComponent>();
42 matRndComp->material = material;
43 matRndComp->setRenderFlag(RenderFlags::CustomMaterial);
44 matRndComp->setChanged();
45 }
46
47 void setAnnotationLineMaterial(Cogs::Core::Context* context, Cogs::Core::EntityPtr entity)
48 {
49 auto material = context->materialInstanceManager->createMaterialInstance(context->materialManager->getDefaultMaterial());
50 material->setPermutation("Line");
51 material->setVariant("LightModel", "BaseColor");
52 material->setVariant("EnableLighting", false);
53 material->setVec4Property(DefaultMaterial::DiffuseColor, glm::vec4(0.8f, 0.8f, 0.8f, 1));
54 material->setFloatProperty(DefaultMaterial::LineWidth, 1.5f);
55 //material->setUIntProperty(material->material->getUIntKey("stipplePattern"), 0x0000000F);
56
57 auto matRndComp = entity->getComponent<MeshRenderComponent>();
58 matRndComp->material = material;
59 matRndComp->setRenderFlag(RenderFlags::CustomMaterial);
60 matRndComp->setChanged();
61 }
62
63 MeshHandle buildVesselSIMRADCoordsys(Context* context,
64 const glm::quat& vesselOrientation,
65 const glm::vec3& vesselPosition,
66 const float size)
67 {
68 glm::quat R;
69 glm::vec3 O;
70 EchoSounder::getArrayToVesselTransform(R, O,
71 glm::vec3(glm::radians(0.f), glm::radians(0.f), glm::radians(0.f)),
72 glm::vec3(0, 0, 0));
73
74 R = vesselOrientation * R;
75 O = vesselPosition + (vesselOrientation * O);
76
77 auto mesh = context->meshManager->create();
78 auto P = mesh->mapPositions(0, 6);
79 auto C = mesh->map<glm::vec4>(VertexDataType::Colors0, VertexFormats::Color4f, 0, 6);
80 P[0] = R*glm::vec3(0, 0, 0) + O; C[0] = glm::vec4(1, 0, 0, 1);
81 P[1] = R*glm::vec3(size, 0, 0) + O; C[1] = glm::vec4(1, 0, 0, 1);
82 P[2] = R*glm::vec3(0, 0, 0) + O; C[2] = glm::vec4(0, 1, 0, 1);
83 P[3] = R*glm::vec3(0, size, 0) + O; C[3] = glm::vec4(0, 1, 0, 1);
84 P[4] = R*glm::vec3(0, 0, 0) + O; C[4] = glm::vec4(0, 0, 1, 1);
85 P[5] = R*glm::vec3(0, 0, size) + O; C[5] = glm::vec4(0, 0, 1, 1);
86
87 mesh->primitiveType = Cogs::PrimitiveType::LineList;
88 mesh->setBounds(Cogs::Geometry::BoundingBox{ glm::vec3(0), glm::vec3(1) });
89
90 return mesh;
91 }
92
93 void getFrontBeams(std::vector<glm::vec3> & output, const std::vector<glm::vec3> & allDirs,
94 uint32_t minorCount, uint32_t majorCount, bool excludeEndPoints = false)
95 {
96 uint32_t eOffset = excludeEndPoints ? 1 : 0;
97 for (uint32_t i = eOffset; i < minorCount - eOffset; ++i) {
98 auto index = minorCount * (majorCount - 1) + i;
99 output.push_back(allDirs[index]);
100 }
101 }
102
103 void getRightBeams(std::vector<glm::vec3> & output, const std::vector<glm::vec3> & allDirs,
104 uint32_t minorCount, uint32_t majorCount, bool excludeEndPoints = false)
105 {
106 uint32_t eOffset = excludeEndPoints ? 1 : 0;
107 for (uint32_t i = eOffset; i < majorCount - eOffset; ++i) {
108 auto index = (majorCount - 1 - i) * minorCount + (minorCount - 1);
109 output.push_back(allDirs[index]);
110 }
111 }
112
113 void getBackBeams(std::vector<glm::vec3> & output, const std::vector<glm::vec3> & allDirs,
114 uint32_t minorCount, uint32_t /*majorCount*/, bool excludeEndPoints = false)
115 {
116 uint32_t eOffset = excludeEndPoints ? 1 : 0;
117 for (uint32_t i = eOffset; i < minorCount - eOffset; ++i) {
118 auto index = minorCount - 1 - i;
119 output.push_back(allDirs[index]);
120 }
121 }
122
123 void getLeftBeams(std::vector<glm::vec3> & output, const std::vector<glm::vec3> & allDirs,
124 uint32_t minorCount, uint32_t majorCount, bool excludeEndPoints = false) {
125 uint32_t eOffset = excludeEndPoints ? 1 : 0;
126 for (uint32_t i = eOffset; i < majorCount - eOffset; ++i) {
127 auto index = i * minorCount;
128 output.push_back(allDirs[index]);
129 }
130 }
131
132
133 std::vector<glm::vec3> getOuterAnnotationBeams(const std::vector<glm::vec3> &dirs,
134 uint32_t minorCount, uint32_t majorCount,
135 Cogs::Core::EchoSounder::AnnotationPosition annoPostion)
136 {
137 std::vector<glm::vec3> outerBeams;
138 if (annoPostion == Cogs::Core::EchoSounder::AnnotationPosition::Front) {
139 getRightBeams(outerBeams, dirs, minorCount, majorCount);
140 getBackBeams(outerBeams, dirs, minorCount, majorCount, true);
141 getLeftBeams(outerBeams, dirs, minorCount, majorCount);
142 }
143 if (annoPostion == Cogs::Core::EchoSounder::AnnotationPosition::Right) {
144 getBackBeams(outerBeams, dirs, minorCount, majorCount);
145 getLeftBeams(outerBeams, dirs, minorCount, majorCount, true);
146 getFrontBeams(outerBeams, dirs, minorCount, majorCount);
147 }
148 return outerBeams;
149 }
150
151 std::vector<glm::vec3> getFrontAnnotationBeams(const std::vector<glm::vec3> &dirs,
152 uint32_t minorCount, uint32_t majorCount,
153 Cogs::Core::EchoSounder::AnnotationPosition annoPostion)
154 {
155 std::vector<glm::vec3> frontDirection;
156 if (annoPostion == Cogs::Core::EchoSounder::AnnotationPosition::Front) {
157 getFrontBeams(frontDirection, dirs, minorCount, majorCount);
158 }
159 else if (annoPostion == Cogs::Core::EchoSounder::AnnotationPosition::Right) {
160 getRightBeams(frontDirection, dirs, minorCount, majorCount);
161 }
162 return frontDirection;
163 }
164}
165
166
167void EchoSounder::PingOutlineComponent::registerType()
168{
169 static constexpr EnumeratorDef annoTypeEnumerator[] = {
170 { "VerticalDepth", AnnotationType::VerticalDepth },
171 { "Range", AnnotationType::Range },
172 };
173 TypeDatabase::createType<AnnotationType>().setEnumerators(annoTypeEnumerator);
174
175 static constexpr EnumeratorDef connectedTicksEnumerator[]{
176 { "None", ConnectedTicksMode::None },
177 { "Fan", ConnectedTicksMode::Fan },
178 { "Grid", ConnectedTicksMode::Grid },
179 };
180 TypeDatabase::createType<ConnectedTicksMode>().setEnumerators(connectedTicksEnumerator);
181
182 static constexpr EnumeratorDef annotationPositionEnumerator[]{
183 { "Front", AnnotationPosition::Front },
184 { "Right", AnnotationPosition::Right },
185 };
186 TypeDatabase::createType<AnnotationPosition>().setEnumerators(annotationPositionEnumerator);
187
188 Field fields[] = {
189 Field(Name("flat"), &PingOutlineComponent::flat),
190 Field(Name("individualBeams"), &PingOutlineComponent::individualBeams),
191 Field(Name("annotationType"), &PingOutlineComponent::annotationType),
192 Field(Name("connectedTicks"), &PingOutlineComponent::connectedTicks),
193 Field(Name("annotationPosition"), &PingOutlineComponent::annotationPosition),
194 Field(Name("showVesselCoordsys"), &PingOutlineComponent::showVesselCoordsys),
195 Field(Name("showBoundingFrustum"), &PingOutlineComponent::showBoundingFrustum),
196 Field(Name("showAABB"), &PingOutlineComponent::showAABB),
197 Field(Name("numTickMarks"), &PingOutlineComponent::numTickMarks),
198 Field(Name("tickLength"), &PingOutlineComponent::tickLength),
199 Field(Name("unit"), &PingOutlineComponent::unit),
200 Field(Name("widthScaleAlongship"), &PingOutlineComponent::widthScaleAlongship),
201 Field(Name("widthScaleAthwartship"), &PingOutlineComponent::widthScaleAthwartship),
202 Field(Name("depthStart"), &PingOutlineComponent::depthStart),
203 Field(Name("depthRange"), &PingOutlineComponent::depthRange),
204 Field(Name("textColor"), &PingOutlineComponent::textColor)
205 };
206 Method methods[] = {
207 Method(Name("initialize"), &PingOutlineComponent::initialize),
208 Method(Name("update"), &PingOutlineComponent::update),
209 };
210 DynamicComponent::registerDerivedType<PingOutlineComponent>()
211 .setFields(fields)
212 .setMethods(methods);
213}
214
215void EchoSounder::PingOutlineComponent::initialize(Context * context)
216{
217 this->context = context;
218 this->dataSystem = ExtensionRegistry::getExtensionSystem<DataSetSystem>(context);
219
220 annotation[0] = context->store->createChildEntity("EchoConfigAnnotation", getContainer(), "Annotation0");
221 annotation[1] = context->store->createChildEntity("EchoConfigAnnotation", getContainer(), "Annotation1");
222
223 vesselCoordSys = context->store->createChildEntity("MeshPart", getContainer(), "CoordSys");
224 setVertexColorMaterial(context, vesselCoordSys);
225
226 boundingFrustum = context->store->createChildEntity("MeshPart", getContainer(), "Frustum");
227 setVertexColorMaterial(context, boundingFrustum);
228
229 axisAlignedBBox = context->store->createChildEntity("MeshPart", getContainer(), "AABB");
230 setVertexColorMaterial(context, axisAlignedBBox);
231
232 annoLineMesh = context->store->createChildEntity("MeshPart", getContainer(), "Annotation mesh");
233 setAnnotationLineMaterial(context, annoLineMesh);
234}
235
236void EchoSounder::PingOutlineComponent::update()
237{
238 if (!this->dataSystem) return;
239
240 auto dataRefComp = getComponent<DataRefComponent>();
241 if (dataRefComp->data) {
242 auto * dataComp = dataRefComp->data->getComponent<DataSetComponent>();
243 auto & dataData = dataSystem->getData(dataComp);
244 auto * groupComp = this->getComponent<BeamGroupComponent>();
245 const auto & config = dataData.persistent->config;
246
247 if ((hasChanged() || groupComp->hasChanged() || (configGen != dataData.configGen) || dataRefComp->hasChanged()) && (0 < config.beamCount))
248 {
249 configGen = dataData.configGen;
250
251 auto depthMin = config.depthOffset;
252 if (std::isfinite(depthStart)) {
253 depthMin = std::max(depthMin, depthStart);
254 }
255 auto depthMax = config.depthOffset + config.sampleCount * config.depthStep;
256 if (std::isfinite(depthRange)) {
257 depthMax = std::min(depthMax, depthMin + depthRange);
258 }
259
260 MeshHandle mesh;
261 if (groupComp->sane) {
262 std::vector<glm::vec3> V;
263 std::vector<uint32_t> indices;
264
265 std::vector<float> directionX(groupComp->beams.size());
266 std::vector<float> directionY(groupComp->beams.size());
267 for (size_t i = 0; i < groupComp->beams.size(); i++) {
268 const auto srcIx = groupComp->beams[i];
269 directionX[i] = config.directionX[srcIx];
270 directionY[i] = config.directionY[srcIx];
271 }
272
273 auto beamMinorClosed = groupComp->minorClosed;
274 auto minorCount = groupComp->minorCount;
275 auto majorCount = groupComp->majorCount;
276
277 const auto srcMinNum = groupComp->minorCount;
278 unsigned srcMinNumPadded = srcMinNum + (beamMinorClosed ? 1u : 0u);
279
280 std::vector<uint32_t> beams(srcMinNumPadded);
281 for (unsigned i = 0; i < srcMinNum; i++) {
282 beams[i] = groupComp->beams[i];
283 }
284 if (beamMinorClosed) {
285 beams[srcMinNum] = beams[0];
286 }
287
288 if (!flat) {
289 inflateFans(directionX, directionY,
290 config.directionX, config.beamWidthX,
291 config.directionY, config.beamWidthY,
292 beams, groupComp->topology, srcMinNumPadded);
293
294 //after inflation, we know we have at least 2 beams in each direction.
295 minorCount = std::max(2u, srcMinNumPadded);
296 majorCount = std::max(2u, majorCount);
297
298 glm::quat rotation;
299 glm::vec3 translation;
300 getArrayToVesselTransform(rotation, translation, config.transducerAlpha, config.transducerOffset);
301 buildBeamBundleOutline2(V, indices, context,
302 rotation, translation,
303 config.coordSys,
304 directionX.data(), majorCount,
305 directionY.data(), minorCount,
306 depthMin, depthMax, false, individualBeams);
307
308 for (uint32_t k = 0; k < 2; k++) {
309 auto annoComp = annotation[k]->getComponent<AnnotationAxisComponent>();
310 annoComp->strings.clear();
311 annoComp->positions.clear();
312 annoComp->setChanged();
313 }
314 }
315 else if (groupComp->majorCount == 1) {
316
317 if (groupComp->minorCount == 1) {
318 //we only have one beam, it's given a width in the data visualization, so draw lines around the extent of the data
319 createBeamExtentGeometry(V, indices, context, directionX, directionY,
320 groupComp->minorCount, config);
321 }
322 else {
323 //when we have multiple beams, data is only visualized between beams. So we draw line through center of beams.
324 createBeamCenterGeometry(V, indices, context, directionX, directionY,
325 individualBeams, groupComp->minorCount, config);
326 }
327
328 }
329
330 createTickGeometryAndAnnotations(context, directionX, directionY, minorCount, majorCount, false, config);
331
332 if (!indices.empty()) {
333 mesh = context->meshManager->create();
334 mesh->setPositions(V);
335 mesh->setIndexes(indices);
336 mesh->primitiveType = Cogs::PrimitiveType::LineList;
337 mesh->setBounds(calculateBounds(mesh.operator->()));
338 }
339 }
340
341 auto * meshComp = getComponent<MeshComponent>();
342 meshComp->meshHandle = mesh;
343 meshComp->setChanged();
344
345 {
346 float xMin = std::numeric_limits<float>::max();
347 float xMax = -std::numeric_limits<float>::max();
348 float yMin = std::numeric_limits<float>::max();
349 float yMax = -std::numeric_limits<float>::max();
350
351 for (auto b : groupComp->beams) {
352 xMin = std::min(xMin, config.directionX[b]);
353 xMax = std::max(xMax, config.directionX[b]);
354 yMin = std::min(yMin, config.directionY[b]);
355 yMax = std::max(yMax, config.directionY[b]);
356 }
357
358 glm::quat arrayOrientationVessel;
359 glm::vec3 arrayPositionVessel;
360 getArrayToVesselTransform(arrayOrientationVessel,
361 arrayPositionVessel,
362 config.transducerAlpha,
363 config.transducerOffset);
364
365 // --- Vessel coordsystem ----------------------------------------------
366 {
367 auto * coordsys_meshComp = vesselCoordSys->getComponent<MeshComponent>();
368 coordsys_meshComp->meshHandle = showVesselCoordsys
369 ? buildVesselSIMRADCoordsys(context,
370 glm::quat(),
371 glm::vec3(),
372 100.f)
373 : MeshHandle::NoHandle;
374 coordsys_meshComp->setChanged();
375 }
376
377 // --- Beam bounding frustum -------------------------------------------
378 {
379 auto * beam_meshComp = boundingFrustum->getComponent<MeshComponent>();
380 if (showBoundingFrustum) {
381 glm::vec4 frustum[6];
382 getBoundingFrustum(frustum,
383 arrayOrientationVessel,
384 arrayPositionVessel,
385 config.coordSys,
386 xMin, xMax, yMin, yMax, depthMin, depthMax);
387 beam_meshComp->meshHandle = buildFrustumOutline(context, frustum);
388 }
389 else {
390 beam_meshComp->meshHandle = MeshHandle::NoHandle;
391 }
392
393 beam_meshComp->setChanged();
394 }
395 // --- Beam bounding box -----------------------------------------------
396 {
397 auto * bbox_meshComp = axisAlignedBBox->getComponent<MeshComponent>();
398 if (showAABB) {
399 glm::vec3 bbmin, bbmax;
400 getAxisAlignedBoundingBox(bbmin, bbmax,
401 arrayOrientationVessel,
402 arrayPositionVessel,
403 config.coordSys,
404 xMin, xMax, yMin, yMax, depthMin, depthMax);
405 if (std::isfinite(verticalDepthMax)) {
406 bbmin.z = std::max(bbmin.z, -verticalDepthMax);
407 bbmax.z = std::max(bbmax.z, -verticalDepthMax);
408 }
409 bbox_meshComp->meshHandle = buildBoxOutline(context, bbmin, bbmax);
410 }
411 else {
412 bbox_meshComp->meshHandle = MeshHandle::NoHandle;
413 }
414 bbox_meshComp->setChanged();
415 }
416 }
417 }
418 }
419 else {
420 if (dataRefComp->hasChanged()) {
421 auto * meshComp = getComponent<MeshComponent>();
422 meshComp->meshHandle = MeshHandle::NoHandle;
423 meshComp->setChanged();
424 }
425 }
426}
427
428void EchoSounder::PingOutlineComponent::createTickGeometryAndAnnotations(Context* context,
429 const std::vector<float>& directionX,
430 const std::vector<float>& directionY,
431 uint32_t minorCount, uint32_t majorCount,
432 bool /*minorClosed*/,
433 const Config& config)
434{
435 uint32_t beamCount = minorCount * majorCount;
436 if (beamCount < 1) return;
437
438 std::vector<glm::vec3> V;
439 std::vector<uint32_t> indices;
440
441 glm::quat rotation;
442 glm::vec3 translation;
443 getArrayToVesselTransform(rotation, translation, config.transducerAlpha, config.transducerOffset);
444
445 std::vector<glm::vec3> dirs;
446
447 if (beamCount == 1) {
448 //if we only have one beam we draw it with an extent (see createBeamExtentGrid), so we need to create similar extent here
449 dirs.resize(2);
450 bool xDom = isXDominant(directionX, directionY); //even if we have just one beam, we use this function to get consistent behaviour for multiple places in code.
451 dirs[0] = rotation *getBeamDir(config.coordSys,
452 directionX[0] - (xDom ? 0.5f : 0.f)*widthScaleAlongship*config.beamWidthX[0],
453 directionY[0] - (xDom ? 0.f : 0.5f)*widthScaleAthwartship*config.beamWidthY[0]);
454 dirs[1] = rotation * getBeamDir(config.coordSys,
455 directionX[0] + (xDom ? 0.5f : 0.f)*widthScaleAlongship*config.beamWidthX[0],
456 directionY[0] + (xDom ? 0.f : 0.5f)*widthScaleAthwartship*config.beamWidthY[0]);
457 minorCount = 2;
458 }
459 else {
460 dirs.resize(beamCount);
461 for (unsigned i = 0; i < beamCount; i++) {
462 dirs[i] = rotation * getBeamDir(config.coordSys, directionX[i], directionY[i]);
463 }
464 }
465
466 float minDistance = std::isfinite(depthStart) ? depthStart : config.depthOffset;
467 float maxDistance = minDistance + (std::isfinite(depthRange) ? depthRange : config.sampleCount*config.depthStep);
468
469 float minDepth = 0.f;
470 float maxDepth = 0.f;
471 switch (annotationType) {
472 case AnnotationType::VerticalDepth :
473 {
474 minDepth = 1e-5f * maxDistance;
475 maxDepth = 1e-5f * maxDistance;
476 for (auto & d : dirs) {
477 minDepth = glm::max(minDepth, -(translation.z + minDistance * d.z));
478 maxDepth = glm::max(maxDepth, -(translation.z + maxDistance * d.z));
479 }
480 break;
481 }
482 case AnnotationType::Range :
483 {
484 minDepth = minDistance;
485 maxDepth = maxDistance;
486 break;
487 }
488 default:
489 assert(false && "Uknown annotation type.");
490 return;
491 }
492
493 auto v = std::max(1.f, (maxDepth - minDepth) / numTickMarks);
494 auto s = std::log10(v);
495 auto m = std::ceil(s);
496 auto q = std::round(std::log2(10.f)*(s - m));
497 auto depthStep = std::exp2(q)*std::pow(10.f, m);
498 auto tickA = static_cast<size_t>(std::ceil(minDepth / depthStep));
499 auto tickB = std::min(tickA + 1000u, static_cast<size_t>(std::floor(maxDepth / depthStep)));
500
501 if (minorCount == 1 || majorCount == 1) {
502 addAnnotations(V, indices, tickA, tickB, depthStep, dirs, translation, maxDistance, true, connectedTicks != ConnectedTicksMode::None);
503 }
504 else {
505 if (connectedTicks == ConnectedTicksMode::Grid) {
506 //we have a grid. Pick outer beams to draw connection lines, and then front beams to draw connection lines with annotation ticks and values
507 std::vector<glm::vec3> outerDirection = getOuterAnnotationBeams(dirs, minorCount, majorCount, annotationPosition);
508 addAnnotations(V, indices, tickA, tickB, depthStep, outerDirection, translation, maxDistance, false, true);
509 }
510
511 std::vector<glm::vec3> frontDirection = getFrontAnnotationBeams(dirs, minorCount, majorCount, annotationPosition);
512 addAnnotations(V, indices, tickA, tickB, depthStep, frontDirection, translation, maxDistance, true, connectedTicks != ConnectedTicksMode::None);
513 }
514
515
516 MeshHandle mesh;
517 auto * annoMeshComp = annoLineMesh->getComponent<MeshComponent>();
518
519 if (!indices.empty()) {
520 mesh = context->meshManager->create();
521 mesh->setPositions(V);
522 mesh->setIndexes(indices);
523 mesh->primitiveType = Cogs::PrimitiveType::LineList;
524 mesh->setBounds(calculateBounds(mesh.operator->()));
525 }
526
527 annoMeshComp->meshHandle = mesh;
528 annoMeshComp->setChanged();
529
530}
531
532void EchoSounder::PingOutlineComponent::addAnnotations(std::vector<glm::vec3> &V,
533 std::vector<uint32_t> &indices,
534 size_t tickA, size_t tickB, float depthStep,
535 const std::vector<glm::vec3> &dirs,
536 const glm::vec3 & translation,
537 float maxDistance, bool showTicks, bool connectTicks)
538{
539 AnnotationAxisComponent* annoComp[2];
540 auto tickDir = dirs.back() - dirs.front();
541 assert(dirs.size() > 1 && tickDir != glm::vec3(0, 0, 0));
542 tickDir = tickLength * depthStep*glm::normalize(tickDir);
543
544 for (size_t k = 0; k < 2; k++) {
545 annoComp[k] = annotation[k]->getComponent<AnnotationAxisComponent>();
546 annoComp[k]->viewDependentAnchor = true;
547 annoComp[k]->viewDependentAnchorReference = (k != 0 ? -1.f : 1.f)*tickDir;
548 annoComp[k]->strings.clear();
549 annoComp[k]->positions.clear();
550 annoComp[k]->setChanged();
551 }
552
553 for (size_t t = tickA; t <= tickB; t++) {
554 auto offset = static_cast<uint32_t>(V.size());
555
556 float d = -(t*depthStep);
557
558 unsigned numCreatedVertices = 0;
559
560 bool first = true;
561 bool qInside = false;
562 glm::vec3 q;
563 for (unsigned i = 0; i < dirs.size(); i++) {
564 //find corresponding point for beam which has the desired depth. For vertical depths, this point may be between beams.
565 switch (annotationType) {
566 case AnnotationType::VerticalDepth:
567 {
568 // Almost horizontal line, skip.
569 if (std::abs(dirs[i].z) < 1e-5) continue;
570
571 // Intersection of ray and z=depth plane
572 auto tt = d / dirs[i].z;
573 auto p = tt * dirs[i];
574
575 // skip lines where intersection is found traversing the beam backwards
576 if (tt < 0) continue;
577
578 // Check if point is further away than maxDistance.
579 bool pInside = tt < maxDistance;
580 if ((first == false) && (pInside != qInside)) {
581
582 // One point too far away and one closer than maxDistance.
583 // We insert the intersection between the line segment [p,q] and a sphere of radius maxDistance,
584 //
585 // <p + t(q-p), p + t(q-p)> = lengthB^2
586 // <p,p> + 2<p,q-p>t + <q-p,q-p>t^2 = lengthB^2
587 // A t^2 + B t + C = 0,
588 //
589 // where A = <p,p>, B=2<p,q-p>, and C=<p,p>-lengthB^2.
590 //
591 // We solve it with the quadratic formula and pick the first solution in [0,1].
592 auto ttt = 0.5f;
593 auto pq = q - p;
594 auto a = glm::dot(pq, pq);
595 if (1e-5*maxDistance <= a) {
596 auto b = 2.f*glm::dot(p, pq);
597 auto c = glm::dot(p, p) - maxDistance * maxDistance;
598 auto t0 = (-b + glm::sqrt(b*b - 4 * a * c)) / (2 * a);
599 auto t1 = (-b - glm::sqrt(b*b - 4 * a * c)) / (2 * a);
600 if (0.f <= t0 && t0 <= 1.f) {
601 ttt = t0;
602 }
603 else if (0.f <= t1 && t1 <= 1.f) {
604 ttt = t1;
605 }
606 }
607 V.push_back(translation + (1.f - ttt)*p + ttt * q); numCreatedVertices++;
608 }
609 if (pInside) {
610 V.push_back(translation + p); numCreatedVertices++;
611 }
612
613 q = p;
614 qInside = pInside;
615 first = false;
616 break;
617 }
618 case AnnotationType::Range:
619 {
620 if (d == 0) continue;
621 V.push_back(translation - (dirs[i] * d)); numCreatedVertices++;
622 break;
623 }
624 default: {
625 assert(false && "Uknown annotation type");
626 }
627 }
628 }
629
630 if (connectTicks) {
631 for (unsigned i = 0; i + 1 < numCreatedVertices; i++) {
632 indices.push_back(offset + i);
633 indices.push_back(offset + i + 1);
634 }
635 }
636
637 if (showTicks) {
638 std::stringstream sstream;
639 // Add tick marks and annotations
640 if (numCreatedVertices >= 2) {
641 sstream.str("");
642 sstream << -d << unit; //coordinate system has negative z as downwards, but we want to show positive values to user
643 annoComp[0]->strings.push_back(sstream.str());
644 annoComp[1]->strings.push_back(sstream.str());
645
646 V.push_back(V[offset] - tickDir);
647 indices.push_back(offset);
648 indices.push_back(offset + numCreatedVertices);
649 annoComp[0]->positions.push_back(V[offset] - 2.f*tickDir);
650
651 V.push_back(V[offset + numCreatedVertices - 1] + tickDir);
652 indices.push_back(offset + numCreatedVertices - 1);
653 indices.push_back(offset + numCreatedVertices + 1);
654 annoComp[1]->positions.push_back(V[offset + numCreatedVertices - 1] + 2.f*tickDir);
655 }
656 }
657 }
658}
659
660
661void EchoSounder::PingOutlineComponent::createBeamCenterGeometry(std::vector<glm::vec3>& V,
662 std::vector<uint32_t>& indices,
663 Context* /*context*/,
664 const std::vector<float>& directionX,
665 const std::vector<float>& directionY,
666 bool individualBeams,
667 const uint32_t bN,
668 const Config& config)
669{
670 if (bN < 1) return;
671
672 glm::quat rotation;
673 glm::vec3 translation;
674 getArrayToVesselTransform(rotation, translation, config.transducerAlpha, config.transducerOffset);
675
676 auto l0 = std::isfinite(depthStart) ? depthStart : config.depthOffset;
677 auto l1 = l0 + (std::isfinite(depthRange) ? depthRange : config.sampleCount * config.depthStep);
678
679 uint32_t offset = static_cast<uint32_t>(V.size());
680 for (uint32_t b = 0; b < bN; b++) {
681 auto d = rotation *getBeamDir(config.coordSys, directionX[b], directionY[b]);
682 V.push_back(translation + l0*d);
683 V.push_back(translation + l1*d);
684 }
685
686 for (uint32_t i = 0; i + 1 < bN; i++) {
687 indices.push_back(offset + 2 * i + 0); // Upper arc
688 indices.push_back(offset + 2 * (i + 1) + 0);
689 indices.push_back(offset + 2 * i + 1); // Lower arc
690 indices.push_back(offset + 2 * (i + 1) + 1);
691 }
692
693 //outer beams:
694 indices.push_back(offset + 0);
695 indices.push_back(offset + 1);
696 indices.push_back(offset + 2 * (bN - 1) + 0);
697 indices.push_back(offset + 2 * (bN - 1) + 1);
698
699 if (individualBeams) { //inner beams
700 for (uint32_t i = 1; i < bN - 1; ++i) {
701 indices.push_back(offset + (2 * i));
702 indices.push_back(offset + (2 * i) + 1);
703 }
704 }
705
706
707}
708
709void EchoSounder::PingOutlineComponent::createBeamExtentGeometry(std::vector<glm::vec3>& V,
710 std::vector<uint32_t>& indices,
711 Context* /*context*/,
712 const std::vector<float>& directionX,
713 const std::vector<float>& directionY,
714 const uint32_t bN,
715 const Config& config)
716{
717 if (bN < 1) return;
718
719 glm::quat rotation;
720 glm::vec3 translation;
721 getArrayToVesselTransform(rotation, translation, config.transducerAlpha, config.transducerOffset);
722
723 bool xDom = isXDominant(directionX, directionY);
724
725
726 for (uint32_t b = 0; b < bN; b++) {
727 uint32_t offset = static_cast<uint32_t>(V.size());
728
729 auto d00 = rotation * getBeamDir(config.coordSys,
730 directionX[b] - (xDom ? 0.5f : 0.f)*widthScaleAlongship*config.beamWidthX[b],
731 directionY[b] - (xDom ? 0.f : 0.5f)*widthScaleAthwartship*config.beamWidthY[b]);
732 auto d01 = rotation * getBeamDir(config.coordSys,
733 directionX[b] + (xDom ? 0.5f : 0.f)*widthScaleAlongship*config.beamWidthX[b],
734 directionY[b] + (xDom ? 0.f : 0.5f)*widthScaleAthwartship*config.beamWidthY[b]);
735
736 auto l0 = std::isfinite(depthStart) ? depthStart : config.depthOffset;
737 auto l1 = l0 + (std::isfinite(depthRange) ? depthRange : config.sampleCount * config.depthStep);
738
739 V.push_back(translation + l0*d00);
740 V.push_back(translation + l1*d00);
741 V.push_back(translation + l0*d01);
742 V.push_back(translation + l1*d01);
743
744 indices.push_back(offset + 0);
745 indices.push_back(offset + 1);
746
747 indices.push_back(offset + 1);
748 indices.push_back(offset + 3);
749
750 indices.push_back(offset + 3);
751 indices.push_back(offset + 2);
752
753 indices.push_back(offset + 2);
754 indices.push_back(offset + 0);
755 }
756}
757
void setChanged()
Sets the component to the ComponentFlags::Changed state with carry.
Definition: Component.h:202
ComponentType * getComponent() const
Definition: Component.h:159
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
class EntityStore * store
Entity store.
Definition: Context.h:231
EntityPtr createChildEntity(const StringView &type, ComponentModel::Entity *parent, const StringView &name=StringView())
Create a new Entity, parenting it to the given parent.
Contains a handle to a Mesh resource to use when rendering using the MeshRenderComponent.
Definition: MeshComponent.h:15
MeshHandle meshHandle
Handle to a Mesh resource to use when rendering.
Definition: MeshComponent.h:29
Renders the contents of a MeshComponent using the given materials.
MaterialInstanceHandle material
Material used to render the mesh.
Field definition describing a single data member of a data structure.
Definition: Field.h:68
Simple method definition.
Definition: Method.h:72
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
std::shared_ptr< ComponentModel::Entity > EntityPtr
Smart pointer for Entity access.
Definition: EntityPtr.h:12
Cogs::Geometry::BoundingBox COGSCORE_DLL_API calculateBounds(Mesh *mesh)
Calculate a bounding box for the given mesh.
Definition: MeshHelper.cpp:283
Contains reflection support.
Definition: Component.h:11
void setIndexes(std::span< const uint32_t > collection)
Set the index data to the collection given.
Definition: Mesh.h:596
void setBounds(Geometry::BoundingBox box)
Set custom bounds for the mesh.
Definition: Mesh.h:298
void setPositions(std::span< const glm::vec3 > positions)
Set the position data of the Mesh.
Definition: Mesh.h:315
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.
@ LineList
List of lines.
Definition: Common.h:120
Represents an unique name.
Definition: Name.h:70