/** * Determine the axis-aligned bounding box containing the vertices of all * line segments at or beneath @a node in the block tree. * * @return Determined AABox (might be empty (i.e., min > max) if no segments). */ static AABoxd segmentBounds(LineSegmentBlockTreeNode const &node) { bool initialized = false; AABoxd bounds; // Iterative pre-order traversal. LineSegmentBlockTreeNode const *cur = &node; LineSegmentBlockTreeNode const *prev = nullptr; while(cur) { while(cur) { LineSegmentBlock const &block = *cur->userData(); if(block.totalCount()) { AABoxd boundsAtNode = segmentBounds(block.all()); if(initialized) { V2d_AddToBox(bounds.arvec2, boundsAtNode.min); } else { V2d_InitBox(bounds.arvec2, boundsAtNode.min); initialized = true; } V2d_AddToBox(bounds.arvec2, boundsAtNode.max); } if(prev == cur->parentPtr()) { // Descending - right first, then left. prev = cur; if(cur->hasRight()) cur = cur->rightPtr(); else cur = cur->leftPtr(); } else if(prev == cur->rightPtr()) { // Last moved up the right branch - descend the left. prev = cur; cur = cur->leftPtr(); } else if(prev == cur->leftPtr()) { // Last moved up the left branch - continue upward. prev = cur; cur = cur->parentPtr(); } } if(prev) { // No left child - back up. cur = prev->parentPtr(); } } return bounds; }
/** * Takes the line segment list and determines if it is convex, possibly * converting it into a BSP leaf. Otherwise, the list is divided into two * halves and recursion will continue on the new sub list. * * This is done by scanning all of the line segments and finding the one * that does the least splitting and has the least difference in numbers * of line segments on either side (why is this valued? -ds). * * If the line segments on the left side are convex create another leaf * else put the line segments into the left list. * * If the line segments on the right side are convex create another leaf * else put the line segments into the right list. * * @param node Tree node for the block containing the line segments to * be partitioned. * * @return Newly created BSP subtree; otherwise @c nullptr (degenerate). */ BspTree *partitionSpace(LineSegmentBlockTreeNode &node) { LOG_AS("Partitioner::partitionSpace"); BspElement *bspElement = nullptr; ///< Built BSP map element at this node. BspTree *rightBspTree = nullptr; BspTree *leftBspTree = nullptr; // Pick a line segment to use as the next partition plane. if(LineSegmentSide *partSeg = choosePartition(node)) { // Reconfigure the half-plane for the next round of partitioning. hplane.configure(*partSeg); /* LOG_TRACE("%s, segment side %p %i (segment #%i) %s %s") << hplane.partition().asText() << partSeg << partSeg->lineSideId() << lineSegments.indexOf(&partSeg->line()) << partSeg->from().origin().asText() << partSeg->to().origin().asText(); */ // Take a copy of the current partition - we'll need this for any // BspNode we produce later. Partition partition(hplane.partition()); // Create left and right block trees. /// @todo There should be no need to use additional independent /// structures to contain these subsets. LineSegmentBlockTree rightTree(node.userData()->bounds()); LineSegmentBlockTree leftTree(node.userData()->bounds()); // Partition the line segements into two subsets according to their // spacial relationship with the half-plane (splitting any which // intersect). divideSegments(node, rightTree, leftTree); node.clear(); addPartitionLineSegments(rightTree, leftTree); // Take a copy of the geometry bounds for each child/sub space // - we'll need this for any BspNode we produce later. AABoxd rightBounds = segmentBounds(rightTree); AABoxd leftBounds = segmentBounds(leftTree); // Recurse on each suspace, first the right space then left. rightBspTree = partitionSpace(rightTree); leftBspTree = partitionSpace(leftTree); // Collapse degenerates upward. if(!rightBspTree || !leftBspTree) return rightBspTree? rightBspTree : leftBspTree; // Make a new BSP node. bspElement = new BspNode(partition, rightBounds, leftBounds); } else { // No partition required/possible -- already convex (or degenerate). LineSegmentSides segments = collectAllSegments(node); node.clear(); subspaces.append(ConvexSubspaceProxy()); ConvexSubspaceProxy &convexSet = subspaces.last(); convexSet.addSegments(segments); for(LineSegmentSide *seg : segments) { // Attribute the segment to the convex subspace. seg->setConvexSubspace(&convexSet); // Disassociate the segment from the block tree. seg->setBlockTreeNode(nullptr); } // Make a new BSP leaf. /// @todo Defer until necessary. BspLeaf *leaf = new BspLeaf; // Attribute the leaf to the convex subspace. convexSet.setBspLeaf(leaf); bspElement = leaf; } // Make a new BSP subtree and link up the children. BspTree *subtree = new BspTree(bspElement, nullptr/*no parent*/, rightBspTree, leftBspTree); if(rightBspTree) rightBspTree->setParent(subtree); if(leftBspTree) leftBspTree->setParent(subtree); return subtree; }
int main(int argc, char** argv) { try { // init command line parser util::ProgramOptions::init(argc, argv); int stack_id = optionStackId.as<int>(); std::string comp_dir = optionComponentDir.as<std::string>(); std::string pg_host = optionPGHost.as<std::string>(); std::string pg_user = optionPGUser.as<std::string>(); std::string pg_pass = optionPGPassword.as<std::string>(); std::string pg_dbase = optionPGDatabase.as<std::string>(); std::cout << "Testing PostgreSQL stores with stack ID " << stack_id << std::endl; // init logger logger::LogManager::init(); logger::LogManager::setGlobalLogLevel(logger::Debug); // create new project configuration ProjectConfiguration pc; pc.setBackendType(ProjectConfiguration::PostgreSql); StackDescription stack; stack.id = stack_id; pc.setCatmaidStack(Raw, stack); pc.setComponentDirectory(comp_dir); pc.setPostgreSqlHost(pg_host); pc.setPostgreSqlUser(pg_user); pc.setPostgreSqlPassword(pg_pass); pc.setPostgreSqlDatabase(pg_dbase); PostgreSqlSliceStore sliceStore(pc, Membrane); // Add first set of slices boost::shared_ptr<Slice> slice1 = createSlice(10, 0); boost::shared_ptr<Slice> slice2 = createSlice(10, 1); boost::shared_ptr<Slice> slice3 = createSlice(10, 2); Slices slices = Slices(); slices.add(slice1); slices.add(slice2); slices.add(slice3); Block block(0, 0, 0); sliceStore.associateSlicesToBlock(slices, block); Blocks blocks; blocks.add(block); Blocks missingBlocks; boost::shared_ptr<Slices> retrievedSlices = sliceStore.getSlicesByBlocks(blocks, missingBlocks); // Create conflict set where each slice ConflictSet conflictSet1; conflictSet1.addSlice(slice1->hashValue()); conflictSet1.addSlice(slice2->hashValue()); conflictSet1.addSlice(slice3->hashValue()); ConflictSets conflictSets; conflictSets.add(conflictSet1); sliceStore.associateConflictSetsToBlock(conflictSets, block); boost::shared_ptr<ConflictSets> retrievedConflictSets = sliceStore.getConflictSetsByBlocks(blocks, missingBlocks); for (const ConflictSet& cs : *retrievedConflictSets) { std::cout << "ConflictSet hash: " << hash_value(cs); for (const SliceHash& sh : cs.getSlices()) { std::cout << " Slice hash: " << sh; } std::cout << std::endl; } PostgreSqlSegmentStore segmentStore(pc, Membrane); util::box<unsigned int, 2> segmentBounds(0, 0, 0, 0); std::vector<double> segmentFeatures; segmentFeatures.push_back(0.0); segmentFeatures.push_back(1.0); segmentFeatures.push_back(2.0); SegmentDescription segment(0, segmentBounds); segment.addLeftSlice(slice1->hashValue()); segment.addRightSlice(slice2->hashValue()); segment.setFeatures(segmentFeatures); boost::shared_ptr<SegmentDescriptions> segments = boost::make_shared<SegmentDescriptions>(); segments->add(segment); segmentStore.associateSegmentsToBlock(*segments, block); boost::shared_ptr<SegmentDescriptions> retrievedSegments = segmentStore.getSegmentsByBlocks(blocks, missingBlocks, false); } catch (boost::exception& e) { handleException(e, std::cerr); } }