char* showBody(const Body* p)
{
    char* buf;
    char* vel;
    char* pos;

    if (!p)
        return NULL;

    vel = showVector(Vel(p));
    pos = showVector(Pos(p));

    if (0 > asprintf(&buf,
                     "body { \n"
                     "      mass     = %g\n"
                     "      position = %s\n"
                     "      velocity = %s\n"
                     "      ignore   = %s\n"
                     "    };\n",
                     Mass(p),
                     pos,
                     vel,
                     showBool(ignoreBody(p))))

    {
        mw_fail("asprintf() failed\n");
    }

    free(vel);
    free(pos);

    return buf;
}
void updateDisplayedBodies(NBodyState* st)
{
    const Body* b;
    FloatPos* r;
    unsigned int i = 0;
    const unsigned int nbody = st->nbody;
    scene_t* scene = st->scene;

    if (!scene)
        return;

    r = scene->r;
    scene->usleepcount += scene->usleepdt;
    scene->info.currentTime = (float) st->tnow;

    /* Read data if not paused. No copying when no screensaver attached */
    if (scene->attached && scene->usleepcount >= scene->dt && (!scene->paused || scene->step))
    {
        scene->usleepcount = 0.0;
        scene->step = FALSE;

      #ifdef _OPENMP
        #pragma omp parallel for private(i, b) schedule(static)
      #endif
        for (i = 0; i < nbody; ++i)
        {
            b = &st->bodytab[i];
            r[i].x = (float) X(Pos(b));
            r[i].y = (float) Y(Pos(b));
            r[i].z = (float) Z(Pos(b));
            r[i].ignore = ignoreBody(b);
        }

        nbodyGraphicsSetOff(&scene->attached);
    }

    scene->changed = TRUE;
}
/* output: Print bodies */
static int nbOutputBodies(FILE* f, const NBodyCtx* ctx, const NBodyState* st, const NBodyFlags* nbf)
{
    Body* p;
    mwvector lbr;
    const Body* endp = st->bodytab + st->nbody;

    nbPrintBodyOutputHeader(f, nbf->outputCartesian);

    for (p = st->bodytab; p < endp; p++)
    {
        fprintf(f, "%8d,", ignoreBody(p));  /* Print if model it belongs to is ignored */
        if (nbf->outputCartesian)
        {
            fprintf(f,
                    " %22.15f, %22.15f, %22.15f, %22.15f, %22.15f, %22.15f\n",
                    X(Pos(p)), Y(Pos(p)), Z(Pos(p)),
                    X(Vel(p)), Y(Vel(p)), Z(Vel(p)));
        }
        else
        {
            lbr = cartesianToLbr(Pos(p), ctx->sunGCDist);
            fprintf(f,
                    " %22.15f, %22.15f, %22.15f, %22.15f, %22.15f, %22.15f\n",
                    L(lbr), B(lbr), R(lbr),
                    X(Vel(p)), Y(Vel(p)), Z(Vel(p)));
        }
    }

    if (fflush(f))
    {
        mwPerror("Body output flush");
        return TRUE;
    }

    return FALSE;
}
void nbUpdateDisplayedBodies(const NBodyCtx* ctx, NBodyState* st)
{
    const Body* b;
    int i = 0;
    const int nbody = st->nbody;
    scene_t* scene = st->scene;
    FloatPos* r;
    mwvector cmPos;

    if (!scene)
        return;

    r = scene->rTrace;
    if (!st->usesExact)
    {
        cmPos = Pos(st->tree.root);

        scene->usleepcount += scene->usleepdt;
        scene->info.currentTime = (float) st->step * ctx->timestep;
        scene->rootCenterOfMass[0] = (float) X(cmPos);
        scene->rootCenterOfMass[1] = (float) Y(cmPos);
        scene->rootCenterOfMass[2] = (float) Z(cmPos);

        /* Tell the graphics about the orbit's history */
        i = scene->currentTracePoint;
        if (i < N_ORBIT_TRACE_POINTS && i < MAX_DRAW_TRACE_POINTS)
        {
            if (X(st->orbitTrace[i]) < REAL_MAX)
            {
                scene->orbitTrace[i].x = (float) X(st->orbitTrace[i]);
                scene->orbitTrace[i].y = (float) Y(st->orbitTrace[i]);
                scene->orbitTrace[i].z = (float) Z(st->orbitTrace[i]);

                scene->currentTracePoint++;
            }
        }
    }

    /* Read data if not paused. No copying when no screensaver attached */
    if (scene->attached && scene->usleepcount >= scene->dt && (!scene->paused || scene->step))
    {
        scene->usleepcount = 0.0;
        scene->step = FALSE;

      #ifdef _OPENMP
        #pragma omp parallel for private(i, b) schedule(static)
      #endif
        for (i = 0; i < nbody; ++i)
        {
            b = &st->bodytab[i];
            r[i].x = (float) X(Pos(b));
            r[i].y = (float) Y(Pos(b));
            r[i].z = (float) Z(Pos(b));
            r[i].ignore = ignoreBody(b);
        }

        nbodyGraphicsSetOff(&scene->attached);
    }

    scene->changed = TRUE;
}