1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright (c) 2012-2017 VideoStitch SAS
// Copyright (c) 2018 stitchEm
#include "geoProps.hpp"
#include <cassert>
#include <cstdlib>
namespace VideoStitch {
namespace Core {
/**
* Represents an edge in the graph of inputs.
*/
class Edge {
public:
/**
* @param overlap The caller retains ownership.
*/
Edge(readerid_t fromId, readerid_t toId) : from(fromId), to(toId), opposite_(NULL) {}
const readerid_t from;
const readerid_t to;
OverlapImpl overlap;
void setOpposite(Edge* opposite) {
opposite_ = opposite;
opposite_->opposite_ = this;
}
Edge* opposite() const { return opposite_; }
private:
Edge* opposite_; // Not owned.
};
/**
* Represents a node in the graph of inputs.
*/
class Node {
public:
explicit Node(readerid_t id) : id(id) {}
/**
* Adds an edge to the node.
* @param edge The edge to add. The caller retains ownership.
*/
void addEdge(Edge* edge) {
assert(edge->from == id);
assert(edge->to != id);
edges.push_back(edge);
}
/**
* Return the outgoing edge to @a toId, or NULL.
* @param toId Id of the edge to find.
*/
Edge* findEdgeTo(readerid_t toId) const {
for (size_t i = 0; i < edges.size(); ++i) {
if (edges[i]->to == toId) {
return edges[i];
}
}
return NULL;
}
/**
* The node's input id.
*/
const readerid_t id;
private:
std::vector<Edge*> edges; // Not owned.
};
GeometricPropsImpl::~GeometricPropsImpl() {
for (size_t i = 0; i < edges.size(); ++i) {
delete edges[i];
}
for (size_t i = 0; i < nodes.size(); ++i) {
delete nodes[i];
}
}
Node* GeometricPropsImpl::createNodeIfNeeded(readerid_t id) {
assert(id >= 0);
if (id >= (int)nodes.size()) {
nodes.resize(id);
}
if (nodes[id] == NULL) {
nodes[id] = new Node(id);
}
return nodes[id];
}
Edge* GeometricPropsImpl::createEdgeIfNeeded(readerid_t firstInput, readerid_t secondInput) {
return createEdgeIfNeeded(createNodeIfNeeded(firstInput), createNodeIfNeeded(secondInput));
}
Edge* GeometricPropsImpl::createEdgeIfNeeded(Node* firstNode, Node* secondNode) {
Edge* edge = firstNode->findEdgeTo(secondNode->id);
if (!edge) {
edge = new Edge(firstNode->id, secondNode->id);
edge->setOpposite(new Edge(secondNode->id, firstNode->id));
edges.push_back(edge);
edges.push_back(edge->opposite());
firstNode->addEdge(edge);
secondNode->addEdge(edge->opposite());
}
return edge;
}
void GeometricPropsImpl::setOverlap(readerid_t firstInput, readerid_t secondInput, int numPixels) {
Edge* edge = createEdgeIfNeeded(firstInput, secondInput);
edge->overlap.setNumPixels(numPixels);
edge->opposite()->overlap.setNumPixels(numPixels);
}
const Overlap* GeometricPropsImpl::getOverlap(readerid_t firstInput, readerid_t secondInput) const {
if (firstInput < 0 || firstInput >= (int)nodes.size()) {
return NULL;
}
if (secondInput < 0 || secondInput >= (int)nodes.size()) {
return NULL;
}
const Edge* edge = nodes[firstInput]->findEdgeTo(secondInput);
if (edge) {
return &edge->overlap;
}
return NULL;
}
} // namespace Core
} // namespace VideoStitch