NEW:add paint tool in assembly view

Change-Id: I108e1e24ca9d033d2279c8153585166971a347a6
This commit is contained in:
liz.li 2023-04-14 11:58:39 +08:00 committed by Lane.Wei
parent 5236f17792
commit ab0c6611c8
13 changed files with 265 additions and 108 deletions

View file

@ -212,7 +212,14 @@ void GLGizmoMmuSegmentation::render_triangles(const Selection &selection) const
++mesh_id;
const Transform3d trafo_matrix = mo->instances[selection.get_instance_idx()]->get_transformation().get_matrix() * mv->get_matrix();
Transform3d trafo_matrix;
if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
trafo_matrix = mo->instances[selection.get_instance_idx()]->get_assemble_transformation().get_matrix() * mv->get_matrix();
trafo_matrix.translate(mv->get_transformation().get_offset() * (GLVolume::explosion_ratio - 1.0) + mo->instances[selection.get_instance_idx()]->get_offset_to_assembly() * (GLVolume::explosion_ratio - 1.0));
}
else {
trafo_matrix = mo->instances[selection.get_instance_idx()]->get_transformation().get_matrix()* mv->get_matrix();
}
bool is_left_handed = trafo_matrix.matrix().determinant() < 0.;
if (is_left_handed)

View file

