/*! parse an ADIF record * * the first record found in data is returned as a SQL log record * Designed for WSJTX ADIF ouput, may not work well on more general * ADIF sources. * @todo validate each field and return a bool */ bool ADIFParse::parse(QByteArray data, Qso *qso) { const QByteArray token_names[] = { "CALL", "GRIDSQUARE", "MODE", "QSO_DATE_OFF", "TIME_OFF", "BAND", "FREQ"}; const int n_token_names = 7; // only common and WSJTX modes will be matched const QByteArray mode_name[] = { "AM", "CW", "FM", "SSB", "USB", "LSB", "FT8", "ISCAT", "JT4", "JT9", "JT65", "MSK144", "QRA64", "RTTY"}; const rmode_t modes[] = { RIG_MODE_AM, RIG_MODE_CW, RIG_MODE_FM, RIG_MODE_USB, RIG_MODE_USB, RIG_MODE_LSB, RIG_MODE_RTTY, RIG_MODE_RTTY, RIG_MODE_RTTY, RIG_MODE_RTTY, RIG_MODE_RTTY, RIG_MODE_RTTY, RIG_MODE_RTTY, RIG_MODE_RTTY}; const int n_mode_names=14; // bands are in the same order as in defines.h const QByteArray band_name[]= { "160M", "80M", "40M", "20M", "15M", "10M", "60M", "30M", "17M", "12M", "6M", "2M", "1.25M", "70CM", "33CM", "23CM"}; qso->clear(); data=data.toUpper(); int end=data.indexOf("<EOR>"); int start=data.indexOf("<EOH>"); if (start==-1) { start=0; } else { start+=5; } data=data.mid(start,end-start); QList<QByteArray>elements=data.split('<'); QDateTime time; time.setTimeSpec(Qt::UTC); QByteArray key,val; for (int i=0;i<elements.size();i++) { parseBit(elements.at(i),key,val); for (int j = 0; j < n_token_names; j++) { if (key == token_names[j]) { switch (j) { case 0: // CALL qso->call=val; break; case 1: // GRID qso->exch=val; qso->rcv_exch[0]=val; break; case 2: // MODE { for (int k=0;k<n_mode_names;k++) { if (val==mode_name[k]) { qso->mode=modes[k]; qso->modeType=getModeType(modes[k]); break; } } break; } case 3: // DATE { int y=val.mid(0,4).toInt(); int m=val.mid(4,2).toInt(); int d=val.mid(6,2).toInt(); time.setDate(QDate(y, m, d)); break; } case 4: // TIME { int h=val.mid(0,2).toInt(); int m=val.mid(2,2).toInt(); int s=0; if (val.size()==6) { s=val.mid(4,2).toInt(); } time.setTime(QTime(h,m,s)); break; } case 5: // BAND { for (int k=0;k<N_BANDS;k++) { if (val==band_name[k]) { qso->band=k; break; } } break; } case 6: // FREQ qso->freq=val.toDouble()*1000000; break; } } } } qso->time=time; return true; }
bool Output::draw(cv::Point2f ui_offset) { boost::timer t1; bool window_decorations_on = getSignal("decor"); setSignal("decor", window_decorations_on); bm::setWindowDecorations(display, win, window_decorations_on); VLOG(3) << "decor draw time" << t1.elapsed(); /* XWindowAttributes xwAttr; Status ret = XGetWindowAttributes( display, win, &xwAttr ); int screen_w = xwAttr.width; int screen_h = xwAttr.height; if (ximage) XPutImage(display, win, gc, ximage, 0, 0, 0, 0, screen_w, screen_h); */ XWindowAttributes xwAttr, xwAttr2; // these don't seem to be updating x and y Window toplevel_parent = get_toplevel_parent(display, win); //Status ret = XGetWindowAttributes( display, win, &xwAttr ); // this has the real x and y position Status ret = XGetWindowAttributes( display, toplevel_parent, &xwAttr ); // this holds the 'true' width and height (the inner window not including // gnome decor?) the x and y are relative to the toplevel_parent Status ret2 = XGetWindowAttributes( display, win, &xwAttr2 ); VLOG(6) << name << " top " << xwAttr.x << " " << xwAttr.y << ", " << xwAttr.width << " " << xwAttr.height << " win " << xwAttr2.x << " " << xwAttr2.y << ", " << xwAttr2.width << " " << xwAttr2.height; // TBD the user ought to be able to force x,y,w,h changes // the logic would be that if the window attributes disagree with the last // update, use those, if the getSignal value is different than the old signal, // that means the user wants the window resized int wm_x = xwAttr.x; // + xwAttr2.x; int wm_y = xwAttr.y; // + xwAttr2.y; if ( (x != wm_x) || (y != wm_y) || (w != xwAttr2.width) || (h != xwAttr2.height) ) { // don't do anything, the window is already set properly x = wm_x; y = wm_y; w = xwAttr2.width; h = xwAttr2.height; VLOG(6) << name << " wm changed display " << x << " " << y << ", " << w << " " << h; setSignal("x", x); setSignal("y", y); setSignal("w", w); setSignal("h", h); } else { // see if user changed anything through vimjay interface, // this has lower priority than window manager changes int new_x = getSignal("x"); int new_y = getSignal("y"); int new_w = getSignal("w"); int new_h = getSignal("h"); if ( (x != new_x) || (y != new_y) || (w != new_w) || (h != new_h) ) { VLOG(6) << name << " vimjay changed display " << CLVAL << new_x << " " << new_y << ", " << new_w << " " << new_h << CLNRM << ", old " << CLVAL << x << " " << y << ", " << w << " " << h << CLNRM; //int dx = new_x - x; //int dy = new_y - y; x = new_x; y = new_y; w = new_w; h = new_h; XWindowChanges values; unsigned int value_mask = 0x0; values.x = x; values.y = y; // if the window is crammed against the right border, increasing width // results in shrinking the window which is strange values.width = w; values.height = h; VLOG(6) << values.x << " " << values.y; // TBD test if different { value_mask = CWWidth | CWHeight; value_mask |= CWX | CWY; XConfigureWindow( display, win, value_mask, &values); } // TBD if (win != toplevel_parent) { // TBD hack, the difference between the toplevel window and the // actual one are overcome by giving all of the offset to win zeroing // out the toplevel, when the wm changes the position it all goes to the toplevel. values.x = 0; values.y = 0; value_mask = CWX | CWY; XConfigureWindow( display, toplevel_parent, value_mask, &values); } setSignal("x", x); setSignal("y", y); setSignal("w", w); setSignal("h", h); } // see if vimjay ui change xywh } // xywh changes cv::Mat in = getImage("in"); //if (in.empty()) return true; if (!(in.empty()) && ximage) { // These aren't used, just provided for convenience // and are set here to make sure the user didn't try to override them // (TBD set to be unwriteable when that functionality is supported setSignal("im_w", Config::inst()->im_width); setSignal("im_h", Config::inst()->im_height); VLOG(4) << "attr time" << t1.elapsed(); // TBD is this necessary or does X do it for me if the window is resized? const cv::Size sz = cv::Size(w, h); cv::Mat scaled; if (sz == in.size()) scaled = in.clone(); else cv::resize(in, scaled, sz, 0, 0, getModeType() ); VLOG(5) << "resize time" << t1.elapsed(); XDestroyImage(ximage); ximage = XGetImage(display, DefaultRootWindow(display), 0, 0, w, h, AllPlanes, ZPixmap); VLOG(4) << "get im time" << t1.elapsed(); // this is slow bm::matToXImage(scaled, ximage, win, *display, *screen); VLOG(4) << "matToXImage time" << t1.elapsed(); XPutImage(display, win, gc, ximage, 0, 0, 0, 0, ximage->width, ximage->height); VLOG(3) << "put image time" << t1.elapsed(); } // ximage and input image is valid return ImageNode::draw(ui_offset); }
bool Output::draw(cv::Point2f ui_offset) { boost::timer t1; bool is_valid = false; bool is_dirty = false; const bool window_decorations_on = getSignal("decor", is_valid, is_dirty); if (is_dirty) { setSignal("decor", window_decorations_on); } cv_bridge::CvImage cv_image; cv_image.header.stamp = ros::Time::now(); cv_image.image = getImage("in"); cv_image.encoding = "rgba8"; sensor_msgs::ImagePtr msg = cv_image.toImageMsg(); /* sensor_msgs::CameraInfoPtr camera_info(new sensor_msgs::CameraInfo(camera_info_manager_->getCameraInfo())); camera_info->height = cv_image.image.cols; camera_info->width = cv_image.image.rows; camera_info->header.stamp = cv_image.header.stamp; camera_info->header.seq = seq_++; */ pub_.publish(msg); //, camera_info); ROS_DEBUG_STREAM_COND(log_level > 4, "decor draw time" << t1.elapsed()); #if 0 XWindowAttributes xwAttr, xwAttr2; // these don't seem to be updating x and y // Status ret = XGetWindowAttributes( display, win, &xwAttr ); /* Occasionally getting this error if decorate/undecorate multiple times. I could set own XSetErrorHandler(), and there are suggestions to XSync or X Error of failed request: BadWindow (invalid Window parameter) Major opcode of failed request: 3 (X_GetWindowAttributes) Resource id in failed request: 0x14030e7 Serial number of failed request: 3334 Current serial number in output stream: 3335 [Thread 0x7ffff7f9b7c0 (LWP 4483) exited] [Inferior 1 (process 4483) exited with code 01] * */ // this has the real x and y position, // but does turning off decorations cause this to change? ROS_DEBUG_STREAM_COND(log_level > 2, name << " 1 top " << toplevel_parent); Status ret = XGetWindowAttributes(display, toplevel_parent, &xwAttr); if (ret == 0) { ROS_ERROR_STREAM("bad xgetwindowattributes"); return false; } if (win == toplevel_parent) { xwAttr2 = xwAttr; } else { // this holds the 'true' width and height (the inner window not including // gnome decor?) the x and y are relative to the toplevel_parent ROS_DEBUG_STREAM_COND(log_level > 2, name << " 2 win " << win); Status ret2 = XGetWindowAttributes(display, win, &xwAttr2); if (ret2 == 0) { ROS_ERROR_STREAM("bad xgetwindowattributes"); return false; } } ROS_DEBUG_STREAM_COND(log_level > 6, name << " top " << xwAttr.x << " " << xwAttr.y << ", " << xwAttr.width << " " << xwAttr.height << " win " << xwAttr2.x << " " << xwAttr2.y << ", " << xwAttr2.width << " " << xwAttr2.height); // TBD the user ought to be able to force x,y,w,h changes // the logic would be that if the window attributes disagree with the last // update, use those, if the getSignal value is different than the old signal, // that means the user wants the window resized int wm_x = xwAttr.x; // + xwAttr2.x; int wm_y = xwAttr.y; // + xwAttr2.y; if ( (x != wm_x) || (y != wm_y) || (w != xwAttr2.width) || (h != xwAttr2.height) ) { // don't do anything, the window is already set properly x = wm_x; y = wm_y; w = xwAttr2.width; h = xwAttr2.height; ROS_DEBUG_STREAM_COND(log_level > 2, name << " wm changed display " << x << " " << y << ", " << w << " " << h); setSignal("x", x); setSignal("y", y); setSignal("w", w); setSignal("h", h); } else { // see if user changed anything through vimjay interface, // this has lower priority than window manager changes int new_x = getSignal("x"); int new_y = getSignal("y"); int new_w = getSignal("w"); int new_h = getSignal("h"); if ( (x != new_x) || (y != new_y) || (w != new_w) || (h != new_h) ) { ROS_DEBUG_STREAM_COND(log_level > 2, name << " vimjay changed display " << CLVAL << new_x << " " << new_y << ", " << new_w << " " << new_h << CLNRM << ", old " << CLVAL << x << " " << y << ", " << w << " " << h << CLNRM); // int dx = new_x - x; // int dy = new_y - y; x = new_x; y = new_y; w = new_w; h = new_h; XWindowChanges values; unsigned int value_mask = 0x0; values.x = x; values.y = y; // if the window is crammed against the right border, increasing width // results in shrinking the window which is strange values.width = w; values.height = h; ROS_DEBUG_STREAM_COND(log_level > 6, values.x << " " << values.y); // TBD test if different { value_mask = CWWidth | CWHeight; value_mask |= CWX | CWY; XConfigureWindow(display, win, value_mask, &values); } // TBD if (win != toplevel_parent) { // TBD hack, the difference between the toplevel window and the // actual one are overcome by giving all of the offset to win zeroing // out the toplevel, when the wm changes the position it all goes to the toplevel. values.x = 0; values.y = 0; value_mask = CWX | CWY; XConfigureWindow(display, toplevel_parent, value_mask, &values); } setSignal("x", x); setSignal("y", y); setSignal("w", w); setSignal("h", h); } // see if vimjay ui change xywh } // xywh changes cv::Mat in = getImage("in"); // if (in.empty()) return true; if (!(in.empty()) && ximage) { // These aren't used, just provided for convenience // and are set here to make sure the user didn't try to override them // (TBD set to be unwriteable when that functionality is supported setSignal("im_w", Config::inst()->im_width); setSignal("im_h", Config::inst()->im_height); ROS_DEBUG_STREAM_COND(log_level > 5, "attr time" << t1.elapsed()); // TBD is this necessary or does X do it for me if the window is resized? const cv::Size sz = cv::Size(w, h); cv::Mat scaled; if (sz == in.size()) scaled = in.clone(); else cv::resize(in, scaled, sz, 0, 0, getModeType()); ROS_DEBUG_STREAM_COND(log_level > 6, "resize time" << t1.elapsed()); XDestroyImage(ximage); ximage = XGetImage(display, DefaultRootWindow(display), 0, 0, w, h, AllPlanes, ZPixmap); ROS_DEBUG_STREAM_COND(log_level > 5, "get im time" << t1.elapsed()); // this is slow bm::matToXImage(scaled, ximage, win, *display, *screen); ROS_DEBUG_STREAM_COND(log_level > 5, "matToXImage time" << t1.elapsed()); XPutImage(display, win, gc, ximage, 0, 0, 0, 0, ximage->width, ximage->height); ROS_DEBUG_STREAM_COND(log_level > 4, "put image time" << t1.elapsed()); } // ximage and input image is valid #endif return ImageNode::draw(ui_offset); }
bool ContourFlip::update() { //if (!ImageNode::update()) return false; if (!Contour::update()) return false; // TBD get dirtiness of in to see if flip map needs to be recomputed if (!isDirty(this, 23)) { return true;} cv::Mat to_flip = getImage("to_flip"); if (to_flip.empty()) { VLOG(2) << name << " in is empty"; return false; } cv::Mat flipped = cv::Mat(to_flip.size(), to_flip.type()); bool valid; bool is_dirty; cv::Mat in = getImage("in", valid, is_dirty, 51); if (is_dirty) { LOG(INFO) << "contour flip updating " << is_dirty; cv::Mat dist = cv::Mat(to_flip.size(), to_flip.type()); const int wd = dist.cols; const int ht = dist.rows; // This is very slow for dense contours, maybe make // scale option that will process the image at a lower resolution // then upscale the off_x,off_y for the remap for (int y = 0; y < ht; y++) { for (int x = 0; x < wd; x++) { float min_dist = 1e9; cv::Point2f min_closest; int count = 0; // TBD just find the nearest contour point for now, don't worry about long segment // or the actual normal of the segment - just flip the pixel on the nearest point for (int i = 0; i < contours0.size(); i++) { for (int j = 0; j < contours0[i].size(); j++) { cv::Point2f v = contours0[i][j]; cv::Point2f w = contours0[i][ (j+1) % contours0[i].size() ]; //const float dx = (contours0[i][j].x - x); //const float dy = (contours0[i][j].y - y); //const float cur_dist = fabs(dx) + fabs(dy); //const float cur_dist = sqrt(dx*dx + dy*dy); cv::Point2f closest; const float cur_dist = minimum_distance( v, w, cv::Point2f(x, y), closest ); if (cur_dist < min_dist) { min_dist = cur_dist; min_closest = closest; } count++; }} if ( (x == 0) && ( y == 0) ) setSignal("count", count); // TBD make a reflection effect instead of straight rolling over the edges? const int src_x = ((x + (int) ( 2 * (min_closest.x - x) ) ) + wd) % wd; const int src_y = ((y + (int) ( 2 * (min_closest.y - y) ) ) + ht) % ht; // TBD this could be a map for remap and if the in image doesn't change it will // be more efficient //flipped.at<cv::Vec4b>(y, x) = to_flip.at<cv::Vec4b>(src_y, src_x); off_x.at<float>(y, x) = src_x - x; off_y.at<float>(y, x) = src_y - y; //LOG_FIRST_N(INFO,20) << src_x << " " << x << ", " << src_y << " " << y; dist.at<cv::Vec4b>(y, x) = cv::Scalar::all(min_dist); // % 255); }} cv::Mat dist_x = base_x + (off_x); //_scaled - offsetx * scalex); cv::Mat dist_y = base_y + (off_y); //_scaled - offsety * scaley); cv::convertMaps(dist_x, dist_y, dist_xy16, dist_int, CV_16SC2, true); setImage("dist", dist); { cv::Mat dist_xy8; cv::Mat dist_xy16_temp; cv::convertMaps(off_x, off_y, dist_xy16_temp, dist_int, CV_16SC2, true); dist_xy16_temp.convertTo(dist_xy8, CV_8UC2, getSignal("map_scale")); cv::Mat mapx = cv::Mat( Config::inst()->getImSize(), CV_8UC4, cv::Scalar(0,0,0,0)); cv::Mat mapy = cv::Mat( Config::inst()->getImSize(), CV_8UC4, cv::Scalar(0,0,0,0)); int chx[] = {0,0, 0,1, 0,2}; mixChannels(&dist_xy8, 1, &mapx, 1, chx, 3 ); int chy[] = {1,0, 1,1, 1,2}; mixChannels(&dist_xy8, 1, &mapy, 1, chy, 3 ); setImage("mapx", mapx); setImage("mapy", mapy); } } if (!dist_xy16.empty()) cv::remap(to_flip, flipped, dist_xy16, cv::Mat(), getModeType(), getBorderType()); setImage("flipped", flipped); return true; }