| 1314 | } |
| 1315 | |
| 1316 | void WriteTwoViewGeometry(const image_t image_id1, |
| 1317 | const image_t image_id2, |
| 1318 | const TwoViewGeometry& two_view_geometry) override { |
| 1319 | THROW_CHECK(!ExistsTwoViewGeometry(image_id1, image_id2)) |
| 1320 | << "Two view geometry between image " << image_id1 << " and " |
| 1321 | << image_id2 << " already exists."; |
| 1322 | Sqlite3StmtContext context(sql_stmt_write_two_view_geometry_); |
| 1323 | |
| 1324 | const image_pair_t pair_id = ImagePairToPairId(image_id1, image_id2); |
| 1325 | SQLITE3_CALL( |
| 1326 | sqlite3_bind_int64(sql_stmt_write_two_view_geometry_, 1, pair_id)); |
| 1327 | |
| 1328 | const TwoViewGeometry* two_view_geometry_ptr = &two_view_geometry; |
| 1329 | |
| 1330 | // Invert the two-view geometry if the image pair has to be swapped. |
| 1331 | std::unique_ptr<TwoViewGeometry> swapped_two_view_geometry; |
| 1332 | if (ShouldSwapImagePair(image_id1, image_id2)) { |
| 1333 | swapped_two_view_geometry = std::make_unique<TwoViewGeometry>(); |
| 1334 | *swapped_two_view_geometry = two_view_geometry; |
| 1335 | swapped_two_view_geometry->Invert(); |
| 1336 | two_view_geometry_ptr = swapped_two_view_geometry.get(); |
| 1337 | } |
| 1338 | |
| 1339 | const FeatureMatchesBlob inlier_matches = |
| 1340 | FeatureMatchesToBlob(two_view_geometry_ptr->inlier_matches); |
| 1341 | WriteDynamicMatrixBlob( |
| 1342 | sql_stmt_write_two_view_geometry_, inlier_matches, 2); |
| 1343 | |
| 1344 | SQLITE3_CALL(sqlite3_bind_int64( |
| 1345 | sql_stmt_write_two_view_geometry_, 5, two_view_geometry_ptr->config)); |
| 1346 | |
| 1347 | // Write NULL for F/E/H if not set, otherwise transpose and write. |
| 1348 | // Important: Transposed matrices must be declared outside if-statements |
| 1349 | // because sqlite3_step reads the bound data after the bind calls. |
| 1350 | Eigen::Matrix3d Ft, Et, Ht; |
| 1351 | if (two_view_geometry_ptr->F.has_value()) { |
| 1352 | Ft = two_view_geometry_ptr->F->transpose(); |
| 1353 | WriteStaticMatrixBlob(sql_stmt_write_two_view_geometry_, Ft, 6); |
| 1354 | } else { |
| 1355 | SQLITE3_CALL(sqlite3_bind_null(sql_stmt_write_two_view_geometry_, 6)); |
| 1356 | } |
| 1357 | if (two_view_geometry_ptr->E.has_value()) { |
| 1358 | Et = two_view_geometry_ptr->E->transpose(); |
| 1359 | WriteStaticMatrixBlob(sql_stmt_write_two_view_geometry_, Et, 7); |
| 1360 | } else { |
| 1361 | SQLITE3_CALL(sqlite3_bind_null(sql_stmt_write_two_view_geometry_, 7)); |
| 1362 | } |
| 1363 | if (two_view_geometry_ptr->H.has_value()) { |
| 1364 | Ht = two_view_geometry_ptr->H->transpose(); |
| 1365 | WriteStaticMatrixBlob(sql_stmt_write_two_view_geometry_, Ht, 8); |
| 1366 | } else { |
| 1367 | SQLITE3_CALL(sqlite3_bind_null(sql_stmt_write_two_view_geometry_, 8)); |
| 1368 | } |
| 1369 | |
| 1370 | // Write NULL for qvec/tvec if cam2_from_cam1 is not set. |
| 1371 | // Important: quat_wxyz and tvec must be declared outside the if-statement |
| 1372 | // because sqlite3_step reads the bound data after the bind calls. |
| 1373 | Eigen::Vector4d quat_wxyz; |