mirror of
https://github.com/Dark98/SliceBeam.git
synced 2026-07-02 16:49:02 +00:00
Auto-orientation
This commit is contained in:
@@ -22,6 +22,8 @@ add_compile_options(-fsigned-char)
|
|||||||
# Suppress all warnings
|
# Suppress all warnings
|
||||||
add_definitions(-w)
|
add_definitions(-w)
|
||||||
add_definitions(-DNDEBUG)
|
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_imports ${CMAKE_SOURCE_DIR}/src/main/jniImports)
|
||||||
set(jni_libs ${CMAKE_SOURCE_DIR}/src/main/jniLibs)
|
set(jni_libs ${CMAKE_SOURCE_DIR}/src/main/jniLibs)
|
||||||
|
|||||||
+2
-2
@@ -21,8 +21,8 @@ android {
|
|||||||
cmake {
|
cmake {
|
||||||
arguments '-DANDROID_STL=c++_shared', '-DANDROID_PLATFORM=21',
|
arguments '-DANDROID_STL=c++_shared', '-DANDROID_PLATFORM=21',
|
||||||
'-DCMAKE_BUILD_TYPE=Release', // Disabling this results in drastically degradation of slicing times on debug builds
|
'-DCMAKE_BUILD_TYPE=Release', // Disabling this results in drastically degradation of slicing times on debug builds
|
||||||
"-DSLIC3R_VERSION=${defaultConfig.versionName}",
|
"-DSLIC3R_VERSION=\"${defaultConfig.versionName}\"",
|
||||||
"-DSLIC3R_BUILD_ID=${defaultConfig.versionCode}"
|
"-DSLIC3R_BUILD_ID=\"${defaultConfig.versionCode}\""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -61,6 +63,20 @@ public class OrientationMenu extends ListBedMenu {
|
|||||||
SliceBeam.EVENT_BUS.fireEvent(new NeedSnackbarEvent(R.string.MenuOrientationArrangeFinished));
|
SliceBeam.EVENT_BUS.fireEvent(new NeedSnackbarEvent(R.string.MenuOrientationArrangeFinished));
|
||||||
}).setEnabled(fragment.getGlView().getRenderer().getModel() != null),
|
}).setEnabled(fragment.getGlView().getRenderer().getModel() != null),
|
||||||
new SpaceItem(portrait ? ViewUtils.dp(8) : 0, portrait ? 0 : ViewUtils.dp(8)),
|
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) -> {
|
new BedMenuItem(R.string.MenuOrientationFlatten, R.drawable.menu_orientation_flatten_28).setEnabled(hasSelection()).setCheckable((buttonView, isChecked) -> {
|
||||||
fragment.getGlView().getRenderer().setInFlattenMode(isChecked);
|
fragment.getGlView().getRenderer().setInFlattenMode(isChecked);
|
||||||
fragment.getGlView().requestRender();
|
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 -> {
|
new BedMenuItem(R.string.MenuOrientationPosition, R.drawable.menu_orientation_position_28).setEnabled(hasSelection()).onClick(v -> {
|
||||||
if (fragment.getGlView().getRenderer().resetFlattenMode()) {
|
if (fragment.getGlView().getRenderer().resetFlattenMode()) {
|
||||||
fragment.getGlView().requestRender();
|
fragment.getGlView().requestRender();
|
||||||
((BedMenuItem) adapter.getItems().get(2)).isChecked = false;
|
((BedMenuItem) adapter.getItems().get(3)).isChecked = false;
|
||||||
adapter.notifyItemChanged(2);
|
adapter.notifyItemChanged(3);
|
||||||
}
|
}
|
||||||
fragment.showUnfoldMenu(new PositionMenu(), v);
|
fragment.showUnfoldMenu(new PositionMenu(), v);
|
||||||
}),
|
}),
|
||||||
new BedMenuItem(R.string.MenuOrientationRotation, R.drawable.menu_orientation_rotation_28).setEnabled(hasSelection()).onClick(v -> {
|
new BedMenuItem(R.string.MenuOrientationRotation, R.drawable.menu_orientation_rotation_28).setEnabled(hasSelection()).onClick(v -> {
|
||||||
if (fragment.getGlView().getRenderer().resetFlattenMode()) {
|
if (fragment.getGlView().getRenderer().resetFlattenMode()) {
|
||||||
fragment.getGlView().requestRender();
|
fragment.getGlView().requestRender();
|
||||||
((BedMenuItem) adapter.getItems().get(2)).isChecked = false;
|
((BedMenuItem) adapter.getItems().get(3)).isChecked = false;
|
||||||
adapter.notifyItemChanged(2);
|
adapter.notifyItemChanged(3);
|
||||||
}
|
}
|
||||||
fragment.showUnfoldMenu(new RotationMenu(), v);
|
fragment.showUnfoldMenu(new RotationMenu(), v);
|
||||||
})
|
})
|
||||||
@@ -86,8 +102,8 @@ public class OrientationMenu extends ListBedMenu {
|
|||||||
|
|
||||||
@EventHandler(runOnMainThread = true)
|
@EventHandler(runOnMainThread = true)
|
||||||
public void onFlattenModeReset(FlattenModeResetEvent e) {
|
public void onFlattenModeReset(FlattenModeResetEvent e) {
|
||||||
((BedMenuItem) adapter.getItems().get(2)).isChecked = false;
|
((BedMenuItem) adapter.getItems().get(3)).isChecked = false;
|
||||||
adapter.notifyItemChanged(2);
|
adapter.notifyItemChanged(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(runOnMainThread = true)
|
@EventHandler(runOnMainThread = true)
|
||||||
@@ -95,7 +111,7 @@ public class OrientationMenu extends ListBedMenu {
|
|||||||
((BedMenuItem) adapter.getItems().get(0)).setEnabled(fragment.getGlView().getRenderer().getModel() != null);
|
((BedMenuItem) adapter.getItems().get(0)).setEnabled(fragment.getGlView().getRenderer().getModel() != null);
|
||||||
adapter.notifyItemChanged(0);
|
adapter.notifyItemChanged(0);
|
||||||
|
|
||||||
for (int i = 2; i <= 4; i++) {
|
for (int i = 2; i <= 5; i++) {
|
||||||
BedMenuItem item = (BedMenuItem) adapter.getItems().get(i);
|
BedMenuItem item = (BedMenuItem) adapter.getItems().get(i);
|
||||||
item.setEnabled(hasSelection());
|
item.setEnabled(hasSelection());
|
||||||
if (item.isCheckable) {
|
if (item.isCheckable) {
|
||||||
@@ -107,7 +123,7 @@ public class OrientationMenu extends ListBedMenu {
|
|||||||
|
|
||||||
@EventHandler(runOnMainThread = true)
|
@EventHandler(runOnMainThread = true)
|
||||||
public void onSelectionChanged(SelectedObjectChangedEvent e) {
|
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);
|
BedMenuItem item = (BedMenuItem) adapter.getItems().get(i);
|
||||||
item.setEnabled(hasSelection());
|
item.setEnabled(hasSelection());
|
||||||
if (item.isCheckable) {
|
if (item.isCheckable) {
|
||||||
|
|||||||
@@ -147,6 +147,10 @@ public class Model {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void autoOrient(int i) {
|
||||||
|
Native.model_auto_orient(pointer, i);
|
||||||
|
}
|
||||||
|
|
||||||
public GCodeProcessorResult slice(String configPath, String gcodePath, SliceListener listener) throws Slic3rRuntimeError {
|
public GCodeProcessorResult slice(String configPath, String gcodePath, SliceListener listener) throws Slic3rRuntimeError {
|
||||||
return new GCodeProcessorResult(Native.model_slice(pointer, configPath, gcodePath, listener));
|
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_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 void model_flatten_rotate(long ptr, int i, long surfacePtr);
|
||||||
static native long[] model_create_flatten_planes(long ptr, int i);
|
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 long model_slice(long ptr, String configPath, String path, SliceListener listener) throws Slic3rRuntimeError;
|
||||||
static native void model_release(long ptr);
|
static native void model_release(long ptr);
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <boost/geometry/index/rtree.hpp>
|
#include <boost/geometry/index/rtree.hpp>
|
||||||
#include <tbb/parallel_for.h>
|
#include <tbb/parallel_for.h>
|
||||||
#include "bbl_utils.hpp"
|
#include "bbl_utils.hpp"
|
||||||
|
#include "libslic3r/AABBMesh.hpp"
|
||||||
|
|
||||||
#if defined(_MSC_VER) && defined(__clang__)
|
#if defined(_MSC_VER) && defined(__clang__)
|
||||||
#define BOOST_NO_CXX17_HDR_STRING_VIEW
|
#define BOOST_NO_CXX17_HDR_STRING_VIEW
|
||||||
@@ -196,7 +197,61 @@ namespace Slic3r {
|
|||||||
return best_orientation.cast<double>();
|
return best_orientation.cast<double>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define BBOX_OFFSET 2.0
|
||||||
|
|
||||||
void preprocess() {
|
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 count_apperance = 0;
|
||||||
{
|
{
|
||||||
int face_count = mesh->facets_count();
|
int face_count = mesh->facets_count();
|
||||||
@@ -211,7 +266,7 @@ namespace Slic3r {
|
|||||||
normals.row(i) = face_normals[i];
|
normals.row(i) = face_normals[i];
|
||||||
normals_quantize.row(i) = quantize_vec3f(face_normals[i]);
|
normals_quantize.row(i) = quantize_vec3f(face_normals[i]);
|
||||||
areas(i) = area;
|
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);
|
count_apperance += (is_apperance(i) == 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -585,12 +640,17 @@ namespace Slic3r {
|
|||||||
auto m = obj->mesh();
|
auto m = obj->mesh();
|
||||||
AutoOrienter orienter(&m);
|
AutoOrienter orienter(&m);
|
||||||
Vec3d orientation = orienter.process();
|
Vec3d orientation = orienter.process();
|
||||||
Vec3d axis;
|
orientation *= -1;
|
||||||
double angle;
|
ModelVolumePtrs ptrs = obj->volumes;
|
||||||
Geometry::rotation_from_two_vectors(orientation, {0, 0, 1}, axis, angle, nullptr);
|
for (int i = 0, c = ptrs.size(); i < c; i++) {
|
||||||
|
auto vol = ptrs[i];
|
||||||
obj->rotate(angle, axis);
|
const Geometry::Transformation& old_transform = vol->get_transformation();
|
||||||
obj->ensure_on_bed();
|
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) {
|
void orient(ModelInstance *instance) {
|
||||||
|
|||||||
@@ -11,6 +11,55 @@ typedef enum {
|
|||||||
eMaxNumFaceTypes
|
eMaxNumFaceTypes
|
||||||
}EnumFaceTypes;
|
}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 Slic3r {
|
||||||
namespace Geometry {
|
namespace Geometry {
|
||||||
void rotation_from_two_vectors(Vec3d& from, Vec3d to, Vec3d& rotation_axis, double& phi, Matrix3d* rotation_matrix) {
|
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/Arrange.hpp"
|
||||||
#include "libslic3r/AABBMesh.hpp"
|
#include "libslic3r/AABBMesh.hpp"
|
||||||
#include "libslic3r/Geometry/ConvexHull.hpp"
|
#include "libslic3r/Geometry/ConvexHull.hpp"
|
||||||
|
#include "bbl/Orient.hpp"
|
||||||
#include "Viewer.hpp"
|
#include "Viewer.hpp"
|
||||||
|
|
||||||
#include "GLModel.hpp"
|
#include "GLModel.hpp"
|
||||||
@@ -810,6 +811,12 @@ extern "C" {
|
|||||||
return arr;
|
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) {
|
JNIEXPORT jlong JNICALL Java_ru_ytkab0bp_slicebeam_slic3r_Native_model_1slice(JNIEnv* env, jclass, jlong ptr, jstring configPath, jstring path, jobject listener) {
|
||||||
try {
|
try {
|
||||||
ModelRef* model = (ModelRef*) (intptr_t) ptr;
|
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>
|
||||||
@@ -51,6 +51,8 @@
|
|||||||
<string name="MenuOrientationArrange">Расст. модели</string>
|
<string name="MenuOrientationArrange">Расст. модели</string>
|
||||||
<string name="MenuOrientationArrangeFinished">Модели расставлены.</string>
|
<string name="MenuOrientationArrangeFinished">Модели расставлены.</string>
|
||||||
<string name="MenuOrientationFlatten">Поверхн.</string>
|
<string name="MenuOrientationFlatten">Поверхн.</string>
|
||||||
|
<string name="MenuOrientationAutoOrient">Автомат.\nОриент.</string>
|
||||||
|
<string name="MenuOrientationAutoOrientDone">Выровнено автоматически.</string>
|
||||||
<string name="MenuOrientationPosition">Позиция</string>
|
<string name="MenuOrientationPosition">Позиция</string>
|
||||||
<string name="MenuOrientationPositionX">X</string>
|
<string name="MenuOrientationPositionX">X</string>
|
||||||
<string name="MenuOrientationPositionY">Y</string>
|
<string name="MenuOrientationPositionY">Y</string>
|
||||||
|
|||||||
@@ -53,6 +53,8 @@
|
|||||||
<string name="MenuOrientationArrange">Arrange models</string>
|
<string name="MenuOrientationArrange">Arrange models</string>
|
||||||
<string name="MenuOrientationArrangeFinished">Models arranged.</string>
|
<string name="MenuOrientationArrangeFinished">Models arranged.</string>
|
||||||
<string name="MenuOrientationFlatten">Surface</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="MenuOrientationPosition">Position</string>
|
||||||
<string name="MenuOrientationPositionX">X</string>
|
<string name="MenuOrientationPositionX">X</string>
|
||||||
<string name="MenuOrientationPositionY">Y</string>
|
<string name="MenuOrientationPositionY">Y</string>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user