Auto-orientation

This commit is contained in:
utkabobr
2025-03-02 22:05:22 +03:00
parent 540f8f6c7c
commit 7f9b1b908a
12 changed files with 499 additions and 17 deletions
+2
View File
@@ -22,6 +22,8 @@ add_compile_options(-fsigned-char)
# Suppress all warnings
add_definitions(-w)
add_definitions(-DNDEBUG)
add_definitions(-DSLIC3R_VERSION=${SLIC3R_VERSION})
add_definitions(-DSLIC3R_BUILD_ID=${SLIC3R_BUILD_ID})
set(jni_imports ${CMAKE_SOURCE_DIR}/src/main/jniImports)
set(jni_libs ${CMAKE_SOURCE_DIR}/src/main/jniLibs)
+2 -2
View File
@@ -21,8 +21,8 @@ android {
cmake {
arguments '-DANDROID_STL=c++_shared', '-DANDROID_PLATFORM=21',
'-DCMAKE_BUILD_TYPE=Release', // Disabling this results in drastically degradation of slicing times on debug builds
"-DSLIC3R_VERSION=${defaultConfig.versionName}",
"-DSLIC3R_BUILD_ID=${defaultConfig.versionCode}"
"-DSLIC3R_VERSION=\"${defaultConfig.versionName}\"",
"-DSLIC3R_BUILD_ID=\"${defaultConfig.versionCode}\""
}
}
}
@@ -19,6 +19,8 @@ import android.widget.TextView;
import androidx.core.content.ContextCompat;
import com.google.android.material.snackbar.Snackbar;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
@@ -61,6 +63,20 @@ public class OrientationMenu extends ListBedMenu {
SliceBeam.EVENT_BUS.fireEvent(new NeedSnackbarEvent(R.string.MenuOrientationArrangeFinished));
}).setEnabled(fragment.getGlView().getRenderer().getModel() != null),
new SpaceItem(portrait ? ViewUtils.dp(8) : 0, portrait ? 0 : ViewUtils.dp(8)),
new BedMenuItem(R.string.MenuOrientationAutoOrient, R.drawable.menu_orientation_auto_28).setEnabled(hasSelection()).onClick(view -> {
if (fragment.getGlView().getRenderer().resetFlattenMode()) {
fragment.getGlView().requestRender();
((BedMenuItem) adapter.getItems().get(3)).isChecked = false;
adapter.notifyItemChanged(3);
}
int i = fragment.getGlView().getRenderer().getSelectedObject();
fragment.getGlView().getRenderer().getModel().autoOrient(i);
fragment.getGlView().getRenderer().invalidateGlModel(i);
fragment.getGlView().requestRender();
SliceBeam.EVENT_BUS.fireEvent(new NeedSnackbarEvent(R.string.MenuOrientationAutoOrientDone, Snackbar.LENGTH_SHORT));
}),
new BedMenuItem(R.string.MenuOrientationFlatten, R.drawable.menu_orientation_flatten_28).setEnabled(hasSelection()).setCheckable((buttonView, isChecked) -> {
fragment.getGlView().getRenderer().setInFlattenMode(isChecked);
fragment.getGlView().requestRender();
@@ -68,16 +84,16 @@ public class OrientationMenu extends ListBedMenu {
new BedMenuItem(R.string.MenuOrientationPosition, R.drawable.menu_orientation_position_28).setEnabled(hasSelection()).onClick(v -> {
if (fragment.getGlView().getRenderer().resetFlattenMode()) {
fragment.getGlView().requestRender();
((BedMenuItem) adapter.getItems().get(2)).isChecked = false;
adapter.notifyItemChanged(2);
((BedMenuItem) adapter.getItems().get(3)).isChecked = false;
adapter.notifyItemChanged(3);
}
fragment.showUnfoldMenu(new PositionMenu(), v);
}),
new BedMenuItem(R.string.MenuOrientationRotation, R.drawable.menu_orientation_rotation_28).setEnabled(hasSelection()).onClick(v -> {
if (fragment.getGlView().getRenderer().resetFlattenMode()) {
fragment.getGlView().requestRender();
((BedMenuItem) adapter.getItems().get(2)).isChecked = false;
adapter.notifyItemChanged(2);
((BedMenuItem) adapter.getItems().get(3)).isChecked = false;
adapter.notifyItemChanged(3);
}
fragment.showUnfoldMenu(new RotationMenu(), v);
})
@@ -86,8 +102,8 @@ public class OrientationMenu extends ListBedMenu {
@EventHandler(runOnMainThread = true)
public void onFlattenModeReset(FlattenModeResetEvent e) {
((BedMenuItem) adapter.getItems().get(2)).isChecked = false;
adapter.notifyItemChanged(2);
((BedMenuItem) adapter.getItems().get(3)).isChecked = false;
adapter.notifyItemChanged(3);
}
@EventHandler(runOnMainThread = true)
@@ -95,7 +111,7 @@ public class OrientationMenu extends ListBedMenu {
((BedMenuItem) adapter.getItems().get(0)).setEnabled(fragment.getGlView().getRenderer().getModel() != null);
adapter.notifyItemChanged(0);
for (int i = 2; i <= 4; i++) {
for (int i = 2; i <= 5; i++) {
BedMenuItem item = (BedMenuItem) adapter.getItems().get(i);
item.setEnabled(hasSelection());
if (item.isCheckable) {
@@ -107,7 +123,7 @@ public class OrientationMenu extends ListBedMenu {
@EventHandler(runOnMainThread = true)
public void onSelectionChanged(SelectedObjectChangedEvent e) {
for (int i = 2; i <= 4; i++) {
for (int i = 2; i <= 5; i++) {
BedMenuItem item = (BedMenuItem) adapter.getItems().get(i);
item.setEnabled(hasSelection());
if (item.isCheckable) {
@@ -147,6 +147,10 @@ public class Model {
return list;
}
public void autoOrient(int i) {
Native.model_auto_orient(pointer, i);
}
public GCodeProcessorResult slice(String configPath, String gcodePath, SliceListener listener) throws Slic3rRuntimeError {
return new GCodeProcessorResult(Native.model_slice(pointer, configPath, gcodePath, listener));
}
@@ -71,6 +71,7 @@ class Native {
static native void model_rotate(long ptr, int i, double x, double y, double z);
static native void model_flatten_rotate(long ptr, int i, long surfacePtr);
static native long[] model_create_flatten_planes(long ptr, int i);
static native void model_auto_orient(long ptr, int i);
static native long model_slice(long ptr, String configPath, String path, SliceListener listener) throws Slic3rRuntimeError;
static native void model_release(long ptr);
+67 -7
View File
@@ -5,6 +5,7 @@
#include <boost/geometry/index/rtree.hpp>
#include <tbb/parallel_for.h>
#include "bbl_utils.hpp"
#include "libslic3r/AABBMesh.hpp"
#if defined(_MSC_VER) && defined(__clang__)
#define BOOST_NO_CXX17_HDR_STRING_VIEW
@@ -196,7 +197,61 @@ namespace Slic3r {
return best_orientation.cast<double>();
}
#define BBOX_OFFSET 2.0
void preprocess() {
float m_sample_interval = 0.5;
AABBMesh indexed_mesh(mesh->its, true);
BoundingBoxf3 bbox = mesh->bounding_box();
bbox.offset(BBOX_OFFSET);
std::vector<FaceProperty> properties(mesh->its.indices.size());
std::unordered_set<size_t> hit_face_indices;
// x-axis rays
for (double y = bbox.min.y(); y < bbox.max.y(); y += m_sample_interval) {
for (double z = bbox.min.z(); z < bbox.max.z(); z += m_sample_interval) {
auto hit_result = indexed_mesh.query_ray_hit({ bbox.min.x(), y, z }, { 1.0, 0.0, 0.0 });
if (hit_result.is_hit())
hit_face_indices.insert(hit_result.face());
hit_result = indexed_mesh.query_ray_hit({ bbox.max.x(), y, z }, { -1.0, 0.0, 0.0 });
if (hit_result.is_hit())
hit_face_indices.insert(hit_result.face());
}
}
// y-axis rays
for (double x = bbox.min.x(); x < bbox.max.x(); x += m_sample_interval) {
for (double z = bbox.min.z(); z < bbox.max.z(); z += m_sample_interval) {
auto hit_result = indexed_mesh.query_ray_hit({ x, bbox.min.y(), z }, { 0.0, 1.0, 0.0 });
if (hit_result.is_hit())
hit_face_indices.insert(hit_result.face());
hit_result = indexed_mesh.query_ray_hit({ x, bbox.max.y(), z }, { 0.0, -1.0, 0.0 });
if (hit_result.is_hit())
hit_face_indices.insert(hit_result.face());
}
}
// z-axis rays
for (double x = bbox.min.x(); x < bbox.max.x(); x += m_sample_interval) {
for (double y = bbox.min.y(); y < bbox.max.y(); y += m_sample_interval) {
auto hit_result = indexed_mesh.query_ray_hit({ x, y, bbox.min.z() }, { 0.0, 0.0, 1.0 });
if (hit_result.is_hit())
hit_face_indices.insert(hit_result.face());
hit_result = indexed_mesh.query_ray_hit({ x, y, bbox.max.z() }, { 0.0, 0.0, -1.0 });
if (hit_result.is_hit())
hit_face_indices.insert(hit_result.face());
}
}
for (size_t facet_idx : hit_face_indices) {
uint32_t vol_facet_idx = facet_idx;
properties[vol_facet_idx].type = EnumFaceTypes::eExteriorAppearance;
}
int count_apperance = 0;
{
int face_count = mesh->facets_count();
@@ -211,7 +266,7 @@ namespace Slic3r {
normals.row(i) = face_normals[i];
normals_quantize.row(i) = quantize_vec3f(face_normals[i]);
areas(i) = area;
// TODO: Fix this // is_apperance(i) = (its.get_property(i).type == EnumFaceTypes::eExteriorAppearance);
is_apperance(i) = (properties[i].type == EnumFaceTypes::eExteriorAppearance);
count_apperance += (is_apperance(i) == 1);
}
}
@@ -585,12 +640,17 @@ namespace Slic3r {
auto m = obj->mesh();
AutoOrienter orienter(&m);
Vec3d orientation = orienter.process();
Vec3d axis;
double angle;
Geometry::rotation_from_two_vectors(orientation, {0, 0, 1}, axis, angle, nullptr);
obj->rotate(angle, axis);
obj->ensure_on_bed();
orientation *= -1;
ModelVolumePtrs ptrs = obj->volumes;
for (int i = 0, c = ptrs.size(); i < c; i++) {
auto vol = ptrs[i];
const Geometry::Transformation& old_transform = vol->get_transformation();
const Vec3d tnormal = orientation;
const Transform3d rotation_matrix = Transform3d(Eigen::Quaterniond().setFromTwoVectors(tnormal, -Vec3d::UnitZ()));
vol->set_transformation(old_transform.get_offset_matrix() * rotation_matrix * old_transform.get_matrix_no_offset());
}
obj->invalidate_bounding_box();
obj->ensure_on_bed(false);
}
void orient(ModelInstance *instance) {
+49
View File
@@ -11,6 +11,55 @@ typedef enum {
eMaxNumFaceTypes
}EnumFaceTypes;
struct FaceProperty
{ // triangle face property
EnumFaceTypes type;
double area;
// stl_normal normal;
std::string to_string() const
{
std::string str;
// skip normal type facet to improve performance
if (type > eNormal && type < eMaxNumFaceTypes) {
str += std::to_string(type);
if (area != 0.f)
str += " " + std::to_string(area);
}
return str;
}
void from_string(const std::string& str)
{
std::string val_str, area_str;
do {
if (str.empty())
break;
this->type = (EnumFaceTypes)std::atoi(str.c_str());
if (this->type <= eNormal || this->type >= eMaxNumFaceTypes)
break;
size_t type_end_pos = str.find(" ");
if (type_end_pos == std::string::npos) {
this->area = 0.f;
return;
}
area_str = str.substr(type_end_pos + 1);
if (!area_str.empty())
this->area = std::atof(area_str.c_str());
else
this->area = 0.f;
return;
} while (0);
this->type = eNormal;
this->area = 0.f;
}
};
namespace Slic3r {
namespace Geometry {
void rotation_from_two_vectors(Vec3d& from, Vec3d to, Vec3d& rotation_axis, double& phi, Matrix3d* rotation_matrix) {
@@ -12,6 +12,7 @@
#include "libslic3r/Arrange.hpp"
#include "libslic3r/AABBMesh.hpp"
#include "libslic3r/Geometry/ConvexHull.hpp"
#include "bbl/Orient.hpp"
#include "Viewer.hpp"
#include "GLModel.hpp"
@@ -810,6 +811,12 @@ extern "C" {
return arr;
}
JNIEXPORT void JNICALL Java_ru_ytkab0bp_slicebeam_slic3r_Native_model_1auto_1orient(JNIEnv* env, jclass, jlong ptr, jint i) {
ModelRef* model = (ModelRef*) (intptr_t) ptr;
ModelObject* obj = model->model.objects[i];
orientation::orient(obj);
}
JNIEXPORT jlong JNICALL Java_ru_ytkab0bp_slicebeam_slic3r_Native_model_1slice(JNIEnv* env, jclass, jlong ptr, jstring configPath, jstring path, jobject listener) {
try {
ModelRef* model = (ModelRef*) (intptr_t) ptr;
@@ -0,0 +1,27 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="28dp"
android:height="28dp"
android:viewportWidth="28"
android:viewportHeight="28">
<path
android:fillColor="#FF000000"
android:pathData="M2.5,14.9c0.3,-0.3 0.9,-0.3 1.2,0l1,0.9V15c0,-3.2 2.6,-5.7 5.7,-5.7h0h1.5c0.5,0 0.9,0.4 0.9,0.9S12.4,11 11.9,11h-1.5c-2.2,0 -4,1.8 -4,4l0,0v0.9l1,-1c0.3,-0.3 0.9,-0.4 1.2,0c0.3,0.3 0.4,0.9 0,1.2c0,0 0,0 0,0l-2.4,2.4c-0.3,0.3 -0.9,0.3 -1.2,0l-2.4,-2.4C2.2,15.8 2.2,15.2 2.5,14.9L2.5,14.9z"
android:fillType="evenOdd"/>
<path
android:fillColor="#FF000000"
android:pathData="M3,22.5L25,22.5"
android:strokeWidth="2"
android:strokeColor="#000000"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
<path
android:fillColor="#FF000000"
android:pathData="M18.9,12.6c-0.1,0.3 -0.2,0.4 -0.5,0.4c-0.3,0 -0.4,-0.2 -0.4,-0.4c0,-0.1 0,-0.2 0.1,-0.4l1.2,-3.4c0.1,-0.4 0.4,-0.6 0.7,-0.6c0.4,0 0.6,0.2 0.7,0.6l1.2,3.4c0,0.1 0.1,0.3 0.1,0.4c0,0.2 -0.2,0.4 -0.4,0.4c-0.2,0 -0.4,-0.1 -0.5,-0.4l-0.3,-0.8h-1.6L18.9,12.6zM20,9.2l-0.6,1.9h1.2L20,9.2L20,9.2z"
android:fillType="evenOdd"/>
<path
android:fillColor="#FF000000"
android:pathData="M20,5c-3.3,0 -6,2.7 -6,6c0,3.3 2.7,6 6,6c3.3,0 6,-2.7 6,-6C26,7.7 23.3,5 20,5zM15,11c0,-2.8 2.2,-5 5,-5c2.8,0 5,2.2 5,5c0,2.8 -2.2,5 -5,5C17.2,16 15,13.8 15,11z"
android:strokeWidth="0.25"
android:strokeColor="#000000"
android:fillType="evenOdd"/>
</vector>
+2
View File
@@ -51,6 +51,8 @@
<string name="MenuOrientationArrange">Расст. модели</string>
<string name="MenuOrientationArrangeFinished">Модели расставлены.</string>
<string name="MenuOrientationFlatten">Поверхн.</string>
<string name="MenuOrientationAutoOrient">Автомат.\nОриент.</string>
<string name="MenuOrientationAutoOrientDone">Выровнено автоматически.</string>
<string name="MenuOrientationPosition">Позиция</string>
<string name="MenuOrientationPositionX">X</string>
<string name="MenuOrientationPositionY">Y</string>
+2
View File
@@ -53,6 +53,8 @@
<string name="MenuOrientationArrange">Arrange models</string>
<string name="MenuOrientationArrangeFinished">Models arranged.</string>
<string name="MenuOrientationFlatten">Surface</string>
<string name="MenuOrientationAutoOrient">Auto\nOrient.</string>
<string name="MenuOrientationAutoOrientDone">Aligned automatically.</string>
<string name="MenuOrientationPosition">Position</string>
<string name="MenuOrientationPositionX">X</string>
<string name="MenuOrientationPositionY">Y</string>
File diff suppressed because one or more lines are too long