Files
core/OdfFile/Reader/Converter/oox_plot_area.cpp
Alexander Trofimov 76ee07f61c [copyright] Update copyright header
Co-authored-by: Alexander Trofimov <alexander.trofimov@onlyoffice.com>
Co-committed-by: Alexander Trofimov <alexander.trofimov@onlyoffice.com>
2026-05-14 08:23:56 +00:00

358 lines
9.6 KiB
C++

/*
* Copyright (C) Ascensio System SIA, 2009-2026
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation, together with the
* additional terms provided in the LICENSE file.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: https://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA by email at info@onlyoffice.com
* or by postal mail at 20A-6 Ernesta Birznieka-Upisha Street, Riga,
* LV-1050, Latvia, European Union.
*
* The interactive user interfaces in modified versions of the Program
* are required to display Appropriate Legal Notices in accordance with
* Section 5 of the GNU AGPL version 3.
*
* No trademark rights are granted under this License.
*
* All non-code elements of the Product, including illustrations,
* icon sets, and technical writing content, are licensed under the
* Creative Commons Attribution-ShareAlike 4.0 International License:
* https://creativecommons.org/licenses/by-sa/4.0/legalcode
*
* This license applies only to such non-code elements and does not
* modify or replace the licensing terms applicable to the Program's
* source code, which remains licensed under the GNU Affero General
* Public License v3.
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
#include "oox_plot_area.h"
#include <random>
#include <xml/simple_xml_writer.h>
#include <boost/algorithm/string.hpp>
#include "../Format/odfcontext.h"
#include "../Format/style_text_properties.h"
#include "../Format/style_chart_properties.h"
#include "oox_chart_shape.h"
#include "../../DataTypes/chartclass.h"
namespace cpdoccore {
namespace oox {
oox_plot_area::oox_plot_area() : no_used_local_tables_(false)
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> distrib(1001, 9999);
axis_id_ += distrib(gen);
}
void oox_plot_area::add_chart(int type)
{
oox_chart_ptr chart;
switch (type)
{
case odf_types::chart_class::line:
chart = oox_line_chart::create();
break;
case odf_types::chart_class::area:
chart = oox_area_chart::create();
break;
case odf_types::chart_class::circle:
chart = oox_pie_chart::create();
break;
case odf_types::chart_class::ring:
chart = oox_doughnut_chart::create();
break;
case odf_types::chart_class::scatter:
chart = oox_scatter_chart::create();
break;
case odf_types::chart_class::radar:
chart = oox_radar_chart::create();
break;
case odf_types::chart_class::bar:
chart = oox_bar_chart::create();
break;
case odf_types::chart_class::stock:
chart = oox_stock_chart::create();
break;
case odf_types::chart_class::bubble:
chart = oox_bubble_chart::create();
break;
case odf_types::chart_class::surface:
chart = oox_area_chart::create();
break;
case odf_types::chart_class::filled_radar:
chart = oox_radar_chart::create(L"filled");
break;
case odf_types::chart_class::gantt:
default:
chart = oox_bar_chart::create();
break;
}
charts_.push_back(chart);
}
void oox_plot_area::add_axis(odf_reader::chart::axis& content)
{
unsigned int id = content.type_ != 0 ? axis_id_++ : 0;
oox_axis_content_ptr ax = oox_axis_content::create(id);
ax->content_ = content;
if (content.dimension_ == L"x") axis_.insert(axis_.begin(), ax);
else axis_.push_back(ax);
}
void oox_plot_area::set_no_local_table(bool val)
{
no_used_local_tables_ = val;
}
void oox_plot_area::set_data_table(odf_reader::chart::simple& content)
{
data_table_content_ = content;
}
void oox_plot_area::reset_cross_axis()//must be called after all additions
{
for (size_t i = 0; i < axis_.size(); i++)
{
for (size_t j = 0; j < charts_.size(); j++)
{
charts_[j]->add_axis(axis_[i]->get_Id());
}
}
for (size_t i = 0; i < axis_.size(); i++)
{
int curr_id = axis_[i]->get_Id();
if (curr_id < 1) continue;
for (size_t j = 0; j < axis_.size(); j++)
{
if (axis_[j]->get_Id() == curr_id)continue;
axis_[j]->add_CrossedId(curr_id);
}
}
}
void oox_plot_area::oox_serialize_view3D(std::wostream& _Wostream)
{
_CP_OPT(std::wstring) strVal;
_CP_OPT(double) doubleVal;
_CP_OPT(bool) perspective;
odf_reader::GetProperty(properties_, L"transform", strVal);
odf_reader::GetProperty(properties_, L"perspective", perspective);
if (!strVal) return;
size_t pos_matrix = strVal->find(L"matrix(");
if (pos_matrix == std::wstring::npos) return;
size_t pos_matrix_end = strVal->find(L")", pos_matrix);
if (pos_matrix_end == std::wstring::npos || pos_matrix_end == pos_matrix + 7) return;
std::wstring tmp = strVal->substr(pos_matrix + 7, pos_matrix_end - 7 - pos_matrix);
std::vector<std::wstring> values;
boost::algorithm::split(values, tmp, boost::algorithm::is_any_of(L" "), boost::algorithm::token_compress_on);
if (values.size() < 12) return;
double left_x = XmlUtils::GetDouble(values[0]);
double up_x = XmlUtils::GetDouble(values[1]);
double forward_x = XmlUtils::GetDouble(values[2]);
double left_y = XmlUtils::GetDouble(values[3]);
double up_y = XmlUtils::GetDouble(values[4]);
double forward_y = XmlUtils::GetDouble(values[5]);
double left_z = XmlUtils::GetDouble(values[6]);
double up_z = XmlUtils::GetDouble(values[7]);
double forward_z = XmlUtils::GetDouble(values[8]);
const double DEG2RAD = 3.1415926 / 180;
double sx, sy, sz, cx, cy, cz, theta_x, theta_y, theta_z = 0;
sy = forward_x;
theta_y = (sy == 0 ? 0 : asin(sy));
cy = cos(theta_y);
theta_y /= DEG2RAD;
sx = -forward_y / cy;
cx = forward_z / cy;
theta_x = (sx == 0 ? 0 : asin(sx));
double theta_x_test = (sx == 0 ? 0 : acos(cx));
theta_x /= DEG2RAD;
sz = -up_x / cy;
cz = left_x / cy;
theta_z = (sz == 0 ? 0 : asin(sz));
double theta_z_test = (sz == 0 ? 0 : acos(cz));
theta_z /= DEG2RAD;
if (this->current_chart_->type_ == CHART_TYPE_RADAR ||
this->current_chart_->type_ == CHART_TYPE_PIE ||
this->current_chart_->type_ == CHART_TYPE_DOUGHNUT)
{
theta_x += 90;
}
else theta_x = (std::abs)(theta_x);
CP_XML_WRITER(_Wostream)
{
CP_XML_NODE(L"c:view3D")
{
CP_XML_NODE(L"c:rotX")
{
CP_XML_ATTR(L"val", (int)(theta_x + 0.5));
}
CP_XML_NODE(L"c:rotY")
{
CP_XML_ATTR(L"val", (int)(theta_y + 0.5));
}
CP_XML_NODE(L"c:depthPercent")
{
CP_XML_ATTR(L"val", 100);
}
if (theta_z > 0 || (perspective && *perspective))
{
CP_XML_NODE(L"c:rAngAx")
{
CP_XML_ATTR(L"val", 0);
}
if (theta_z > 0)
{
CP_XML_NODE(L"c:perspective")
{
CP_XML_ATTR(L"val", (int)(theta_z * 2 + 0.5));
}
}
}
else
{
CP_XML_NODE(L"c:rAngAx")
{
CP_XML_ATTR(L"val", 1);
}
}
}
}
}
void oox_plot_area::oox_serialize(std::wostream & _Wostream)
{
reset_cross_axis();
oox_chart_shape shape;
shape.set(graphic_properties_, fill_);
CP_XML_WRITER(_Wostream)
{
CP_XML_NODE(L"c:plotArea")
{
//CP_XML_NODE(L"c:layout"){}
bool axisPresent = true;
for (size_t i = 0; i < charts_.size(); i++)
{
charts_[i]->oox_serialize(CP_XML_STREAM());
if (charts_[i]->type_ == CHART_TYPE_PIE ||
charts_[i]->type_ == CHART_TYPE_DOUGHNUT) axisPresent = false;
}
if (axisPresent)
{
for (size_t i = 0; i < axis_.size(); i++)
{
axis_[i]->oox_serialize(CP_XML_STREAM());
}
}
if (data_table_content_.bEnabled)
{
_CP_OPT(bool) boolVal;
CP_XML_NODE(L"c:dTable")
{
odf_reader::GetProperty(data_table_content_.properties_, L"show-horizontal-border", boolVal);
if (boolVal)
{
CP_XML_NODE(L"c:showHorzBorder")
{
CP_XML_ATTR(L"val", *boolVal);
}
}
odf_reader::GetProperty(data_table_content_.properties_, L"show-vertical-border", boolVal);
if (boolVal)
{
CP_XML_NODE(L"c:showVertBorder")
{
CP_XML_ATTR(L"val", *boolVal);
}
}
odf_reader::GetProperty(data_table_content_.properties_, L"show-outline", boolVal);
if (boolVal)
{
CP_XML_NODE(L"c:showOutline")
{
CP_XML_ATTR(L"val", *boolVal);
}
}
odf_reader::GetProperty(data_table_content_.properties_, L"show-keys", boolVal);
if (boolVal)
{
CP_XML_NODE(L"c:showKeys")
{
CP_XML_ATTR(L"val", *boolVal);
}
}
oox_chart_shape shape_table;
shape_table.set(data_table_content_.graphic_properties_, data_table_content_.fill_);
shape_table.oox_serialize(CP_XML_STREAM());
if (data_table_content_.text_properties_)
{
CP_XML_NODE(L"c:txPr")
{
CP_XML_NODE(L"a:bodyPr") {}
CP_XML_NODE(L"a:lstStyle") {}
CP_XML_NODE(L"a:p")
{
CP_XML_NODE(L"a:pPr")
{
CP_XML_NODE(L"a:defRPr")
{
//odf_reader::fonts_container & fonts = context.fontContainer();
odf_reader::fonts_container fonts;
data_table_content_.text_properties_->oox_serialize(CP_XML_STREAM(), true, fonts);
}
}
}
}
}
}
}
shape.oox_serialize(CP_XML_STREAM());
}
}
}
}
}