/*
 *  $Id: volumize.c 29972 2026-05-21 17:17:25Z yeti-dn $
 *  Copyright (C) 2015-2016 David Necas (Yeti), Petr Klapetek.
 *  E-mail: yeti@gwyddion.net, klapetek@gwyddion.net.
 *
 *  This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
 *  License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any
 *  later version.
 *
 *  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 *  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 *  details.
 *
 *  You should have received a copy of the GNU General Public License along with this program; if not, write to the
 *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "config.h"
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
#include <gwy.h>

#define RUN_MODES (GWY_RUN_IMMEDIATE)
#define MAXPIX 600

static gboolean  module_register        (void);
static void      module_main            (GwyFile *data,
                                         GwyRunModeFlags mode);
static GwyBrick* create_brick_from_field(GwyField *dfield);

static GwyModuleInfo module_info = {
    GWY_MODULE_ABI_VERSION,
    &module_register,
    N_("Converts field to 3D volume data."),
    "Petr Klapetek <klapetek@gwyddion.net>",
    "1.2",
    "David Nečas (Yeti) & Petr Klapetek",
    "2013",
};

GWY_MODULE_QUERY2(module_info, volumize)

static gboolean
module_register(void)
{
    gwy_image_func_register("volumize",
                            module_main,
                            N_("/_Basic Operations/Volumize"),
                            GWY_ICON_VOLUMIZE,
                            RUN_MODES,
                            GWY_MENU_FLAG_IMAGE,
                            N_("Convert field to 3D data"));

    return TRUE;
}

static void
module_main(GwyFile *data, GwyRunModeFlags mode)
{
    GwyField *dfield = NULL;
    GwyBrick *brick;
    gint newid;

    g_return_if_fail(mode & RUN_MODES);

    gwy_data_browser_get_current(GWY_APP_FIELD, &dfield, 0);

    brick = create_brick_from_field(dfield);
    dfield = gwy_field_copy(dfield);
    gwy_brick_sum_plane(brick, dfield, 0, 0, 0,
                        gwy_brick_get_xres(brick), gwy_brick_get_yres(brick),
                        -1, FALSE);

    newid = gwy_file_add_volume(data, brick, dfield);

    gwy_file_set_visible(data, GWY_FILE_VOLUME, newid, TRUE);
    g_object_unref(brick);
    g_object_unref(dfield);
    gwy_log_add_full(data, GWY_FILE_VOLUME, -1, newid, "image::volumize", NULL);
}

static GwyBrick*
create_brick_from_field(GwyField *dfield)
{
    gint xres, yres, zres;
    gint col, row, lev;
    gdouble ratio, *bdata, *ddata;
    gdouble xreal, yreal, zreal, offset;
    gboolean freeme = FALSE;
    GwyField *lowres;
    GwyBrick *brick;

    xres = gwy_field_get_xres(dfield);
    yres = gwy_field_get_yres(dfield);
    zres = MAX(xres, yres);

    if (xres*yres > MAXPIX*MAXPIX) {
        ratio = (MAXPIX*MAXPIX)/(gdouble)(xres*yres);
        lowres = gwy_field_new_alike(dfield, TRUE);
        gwy_field_assign(lowres, dfield);
        xres *= ratio;
        yres *= ratio;
        freeme = TRUE;
        gwy_field_resample(lowres, xres, yres, GWY_INTERPOLATION_LINEAR);
    }
    else
        lowres = dfield;

    zres = MAX(xres, yres);

    xreal = gwy_field_get_xreal(dfield);
    yreal = gwy_field_get_yreal(dfield);
    offset = gwy_field_min(lowres);
    zreal = gwy_field_max(lowres) - offset;

    brick = gwy_brick_new(xres, yres, zres, xreal, yreal, zreal, TRUE);

    gwy_unit_assign(gwy_brick_get_unit_x(brick), gwy_field_get_unit_xy(dfield));
    gwy_unit_assign(gwy_brick_get_unit_y(brick), gwy_field_get_unit_xy(dfield));
    gwy_unit_assign(gwy_brick_get_unit_z(brick), gwy_field_get_unit_z(dfield));

    ddata = gwy_field_get_data(lowres);
    bdata = gwy_brick_get_data(brick);

    for (lev = 0; lev < zres; lev++) {
        for (row = 0; row < yres; row++) {
            for (col = 0; col < xres; col++) {
                if (ddata[col + xres*row] >= lev*zreal/zres + offset)
                    bdata[col + xres*row + xres*yres*lev] = 1;
            }
        }
    }
    if (freeme)
        g_clear_object(&lowres);

    return brick;
}

/* vim: set cin columns=120 tw=118 et ts=4 sw=4 cino=>1s,e0,n0,f0,{0,}0,^0,\:1s,=0,g1s,h0,t0,+1s,c3,(0,u0 : */
