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.
Related
When running the simulation in omnet++ 5.7 the execution stops suddenly and closes.
This is the code that is being run in omnet
auto simulation = getSimulation();
for (i = 1; i <= simulation->getLastComponentId(); i++) {
int x, y, id;
//scan the simulation module vector
mod = (cModule*)simulation->getModule(i);
if (strcmp(mod->getName(), "node") == 0) {
id = ((Node*)mod)->myId;
x = ((Node*)mod)->xpos;
y = ((Node*)mod)->ypos;
nodePtr[id] = ((Node*)mod);
if (id != this->myId) {
cGate* g;
char gName1[32], gName2[32];
// make new gate here
if (this->hasGate(gName1)) {
this->gate(gName1)->disconnect();
this->deleteGate(gName1);
}
this->addGate(gName1, cGate::OUTPUT, false);
// make new gate at other side
if (mod->hasGate(gName2)) {
mod->gate(gName2)->disconnect();
mod->deleteGate(gName2);
}
mod->addGate(gName2, omnetpp::cGate::INPUT, false);
//CHANNEL
cIdealChannel* ch = NULL;
this->gate(gName1)->connectTo(mod->gate(gName2), ch);
g = this->gate(gName1);
g->setDisplayString(g->getDisplayString());
}
}
}
I assume that the last line g->setDisplayString(g->getDisplayString()); is probably where the code breaks. The code repeats in the for loop with i<= simulation->getLastComponentId(). I'm new to Omnet++. Any suggestion to fix this would be helpful.
Thanks.
Several things in your code may be source of crashing:
getModule(i) may return nullptr, see OMNeT++ Simulation API, so you should check in the code whether result is not nullptr.
gName1 and gName2 are not set!
Other issues:
instead of (Node*)mod use dynamic_cast<Node*)>(mod) and check whether results is not nullptr.
instead of strcmp(mod->getName(), "node") == 0 I advice using mod->isName("node") - see OMNeT++ Simulation API
if you want to obtain a module whose name is "node", you do not need to manually check the name of every module - there is a useful method getModuleByPath() see OMNeT++ Simulation Manual
I am trying to come up with a "minimal" way of running a graph slam application using MRPT. The sensor data (LaserScan / Odometry) will be provided by a custom middleware similiar to ROS. After reading docs and source codes (both for the MRPT and the ROS bridge) extensively, I came up with the following snippet:
std::string config_file = "../../../laser_odometry.ini";
std::string rawlog_fname = "";
std::string fname_GT = "";
auto node_reg = mrpt::graphslam::deciders::CICPCriteriaNRD<mrpt::graphs::CNetworkOfPoses2DInf>{};
auto edge_reg = mrpt::graphslam::deciders::CICPCriteriaERD<mrpt::graphs::CNetworkOfPoses2DInf>{};
auto optimizer = mrpt::graphslam::optimizers::CLevMarqGSO<mrpt::graphs::CNetworkOfPoses2DInf>{};
auto win3d = mrpt::gui::CDisplayWindow3D{"Slam", 800, 600};
auto win_observer = mrpt::graphslam::CWindowObserver{};
auto win_manager = mrpt::graphslam::CWindowManager{&win3d, &win_observer};
auto engine = mrpt::graphslam::CGraphSlamEngine<mrpt::graphs::CNetworkOfPoses2DInf>{
config_file, rawlog_fname, fname_GT, &win_manager, &node_reg, &edge_reg, &optimizer};
for (size_t measurement_count = 0;;) {
// grab laser scan from the network, then fill it (hardcoded values for now), e.g:
auto scan_ptr = mrpt::obs::CObservation2DRangeScan::Create();
scan_ptr->timestamp = std::chrono::system_clock::now().time_since_epoch().count();
scan_ptr->rightToLeft = true;
scan_ptr->sensorLabel = "";
scan_ptr->aperture = 3.14; // rad (max-min)
scan_ptr->maxRange = 3.0; // m
scan_ptr->sensorPose = mrpt::poses::CPose3D{};
scan_ptr->resizeScan(30);
for (int i = 0; i < 30; ++i) {
scan_ptr->setScanRange(i, 0.5);
scan_ptr->setScanRangeValidity(i, true);
}
{ // Send LaserScan measurement to the slam engine
auto obs_ptr = std::dynamic_pointer_cast<mrpt::obs::CObservation>(scan_ptr);
engine.execGraphSlamStep(obs_ptr, measurement_count);
++measurement_count;
}
// grab odometry from the network, then fill it (hardcoded values for now), e.g:
auto odometry_ptr = mrpt::obs::CObservationOdometry::Create();
odometry_ptr->timestamp = std::chrono::system_clock::now().time_since_epoch().count();
odometry_ptr->hasVelocities = false;
odometry_ptr->odometry.x(0);
odometry_ptr->odometry.y(0);
odometry_ptr->odometry.phi(0);
{ // Send Odometry measurement to the slam engine
auto obs_ptr = std::dynamic_pointer_cast<mrpt::obs::CObservation>(odometry_ptr);
engine.execGraphSlamStep(obs_ptr, measurement_count);
++measurement_count;
}
// Get pose estimation from the engine
auto pose = engine.getCurrentRobotPosEstimation();
}
Am I in the right direction here? Did I miss something?
Hmm, at a first look the script seems fine, you are providing odometry and the laser scan in two different steps and in Observation form.
Minor note
auto node_reg = mrpt::graphslam::deciders::CICPCriteriaNRD{};
If you want to run with Odometry + laser scans use CFixedIntervalsNRD instead. It's much better tested and actually makes use of those measurements.
There is no minimal graphslam-engine example at present in MRPT but here's here's the main method for running graph-slam with datasets:
https://github.com/MRPT/mrpt/blob/26ee0f2d3a9366c50faa5f78d0388476ae886808/libs/graphslam/include/mrpt/graphslam/apps_related/CGraphSlamHandler_impl.h#L395
template <class GRAPH_T>
void CGraphSlamHandler<GRAPH_T>::execute()
{
using namespace mrpt::obs;
ASSERTDEB_(m_engine);
// Variables initialization
mrpt::io::CFileGZInputStream rawlog_stream(m_rawlog_fname);
CActionCollection::Ptr action;
CSensoryFrame::Ptr observations;
CObservation::Ptr observation;
size_t curr_rawlog_entry;
auto arch = mrpt::serialization::archiveFrom(rawlog_stream);
// Read the dataset and pass the measurements to CGraphSlamEngine
bool cont_exec = true;
while (CRawlog::getActionObservationPairOrObservation(
arch, action, observations, observation, curr_rawlog_entry) &&
cont_exec)
{
// actual call to the graphSLAM execution method
// Exit if user pressed C-c
cont_exec = m_engine->_execGraphSlamStep(
action, observations, observation, curr_rawlog_entry);
}
m_logger->logFmt(mrpt::system::LVL_WARN, "Finished graphslam execution.");
}
You basically grab the data and then continuously feed them to CGraphSlamEngine via either execGraphSlamStep or _execGraphSlamStep methods.
Here's also the relevant snippet for processing measurements in the corresponding ROS wrapper that operates with measurements from ROS topics:
https://github.com/mrpt-ros-pkg/mrpt_slam/blob/8b32136e2a381b1759eb12458b4adba65e2335da/mrpt_graphslam_2d/include/mrpt_graphslam_2d/CGraphSlamHandler_ROS_impl.h#L719
template<class GRAPH_T>
void CGraphSlamHandler_ROS<GRAPH_T>::processObservation(
mrpt::obs::CObservation::Ptr& observ) {
this->_process(observ);
}
template<class GRAPH_T>
void CGraphSlamHandler_ROS<GRAPH_T>::_process(
mrpt::obs::CObservation::Ptr& observ) {
using namespace mrpt::utils;
if (!this->m_engine->isPaused()) {
this->m_engine->execGraphSlamStep(observ, m_measurement_cnt);
m_measurement_cnt++;
}
}
I'm having problem with the strings in cocos2dx & C++. I want to pass the variable background to Sprite::create(background) however, I get an error. If it was in java the following code will work, but since I'm not used to C++ it may be different. Plus, if it was a int how will I pass it ? How will I be able to solve this? Some tips or samples will be great! I will love to hear from you!
void GameLayer::initBackground()
{
UserDefault *_userDef = UserDefault::getInstance();
//int型
auto _int =_userDef->getIntegerForKey("back");
auto string background = "Background1.png";
if (_int == 0) {
background = "Background2.png";
}
auto bgForCharacter = Sprite::create(background);
bgForCharacter->setAnchorPoint(Point(0, 1));
bgForCharacter->setPosition(Point(0, WINSIZE.height));
addChild(bgForCharacter, ZOrder::BgForCharacter);
auto bgForPuzzle = Sprite::create("Background2.png");
bgForPuzzle->setAnchorPoint(Point::ZERO);
bgForPuzzle->setPosition(Point::ZERO);
addChild(bgForPuzzle, ZOrder::BgForPuzzle);
}
auto userDefault=UserDefault::getInstance();
int value=userDefault->getIntegerForKey("back"); //find value for back if exist then it return that value else return 0
auto sprite = Sprite::create(value==0?"Background2.png":"Background1.png");
sprite->setPosition(100, 100);
this->addChild(sprite, 0);
When you want to change your background just put any value rather than 0
UserDefault::getInstance()->setIntegerForKey("back", 1);
I recently purchased a delta 3d printer kit that uses the marlin software, MKS mini (kossel) main board (uses Arduino bootloader & Marlin Firmware), and reprapdiscount smart controller LCD display (4 rows x 20 characters).
I have almost zero programming experience, and I would like some help to create a "splash screen" that is called on boot only, then goes back to the status screen after a certain time. I have already scoured the internet on how to do this, but the only ones that had any viable options were for the FULL GRAPHICS version LCD display - which is not what I have. I have found the .cpp file used for this specific LCD display - however with my limited programming knowledge, I cannot figure out how to add a splash screen on start.
I'm pretty sure that I have to create a void function at the beginning of the menu implementation (see below), but i'm not sure what / how to call it so that it starts first, then switches to the status screen afterwards. I can write the pseudo code for it, but don't know the full code...
side-note: I just realized that in the menu items, it shows the reference variable of the text, which is actually contained in another file called language.h
PSEUDO CODE of what I would like it to do:
//start->boot printer
static void splashscreen()
{
/*splashlines are defined in language.h file*/
static void splashline1(); // hello
static void splashline2(); // world
static void splashline3(); // i'm
static void splashline4(); // here!
wait 3 seconds;
switch to -> static void lcd_status_screen();
}
Any help would be greatly appreciated!
Unfortunately the post is limited to 30,000 characters, and posting the original code will put me at over 50,000... so I will try to post
relevant code snippets:
THANKS IN ADVANCE!!
EDITED
~ LCD status screen code ~
#ifdef ULTIPANEL
static float manual_feedrate[] = MANUAL_FEEDRATE;
#endif // ULTIPANEL
/* !Configuration settings */
//Function pointer to menu functions.
typedef void (*menuFunc_t)();
uint8_t lcd_status_message_level;
char lcd_status_message[LCD_WIDTH+1] = WELCOME_MSG;
/** forward declerations **/
void copy_and_scalePID_i();
void copy_and_scalePID_d();
/* Different menus */
static void lcd_status_screen();
#ifdef ULTIPANEL
extern bool powersupply;
static void lcd_main_menu();
static void lcd_tune_menu();
static void lcd_prepare_menu();
static void lcd_move_menu();
static void lcd_control_menu();
static void lcd_control_temperature_menu();
static void lcd_control_temperature_preheat_pla_settings_menu();
static void lcd_control_temperature_preheat_abs_settings_menu();
static void lcd_control_motion_menu();
~ EDITED Start of coding ~
menuFunc_t currentMenu = lcd_status_screen; /* function pointer to the currently active menu */
uint32_t lcd_next_update_millis;
uint8_t lcd_status_update_delay;
uint8_t lcdDrawUpdate = 2; /* Set to none-zero when the LCD needs to draw, decreased after every draw. Set to 2 in LCD routines so the LCD gets atleast 1 full redraw (first redraw is partial) */
//prevMenu and prevEncoderPosition are used to store the previous menu location when editing settings.
menuFunc_t prevMenu = NULL;
uint16_t prevEncoderPosition;
//Variables used when editing values.
const char* editLabel;
void* editValue;
int32_t minEditValue, maxEditValue;
menuFunc_t callbackFunc;
// placeholders for Ki and Kd edits
float raw_Ki, raw_Kd;
/* Main status screen. It's up to the implementation specific part to show what is needed. As this is very display dependend */
static void lcd_status_screen()
{
if (lcd_status_update_delay)
lcd_status_update_delay--;
else
lcdDrawUpdate = 1;
if (lcdDrawUpdate)
{
lcd_implementation_status_screen();
lcd_status_update_delay = 10; /* redraw the main screen every second. This is easier then trying keep track of all things that change on the screen */
}
#ifdef ULTIPANEL
if (LCD_CLICKED)
{
currentMenu = lcd_main_menu;
encoderPosition = 0;
lcd_quick_feedback();
}
// Dead zone at 100% feedrate
if ((feedmultiply < 100 && (feedmultiply + int(encoderPosition)) > 100) ||
(feedmultiply > 100 && (feedmultiply + int(encoderPosition)) < 100))
{
encoderPosition = 0;
feedmultiply = 100;
}
if (feedmultiply == 100 && int(encoderPosition) > ENCODER_FEEDRATE_DEADZONE)
{
feedmultiply += int(encoderPosition) - ENCODER_FEEDRATE_DEADZONE;
encoderPosition = 0;
}
else if (feedmultiply == 100 && int(encoderPosition) < -ENCODER_FEEDRATE_DEADZONE)
{
feedmultiply += int(encoderPosition) + ENCODER_FEEDRATE_DEADZONE;
encoderPosition = 0;
}
else if (feedmultiply != 100)
{
feedmultiply += int(encoderPosition);
encoderPosition = 0;
}
if (feedmultiply < 10)
feedmultiply = 10;
if (feedmultiply > 999)
feedmultiply = 999;
#endif//ULTIPANEL
}
As Joel Cornett suggested, look up the gaps in knowledge and ask specifically about those gaps. In that case, it seems what you need is the following:
How to code a timed pause for the "splash" to display.
Where to initialize the code you want (I think you may have overlooked it, as I don't think see it in the code you posted).
How to make the code proceed to the status screen without looping on itself.
Try to edit your post / split your questions into individual posts. You may get a better response rate from that.
How should one create an interface for tweening something using C++? For instance, I want to fade a picture in over a duration of five seconds using a static function call like:
Graphics::FadeSurface( Surface mySurface, int FrameHeight, int NumOfFrames,
int FadeDirection, double Duration )
I have a hard-coded setup that creates an object for each tween action that needs to be performed. I have been using a DeltaTime variable that keeps track of how much time has passed since the program has launched to control logic and such. I've included an example (much less refined) to show you kind of what I'm trying to do:
Example Logic Loop:
gameLoop( double DeltaTime ){
// ...
// logic
// ...
bool isItDone = otherClass.HaveFiveSecondsElapsed( double DeltaTime );
if( isItDone == true )
exit(1);
// ...
// logic
// ...
}
Example Tweening Class:
other_Class::other_Class(){
InitialTime = 0;
InitialTime_isSet = false;
}
bool other_class::HaveFiveSecondsElapsed( double DeltaTime ){
// Setting InitialTime if it hasn't already been set
if( otherClass.InitialTime_isSet == false ){
otherClass.InitialTime = DeltaTime;
otherClass.InitialTime_isSet = true;
}
bool toReturn = false;
if( DeltaTime - InitialTime > 5 )
toReturn = true;
return toReturn;
}
Any help is greatly appreciated. Thanks!
I built a Tween engine for java that is generic enough to be used to tween any attribute of any object. The generic part is done through the definition of a "Tweenable" interface that users need to implement to tween their objects.
I greatly encourage you to use it as inspiration to build your engine, or directly port it. I can also plan a home-made port to C++, but it would be quite a lot of work to maintain it up-to-date with the current java version (which grows very fast).
http://code.google.com/p/java-universal-tween-engine/
NB: I made a more elaborated answer about this engine in this question:
Android: tween animation of a bitmap