@ -85,10 +85,15 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection) const
continue;
++mesh_id;
const Transform3d trafo_matrix =
mo->instances[selection.get_instance_idx()]->get_transformation().get_matrix() *
mv->get_matrix();
Transform3d trafo_matrix;
if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
trafo_matrix = mo->instances[selection.get_instance_idx()]->get_assemble_transformation().get_matrix() * mv->get_matrix();
trafo_matrix.translate(mv->get_transformation().get_offset() * (GLVolume::explosion_ratio - 1.0) + mo->instances[selection.get_instance_idx()]->get_offset_to_assembly() * (GLVolume::explosion_ratio - 1.0));
}
else {
trafo_matrix = mo->instances[selection.get_instance_idx()]->get_transformation().get_matrix()* mv->get_matrix();
}
bool is_left_handed = trafo_matrix.matrix().determinant() < 0.;
if (is_left_handed)
@ -124,7 +129,16 @@ void GLGizmoPainterBase::render_cursor() const
std::vector<Transform3d> trafo_matrices;
for (const ModelVolume* mv : mo->volumes) {
if (mv->is_model_part())
trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix());
{
if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
Transform3d temp = mi->get_assemble_transformation().get_matrix() * mv->get_matrix();
temp.translate(mv->get_transformation().get_offset() * (GLVolume::explosion_ratio - 1.0) + mi->get_offset_to_assembly() * (GLVolume::explosion_ratio - 1.0));
trafo_matrices.emplace_back(temp);
}
else {
trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix());
}
}
}
// Raycast and return if there's no hit.
update_raycast_cache(m_parent.get_local_mouse_position(), camera, trafo_matrices);
@ -230,17 +244,35 @@ void GLGizmoPainterBase::render_cursor_height_range(const Transform3d& trafo) co
const BoundingBoxf3 box = bounding_box();
Vec3d hit_world = trafo * Vec3d(m_rr.hit(0), m_rr.hit(1), m_rr.hit(2));
float max_z = (float)box.max.z();
float min_z = (float)box.min.z();
float cursor_z = std::clamp((float)hit_world.z(), 0.f, max_z);
std::array<float, 2> zs = { cursor_z, std::clamp(cursor_z + m_cursor_height, 0.f, max_z) };
for (int i = 0; i < zs.size(); i++) {
update_contours(zs[i], max_z);
float cursor_z = std::clamp((float)hit_world.z(), min_z, max_z);
std::array<float, 2> zs = { cursor_z, std::clamp(cursor_z + m_cursor_height, min_z, max_z) };
const Selection& selection = m_parent.get_selection();
const ModelObject* model_object = wxGetApp().model().objects[selection.get_object_idx()];
const ModelInstance* mi = model_object->instances[selection.get_instance_idx()];
for (const ModelVolume* mv : model_object->volumes) {
TriangleMesh vol_mesh = mv->mesh();
if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
Transform3d temp = mi->get_assemble_transformation().get_matrix() * mv->get_matrix();
temp.translate(mv->get_transformation().get_offset() * (GLVolume::explosion_ratio - 1.0) + mi->get_offset_to_assembly() * (GLVolume::explosion_ratio - 1.0));
vol_mesh.transform(temp);
}
else {
vol_mesh.transform(mi->get_transformation().get_matrix() * mv->get_matrix());
}
for (int i = 0; i < zs.size(); i++) {
update_contours(vol_mesh, zs[i], max_z, min_z);
glsafe(::glPushMatrix());
glsafe(::glTranslated(m_cut_contours.shift.x(), m_cut_contours.shift.y(), m_cut_contours.shift.z()));
glsafe(::glLineWidth(2.0f));
m_cut_contours.contours.render();
glsafe(::glPopMatrix());
}
glsafe(::glPushMatrix());
glsafe(::glTranslated(m_cut_contours.shift.x(), m_cut_contours.shift.y(), m_cut_contours.shift.z()));
glsafe(::glLineWidth(2.0f));
m_cut_contours.contours.render();
glsafe(::glPopMatrix());
}
}
@ -257,7 +289,7 @@ BoundingBoxf3 GLGizmoPainterBase::bounding_box() const
return ret;
}
void GLGizmoPainterBase::update_contours(float cursor_z, float max_z) const
void GLGizmoPainterBase::update_contours(const TriangleMesh& vol_mesh, float cursor_z, float max_z, float min_z) const
{
const Selection& selection = m_parent.get_selection();
const GLVolume* first_glvolume = selection.get_volume(*selection.get_volume_idxs().begin());
@ -266,33 +298,32 @@ void GLGizmoPainterBase::update_contours(float cursor_z, float max_z) const
const ModelObject* model_object = wxGetApp().model().objects[selection.get_object_idx()];
const int instance_idx = selection.get_instance_idx();
if (0.0 < cursor_z && cursor_z < max_z) {
if (m_cut_contours.cut_z != cursor_z || m_cut_contours.object_id != model_object->id() || m_cut_contours.instance_idx != instance_idx) {
m_cut_contours.cut_z = cursor_z;
if (min_z < cursor_z && cursor_z < max_z) {
if (m_cut_contours.cut_z != cursor_z || m_cut_contours.object_id != model_object->id() || m_cut_contours.instance_idx != instance_idx) {
m_cut_contours.cut_z = cursor_z;
if (m_cut_contours.object_id != model_object->id())
m_cut_contours.mesh = model_object->raw_mesh();
m_cut_contours.mesh = vol_mesh;
m_cut_contours.position = box.center();
m_cut_contours.shift = Vec3d::Zero();
m_cut_contours.object_id = model_object->id();
m_cut_contours.instance_idx = instance_idx;
m_cut_contours.contours.reset();
m_cut_contours.position = box.center();
m_cut_contours.shift = Vec3d::Zero();
m_cut_contours.object_id = model_object->id();
m_cut_contours.instance_idx = instance_idx;
m_cut_contours.contours.reset();
MeshSlicingParams slicing_params;
slicing_params.trafo = first_glvolume->get_instance_transformation().get_matrix();
const Polygons polys = slice_mesh(m_cut_contours.mesh.its, cursor_z, slicing_params);
if (!polys.empty()) {
m_cut_contours.contours.init_from(polys, static_cast<float>(cursor_z));
m_cut_contours.contours.set_color(-1, { 1.0f, 1.0f, 1.0f, 1.0f });
MeshSlicingParams slicing_params;
slicing_params.trafo = Transform3d::Identity().matrix();
const Polygons polys = slice_mesh(m_cut_contours.mesh.its, cursor_z, slicing_params);
if (!polys.empty()) {
m_cut_contours.contours.init_from(polys, static_cast<float>(cursor_z));
m_cut_contours.contours.set_color(-1, { 1.0f, 1.0f, 1.0f, 1.0f });
}
}
else if (box.center() != m_cut_contours.position) {
m_cut_contours.shift = box.center() - m_cut_contours.position;
}
}
else if (box.center() != m_cut_contours.position) {
m_cut_contours.shift = box.center() - m_cut_contours.position;
}
}
else
m_cut_contours.contours.reset();
else
m_cut_contours.contours.reset();
}
bool GLGizmoPainterBase::is_mesh_point_clipped(const Vec3d& point, const Transform3d& trafo) const
@ -451,8 +482,12 @@ std::vector<GLGizmoPainterBase::ProjectedHeightRange> GLGizmoPainterBase::get_pr
const Selection& selection = m_parent.get_selection();
const ModelObject* mo = m_c->selection_info()->model_object();
const ModelInstance* mi = mo->instances[selection.get_instance_idx()];
const Transform3d instance_trafo = mi->get_transformation().get_matrix();
const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix(true);
const Transform3d instance_trafo = m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView ?
mi->get_assemble_transformation().get_matrix() :
mi->get_transformation().get_matrix();
const Transform3d instance_trafo_not_translate = m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView ?
mi->get_assemble_transformation().get_matrix(true) :
mi->get_transformation().get_matrix(true);
for (int mesh_idx = 0; mesh_idx < part_volumes.size(); mesh_idx++) {
if (mesh_idx == m_rr.mesh_id)
@ -518,8 +553,12 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
const Selection &selection = m_parent.get_selection();
const ModelObject *mo = m_c->selection_info()->model_object();
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
const Transform3d trafo_matrix_not_translate = mi->get_transformation().get_matrix(true) * mo->volumes[m_rr.mesh_id]->get_matrix(true);
const Transform3d trafo_matrix = mi->get_transformation().get_matrix() * mo->volumes[m_rr.mesh_id]->get_matrix();
const Transform3d trafo_matrix_not_translate = m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView ?
mi->get_assemble_transformation().get_matrix(true) * mo->volumes[m_rr.mesh_id]->get_matrix(true) :
mi->get_transformation().get_matrix(true) * mo->volumes[m_rr.mesh_id]->get_matrix(true);
const Transform3d trafo_matrix = m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView ?
mi->get_assemble_transformation().get_matrix() * mo->volumes[m_rr.mesh_id]->get_matrix() :
mi->get_transformation().get_matrix() * mo->volumes[m_rr.mesh_id]->get_matrix();
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), trafo_matrix_not_translate, this->get_clipping_plane_in_volume_coordinates(trafo_matrix), m_smart_fill_angle,
m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f, true);
m_triangle_selectors[m_rr.mesh_id]->request_update_render_data();
@ -581,8 +620,12 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
const Selection &selection = m_parent.get_selection();
const ModelObject *mo = m_c->selection_info()->model_object();
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
const Transform3d instance_trafo = mi->get_transformation().get_matrix();
const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix(true);
Transform3d instance_trafo = m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView ?
mi->get_assemble_transformation().get_matrix() :
mi->get_transformation().get_matrix();
Transform3d instance_trafo_not_translate = m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView ?
mi->get_assemble_transformation().get_matrix(true) :
mi->get_transformation().get_matrix(true);
std::vector<const ModelVolume*> part_volumes;
// Precalculate transformations of individual meshes.
@ -590,7 +633,14 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
std::vector<Transform3d> trafo_matrices_not_translate;
for (const ModelVolume *mv : mo->volumes)
if (mv->is_model_part()) {
trafo_matrices.emplace_back(instance_trafo * mv->get_matrix());
if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
Transform3d temp = instance_trafo * mv->get_matrix();
temp.translate(mv->get_transformation().get_offset() * (GLVolume::explosion_ratio - 1.0) + mi->get_offset_to_assembly() * (GLVolume::explosion_ratio - 1.0));
trafo_matrices.emplace_back(temp);
}
else {
trafo_matrices.emplace_back(instance_trafo* mv->get_matrix());
}
trafo_matrices_not_translate.emplace_back(instance_trafo_not_translate * mv->get_matrix(true));
part_volumes.push_back(mv);
}
@ -713,15 +763,26 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
const Selection &selection = m_parent.get_selection();
const ModelObject *mo = m_c->selection_info()->model_object();
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
const Transform3d instance_trafo = mi->get_transformation().get_matrix();
const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix(true);
const Transform3d instance_trafo = m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView ?
mi->get_assemble_transformation().get_matrix() :
mi->get_transformation().get_matrix();
const Transform3d instance_trafo_not_translate = m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView ?
mi->get_assemble_transformation().get_matrix(true) :
mi->get_transformation().get_matrix(true);
// Precalculate transformations of individual meshes.
std::vector<Transform3d> trafo_matrices;
std::vector<Transform3d> trafo_matrices_not_translate;
for (const ModelVolume *mv : mo->volumes)
if (mv->is_model_part()) {
trafo_matrices.emplace_back(instance_trafo * mv->get_matrix());
if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
Transform3d temp = instance_trafo * mv->get_matrix();
temp.translate(mv->get_transformation().get_offset() * (GLVolume::explosion_ratio - 1.0) + mi->get_offset_to_assembly() * (GLVolume::explosion_ratio - 1.0));
trafo_matrices.emplace_back(temp);
}
else {
trafo_matrices.emplace_back(instance_trafo * mv->get_matrix());
}
trafo_matrices_not_translate.emplace_back(instance_trafo_not_translate * mv->get_matrix(true));
}
@ -811,7 +872,8 @@ void GLGizmoPainterBase::update_raycast_cache(const Vec2d& mouse_position,
hit,
normal,
m_c->object_clipper()->get_clipping_plane(),
&facet))
&facet,
m_parent.get_canvas_type() != GLCanvas3D::CanvasAssembleView))
{
// In case this hit is clipped, skip it.
if (is_mesh_point_clipped(hit.cast<double>(), trafo_matrices[mesh_id]))

View file

@ -368,7 +368,7 @@ private:
mutable CutContours m_cut_contours;
BoundingBoxf3 bounding_box() const;
void update_contours(float cursor_z, float max_z) const;
void update_contours(const TriangleMesh& vol_mesh, float cursor_z, float max_z, float min_z) const;
protected:
void on_set_state() override;

View file

@ -145,6 +145,11 @@ void InstancesHider::on_update()
const ModelObject* mo = get_pool()->selection_info()->model_object();
int active_inst = get_pool()->selection_info()->get_active_instance();
GLCanvas3D* canvas = get_pool()->get_canvas();
double z_min;
if (canvas->get_canvas_type() == GLCanvas3D::CanvasAssembleView)
z_min = std::numeric_limits<double>::max();
else
z_min = -SINKING_Z_THRESHOLD;
if (mo && active_inst != -1) {
canvas->toggle_model_objects_visibility(false);
@ -152,7 +157,7 @@ void InstancesHider::on_update()
canvas->toggle_sla_auxiliaries_visibility(m_show_supports, mo, active_inst);
canvas->set_use_clipping_planes(true);
// Some objects may be sinking, do not show whatever is below the bed.
canvas->set_clipping_plane(0, ClippingPlane(Vec3d::UnitZ(), -SINKING_Z_THRESHOLD));
canvas->set_clipping_plane(0, ClippingPlane(Vec3d::UnitZ(), z_min));
canvas->set_clipping_plane(1, ClippingPlane(-Vec3d::UnitZ(), std::numeric_limits<double>::max()));
@ -164,7 +169,7 @@ void InstancesHider::on_update()
m_clippers.clear();
for (const TriangleMesh* mesh : meshes) {
m_clippers.emplace_back(new MeshClipper);
m_clippers.back()->set_plane(ClippingPlane(-Vec3d::UnitZ(), -SINKING_Z_THRESHOLD));
m_clippers.back()->set_plane(ClippingPlane(-Vec3d::UnitZ(), z_min));
m_clippers.back()->set_mesh(*mesh);
}
m_old_meshes = meshes;
@ -404,18 +409,30 @@ void ObjectClipper::render_cut() const
return;
const SelectionInfo* sel_info = get_pool()->selection_info();
const ModelObject* mo = sel_info->model_object();
Geometry::Transformation inst_trafo = mo->instances[sel_info->get_active_instance()]->get_transformation();
Geometry::Transformation inst_trafo;
bool is_assem_cnv = get_pool()->get_canvas()->get_canvas_type() == GLCanvas3D::CanvasAssembleView;
inst_trafo = is_assem_cnv ?
mo->instances[sel_info->get_active_instance()]->get_assemble_transformation() :
mo->instances[sel_info->get_active_instance()]->get_transformation();
auto offset_to_assembly = mo->instances[0]->get_offset_to_assembly();
size_t clipper_id = 0;
for (const ModelVolume* mv : mo->volumes) {
Geometry::Transformation vol_trafo = mv->get_transformation();
Geometry::Transformation trafo = inst_trafo * vol_trafo;
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift()));
if (is_assem_cnv) {
trafo.set_offset(trafo.get_offset() + offset_to_assembly * (GLVolume::explosion_ratio - 1.0) + vol_trafo.get_offset() * (GLVolume::explosion_ratio - 1.0));
}
else {
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift()));
}
auto& clipper = m_clippers[clipper_id];
clipper->set_plane(*m_clp);
clipper->set_transformation(trafo);
clipper->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), -SINKING_Z_THRESHOLD));
if (is_assem_cnv)
clipper->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), std::numeric_limits<double>::max()));
else
clipper->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), -SINKING_Z_THRESHOLD));
glsafe(::glPushMatrix());
// BBS
glsafe(::glColor3f(0.25f, 0.25f, 0.25f));
@ -438,14 +455,27 @@ void ObjectClipper::set_position(double pos, bool keep_normal)
// camera_dir(2) = 0;
Vec3d normal = (keep_normal && m_clp) ? m_clp->get_normal() : /*-camera_dir;*/ -wxGetApp().plater()->get_camera().get_dir_forward();
const Vec3d& center = mo->instances[active_inst]->get_offset() + Vec3d(0., 0., z_shift);
Vec3d center;
if (get_pool()->get_canvas()->get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
const SelectionInfo* sel_info = get_pool()->selection_info();
auto trafo = mo->instances[sel_info->get_active_instance()]->get_assemble_transformation();
auto offset_to_assembly = mo->instances[0]->get_offset_to_assembly();
center = trafo.get_offset() + offset_to_assembly * (GLVolume::explosion_ratio - 1.0);
}
else {
center = mo->instances[active_inst]->get_offset() + Vec3d(0., 0., z_shift);
}
float dist = normal.dot(center);
if (pos < 0.)
pos = m_clp_ratio;
m_clp_ratio = pos;
m_clp.reset(new ClippingPlane(normal, (dist - (-m_active_inst_bb_radius) - m_clp_ratio * 2*m_active_inst_bb_radius)));
m_clp.reset(new ClippingPlane(normal, (dist - (-m_active_inst_bb_radius) - m_clp_ratio * 2 * m_active_inst_bb_radius)));
get_pool()->get_canvas()->set_as_dirty();
}

