I am trying to generate bar graph using JSON Data which i am getting from Web-services, basically my requirement is to show a "Bar Graph" using "JSON" data.
Basically I am Android Developer and very new to Blackberry 10 Native, so i don't know much about Blackberry, So If any one can guide me regarding generating graph in Blackberry-10.
I have searched a lot in google and every where else where i can, but i didn't come with any conclusion. Still i am searching a solution for it, So basically my "JSON" data is in following format.
{"Ax":"3:41","Ay":"04:41","Bx":"10:47 ","By":"12:47","Cx":"18:30","Cy":"19:30","Az":3,"Bz":2,"Cz":1,"condition":2}
Here "Ax":"3:41","Ay":"04:41" this is parameter is hour of starting and ending work, and at last it calculates the total number of hour like "Az":3,"Bz":2,"Cz":1 and generate graph based on that. So similarly my graph would look something like this
http://postimg.org/image/nb6dnpwax/
Please help me how can i generate graph based on this, some of the link which i have refered to generate graph is
http://elycharts.com/examples
http://g.raphaeljs.com/
How to make charts/graphs (such as line graphs, bar graphs, circle graphs), etc. in C++, Qt, QML, Blackberry 10 Cascades Beta 3 SDK?
http://devblog.blackberry.com/2014/01/conference-app-secrets-part-3-json-vs-xml/
One thing i am clearly mentioning is i want solution using qml and C++ way with Blackberry-10 so please do not suggest any other method like Java and other all.
Thank you in advance for helping me out.
So there is this article on BlackBerry Support Forums. All the basics are there, but I do so much work with runtime generated images I decided to create a class to encapsulate it. As requested here is a simple sample based on one of the Cascades templates. You should also become familiar with the documentation at:
http://qt-project.org/doc/qt-4.8/
https://developer.blackberry.com/native/documentation/cascades/
And the sample files at the BlackBerry GIT Hub.
QML file:
/*
* Copyright (c) 2011-2014 BlackBerry Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import bb.cascades 1.2
Page {
Container {
layout: DockLayout {
}
Label {
// Localized text with the dynamic translation and locale updates support
text: qsTr("Bar Graph") + Retranslate.onLocaleOrLanguageChanged
textStyle.base: SystemDefaults.TextStyles.BigText
horizontalAlignment: HorizontalAlignment.Center
}
ImageView {
objectName: "barGraph"
verticalAlignment: VerticalAlignment.Center
horizontalAlignment: HorizontalAlignment.Center
}
}
}
Here is the header file:
/*
* DrawableImage.hpp
*
* Created on: Jul 11, 2014
* Author: richard
*/
#ifndef DRAWABLEIMAGE_HPP_
#define DRAWABLEIMAGE_HPP_
#include <bb/ImageData>
#include <QtGui/QImage>
#include <bb/cascades/ImageView>
namespace net
{
namespace test
{
class DrawableImage : public QImage
{
public:
DrawableImage();
DrawableImage(QSize imageSize, QImage::Format format);
virtual ~DrawableImage();
void emitRenderingBegin();
void emitRenderingFinished();
DrawableImage& operator = (const QImage &image) { QImage::operator =(image); return *this; }
QPainter &painter();
public:
void updateToView(bb::cascades::ImageView *imageView);
private:
void deleteBuffer();
QPainter m_painter;
QSize m_sizeInPixels;
unsigned char* m_buffer; // pixel data in PixelBufferData format
};
} /* namespace test */
} /* namespace net */
#endif /* DRAWABLEIMAGE_HPP_ */
And the cpp file:
/*
* DrawableImage.cpp
*
* Created on: Jul 11, 2014
* Author: richard
*/
#include <src/DrawableImage.hpp>
namespace net
{
namespace test
{
DrawableImage::DrawableImage()
: m_painter(), m_sizeInPixels(0,0), m_buffer(NULL)
{
// TODO Auto-generated constructor stub
}
DrawableImage::DrawableImage(QSize imageSize, QImage::Format format)
: QImage(imageSize, format), m_painter(), m_sizeInPixels(0,0), m_buffer(NULL)
{
}
DrawableImage::~DrawableImage() {
// TODO Auto-generated destructor stub
}
/*
void DrawableImage::emitRenderingBegin() {
emit renderingBegin();
}
void DrawableImage::emitRenderingFinished() {
emit renderingFinished();
}
*/
QPainter& DrawableImage::painter() {
if (!m_painter.isActive()) {
m_painter.begin(this);
}
return m_painter;
}
void DrawableImage::deleteBuffer()
{
if (m_buffer != 0)
{
delete [] m_buffer;
m_buffer = 0;
}
}
void DrawableImage::updateToView(bb::cascades::ImageView *imageView) {
if (m_painter.isActive()) {
m_painter.end();
}
Q_ASSERT(imageView != NULL);
QImage swapped = rgbSwapped();
QSize swappedSize = swapped.size();
int w = swappedSize.width();
int h = swappedSize.height();
int numBytes = w * h * 4;
if (swappedSize != m_sizeInPixels)
{
deleteBuffer();
m_sizeInPixels = QSize(w, h);
m_buffer = new uchar[numBytes];
}
// Copy the memory over.
// We'll add defensive code in case rgbSwapped has a different size
const uchar* from = swapped.constBits();
int numFromBytes = swapped.numBytes();
int numToCopy = std::min(numFromBytes, numBytes);
memcpy(m_buffer, from, numToCopy);
if (numToCopy < numBytes)
{
memset(m_buffer + numToCopy, 0x00, numBytes - numToCopy);
}
bb::ImageData imageData = bb::ImageData::fromPixels(m_buffer, bb::PixelFormat::RGBA_Premultiplied,
m_sizeInPixels.width(),
m_sizeInPixels.height(),
m_sizeInPixels.width() * 4);
imageView->setImage(imageData);
}
} /* namespace test */
} /* namespace net */
And here is the applicationui.cpp (applicationui.hpp is not modified):
/*
* Copyright (c) 2011-2014 BlackBerry Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "applicationui.hpp"
#include <bb/cascades/Application>
#include <bb/cascades/QmlDocument>
#include <bb/cascades/AbstractPane>
#include <bb/cascades/LocaleHandler>
#include <src/DrawableImage.hpp>
using namespace bb::cascades;
using namespace net::test;
ApplicationUI::ApplicationUI() :
QObject()
{
// prepare the localization
m_pTranslator = new QTranslator(this);
m_pLocaleHandler = new LocaleHandler(this);
bool res = QObject::connect(m_pLocaleHandler, SIGNAL(systemLanguageChanged()), this, SLOT(onSystemLanguageChanged()));
// This is only available in Debug builds
Q_ASSERT(res);
// Since the variable is not used in the app, this is added to avoid a
// compiler warning
Q_UNUSED(res);
// initial load
onSystemLanguageChanged();
// Create scene document from main.qml asset, the parent is set
// to ensure the document gets destroyed properly at shut down.
QmlDocument *qml = QmlDocument::create("asset:///main.qml").parent(this);
// Create root object for the UI
AbstractPane *root = qml->createRootObject<AbstractPane>();
/*
* This code exercises the DrawableImage
*/
QSize graphImageSize(700, 700);
DrawableImage graph;
ImageView* graphImageView = root->findChild<ImageView*>("barGraph");
// Initialise graph and fill with transparent black.
graph = QImage(graphImageSize, QImage::Format_ARGB32_Premultiplied);
graph.fill(Qt::black);
// Set the background mode
graph.painter().setBackgroundMode(Qt::TransparentMode);
// Set rendering hints
graph.painter().setRenderHint(QPainter::Antialiasing, true);
for (int i = 0; i < 10; i++) {
int x = i * (graphImageSize.width()/10);
int h = i * (graphImageSize.height()/10) + graphImageSize.height()/20;
int w = graphImageSize.width()/10 - 20;
graph.painter().fillRect( x + 10, graphImageSize.height()-h, w, h, Qt::darkGreen);
}
// Once the image is drawn transfer it to the Cascades ImageView
graph.updateToView(graphImageView);
// Set created root object as the application scene
Application::instance()->setScene(root);
}
void ApplicationUI::onSystemLanguageChanged()
{
QCoreApplication::instance()->removeTranslator(m_pTranslator);
// Initiate, load and install the application translation files.
QString locale_string = QLocale().name();
QString file_name = QString("BarGraph_%1").arg(locale_string);
if (m_pTranslator->load(file_name, "app/native/qm")) {
QCoreApplication::instance()->installTranslator(m_pTranslator);
}
}
You will also need to add a LIBS line to the .pro file:
APP_NAME = BarGraph
CONFIG += qt warn_on cascades10
LIBS += -lbb
include(config.pri)
This is the result:
Related
I am trying to include the C++ library PROJ.4 in my C++ project for manipulating map data. So far I have not been able to make any headway.
I am wondering if there is a good samaritan out there with experience integrating PROJ.4 in their projects on Windows. Do you have a step by step knowledge of how to integrate the source code into your project?
The downloaded file has an "src" folder separate from an "include" folder. Their website says to include the header "proj.h" which is located in the "src" folder. I tried that in a Sandbox to no avail.
I am missing the steps to prepare the source code to integrate in my C++ project. If anyone has gone through the steps from the source code and can walk me through it, I would greatly appreciate it.
#include <stdio.h>
#include <C:\PROJ4\src\proj.h>
int main(void) {
PJ_CONTEXT* C;
PJ* P;
PJ* P_for_GIS;
PJ_COORD a, b;
C = proj_context_create();
P = proj_create_crs_to_crs(C,
"EPSG:4326",
"+proj=utm +zone=32 +datum=WGS84", /* or EPSG:32632 */
NULL);
if (0 == P) {
fprintf(stderr, "Oops\n");
return 1;
}
/* This will ensure that the order of coordinates for the input CRS */
/* will be longitude, latitude, whereas EPSG:4326 mandates latitude, */
/* longitude */
P_for_GIS = proj_normalize_for_visualization(C, P);
if (0 == P_for_GIS) {
fprintf(stderr, "Oops\n");
return 1;
}
proj_destroy(P);
P = P_for_GIS;
/* a coordinate union representing Copenhagen: 55d N, 12d E */
/* Given that we have used proj_normalize_for_visualization(), the order of
/* coordinates is longitude, latitude, and values are expressed in degrees. */
a = proj_coord(12, 55, 0, 0);
/* transform to UTM zone 32, then back to geographical */
b = proj_trans(P, PJ_FWD, a);
printf("easting: %.3f, northing: %.3f\n", b.enu.e, b.enu.n);
b = proj_trans(P, PJ_INV, b);
printf("longitude: %g, latitude: %g\n", b.lp.lam, b.lp.phi);
/* Clean up */
proj_destroy(P);
proj_context_destroy(C); /* may be omitted in the single threaded case */
return 0;
}
I'm learning C# and have some experience with it. For a small project I need to implement a C++ dll into my C# app. It is a licenseplate recognition sdk.I can initialize it, so calling to this C++ code is working. But I have a problem to receive a struct back from the c++ code with strings in it. I tried a lot, read here a lot, but I don't get it working. This is C# side:
[DllImport("D:\\processor.dll", EntryPoint = "StartALPR", CallingConvention = CallingConvention.Cdecl)]
[return:MarshalAs(UnmanagedType.LPStruct)]
public static extern TMyData StartALPR(TImageSource tImageSource);
The C# struct TMyData :
[StructLayout(LayoutKind.Sequential)]
public struct TMyData
{
[MarshalAs(UnmanagedType.LPTStr)]
public string PlateString;
[MarshalAs(UnmanagedType.LPTStr)]
public string PlateXML;
[MarshalAs(UnmanagedType.LPTStr)]
public string LastError;
};
And this is the method we call to send tImageSource which contains a string with a filepath to an image to analyze.
alprResult = StartALPR(tImageSource);
The file is analyzed, so that's working. I can see the plate strings in the output of VS2015.
But I'm expecting a struct "alprResult" back as defined in TMydata, but I get an exception that the method sign is not compatible with the pinvoke sign. The only information I have is an example of how to use this dll/code in C++. This is the C++ code :
TImageSource SImageSource;
TMyData *pd;
/* Set input image */
SImageSource.MyImageFile = AnsiString(CarImage).c_str();
Memo1->Lines->Clear();
/* Starting plate detect and recognition */
pd = StartALPR(&SImageSource);
/* Standard XML result, the plate datas with numbers and positions */
Memo1->Lines->Add(pd->PlateXML);
/* last error message */
Memo2->Lines->Add(pd->LastError);
/* Best characters on plate */
Edit1->Text = pd->PlateString;
This is the C++ struct from the same example :
struct TMyData;
typedef TMyData *PMyData;
struct TMyData
{
/**
PlateString: Best license plate number of the plate group
*/
const char * PlateString;
/**
PlateXML: Plate group data in standard XML string
*/
const char * PlateXML;
/**
LastError: Laast config error ex: bad file extensions .. Default: empty
*/
const char * LastError;
};
How can I use this in C#?
Thanks in advance.
I actually had to solve a similar issue to this recently. I simply serialized the data into a struct and shipped it over a local zeromq socket.
//
// Weather update server in C++
// Binds PUB socket to tcp://*:5556
// Publishes random weather updates
//
// Olivier Chamoux <olivier.chamoux#fr.thalesgroup.com>
//
#include <zmq.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#if (defined (WIN32))
#include <zhelpers.hpp>
#endif
#define within(num) (int) ((float) num * random () / (RAND_MAX + 1.0))
int main () {
// Prepare our context and publisher
zmq::context_t context (1);
zmq::socket_t publisher (context, ZMQ_PUB);
publisher.bind("tcp://*:5556");
publisher.bind("ipc://weather.ipc"); // Not usable on Windows.
// Initialize random number generator
srandom ((unsigned) time (NULL));
while (1) {
int zipcode, temperature, relhumidity;
// Get values that will fool the boss
zipcode = within (100000);
temperature = within (215) - 80;
relhumidity = within (50) + 10;
// Send message to all subscribers
zmq::message_t message(20);
snprintf ((char *) message.data(), 20 ,
"%05d %d %d", zipcode, temperature, relhumidity);
publisher.send(message);
}
return 0;
}
and now the client
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using ZeroMQ;
namespace Examples
{
static partial class Program
{
public static void WUClient(string[] args)
{
//
// Weather update client
// Connects SUB socket to tcp://127.0.0.1:5556
// Collects weather updates and finds avg temp in zipcode
//
// Author: metadings
//
if (args == null || args.Length < 2)
{
Console.WriteLine();
Console.WriteLine("Usage: ./{0} WUClient [ZipCode] [Endpoint]", AppDomain.CurrentDomain.FriendlyName);
Console.WriteLine();
Console.WriteLine(" ZipCode The zip code to subscribe. Default is 72622 Nürtingen");
Console.WriteLine(" Endpoint Where WUClient should connect to.");
Console.WriteLine(" Default is tcp://127.0.0.1:5556");
Console.WriteLine();
if (args.Length < 1)
args = new string[] { "72622", "tcp://127.0.0.1:5556" };
else
args = new string[] { args[0], "tcp://127.0.0.1:5556" };
}
string endpoint = args[1];
// Socket to talk to server
using (var context = new ZContext())
using (var subscriber = new ZSocket(context, ZSocketType.SUB))
{
string connect_to = args[1];
Console.WriteLine("I: Connecting to {0}…", connect_to);
subscriber.Connect(connect_to);
/* foreach (IPAddress address in WUProxy_GetPublicIPs())
{
var epgmAddress = string.Format("epgm://{0};239.192.1.1:8100", address);
Console.WriteLine("I: Connecting to {0}…", epgmAddress);
subscriber.Connect(epgmAddress);
}
} */
// Subscribe to zipcode
string zipCode = args[0];
Console.WriteLine("I: Subscribing to zip code {0}…", zipCode);
subscriber.Subscribe(zipCode);
// Process 10 updates
int i = 0;
long total_temperature = 0;
for (; i < 20; ++i)
{
using (var replyFrame = subscriber.ReceiveFrame())
{
string reply = replyFrame.ReadString();
Console.WriteLine(reply);
total_temperature += Convert.ToInt64(reply.Split(' ')[1]);
}
}
Console.WriteLine("Average temperature for zipcode '{0}' was {1}°", zipCode, (total_temperature / i));
}
}
}
}
I would like to code my own general block with 1 input and 1 output for GNU Radio in C++. I followed the steps in gnuradio.org using gr_modtool. It can works well. But when I connect other block(scope sink2) with the same source there is no output in it.
I connect the flow graph as:
/-> Scope Sink2
Signal Source -> Throttle -|
\-> my own block -> Scope Sink1
I'm using GNU Radio Companion v3.7.6.1-65-g500517ac
I created the block 'energy_de'. This create among other four files:
energy_de.h
#ifndef INCLUDED_CPP_ENERGY_DE_H
#define INCLUDED_CPP_ENERGY_DE_H
#include <cpp/api.h>
#include <gnuradio/block.h>
namespace gr {
namespace cpp {
/*!
* \brief <+description of block+>
* \ingroup cpp
*
*/
class CPP_API energy_de : virtual public gr::block
{
public:
typedef boost::shared_ptr<energy_de> sptr;
/*!
* \brief Return a shared_ptr to a new instance of cpp::energy_de.
*
* To avoid accidental use of raw pointers, cpp::energy_de's
* constructor is in a private implementation
* class. cpp::energy_de::make is the public interface for
* creating new instances.
*/
static sptr make(float makenoise);
virtual float noise () const = 0;
virtual void set_noise (float noise) = 0;
};
} // namespace cpp
} // namespace gr
energy_de_impl.h
#ifndef INCLUDED_CPP_ENERGY_DE_IMPL_H
#define INCLUDED_CPP_ENERGY_DE_IMPL_H
#include <cpp/energy_de.h>
namespace gr {
namespace cpp {
class energy_de_impl : public energy_de
{
private:
float d_noise;
public:
energy_de_impl(float noise);
~energy_de_impl();
// Where all the action really happens
void forecast (int noutput_items, gr_vector_int &ninput_items_required);
float noise() const { return d_noise; }
void set_noise(float noise) { d_noise = noise; }
int general_work(int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
};
} // namespace cpp
} // namespace gr
energy_de_impl.cc
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "energy_de_impl.h"
namespace gr {
namespace cpp {
energy_de::sptr
energy_de::make(float noise)
{
return gnuradio::get_initial_sptr
(new energy_de_impl(noise));
}
/*
* The private constructor
*/
energy_de_impl::energy_de_impl(float noise)
: gr::block("energy_de",
gr::io_signature::make(1, 1, sizeof(float)),
gr::io_signature::make(1, 1, sizeof(float))),
d_noise(noise)
{
}
/*
* Our virtual destructor.
*/
energy_de_impl::~energy_de_impl()
{
}
void
energy_de_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required)
{
ninput_items_required[0] = noutput_items;
}
int
energy_de_impl::general_work (int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
const float *in = (const float *) input_items[0];
float *out = (float *) output_items[0];
for(int i = 0; i < noutput_items; i++){
if (in[i]*in[i] > d_noise){
out[i] = 1.0;
}
else{
out[i] = 0.0;
}
}
return noutput_items;
}
} /* namespace cpp */
} /* namespace gr */
cpp_energy_de.xml
<?xml version="1.0"?>
<block>
<name>energy_de</name>
<key>cpp_energy_de</key>
<category>cpp</category>
<import>import cpp</import>
<make>cpp.energy_de($noise)</make>
<callback>set_niose($noise)</callback>
<param>
<name>noise</name>
<key>noise</key>
<type>float</type>
</param>
<sink>
<name>in</name>
<type>float</type>
</sink>
<source>
<name>out</name>
<type>float</type>
</source>
</block>
Why I cannot get an out put from Scope Sink2? What have I forgotten to write inside the four files? Is this the problem about input_items buffer of my block?
When using a general block rather than a sync_block, your general_work must call consume, indicating how many items you've read, otherwise your own block's input buffer (== throttle's output buffer) quickly fills up, throttle can't put new samples into it and your flow graph halts. At that point, your scope sink might simply not have enough input to show anything.
I think for your use case, just using a sync_block would be much easier, and hence, the correct way to do this.
I'd like to point you to a mail I've written today to the discuss GNU Radio mailing list. It explains the buffer space concepts behind this.
/->A->Null Sink
File Source -|
\->B->File Sink
[...]
So the mechanism below is: the output buffer of File Source is the
input buffer of A and the input buffer of B. No memory duplication
here.
File Source has a buffer writer with a write pointer, and A and B have
their own read pointers pointing into that buffer.
When File Source produces N items, the write pointer advances by N.
Similarly, when A consumes M items, A's read pointer advances by M.
When calling (general_)work, the input_items buffer(s) is (are) really
just a pointer (start_of_buffer + read pointer). Equivalently, the
output_items buffer(s) is (are) really just pointing to the write
pointer.
File Source is only allowed to produce so many items that the write pointer doesn't advance beyond the minimum read pointer, because in that case, it would overwrite samples that a downstream block hasn't consumed.
I'd like to code my own sink block with 1 input port and 0 output ports for GNU Radio in C++. I read and followed the steps described here:
http://gnuradio.org/redmine/projects/gnuradio/wiki/BlocksCodingGuide
http://gnuradio.org/redmine/projects/gnuradio/wiki/OutOfTreeModules
http://gnuradio.org/redmine/projects/gnuradio/wiki/OutOfTreeModulesConfig
http://gnuradio.org/redmine/projects/gnuradio/wiki/Guided_Tutorial_GNU_Radio_in_C++
I'm using
Ubuntu 14.04.3 LTS
Eclipse 4.5.1
CDT 8.8.0.201509131935
GNU Radio 3.7.8
Using gr_modtool I created the new module "jammertrap". Inside it, I created the block "bandpower". This created among others the three files
bandpower.h inside /home/sdr/gnuradio/gr-jammertrap/include/jammertrap/
bandpower_impl.h inside /home/sdr/gnuradio/gr-jammertrap/lib/
bandpower_impl.cc inside /home/sdr/gnuradio/gr-jammertrap/lib/
bandpower.h:
#ifndef INCLUDED_JAMMERTRAP_BANDPOWER_H
#define INCLUDED_JAMMERTRAP_BANDPOWER_H
#include <jammertrap/api.h>
#include <gnuradio/block.h>
namespace gr
{
namespace jammertrap
{
class JAMMERTRAP_API bandpower : virtual public gr::block
{
public:
typedef boost::shared_ptr<bandpower> sptr;
// Return a shared_ptr to a new instance of jammertrap::bandpower.
// To avoid accidental use of raw pointers, jammertrap::bandpower's constructor is in a private implementation class.
// jammertrap::bandpower::make is the public interface for creating new instances.
static sptr make();
};
} // namespace jammertrap
} // namespace gr
#endif /* INCLUDED_JAMMERTRAP_BANDPOWER_H */
bandpower_impl.h:
#ifndef INCLUDED_JAMMERTRAP_BANDPOWER_IMPL_H
#define INCLUDED_JAMMERTRAP_BANDPOWER_IMPL_H
#include <jammertrap/bandpower.h>
namespace gr
{
namespace jammertrap
{
class bandpower_impl : public bandpower
{
private:
double d_bandpower_;
public:
bandpower_impl();
~bandpower_impl();
void forecast (int noutput_items, gr_vector_int &ninput_items_required);
// Where all the action really happens
int general_work(int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items);
// Returns the calculated RMS Bandpower
double get_bandpower();
};
} // namespace jammertrap
} // namespace gr
#endif /* INCLUDED_JAMMERTRAP_BANDPOWER_IMPL_H */
bandpower_impl.cc:
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "bandpower_impl.h"
namespace gr
{
namespace jammertrap
{
bandpower::sptr
bandpower::make()
{
return gnuradio::get_initial_sptr (new bandpower_impl());
}
// The private constructor
bandpower_impl::bandpower_impl() : gr::block("bandpower", gr::io_signature::make(1, 1, sizeof(gr_complex)), gr::io_signature::make(0, 0, 0))
{
d_bandpower_ = 0;
}
// Our virtual destructor
bandpower_impl::~bandpower_impl()
{}
void bandpower_impl::forecast(int noutput_items, gr_vector_int &ninput_items_required)
{
// ninput_items_required[0] = noutput_items;
}
int bandpower_impl::general_work(int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items)
{
const gr_complex *in = (const gr_complex *) input_items[0];
d_bandpower_ = 0;
for(int i = 0; i < noutput_items; i++)
{
d_bandpower_ += (in[i].real() * in[i].real()) + (in[i].imag() * in[i].imag());
}
d_bandpower_ = sqrt(d_bandpower_ / noutput_items);
// Tell runtime system how many input items we consumed on each input stream.
consume_each (noutput_items);
// Tell runtime system how many output items we produced
return noutput_items;
}
double bandpower_impl::get_bandpower()
{
return d_bandpower_;
}
} /* namespace jammertrap */
} /* namespace gr */
To make and install this new block, I entered the following commands inside /home/sdr/gnuradio/gr-jammertrap/build:
cmake ../
make
make test // Result: "test_jammertrap" and "qa_bandpower" passed successful
sudo make install
This sink block "bandpower" should receive items of type gr_complex, compute the average received power and store this value inside the private member "d_bandpower_".
Additional I defined the method "get_bandpower()" to get the stored value.
Inside another program, I created a flowgraph class with the two blocks
osmosdr::source:sptr osmosdr_source_;
gr::jammertrap::bandpower::sptr bandpower_measurement_;
and instanced them with
osmosdr_source_ = osmosdr::source::make(std::string());
bandpower_measurement_ = gr::jammertrap::bandpower::make();
After starting the flowgraph, I want to read the calculated bandpower by calling get_bandpower() but Eclipse shows no method "bandpower_measurement_->get_bandpower()"
What have I forgotten to write inside bandpower.h, bandpower_impl.h or bandpower_impl.cc?
The public API of the normal OOT layout is in the bandpower.h, so you must add a
virtual double get_bandpower() = 0;
in that file.
Then, you overload/implement that, like you do, in the _impl.cc/_impl.h.
By the way, I slightly object the math behind your implementation: as noutput_items, ie. the number of input items available, changes depending on buffer fillage / runtime behaviour, your "averaging length" is not constant, which means that if your flow graph runs fast, your buffers will usually be full, and your averaging length high, whilst in a "trickle" situation, the length will be much smaller (down to noutput_items==1, in extreme cases). Hence, the variance of your power estimator will depend on computational aspects.
That's not a good thing. Better work with a constant number of items you average about. In your case, you can use set_output_multiple (because a sink is also a sync block, this also affects the input multiples) to guarantee you always get a multiple of a fixed number.
Other than that, there's already blocks that can do what you want:
Probe Avg Mag²: has a method level() which does the same as your get_bandpower (aside from the √(.) )
Complex to Mag ⟶ Decimating FIR Filter ⟶ Probe Signal: does the √(Re²+Im²), before passing it on to a filter with 123 (that was just my arbitrary fixed length) taps of 1/length, and decimating it to one value every average. Result get send to the Signal Probe, which has a signal() method, which does what your get_bandpower does. CPU load of this is relatively small -- it's really just the magnitude finding for every sample, and then 123 real multiplications + 123 real additions per 123 samples,in the filter, all SIMD increased, so basically, less than 1 FMAC per sample.
Complex to Mag ⟶ Moving Average ⟶ Probe Signal: Names say it all. Nothing magical here.
I want to ask you guys to help me with creating keyframes in Max SDK C++.
What I've done:
Created a Controller Plugin
Inside the getValue function I've done my translations via code.
I also wrote the setValue function.
Which I think manages keyframes and stores the controllers position in a given time in a given keyframe. In this way I achieved to be able to set keys manually, but I really would like, to work with the Auto Key turned on in Max.
On the other hand, I can't see the freshly added keys values. So please help me, how could I add keyframes?
Many Thanks:
Banderas
void maxProject3::GetValue(TimeValue t, void *ptr, Interval &valid, GetSetMethod method)
{
Point3 p3OurAbsValue(0, 0, 0);
tomb[0]=0;
//These positions stores my data they are globals
XPosition += (accX);
YPosition += (accY);
ZPosition += (accZ);
p3OurAbsValue.x = XPosition;
p3OurAbsValue.y = YPosition;
p3OurAbsValue.z = ZPosition;
valid.Set(t,t+1); //This answer is only valid at the calling time.
MatrixCtrl->GetValue(t, &p3OurAbsValue.y, valid, CTRL_RELATIVE);
if (method == CTRL_ABSOLUTE)
{
Point3* p3InVal = (Point3*)ptr;
*p3InVal = p3OurAbsValue;
}
else // CTRL_RELATIVE
{
//We do our translations on a Matrix
Matrix3* m3InVal = (Matrix3*)ptr;
//m3InVal->PreTranslate(p3OurAbsValue);
m3InVal->PreRotateX(rotX);
m3InVal->PreRotateY(rotY);
m3InVal->PreRotateZ(rotZ);
}
}
int maxProject3::NumSubs() {
return 1;
}
Animatable* maxProject3::SubAnim(int n) {
return MatrixCtrl;
}
void maxProject3::SetValue(TimeValue t, void *ptr, int commit, GetSetMethod method)
{
Matrix3* m3InVal = (Matrix3*)ptr;
MatrixCtrl->AddNewKey(t, ADDKEY_SELECT);
MatrixCtrl->SetValue(t, &m3InVal, commit, CTRL_RELATIVE);
}
To turn on the Auto key mode try using AnimateOn() before your transformation. Also add AnimateOff() to turn off the auto key mode in the end.
I did it in one of my project to create material id animation using auto key mode.
/** Auto key on*/
AnimateOn();
/** Creating material id animation */
for(int mtl_id = 1; mtl_id <= num_sub_mtl; ++mtl_id, time += time_step)
{
mtl_modifier->GetParamBlock()->SetValue(MATMOD_MATID,time,mtl_id);
}
/** Auto key off*/
AnimateOff();
Also as a suggestion, use the max script listener to know whats happening when the animation is created using 3ds Max GUI. This will help you to recreate the animation using Max SDK.