void build_local_element_map(RegionVector &part_mesh, std::vector<INT> &local_element_map) { size_t global = 0; size_t offset = 0; for (size_t p = 0; p < part_mesh.size(); p++) { Ioss::ElementBlockContainer ebs = part_mesh[p]->get_element_blocks(); Ioss::ElementBlockContainer::const_iterator i = ebs.begin(); while (i != ebs.end()) { Ioss::ElementBlock *eb = *i++; size_t num_elem = eb->get_property("entity_count").get_int(); if (entity_is_omitted(eb)) { // Fill local_element_map with -1 for the omitted elements. for (size_t j = 0; j < num_elem; j++) { local_element_map[offset+j] = -1; } } else { for (size_t j = 0; j < num_elem; j++) { local_element_map[offset+j] = global++; } } offset += num_elem; } } }
// records regions of contiguous identity in the alignment void CColorspaceUtilities::FindIndenticalRegions(char* pReference, char* pQuery, const unsigned short pairwiseLen, RegionVector& rv) { for(unsigned short i = 0; i < pairwiseLen; i++) { if(pReference[i] == pQuery[i]) { RegionT r(i); unsigned short end = i; while((end < pairwiseLen) && (pReference[end] == pQuery[end])) { ++r.Length; ++end; } rv.push_back(r); i = end; } } }
void eliminate_omitted_nodes(RegionVector &part_mesh, std::vector<INT> &global_node_map, std::vector<INT> &local_node_map) { size_t offset = 0; size_t j = 0; size_t part_count = part_mesh.size(); for (size_t p = 0; p < part_count; p++) { bool has_omissions = part_mesh[p]->get_property("block_omission_count").get_int() > 0; Ioss::NodeBlock *nb = part_mesh[p]->get_node_blocks()[0]; size_t loc_size = nb->get_property("entity_count").get_int(); if (has_omissions) { // If there are any omitted element blocks for this part, don't // map the nodes that are only connected to omitted element // blocks. std::vector<char> node_status; nb->get_field_data("node_connectivity_status", node_status); for (size_t i=0; i < node_status.size(); i++) { if (node_status[i] != 1) { local_node_map[offset+i] = j; global_node_map.push_back(j+1); j++; } else { local_node_map[offset+i] = -1; } } } else { for (size_t i=0; i < loc_size; i++) { local_node_map[offset+i] = j; global_node_map.push_back(j+1); j++; } } offset += loc_size; } }
bool Probes::JITWatcher::CollectNativeRegions(RegionVector ®ions, JSRuntime *rt, mjit::JITChunk *jit, mjit::JSActiveFrame *outerFrame, mjit::JSActiveFrame **inlineFrames) { regions.resize(jit->nInlineFrames * 2 + 2); mjit::JSActiveFrame **stack = rt->array_new<mjit::JSActiveFrame*>(jit->nInlineFrames+2); if (!stack) return false; uint32_t depth = 0; uint32_t ip = 0; stack[depth++] = NULL; stack[depth++] = outerFrame; regions[0].frame = outerFrame; regions[0].script = outerFrame->script; regions[0].pc = outerFrame->script->code; regions[0].enter = true; ip++; for (uint32_t i = 0; i <= jit->nInlineFrames; i++) { mjit::JSActiveFrame *frame = (i < jit->nInlineFrames) ? inlineFrames[i] : outerFrame; // Not a down frame; pop the current frame, then pop until we reach // this frame's parent, recording subframe ends as we go while (stack[depth-1] != frame->parent) { depth--; JS_ASSERT(depth > 0); // Pop up from regions[ip-1].frame to top of the stack: start a // region in the destination frame and close off the source // (origin) frame at the end of its script mjit::JSActiveFrame *src = regions[ip-1].frame; mjit::JSActiveFrame *dst = stack[depth-1]; JS_ASSERT_IF(!dst, i == jit->nInlineFrames); regions[ip].frame = dst; regions[ip].script = dst ? dst->script : NULL; regions[ip].pc = src->parentPC + 1; regions[ip-1].endpc = src->script->code + src->script->length; regions[ip].enter = false; ip++; } if (i < jit->nInlineFrames) { // Push a frame (enter an inlined function). Start a region at the // beginning of the new frame's script, and end the previous region // at parentPC. stack[depth++] = frame; regions[ip].frame = frame; regions[ip].script = frame->script; regions[ip].pc = frame->script->code; regions[ip-1].endpc = frame->parentPC; regions[ip].enter = true; ip++; } } // Final region is always zero-length and not particularly useful ip--; regions.popBack(); mjit::JSActiveFrame *prev = NULL; for (NativeRegion *iter = regions.begin(); iter != regions.end(); ++iter) { mjit::JSActiveFrame *frame = iter->frame; if (iter->enter) { // Pushing down a frame, so region starts at the beginning of the // (destination) frame iter->mainOffset = frame->mainCodeStart; iter->stubOffset = frame->stubCodeStart; } else { // Popping up a level, so region starts at the end of the (source) frame iter->mainOffset = prev->mainCodeEnd; iter->stubOffset = prev->stubCodeEnd; } prev = frame; } JS_ASSERT(ip == 2 * jit->nInlineFrames + 1); rt->array_delete(stack); // All of the stub code comes immediately after the main code for (NativeRegion *iter = regions.begin(); iter != regions.end(); ++iter) iter->stubOffset += outerFrame->mainCodeEnd; return true; }
void generate_element_ids(RegionVector &part_mesh, const std::vector<INT> &local_element_map, std::vector<INT> &global_element_map) { // Follow same logic as 'build_local_element_map' to ensure elements // are processed in same order. // Many models do not use the element number map at all, so they // will have a 1..numel map. If all parts have that, then we don't // want to do any fancy duplicate removal and other processing, just // output a 1..numel map for the output mesh... We still generate // the global_element_map, but check whether any of the part blocks // have a non-1..numel map... bool has_map = false; size_t offset = 0; for (size_t p = 0; p < part_mesh.size(); p++) { Ioss::ElementBlockContainer ebs = part_mesh[p]->get_element_blocks(); Ioss::ElementBlockContainer::const_iterator i = ebs.begin(); while (i != ebs.end()) { Ioss::ElementBlock *eb = *i++; INT num_elem = eb->get_property("entity_count").get_int(); if (!entity_is_omitted(eb)) { std::vector<INT> part_ids; eb->get_field_data("ids", part_ids); if (!has_map) { INT eb_offset = eb->get_offset(); for (INT j = 0; j < num_elem; j++) { if (part_ids[j] != eb_offset+j+1) { has_map = true; break; } } } for (INT j = 0; j < num_elem; j++) { INT gpos = local_element_map[offset+j]; if (gpos >= 0) global_element_map[gpos] = part_ids[j]; } } offset += num_elem; } } // Check for duplicates... // NOTE: Used to use an indexed sort here, but if there was a // duplicate id, it didnt really care whether part 1 or part N's // index came first which causes really screwy element maps. // Instead, lets sort a vector containing pairs of <id, index> where // the index will always? increase for increasing part numbers... std::vector<std::pair<INT,INT> > index(global_element_map.size()); for (size_t i=0; i < index.size(); i++) { index[i] = std::make_pair(global_element_map[i],(INT)i); } std::sort(index.begin(), index.end()); INT max_id = index[index.size()-1].first + 1; size_t beg = 0; for (size_t i=1; i < index.size(); i++) { if (index[beg].first == index[i].first) { // Duplicate found... Assign it a new id greater than any // existing id... (What happens if we exceed INT_MAX?) global_element_map[index[i].second] = max_id++; // Keep 'beg' the same in case multiple duplicate of this value. } else { beg = i; } } }
void build_reverse_node_map(Ioss::Region &global, RegionVector &part_mesh, std::vector<INT> &global_node_map, std::vector<INT> &local_node_map) { // Instead of using <set> and <map>, consider using a sorted vector... // Append all local node maps to the global node map. // Sort the global node map // Remove duplicates. // Position within map is now the map... // When building the local-part node to global id, use binary_search... size_t part_count = part_mesh.size(); // Global node map and count. std::vector<std::vector<int> > global_nodes(part_count); size_t tot_size = 0; for (size_t p = 0; p < part_count; p++) { Ioss::NodeBlock *nb = part_mesh[p]->get_node_blocks()[0]; size_t loc_size = nb->get_property("entity_count").get_int(); tot_size += loc_size; global_nodes[p].resize(loc_size); } global_node_map.resize(tot_size); size_t offset = 0; bool any_omitted_nodes = false; for (size_t p = 0; p < part_count; p++) { Ioss::NodeBlock *nb = part_mesh[p]->get_node_blocks()[0]; nb->get_field_data("ids", global_nodes[p]); // If there are any omitted element blocks for this part, set // the global id of any nodes that are only connected to omitted // element blocks to 0. bool has_omissions = part_mesh[p]->get_property("block_omission_count").get_int() > 0; if (has_omissions) { std::vector<char> node_status; nb->get_field_data("node_connectivity_status", node_status); for (size_t i=0; i < node_status.size(); i++) { if (node_status[i] == 1) { any_omitted_nodes = true; global_nodes[p][i] = 0; } } } std::copy(global_nodes[p].begin(), global_nodes[p].end(), &global_node_map[offset]); offset += global_nodes[p].size(); } // Now, sort the global_node_map array and remove duplicates... uniqify(global_node_map); // If any omitted nodes, remove them from the global_node_map. // The id will be 0 if (any_omitted_nodes) { typename std::vector<INT>::iterator pos = std::remove(global_node_map.begin(), global_node_map.end(), 0); global_node_map.erase(pos, global_node_map.end()); } size_t output_node_count = global_node_map.size(); // See whether the node numbers are contiguous. If so, we can map // the nodes back to their original location. Since the nodes are // sorted and there are no duplicates, we just need to see if the id // at global_node_map.size() == global_node_map.size(); size_t max_id = global_node_map[output_node_count-1]; bool is_contiguous = max_id == output_node_count; std::cerr << "Node map " << (is_contiguous ? "is" : "is not") << " contiguous.\n"; // Create the map that maps from a local part node to the // global map. This combines the mapping local part node to // 'global id' and then 'global id' to global position. The // mapping is now a direct lookup instead of a lookup followed by // a reverse map. typedef typename std::vector<INT>::iterator V_INT_iterator; V_INT_iterator cur_pos = global_node_map.begin(); for (size_t p = 0; p < part_count; p++) { size_t noffset = part_mesh[p]->get_property("node_offset").get_int(); size_t node_count = global_nodes[p].size(); for (size_t i = 0; i < node_count; i++) { INT global_node = global_nodes[p][i]; if (global_node > 0) { if (cur_pos == global_node_map.end() || *cur_pos != global_node) { std::pair<V_INT_iterator, V_INT_iterator> iter = std::equal_range(global_node_map.begin(), global_node_map.end(), global_node); if (iter.first == iter.second) { INT n = global_node; std::cerr << n << "\n"; SMART_ASSERT(iter.first != iter.second); } cur_pos = iter.first; } size_t nodal_value = cur_pos - global_node_map.begin(); local_node_map[noffset+i] = nodal_value; ++cur_pos; } else { local_node_map[noffset+i] = -1; } } } // Update the nodal ids to give a unique, non-repeating set. If contiguous, then // there is nothing to do. If not contiguous, then need to determine if there are any // repeats (id reuse) and if so, generate a new id for the repeated uses. if (!is_contiguous) { bool repeat_found = false; INT id_last = global_node_map[0]; for (size_t i=1; i < output_node_count; i++) { if (global_node_map[i] == id_last) { global_node_map[i] = ++max_id; repeat_found = true; } else { id_last = global_node_map[i]; } } if (repeat_found) { std::cerr << "Duplicate node ids were found. Their ids have been renumbered to remove duplicates.\n"; } } }
void match_node_xyz(RegionVector &part_mesh, double tolerance, std::vector<INT> &global_node_map, std::vector<INT> &local_node_map) { // See if any omitted element blocks... bool has_omissions = false; for (auto & elem : part_mesh) { if (elem->get_property("block_omission_count").get_int() > 0) { has_omissions = true; break; } } if (!has_omissions) { for (size_t i=0; i < local_node_map.size(); i++) { local_node_map[i] = i; } } else { std::vector<INT> dummy; eliminate_omitted_nodes(part_mesh, dummy, local_node_map); // The local_node_map is not quite in the correct format after the // call to 'eliminate_omitted_nodes'. We need all non-omitted // nodes to have local_node_map[i] == i. for (size_t i=0; i < local_node_map.size(); i++) { if (local_node_map[i] >= 0) local_node_map[i] = i; } } size_t part_count = part_mesh.size(); enum {X=0, Y=1, Z=2}; for (size_t ip=0; ip < part_count; ip++) { vector3d i_max; vector3d i_min; std::vector<double> i_coord; Ioss::NodeBlock *inb = part_mesh[ip]->get_node_blocks()[0]; inb->get_field_data("mesh_model_coordinates", i_coord); find_range(i_coord, i_min, i_max); size_t i_offset = part_mesh[ip]->get_property("node_offset").get_int(); for (size_t jp=ip+1; jp < part_count; jp++) { vector3d j_max; vector3d j_min; std::vector<double> j_coord; Ioss::NodeBlock *jnb = part_mesh[jp]->get_node_blocks()[0]; jnb->get_field_data("mesh_model_coordinates", j_coord); find_range(j_coord, j_min, j_max); size_t j_offset = part_mesh[jp]->get_property("node_offset").get_int(); // See if the ranges overlap... vector3d max; vector3d min; max.x = std::min(i_max.x, j_max.x); max.y = std::min(i_max.y, j_max.y); max.z = std::min(i_max.z, j_max.z); min.x = std::max(i_min.x, j_min.x); min.y = std::max(i_min.y, j_min.y); min.z = std::max(i_min.z, j_min.z); double delta[3]; int XYZ = X; delta[XYZ] = max.x - min.x; delta[Y] = max.y - min.y; if (delta[Y] > delta[XYZ]) XYZ = Y; delta[Z] = max.z - min.z; if (delta[Z] > delta[XYZ]) XYZ = Z; double epsilon = (delta[X] + delta[Y] + delta[Z]) / 1.0e3; if (epsilon < 0.0) { std::cout << "Parts " << ip << " and " << jp << " do not overlap.\n"; continue; } min -= epsilon; max += epsilon; if (tolerance >= 0.0) epsilon = tolerance; std::vector<INT> j_inrange; std::vector<INT> i_inrange; find_in_range(j_coord, min, max, j_inrange); find_in_range(i_coord, min, max, i_inrange); // Index sort all nodes on the coordinate range with the maximum delta. index_coord_sort(i_coord, i_inrange, XYZ); index_coord_sort(j_coord, j_inrange, XYZ); if (i_inrange.size() < j_inrange.size()) { do_matching(i_inrange, i_coord, i_offset, j_inrange, j_coord, j_offset, epsilon, XYZ, local_node_map); } else { do_matching(j_inrange, j_coord, j_offset, i_inrange, i_coord, i_offset, epsilon, XYZ, local_node_map); } } } // Build the global and local maps... size_t j = 1; for (size_t i=0; i < local_node_map.size(); i++) { if (local_node_map[i] == (INT)i) { global_node_map.push_back(j); local_node_map[i] = j-1; j++; } else if (local_node_map[i] >= 0) { local_node_map[i] = local_node_map[local_node_map[i]]; } } }
bool ScanMatcher::scanMatchingLChierarchical(OptimizableGraph::VertexSet& referenceVset, OptimizableGraph::Vertex* _referenceVertex, OptimizableGraph::VertexSet& currvset, OptimizableGraph::Vertex* _currentVertex, std::vector<SE2>& trel, double maxScore){ //cerr << "Loop Closing Scan Matching" << endl; //cerr << "Size of Vset " << referenceVset.size() << endl; VertexSE2* currentVertex=dynamic_cast<VertexSE2*>(_currentVertex); VertexSE2* referenceVertex =dynamic_cast<VertexSE2*>(_referenceVertex); resetGrid(); trel.clear(); RawLaser::Point2DVector scansInRefVertex; transformPointsFromVSet(referenceVset, _referenceVertex, scansInRefVertex); _grid.addAndConvolvePoints<RawLaser::Point2DVector>(scansInRefVertex.begin(), scansInRefVertex.end(), _kernel); RawLaser::Point2DVector scansInCurVertex; transformPointsFromVSet(currvset, _currentVertex, scansInCurVertex); Vector2dVector reducedScans; CharGrid::subsample(reducedScans, scansInCurVertex, 0.1); //cerr << "subsampling: " << scansInCurVertex.size() << " -> " << reducedScans.size() << endl; SE2 delta = referenceVertex->estimate().inverse() * currentVertex->estimate(); Vector3d initGuess(delta.translation().x(), delta.translation().y(), delta.rotation().angle()); Vector3f lower(-2.+initGuess.x(), -2.+initGuess.y(), -1.+initGuess.z()); Vector3f upper(+2.+initGuess.x(), 2.+initGuess.y(), 1.+initGuess.z()); RegionVector regions; Region reg; reg.lowerLeft = lower; reg.upperRight = upper; regions.push_back(reg); std::vector<MatcherResult> mresvec; double thetaRes = 0.025; // was 0.0125*.5 // clock_t t_ini, t_fin; // double secs; // t_ini = clock(); _grid.hierarchicalSearch(mresvec, reducedScans, regions, thetaRes, maxScore, 0.5, 0.5, 0.2, 3); // t_fin = clock(); // secs = (double)(t_fin - t_ini) / CLOCKS_PER_SEC; // printf("%.16g ms. Matcher results: %i\n", secs * 1000.0, (int) mresvec.size()); if (mresvec.size()){ Vector3d adj=mresvec[0].transformation; SE2 transf; transf.setTranslation(Vector2d(adj.x(), adj.y())); transf.setRotation(adj.z()); // cerr << " bestScore = " << mresvec[0].score << endl; //cerr << "Found Loop Closure Edge. Transf: " << adj.x() << " " << adj.y() << " " << adj.z() << endl << endl; trel.push_back(transf); } if (trel.size()) return true; return false; }
bool ScanMatcher::scanMatchingLC(OptimizableGraph::VertexSet& referenceVset, OptimizableGraph::Vertex* _referenceVertex, OptimizableGraph::VertexSet& currvset, OptimizableGraph::Vertex* _currentVertex, std::vector<SE2>& trel, double maxScore){ cerr << "Loop Closing Scan Matching" << endl; //cerr << "Size of Vset " << referenceVset.size() << endl; VertexSE2* referenceVertex =dynamic_cast<VertexSE2*>(_referenceVertex); resetGrid(); trel.clear(); RawLaser::Point2DVector scansInRefVertex; transformPointsFromVSet(referenceVset, _referenceVertex, scansInRefVertex); _grid.addAndConvolvePoints<RawLaser::Point2DVector>(scansInRefVertex.begin(), scansInRefVertex.end(), _kernel); RawLaser::Point2DVector scansInCurVertex; transformPointsFromVSet(currvset, _currentVertex, scansInCurVertex); Vector2dVector reducedScans; CharGrid::subsample(reducedScans, scansInCurVertex, 0.1); RegionVector regions; RegionVector regionspi; for (OptimizableGraph::VertexSet::iterator it = referenceVset.begin(); it != referenceVset.end(); it++){ VertexSE2 *vertex = (VertexSE2*) *it; Region reg; SE2 relposv(.0, .0, .0); if (vertex->id() != referenceVertex->id()) relposv = referenceVertex->estimate().inverse() * vertex->estimate(); Vector3f lower(-.5+relposv.translation().x(), -2.+relposv.translation().y(), -1.+relposv.rotation().angle()); Vector3f upper( .5+relposv.translation().x(), 2.+relposv.translation().y(), 1.+relposv.rotation().angle()); reg.lowerLeft = lower; reg.upperRight = upper; regions.push_back(reg); lower[2] += M_PI; upper[2] += M_PI; reg.lowerLeft = lower; reg.upperRight = upper; regionspi.push_back(reg); } std::vector<MatcherResult> mresvec; double thetaRes = 0.025; // was 0.0125*.5 //Results discretization double dx = 0.5, dy = 0.5, dth = 0.2; std::map<DiscreteTriplet, MatcherResult> resultsMap; clock_t t_ini, t_fin; double secs; t_ini = clock(); _grid.greedySearch(mresvec, reducedScans, regions, thetaRes, maxScore, dx, dy, dth); t_fin = clock(); secs = (double)(t_fin - t_ini) / CLOCKS_PER_SEC; printf("%.16g ms. Matcher results: %i\n", secs * 1000.0, (int) mresvec.size()); if (mresvec.size()){ mresvec[0].transformation[2] = normalize_theta(mresvec[0].transformation[2]); cerr << "Found Loop Closure Edge. Transf: " << mresvec[0].transformation.x() << " " << mresvec[0].transformation.y() << " " << mresvec[0].transformation.z() << endl; CharGrid::addToPrunedMap(resultsMap, mresvec[0], dx, dy, dth); } t_ini = clock(); _grid.greedySearch(mresvec, reducedScans, regionspi, thetaRes, maxScore, dx, dy, dth); t_fin = clock(); secs = (double)(t_fin - t_ini) / CLOCKS_PER_SEC; printf("%.16g ms. Matcher results: %i\n", secs * 1000.0, (int) mresvec.size()); if (mresvec.size()){ mresvec[0].transformation[2] = normalize_theta(mresvec[0].transformation[2]); cerr << "Found Loop Closure Edge PI. Transf: " << mresvec[0].transformation.x() << " " << mresvec[0].transformation.y() << " " << mresvec[0].transformation.z() << endl; CharGrid::addToPrunedMap(resultsMap, mresvec[0], dx, dy, dth); } for (std::map<DiscreteTriplet, MatcherResult>::iterator it = resultsMap.begin(); it!= resultsMap.end(); it++){ MatcherResult res = it->second; Vector3d adj=res.transformation; SE2 transf; transf.setTranslation(Vector2d(adj.x(), adj.y())); transf.setRotation(normalize_theta(adj.z())); trel.push_back(transf); std::cerr << "Final result: " << transf.translation().x() << " " << transf.translation().y() << " " << transf.rotation().angle() << std::endl; } if (trel.size()) return true; return false; }
void AlignmentView::paintEvent(QPaintEvent * event) { DrawingArea::paintEvent(event); if ( alignment == 0 ) { return; } if ( width() <= frameWidth() * 2 ) { return; } QPainter painter(this); // painter.setRenderHints(0); QImage image(width() - frameWidth() * 2, height() - frameWidth() * 2, QImage::Format_RGB32); // setColors(); image.setColorCount(62); image.setColorTable(colors); image.fill(qRgb(180, 180, 180)); int * hues = new int[image.width()]; for ( int i = 0; i < image.width(); i++ ) { hues[i] = i * 128 / image.width(); } if ( highlight && highlightGradient ) { float radius = .06; float offset = wrap(trackViews[highlightTrack].getLcbOffset(highlightLcb, highlightOffset), 0, 1); float lcbOffset; int lcb = trackViews[highlightTrack].getLcb ( (offset - radius) * image.width(), image.width(), lcbOffset ); RegionVector * track = (*alignment->getTracks())[getIdByTrack(highlightTrack)]; int i = 0; // seek to lcb. TODO: Track method? // while ( (*track)[i]->getLcb() != lcb ) { i++; } int delta = trackViews[highlightTrack].getRc() ? -1 : 1; float highlightStart = wrap((*track)[i]->getStartScaled() * delta + trackViews[highlightTrack].getOffset(), 0, 1); while ( wrap((*track)[i]->getStartScaled() * delta + trackViews[highlightTrack].getOffset(), 0, 1) < offset + radius ) { const gav::Region * region = (*alignment->getLcb((*track)[i]->getLcb()).regions)[0]; int start = region->getStartScaled() * image.width(); int end = region->getEndScaled() * image.width(); for ( int j = start; j <= end; j++ ) { hues[j] = 60 + (wrap((*track)[i]->getStartScaled() * delta - highlightStart + trackViews[highlightTrack].getOffset(), 0, 1)) * 59 / (radius * 2); } i += delta; if ( i < 0 ) { i += track->size();break; } else if ( i == track->size() ) { i = 0;break; } } /* for ( int i = wrap(offset - radius, 0, 1) * image.width(); i <= wrap(offset + radius, 0, 1) * image.width() && i < image.width(); i++ ) { int lcb = trackViews[highlightTrack].getLcb ( i, image.width(), lcbOffset ); if ( i < 0 ) { i += image.width(); } else if ( i >= image.width() ) { i -= image.width(); } int position = (int)(getRefPos(lcb, lcbOffset) * image.width()); hues[position] = 60 + (i - (offset - radius) * image.width()) * 59 / (2 * radius * image.width()); }*/ } for ( int i = trackViews.size() - 1; i >= 0; i-- ) { trackViews[i].draw(&image, palette, hues, progress, getTrackHeight(i), getTrackHeight(i + 1) - getTrackHeight(i), highlight, highlightLcb, highlightOffset); } delete [] hues; QTime time = QTime::currentTime(); frames++; if ( time.second() != secLast ) { //printf("fps: %d\n", frames); frames = 0; } secLast = time.second(); painter.drawImage(frameWidth(), frameWidth(), image); for ( int i = 1; i < trackViews.size(); i++ ) { float childSize = getTrackHeight(i + 1) - getTrackHeight(i); int shade; if ( childSize >= 20 ) { shade = 255; } else if ( childSize < 2 ) { shade = 0; } else { shade = 256 * (childSize - 2) / 18; } if ( i == getTrackFocus() || i == getTrackFocus() + 1 ) { painter.setPen(QColor::fromRgba(qRgba(255, 255, 255, 255))); } else if ( i == getTrackHover() || i == getTrackHover() + 1 ) { painter.setPen(QColor::fromRgba(qRgba(180, 180, 180, 255))); } else { painter.setPen(QColor::fromRgba(qRgba(0, 0, 0, shade))); } if ( shade > 0 ) { painter.drawLine(frameWidth(), getTrackHeight(i) + frameWidth(), width() - frameWidth() - 1, getTrackHeight(i) + frameWidth()); } } if ( highlightGradient ) { float radius = .06; float offset = wrap(trackViews[highlightTrack].getLcbOffset(highlightLcb, highlightOffset), 0, 1); int x1 = (offset - radius) * image.width(); int x2 = (offset + radius) * image.width(); int y1 = getTrackHeight(highlightTrack); int y2 = getTrackHeight(highlightTrack + 1); QPen pen; pen.setWidth(3); pen.setColor(Qt::white); painter.setPen(pen); painter.drawRect(x1 - 1, y1 - 1, x2 - x1 + 2, y2 - y1 + 2); } if ( highlight ) { highlightTrack = getTrackHover(); int gap = 5;//cursorSize * .3; int y = cursorY;//(highlightTrack + .5) * image.height() / trackViews.size() - cursorSize / 20; int y1 = getTrackHeight(highlightTrack) - cursorSize / 20 + frameWidth() + 1; int y2 = getTrackHeight(highlightTrack + 1) + cursorSize / 20 + frameWidth() + 1; QPen pen; pen.setWidth(2 + cursorSize / 10); pen.setColor(QColor::fromHsl(120, 255, 127).rgb()); painter.setPen(pen); painter.drawRect(cursorX - gap + frameWidth(), y1, gap * 2, y2 - y1); pen.setColor(Qt::white); painter.setPen(pen); return; painter.drawLine(cursorX - cursorSize, y - cursorSize, cursorX - gap, y - gap); painter.drawLine(cursorX - cursorSize, y + cursorSize, cursorX - gap, y + gap); painter.drawLine(cursorX + cursorSize, y - cursorSize, cursorX + gap, y - gap); painter.drawLine(cursorX + cursorSize, y + cursorSize, cursorX + gap, y + gap); } }