View file

@ -54,9 +54,16 @@ GLGizmosManager::GLGizmosManager(GLCanvas3D& parent)
std::vector<size_t> GLGizmosManager::get_selectable_idxs() const
{
std::vector<size_t> out;
for (size_t i=0; i<m_gizmos.size(); ++i)
if (m_gizmos[i]->is_selectable())
out.push_back(i);
if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
for (size_t i = 0; i < m_gizmos.size(); ++i)
if (m_gizmos[i]->get_sprite_id() == (unsigned int)MmuSegmentation)
out.push_back(i);
}
else {
for (size_t i = 0; i < m_gizmos.size(); ++i)
if (m_gizmos[i]->is_selectable())
out.push_back(i);
}
return out;
}
@ -78,6 +85,8 @@ size_t GLGizmosManager::get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const
#if BBS_TOOLBAR_ON_TOP
//float space_width = GLGizmosManager::Default_Icons_Size * wxGetApp().toolbar_icon_scale();;
float top_x = std::max(m_parent.get_main_toolbar_width() + border, 0.5f * (cnv_w - width + m_parent.get_main_toolbar_width() + m_parent.get_collapse_toolbar_width() - m_parent.get_assemble_view_toolbar_width()) + border);
if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView)
top_x = 0.5f * cnv_w + 0.5f * (m_parent.get_assembly_paint_toolbar_width());
float top_y = 0;
float stride_x = m_layout.scaled_stride_x();
@ -1372,17 +1381,23 @@ void GLGizmosManager::do_render_overlay() const
float width = get_scaled_total_width();
float zoomed_border = m_layout.scaled_border() * inv_zoom;
//BBS: GUI refactor: GLToolbar&&Gizmo adjust
float zoomed_top_x;
if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
zoomed_top_x = 0.5f * m_parent.get_assembly_paint_toolbar_width() * inv_zoom;
}
else {
//BBS: GUI refactor: GLToolbar&&Gizmo adjust
#if BBS_TOOLBAR_ON_TOP
float main_toolbar_width = (float)m_parent.get_main_toolbar_width();
float assemble_view_width = (float)m_parent.get_assemble_view_toolbar_width();
float collapse_width = (float)m_parent.get_collapse_toolbar_width();
//float space_width = GLGizmosManager::Default_Icons_Size * wxGetApp().toolbar_icon_scale();
//float zoomed_top_x = 0.5f *(cnv_w + main_toolbar_width - 2 * space_width - width) * inv_zoom;
float main_toolbar_width = (float)m_parent.get_main_toolbar_width();
float assemble_view_width = (float)m_parent.get_assemble_view_toolbar_width();
float collapse_width = (float)m_parent.get_collapse_toolbar_width();
//float space_width = GLGizmosManager::Default_Icons_Size * wxGetApp().toolbar_icon_scale();
//float zoomed_top_x = 0.5f *(cnv_w + main_toolbar_width - 2 * space_width - width) * inv_zoom;
float main_toolbar_left = std::max(-0.5f * cnv_w, -0.5f * (main_toolbar_width + get_scaled_total_width() + assemble_view_width - collapse_width)) * inv_zoom;
//float zoomed_top_x = 0.5f *(main_toolbar_width + collapse_width - width - assemble_view_width) * inv_zoom;
float zoomed_top_x = main_toolbar_left + (main_toolbar_width) *inv_zoom;
float main_toolbar_left = std::max(-0.5f * cnv_w, -0.5f * (main_toolbar_width + get_scaled_total_width() + assemble_view_width - collapse_width)) * inv_zoom;
//float zoomed_top_x = 0.5f *(main_toolbar_width + collapse_width - width - assemble_view_width) * inv_zoom;
zoomed_top_x = main_toolbar_left + (main_toolbar_width)*inv_zoom;
}
float zoomed_top_y = 0.5f * cnv_h * inv_zoom;
#else
//float zoomed_top_x = (-0.5f * cnv_w) * inv_zoom;