Skip to content

Commit 2172eb2

Browse files
committed
Move new functions to own file
1 parent 9c8361d commit 2172eb2

File tree

4 files changed

+142
-101
lines changed

4 files changed

+142
-101
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ find_package(ManiVault COMPONENTS Core PointData ClusterData ColorData ImageData
4040
set(PLUGIN
4141
src/ScatterplotPlugin.h
4242
src/ScatterplotPlugin.cpp
43+
src/MappingUtils.h
44+
src/MappingUtils.cpp
4345
)
4446

4547
set(UI

src/MappingUtils.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#include "MappingUtils.h"
2+
3+
#include <Dataset.h>
4+
#include <LinkedData.h>
5+
#include <PointData/PointData.h>
6+
#include <Set.h>
7+
8+
#include <algorithm>
9+
#include <cstdint>
10+
#include <functional>
11+
#include <map>
12+
#include <optional>
13+
#include <ranges>
14+
#include <vector>
15+
16+
bool parentHasSameNumPoints(const mv::Dataset<mv::DatasetImpl> data, const mv::Dataset<Points>& other) {
17+
if (data->isDerivedData()) {
18+
const auto parent = data->getParent();
19+
if (parent->getDataType() == PointType) {
20+
const auto parentPoints = mv::Dataset<Points>(parent);
21+
return parentPoints->getNumPoints() == other->getNumPoints();
22+
}
23+
}
24+
return false;
25+
}
26+
27+
using CheckFunc = std::function<bool(const mv::LinkedData& linkedData, const mv::Dataset<Points>& target)>;
28+
29+
std::optional<const mv::LinkedData*> getSelectionMapping(const mv::Dataset<Points>& source, const mv::Dataset<Points>& target, CheckFunc checkMapping) {
30+
const std::vector<mv::LinkedData>& linkedDatas = source->getLinkedData();
31+
32+
if (linkedDatas.empty())
33+
return std::nullopt;
34+
35+
// find linked data between source and target OR source and target's parent, if target is derived and they have the same number of points
36+
const auto it = std::ranges::find_if(linkedDatas, [&target, &checkMapping](const mv::LinkedData& linkedData) -> bool {
37+
return checkMapping(linkedData, target);
38+
});
39+
40+
if (it != linkedDatas.end()) {
41+
return &(*it); // return pointer to the found object
42+
}
43+
44+
return std::nullopt; // nothing found
45+
}
46+
47+
std::optional<const mv::LinkedData*> getSelectionMappingColorsToPositions(const mv::Dataset<Points>& colors, const mv::Dataset<Points>& positions) {
48+
auto testTargetAndParent = [](const mv::LinkedData& linkedData, const mv::Dataset<Points>& positions) -> bool {
49+
const mv::Dataset<mv::DatasetImpl> mapTargetData = linkedData.getTargetDataset();
50+
return mapTargetData == positions || parentHasSameNumPoints(mapTargetData, positions);
51+
};
52+
53+
return getSelectionMapping(colors, positions, testTargetAndParent);
54+
}
55+
56+
std::optional<const mv::LinkedData*> getSelectionMappingPositionsToColors(const mv::Dataset<Points>& positions, const mv::Dataset<Points>& colors) {
57+
auto testTarget = [](const mv::LinkedData& linkedData, const mv::Dataset<Points>& colors) -> bool {
58+
return linkedData.getTargetDataset() == colors;
59+
};
60+
61+
auto mapping = getSelectionMapping(positions, colors, testTarget);
62+
63+
if (!mapping.has_value() && parentHasSameNumPoints(positions, positions)) {
64+
const auto positionsParent = positions->getParent<Points>();
65+
mapping = getSelectionMapping(positionsParent, colors, testTarget);
66+
}
67+
68+
return mapping;
69+
}
70+
71+
bool checkSurjectiveMapping(const mv::LinkedData& linkedData, const std::uint32_t numPointsInTarget) {
72+
const std::map<std::uint32_t, std::vector<std::uint32_t>>& linkedMap = linkedData.getMapping().getMap();
73+
74+
std::vector<bool> found(numPointsInTarget, false);
75+
std::uint32_t count = 0;
76+
77+
for (const auto& [key, vec] : linkedMap) {
78+
for (std::uint32_t val : vec) {
79+
if (val >= numPointsInTarget) continue; // Skip values that are too large
80+
81+
if (!found[val]) {
82+
found[val] = true;
83+
if (++count == numPointsInTarget)
84+
return true;
85+
}
86+
}
87+
}
88+
89+
return false; // The previous loop would have returned early if the entire taget set was covered
90+
}
91+
92+
bool checkSelectionMapping(const mv::Dataset<Points>& colors, const mv::Dataset<Points>& positions) {
93+
94+
// Check if there is a mapping
95+
auto mapping = getSelectionMappingColorsToPositions(colors, positions);
96+
auto numTargetPoints = positions->getNumPoints();
97+
98+
if (!mapping.has_value() || mapping.value() == nullptr) {
99+
100+
mapping = getSelectionMappingPositionsToColors(positions, colors);
101+
numTargetPoints = colors->getNumPoints();
102+
103+
if (!mapping.has_value() || mapping.value() == nullptr)
104+
return false;
105+
}
106+
107+
const bool mappingCoversData = checkSurjectiveMapping(*(mapping.value()), numTargetPoints);
108+
109+
return mappingCoversData;
110+
}

src/MappingUtils.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#pragma once
2+
3+
#include <Dataset.h>
4+
#include <LinkedData.h>
5+
#include <PointData/PointData.h>
6+
#include <Set.h>
7+
8+
#include <cstdint>
9+
#include <functional>
10+
#include <optional>
11+
12+
// This only checks the immedeate parent and is deliberately not recursive
13+
// We might consider the latter in the future, but might need to cover edge cases
14+
bool parentHasSameNumPoints(const mv::Dataset<mv::DatasetImpl> data, const mv::Dataset<Points>& other);
15+
16+
using CheckFunc = std::function<bool(const mv::LinkedData& linkedData, const mv::Dataset<Points>& target)>;
17+
18+
std::optional<const mv::LinkedData*> getSelectionMapping(const mv::Dataset<Points>& source, const mv::Dataset<Points>& target, CheckFunc checkMapping);
19+
20+
std::optional<const mv::LinkedData*> getSelectionMappingColorsToPositions(const mv::Dataset<Points>& colors, const mv::Dataset<Points>& positions);
21+
22+
std::optional<const mv::LinkedData*> getSelectionMappingPositionsToColors(const mv::Dataset<Points>& positions, const mv::Dataset<Points>& colors);
23+
24+
// Check if the mapping is surjective, i.e. hits all elements in the target
25+
bool checkSurjectiveMapping(const mv::LinkedData& linkedData, const std::uint32_t numPointsInTarget);
26+
27+
// returns whether there is a selection map from colors to positions or positions to colors (or respective parents)
28+
// checks whether the mapping covers all elements in the target
29+
bool checkSelectionMapping(const mv::Dataset<Points>& colors, const mv::Dataset<Points>& positions);

src/ScatterplotPlugin.cpp

Lines changed: 1 addition & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "ScatterplotPlugin.h"
22

3+
#include "MappingUtils.h"
34
#include "ScatterplotWidget.h"
45

56
#include <Application.h>
@@ -46,107 +47,6 @@ Q_PLUGIN_METADATA(IID "studio.manivault.ScatterplotPlugin")
4647
using namespace mv;
4748
using namespace mv::util;
4849

49-
// This only checks the immedeate parent and is deliberately not recursive
50-
// We might consider the latter in the future, but might need to cover edge cases
51-
static bool parentHasSameNumPoints(const mv::Dataset<DatasetImpl> data, const mv::Dataset<Points>& other) {
52-
if (data->isDerivedData()) {
53-
const auto parent = data->getParent();
54-
if (parent->getDataType() == PointType) {
55-
const auto parentPoints = mv::Dataset<Points>(parent);
56-
return parentPoints->getNumPoints() == other->getNumPoints();
57-
}
58-
}
59-
return false;
60-
}
61-
62-
using CheckFunc = std::function<bool(const mv::LinkedData& linkedData, const mv::Dataset<Points>& target)>;
63-
64-
static std::optional<const mv::LinkedData*> getSelectionMapping(const mv::Dataset<Points>& source, const mv::Dataset<Points>& target, CheckFunc checkMapping) {
65-
const std::vector<mv::LinkedData>& linkedDatas = source->getLinkedData();
66-
67-
if (linkedDatas.empty())
68-
return std::nullopt;
69-
70-
// find linked data between source and target OR source and target's parent, if target is derived and they have the same number of points
71-
const auto it = std::ranges::find_if(linkedDatas, [&target, &checkMapping](const mv::LinkedData& linkedData) -> bool {
72-
return checkMapping(linkedData, target);
73-
});
74-
75-
if (it != linkedDatas.end()) {
76-
return &(*it); // return pointer to the found object
77-
}
78-
79-
return std::nullopt; // nothing found
80-
}
81-
82-
static std::optional<const mv::LinkedData*> getSelectionMappingColorsToPositions(const mv::Dataset<Points>& colors, const mv::Dataset<Points>& positions) {
83-
auto testTargetAndParent = [](const mv::LinkedData& linkedData, const mv::Dataset<Points>& positions) -> bool {
84-
const Dataset<DatasetImpl> mapTargetData = linkedData.getTargetDataset();
85-
return mapTargetData == positions || parentHasSameNumPoints(mapTargetData, positions);
86-
};
87-
88-
return getSelectionMapping(colors, positions, testTargetAndParent);
89-
}
90-
91-
static std::optional<const mv::LinkedData*> getSelectionMappingPositionsToColors(const mv::Dataset<Points>& positions, const mv::Dataset<Points>& colors) {
92-
auto testTarget = [](const mv::LinkedData& linkedData, const mv::Dataset<Points>& colors) -> bool {
93-
return linkedData.getTargetDataset() == colors;
94-
};
95-
96-
auto mapping = getSelectionMapping(positions, colors, testTarget);
97-
98-
if (!mapping.has_value() && parentHasSameNumPoints(positions, positions)) {
99-
const auto positionsParent = positions->getParent<Points>();
100-
mapping = getSelectionMapping(positionsParent, colors, testTarget);
101-
}
102-
103-
return mapping;
104-
}
105-
106-
// Check if the mapping is surjective, i.e. hits all elements in the target
107-
static bool checkSurjectiveMapping(const mv::LinkedData& linkedData, const std::uint32_t numPointsInTarget) {
108-
const std::map<std::uint32_t, std::vector<std::uint32_t>>& linkedMap = linkedData.getMapping().getMap();
109-
110-
std::vector<bool> found(numPointsInTarget, false);
111-
std::uint32_t count = 0;
112-
113-
for (const auto& [key, vec] : linkedMap) {
114-
for (std::uint32_t val : vec) {
115-
if (val >= numPointsInTarget) continue; // Skip values that are too large
116-
117-
if (!found[val]) {
118-
found[val] = true;
119-
if (++count == numPointsInTarget)
120-
return true;
121-
}
122-
}
123-
}
124-
125-
return false; // The previous loop would have returned early if the entire taget set was covered
126-
}
127-
128-
// returns whether there is a selection map from colors to positions or positions to colors (or respective parents)
129-
// checks whether the mapping covers all elements in the target
130-
static bool checkSelectionMapping(const mv::Dataset<Points>& colors, const mv::Dataset<Points>& positions) {
131-
132-
// Check if there is a mapping
133-
auto mapping = getSelectionMappingColorsToPositions(colors, positions);
134-
auto numTargetPoints = positions->getNumPoints();
135-
136-
if (!mapping.has_value() || mapping.value() == nullptr) {
137-
138-
mapping = getSelectionMappingPositionsToColors(positions, colors);
139-
numTargetPoints = colors->getNumPoints();
140-
141-
if (!mapping.has_value() || mapping.value() == nullptr)
142-
return false;
143-
}
144-
145-
const bool mappingCoversData = checkSurjectiveMapping(*(mapping.value()), numTargetPoints);
146-
147-
return mappingCoversData;
148-
}
149-
15050
ScatterplotPlugin::ScatterplotPlugin(const PluginFactory* factory) :
15151
ViewPlugin(factory),
15252
_dropWidget(nullptr),

0 commit comments

Comments
 (0)