@@ -218,5 +218,12 @@
|
|||||||
"Add User": "Benutzer hinzufügen",
|
"Add User": "Benutzer hinzufügen",
|
||||||
"Password": "Passwort",
|
"Password": "Passwort",
|
||||||
"Is Admin": "Ist Administrator",
|
"Is Admin": "Ist Administrator",
|
||||||
"Create User": "Benutzer erstellen"
|
"Create User": "Benutzer erstellen",
|
||||||
|
"Build Plate Model Path (.stl)": "Pfad zum Build-Platte-Modell (.stl)",
|
||||||
|
"Absolute path to a custom build plate STL model to show in the plater. Leave empty to use none.": "Absoluter Pfad zum benutzerdefinierten Build-Platte-STL-Modell, das im Plater angezeigt werden soll. Leer lassen, um keines zu verwenden.",
|
||||||
|
"Default Material Profile": "Standard Materialprofil",
|
||||||
|
"Slicing Engine Configurations": "Slicer-Engine-Konfigurationen",
|
||||||
|
"Slicing Engine": "Slicer-Engine",
|
||||||
|
"Select the engine to be used globally. Ensure the selected engine is installed and accessible on the server.": "Wählen Sie die Engine aus, die global verwendet werden soll. Stellen Sie sicher, dass die ausgewählte Engine installiert und auf dem Server zugänglich ist.",
|
||||||
|
"Material Profile": "Materialprofil"
|
||||||
}
|
}
|
||||||
@@ -218,5 +218,12 @@
|
|||||||
"Add User": "Add User",
|
"Add User": "Add User",
|
||||||
"Password": "Password",
|
"Password": "Password",
|
||||||
"Is Admin": "Is Admin",
|
"Is Admin": "Is Admin",
|
||||||
"Create User": "Create User"
|
"Create User": "Create User",
|
||||||
|
"Build Plate Model Path (.stl)": "Build Plate Model Path (.stl)",
|
||||||
|
"Absolute path to a custom build plate STL model to show in the plater. Leave empty to use none.": "Absolute path to a custom build plate STL model to show in the plater. Leave empty to use none.",
|
||||||
|
"Default Material Profile": "Default Material Profile",
|
||||||
|
"Slicing Engine Configurations": "Slicing Engine Configurations",
|
||||||
|
"Slicing Engine": "Slicing Engine",
|
||||||
|
"Select the engine to be used globally. Ensure the selected engine is installed and accessible on the server.": "Select the engine to be used globally. Ensure the selected engine is installed and accessible on the server.",
|
||||||
|
"Material Profile": "Material Profile"
|
||||||
}
|
}
|
||||||
@@ -218,5 +218,12 @@
|
|||||||
"Add User": "添加用户",
|
"Add User": "添加用户",
|
||||||
"Password": "密码",
|
"Password": "密码",
|
||||||
"Is Admin": "设为管理员",
|
"Is Admin": "设为管理员",
|
||||||
"Create User": "创建用户"
|
"Create User": "创建用户",
|
||||||
|
"Build Plate Model Path (.stl)": "构建板模型路径 (.stl)",
|
||||||
|
"Absolute path to a custom build plate STL model to show in the plater. Leave empty to use none.": "保存自定义构建板 STL 模型的绝对路径,以在 plater 中显示。留空以使用默认值。",
|
||||||
|
"Default Material Profile": "默认材料配置",
|
||||||
|
"Slicing Engine Configurations": "切片引擎配置",
|
||||||
|
"Slicing Engine": "切片引擎",
|
||||||
|
"Select the engine to be used globally. Ensure the selected engine is installed and accessible on the server.": "选择要全局使用的引擎。确保所选引擎已安装且在服务器上可访问。",
|
||||||
|
"Material Profile": "材料配置"
|
||||||
}
|
}
|
||||||
@@ -46,6 +46,7 @@ def settings():
|
|||||||
default_support = request.form.get('default_support', 'false')
|
default_support = request.form.get('default_support', 'false')
|
||||||
default_support_pattern = request.form.get('default_support_pattern', 'tree')
|
default_support_pattern = request.form.get('default_support_pattern', 'tree')
|
||||||
default_quality = request.form.get('default_quality', 'base_global_standard.inst.cfg')
|
default_quality = request.form.get('default_quality', 'base_global_standard.inst.cfg')
|
||||||
|
default_material = request.form.get('default_material', '')
|
||||||
gcode_upload_folder = request.form.get('gcode_upload_folder', '').strip()
|
gcode_upload_folder = request.form.get('gcode_upload_folder', '').strip()
|
||||||
slicer_engine = request.form.get('slicer_engine', 'cura')
|
slicer_engine = request.form.get('slicer_engine', 'cura')
|
||||||
build_plate_model_path = request.form.get('build_plate_model_path', '').strip()
|
build_plate_model_path = request.form.get('build_plate_model_path', '').strip()
|
||||||
@@ -59,6 +60,7 @@ def settings():
|
|||||||
('default_support', default_support),
|
('default_support', default_support),
|
||||||
('default_support_pattern', default_support_pattern),
|
('default_support_pattern', default_support_pattern),
|
||||||
('default_quality', default_quality),
|
('default_quality', default_quality),
|
||||||
|
('default_material', default_material),
|
||||||
('gcode_upload_folder', gcode_upload_folder),
|
('gcode_upload_folder', gcode_upload_folder),
|
||||||
('slicer_engine', slicer_engine),
|
('slicer_engine', slicer_engine),
|
||||||
('build_plate_model_path', build_plate_model_path),
|
('build_plate_model_path', build_plate_model_path),
|
||||||
|
|||||||
@@ -355,10 +355,11 @@ def plater():
|
|||||||
default_support = configs.get('default_support', 'false')
|
default_support = configs.get('default_support', 'false')
|
||||||
default_support_pattern = configs.get('default_support_pattern', 'tree')
|
default_support_pattern = configs.get('default_support_pattern', 'tree')
|
||||||
default_quality = configs.get('default_quality', 'base_global_standard.inst.cfg')
|
default_quality = configs.get('default_quality', 'base_global_standard.inst.cfg')
|
||||||
|
default_material = configs.get('default_material', '')
|
||||||
|
|
||||||
user_files = PrintFile.query.filter_by(user_id=current_user.id, file_type='stl').order_by(PrintFile.created_at.desc()).all()
|
user_files = PrintFile.query.filter_by(user_id=current_user.id, file_type='stl').order_by(PrintFile.created_at.desc()).all()
|
||||||
models = [{'id': f.id, 'name': f.original_filename, 'status': f.status, 'url': url_for('main.serve_proxy_file', file_id=f.id), 'transform_matrix': f.transform_matrix} for f in user_files]
|
models = [{'id': f.id, 'name': f.original_filename, 'status': f.status, 'url': url_for('main.serve_proxy_file', file_id=f.id), 'transform_matrix': f.transform_matrix} for f in user_files]
|
||||||
return render_template('slice/plater.html', w=w, h=h, hd=hd, last_quality=default_quality, models=models, offset_x=offset_x, offset_y=offset_y, default_infill=default_infill, default_support=default_support, default_support_pattern=default_support_pattern, quota_exceeded=quota_exceeded, configs=configs)
|
return render_template('slice/plater.html', w=w, h=h, hd=hd, last_quality=default_quality, last_material=default_material, models=models, offset_x=offset_x, offset_y=offset_y, default_infill=default_infill, default_support=default_support, default_support_pattern=default_support_pattern, quota_exceeded=quota_exceeded, configs=configs)
|
||||||
|
|
||||||
@main_bp.route('/file/<int:file_id>')
|
@main_bp.route('/file/<int:file_id>')
|
||||||
@login_required
|
@login_required
|
||||||
@@ -390,6 +391,7 @@ def merge_and_slice():
|
|||||||
data = request.json
|
data = request.json
|
||||||
pieces = data.get('pieces', [])
|
pieces = data.get('pieces', [])
|
||||||
quality = data.get('quality', 'base_global_standard.inst.cfg')
|
quality = data.get('quality', 'base_global_standard.inst.cfg')
|
||||||
|
material = data.get('material', '')
|
||||||
infill_density = data.get('infill', '20')
|
infill_density = data.get('infill', '20')
|
||||||
support_enable = data.get('support', 'false')
|
support_enable = data.get('support', 'false')
|
||||||
support_pattern = data.get('support_pattern', 'lines')
|
support_pattern = data.get('support_pattern', 'lines')
|
||||||
@@ -427,6 +429,7 @@ def merge_and_slice():
|
|||||||
"matrix": p['raw_matrix'],
|
"matrix": p['raw_matrix'],
|
||||||
"settings": {
|
"settings": {
|
||||||
"quality": quality,
|
"quality": quality,
|
||||||
|
"material": material,
|
||||||
"infill": infill_density,
|
"infill": infill_density,
|
||||||
"support": support_enable,
|
"support": support_enable,
|
||||||
"support_pattern": support_pattern
|
"support_pattern": support_pattern
|
||||||
@@ -450,6 +453,7 @@ def merge_and_slice():
|
|||||||
"parts": [],
|
"parts": [],
|
||||||
"settings": {
|
"settings": {
|
||||||
"quality": quality,
|
"quality": quality,
|
||||||
|
"material": material,
|
||||||
"infill": infill_density,
|
"infill": infill_density,
|
||||||
"support": support_enable,
|
"support": support_enable,
|
||||||
"support_pattern": support_pattern
|
"support_pattern": support_pattern
|
||||||
@@ -471,6 +475,7 @@ def merge_and_slice():
|
|||||||
"matrix": pieces[0].get('raw_matrix', pieces[0]['matrix']),
|
"matrix": pieces[0].get('raw_matrix', pieces[0]['matrix']),
|
||||||
"settings": {
|
"settings": {
|
||||||
"quality": quality,
|
"quality": quality,
|
||||||
|
"material": material,
|
||||||
"infill": infill_density,
|
"infill": infill_density,
|
||||||
"support": support_enable,
|
"support": support_enable,
|
||||||
"support_pattern": support_pattern
|
"support_pattern": support_pattern
|
||||||
@@ -482,7 +487,7 @@ def merge_and_slice():
|
|||||||
temp_filename = f"temp_edit_{uuid.uuid4().hex}.stl"
|
temp_filename = f"temp_edit_{uuid.uuid4().hex}.stl"
|
||||||
temp_filepath = os.path.join(current_app.config['UPLOAD_FOLDER'], temp_filename)
|
temp_filepath = os.path.join(current_app.config['UPLOAD_FOLDER'], temp_filename)
|
||||||
|
|
||||||
merge_and_slice_task(target_file_id, inputs, temp_filepath, quality, infill_density, support_enable, support_pattern, delete_stl=True)
|
merge_and_slice_task(target_file_id, inputs, temp_filepath, quality, material, infill_density, support_enable, support_pattern, delete_stl=True)
|
||||||
elif len(inputs) == 1 and is_edit:
|
elif len(inputs) == 1 and is_edit:
|
||||||
target_file_id = pieces[0]['file_id']
|
target_file_id = pieces[0]['file_id']
|
||||||
print_file = PrintFile.query.get(target_file_id)
|
print_file = PrintFile.query.get(target_file_id)
|
||||||
@@ -495,7 +500,7 @@ def merge_and_slice():
|
|||||||
temp_filename = f"temp_{uuid.uuid4().hex}.stl"
|
temp_filename = f"temp_{uuid.uuid4().hex}.stl"
|
||||||
temp_filepath = os.path.join(current_app.config['UPLOAD_FOLDER'], temp_filename)
|
temp_filepath = os.path.join(current_app.config['UPLOAD_FOLDER'], temp_filename)
|
||||||
|
|
||||||
merge_and_slice_task(target_file_id, inputs, temp_filepath, quality, infill_density, support_enable, support_pattern, delete_stl=True)
|
merge_and_slice_task(target_file_id, inputs, temp_filepath, quality, material, infill_density, support_enable, support_pattern, delete_stl=True)
|
||||||
else:
|
else:
|
||||||
# Multiple models, create a new "Merged Slice" PrintFile entry to keep track of combination
|
# Multiple models, create a new "Merged Slice" PrintFile entry to keep track of combination
|
||||||
timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
|
timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
|
||||||
@@ -508,6 +513,7 @@ def merge_and_slice():
|
|||||||
"parts": [],
|
"parts": [],
|
||||||
"settings": {
|
"settings": {
|
||||||
"quality": quality,
|
"quality": quality,
|
||||||
|
"material": material,
|
||||||
"infill": infill_density,
|
"infill": infill_density,
|
||||||
"support": support_enable,
|
"support": support_enable,
|
||||||
"support_pattern": support_pattern
|
"support_pattern": support_pattern
|
||||||
@@ -534,7 +540,7 @@ def merge_and_slice():
|
|||||||
db.session.add(print_file)
|
db.session.add(print_file)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
merge_and_slice_task(print_file.id, inputs, merged_filepath, quality, infill_density, support_enable, support_pattern, delete_stl=False)
|
merge_and_slice_task(print_file.id, inputs, merged_filepath, quality, material, infill_density, support_enable, support_pattern, delete_stl=False)
|
||||||
|
|
||||||
return jsonify({'success': True, 'message': 'Plater slice queued!'})
|
return jsonify({'success': True, 'message': 'Plater slice queued!'})
|
||||||
|
|
||||||
@@ -553,5 +559,6 @@ def engine_options(engine_name):
|
|||||||
from app.utils.slice_engines import get_slicer_engine
|
from app.utils.slice_engines import get_slicer_engine
|
||||||
engine = get_slicer_engine(engine_name)
|
engine = get_slicer_engine(engine_name)
|
||||||
presets = engine.get_quality_presets(current_app)
|
presets = engine.get_quality_presets(current_app)
|
||||||
patterns = engine.get_support_patterns()
|
patterns = engine.get_support_patterns(current_app)
|
||||||
return jsonify({'presets': presets, 'support_patterns': patterns})
|
materials = engine.get_materials(current_app) if hasattr(engine, 'get_materials') else []
|
||||||
|
return jsonify({'presets': presets, 'support_patterns': patterns, 'materials': materials})
|
||||||
|
|||||||
@@ -12,25 +12,25 @@
|
|||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="offset_x" class="form-label">{{ _('Plater Origin Offset X (mm)') }}</label>
|
<label for="offset_x" class="form-label">{{ _('Plater Origin Offset X (mm)') }}</label>
|
||||||
<input type="number" class="form-control" name="offset_x" id="offset_x" value="{{ configs.get('offset_x', '0') }}">
|
<input type="number" class="form-control" name="offset_x" id="offset_x" value="{{ configs.get('offset_x', '0') }}">
|
||||||
<div class="form-text">{{ _('Adjust the X-axis compilation offset for combined files on the build plate.') }}</div>
|
<div class="form-text"><i class="bi bi-info-circle me-1"></i>{{ _('Adjust the X-axis compilation offset for combined files on the build plate.') }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="offset_y" class="form-label">{{ _('Plater Origin Offset Y (mm)') }}</label>
|
<label for="offset_y" class="form-label">{{ _('Plater Origin Offset Y (mm)') }}</label>
|
||||||
<input type="number" class="form-control" name="offset_y" id="offset_y" value="{{ configs.get('offset_y', '0') }}">
|
<input type="number" class="form-control" name="offset_y" id="offset_y" value="{{ configs.get('offset_y', '0') }}">
|
||||||
<div class="form-text">{{ _('Adjust the Y-axis compilation offset for combined files on the build plate.') }}</div>
|
<div class="form-text"><i class="bi bi-info-circle me-1"></i>{{ _('Adjust the Y-axis compilation offset for combined files on the build plate.') }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="proxy_skip_size_mb" class="form-label">{{ _('Proxy Skip Size (MB)') }}</label>
|
<label for="proxy_skip_size_mb" class="form-label">{{ _('Proxy Skip Size (MB)') }}</label>
|
||||||
<input type="number" class="form-control" name="proxy_skip_size_mb" id="proxy_skip_size_mb" value="{{ configs.get('proxy_skip_size_mb', '5.0') }}" step="0.1" min="0">
|
<input type="number" class="form-control" name="proxy_skip_size_mb" id="proxy_skip_size_mb" value="{{ configs.get('proxy_skip_size_mb', '5.0') }}" step="0.1" min="0">
|
||||||
<div class="form-text">{{ _('Files smaller than this will not generate a simplified proxy.') }}</div>
|
<div class="form-text"><i class="bi bi-info-circle me-1"></i>{{ _('Files smaller than this will not generate a simplified proxy.') }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="gcode_upload_folder" class="form-label"><i class="bi bi-folder2-open me-2"></i>{{ _('Custom GCode Output Folder') }}</label>
|
<label for="gcode_upload_folder" class="form-label"><i class="bi bi-folder2-open me-2"></i>{{ _('Custom GCode Output Folder') }}</label>
|
||||||
<input type="text" class="form-control" name="gcode_upload_folder" id="gcode_upload_folder" value="{{ configs.get('gcode_upload_folder', '') }}">
|
<input type="text" class="form-control" name="gcode_upload_folder" id="gcode_upload_folder" value="{{ configs.get('gcode_upload_folder', '') }}">
|
||||||
<div class="form-text">{{ _('Absolute path to save locally sliced GCode files (e.g. OctoPrint uploads folder like "/home/pi/.octoprint/uploads"). Leave empty to use system default.') }}</div>
|
<div class="form-text"><i class="bi bi-info-circle me-1"></i>{{ _('Absolute path to save locally sliced GCode files (e.g. OctoPrint uploads folder like "/home/pi/.octoprint/uploads"). Leave empty to use system default.') }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h5 class="card-title text-primary border-bottom pb-2 mt-4 mb-3"><i class="bi bi-grid-3x3 me-2"></i>{{ _('Default Plater Settings') }}</h5>
|
<h5 class="card-title text-primary border-bottom pb-2 mt-4 mb-3"><i class="bi bi-grid-3x3 me-2"></i>{{ _('Default Plater Settings') }}</h5>
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="build_plate_model_path" class="form-label">{{ _('Build Plate Model Path (.stl)') }}</label>
|
<label for="build_plate_model_path" class="form-label">{{ _('Build Plate Model Path (.stl)') }}</label>
|
||||||
<input type="text" class="form-control" name="build_plate_model_path" id="build_plate_model_path" value="{{ configs.get('build_plate_model_path', '') }}">
|
<input type="text" class="form-control" name="build_plate_model_path" id="build_plate_model_path" value="{{ configs.get('build_plate_model_path', '') }}">
|
||||||
<div class="form-text">{{ _('Absolute path to a custom build plate STL model to show in the plater. Leave empty to use none.') }}</div>
|
<div class="form-text"><i class="bi bi-info-circle me-1"></i>{{ _('Absolute path to a custom build plate STL model to show in the plater. Leave empty to use none.') }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@@ -62,13 +62,20 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-4">
|
<div class="mb-3">
|
||||||
<label for="default_quality" class="form-label">{{ _('Default Quality Profile') }}</label>
|
<label for="default_quality" class="form-label">{{ _('Default Quality Profile') }}</label>
|
||||||
<select class="form-select" name="default_quality" id="default_quality" data-selected="{{ configs.get('default_quality', 'base_global_standard.inst.cfg') }}">
|
<select class="form-select" name="default_quality" id="default_quality" data-selected="{{ configs.get('default_quality', 'base_global_standard.inst.cfg') }}">
|
||||||
<!-- Loaded via JS -->
|
<!-- Loaded via JS -->
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="default_material" class="form-label">{{ _('Default Material Profile') }}</label>
|
||||||
|
<select class="form-select" name="default_material" id="default_material" data-selected="{{ configs.get('default_material', '') }}">
|
||||||
|
<!-- Loaded via JS -->
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h5 class="card-title text-primary border-bottom pb-2 mt-4 mb-3"><i class="bi bi-cpu me-2"></i>{{ _('Slicing Engine Configurations') }}</h5>
|
<h5 class="card-title text-primary border-bottom pb-2 mt-4 mb-3"><i class="bi bi-cpu me-2"></i>{{ _('Slicing Engine Configurations') }}</h5>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="slicer_engine" class="form-label">{{ _('Slicing Engine') }}</label>
|
<label for="slicer_engine" class="form-label">{{ _('Slicing Engine') }}</label>
|
||||||
@@ -151,6 +158,7 @@ function submitSettings(event) {
|
|||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
const engineSelect = document.getElementById('slicer_engine');
|
const engineSelect = document.getElementById('slicer_engine');
|
||||||
const qualitySelect = document.getElementById('default_quality');
|
const qualitySelect = document.getElementById('default_quality');
|
||||||
|
const materialSelect = document.getElementById('default_material');
|
||||||
const patternSelect = document.getElementById('default_support_pattern');
|
const patternSelect = document.getElementById('default_support_pattern');
|
||||||
|
|
||||||
function updateOptions(engine) {
|
function updateOptions(engine) {
|
||||||
@@ -166,6 +174,21 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
});
|
});
|
||||||
if(selQ) qualitySelect.value = selQ;
|
if(selQ) qualitySelect.value = selQ;
|
||||||
|
|
||||||
|
const selM = materialSelect.getAttribute('data-selected');
|
||||||
|
materialSelect.innerHTML = '';
|
||||||
|
// Add an empty option for material (optional fallback)
|
||||||
|
const emptyOpt = document.createElement('option');
|
||||||
|
emptyOpt.value = ''; emptyOpt.textContent = "{{ _('Auto / Default') }}";
|
||||||
|
materialSelect.appendChild(emptyOpt);
|
||||||
|
if(data.materials) {
|
||||||
|
data.materials.forEach(p => {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = p.id; opt.textContent = p.name;
|
||||||
|
materialSelect.appendChild(opt);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if(selM) materialSelect.value = selM;
|
||||||
|
|
||||||
const selP = patternSelect.getAttribute('data-selected');
|
const selP = patternSelect.getAttribute('data-selected');
|
||||||
patternSelect.innerHTML = '';
|
patternSelect.innerHTML = '';
|
||||||
data.support_patterns.forEach(p => {
|
data.support_patterns.forEach(p => {
|
||||||
|
|||||||
@@ -65,6 +65,7 @@
|
|||||||
<ul class="dropdown-menu dropdown-menu-end shadow" aria-labelledby="langDropdown">
|
<ul class="dropdown-menu dropdown-menu-end shadow" aria-labelledby="langDropdown">
|
||||||
<li><a class="dropdown-item {% if request.cookies.get('lang') == 'en' %}active{% endif %}" href="{{ url_for('main.set_language', lang='en') }}"><i class="bi bi-translate me-2"></i>English</a></li>
|
<li><a class="dropdown-item {% if request.cookies.get('lang') == 'en' %}active{% endif %}" href="{{ url_for('main.set_language', lang='en') }}"><i class="bi bi-translate me-2"></i>English</a></li>
|
||||||
<li><a class="dropdown-item {% if request.cookies.get('lang') == 'zh-cn' %}active{% endif %}" href="{{ url_for('main.set_language', lang='zh-cn') }}"><i class="bi bi-translate me-2"></i>中文 (简体)</a></li>
|
<li><a class="dropdown-item {% if request.cookies.get('lang') == 'zh-cn' %}active{% endif %}" href="{{ url_for('main.set_language', lang='zh-cn') }}"><i class="bi bi-translate me-2"></i>中文 (简体)</a></li>
|
||||||
|
<li><a class="dropdown-item {% if request.cookies.get('lang') == 'de' %}active{% endif %}" href="{{ url_for('main.set_language', lang='de') }}"><i class="bi bi-translate me-2"></i>Deutsch</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -66,9 +66,26 @@ document.addEventListener('DOMContentLoaded', async function() {
|
|||||||
'SKIRT': new THREE.Color(0x00ffff),
|
'SKIRT': new THREE.Color(0x00ffff),
|
||||||
'SUPPORT-INTERFACE': new THREE.Color(0x2b6b2b),
|
'SUPPORT-INTERFACE': new THREE.Color(0x2b6b2b),
|
||||||
'TRAVEL': new THREE.Color(0x405060),
|
'TRAVEL': new THREE.Color(0x405060),
|
||||||
'DEFAULT': new THREE.Color(0xaaaaaa),
|
'DEFAULT': new THREE.Color(0xaaaaaa)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Additional aliases mapped to basic COLORS
|
||||||
|
const COLOR_ALIASES = {
|
||||||
|
'External perimeter': COLORS['WALL-OUTER'],
|
||||||
|
'Overhang perimeter': COLORS['WALL-OUTER'],
|
||||||
|
'Perimeter': COLORS['WALL-INNER'],
|
||||||
|
'Internal infill': COLORS['FILL'],
|
||||||
|
'Solid infill': COLORS['FILL'],
|
||||||
|
'Top solid infill': COLORS['FILL'],
|
||||||
|
'Bridge infill': COLORS['FILL'],
|
||||||
|
'Support material': COLORS['SUPPORT'],
|
||||||
|
'Skirt/Brim': COLORS['SKIRT'],
|
||||||
|
'Support material interface': COLORS['SUPPORT-INTERFACE']
|
||||||
|
};
|
||||||
|
|
||||||
|
// Merge aliases into COLORS
|
||||||
|
Object.assign(COLORS, COLOR_ALIASES);
|
||||||
|
|
||||||
// Inject printer machine dimensions via Jinja
|
// Inject printer machine dimensions via Jinja
|
||||||
const bedWidth = {{ machine_width | default(220) }};
|
const bedWidth = {{ machine_width | default(220) }};
|
||||||
const bedDepth = {{ machine_depth | default(220) }};
|
const bedDepth = {{ machine_depth | default(220) }};
|
||||||
@@ -83,6 +100,23 @@ document.addEventListener('DOMContentLoaded', async function() {
|
|||||||
'SKIRT': 7, 'SUPPORT-INTERFACE': 8
|
'SKIRT': 7, 'SUPPORT-INTERFACE': 8
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Aliases for TYPE_INDEX
|
||||||
|
const TYPE_INDEX_ALIASES = {
|
||||||
|
'External perimeter': 1,
|
||||||
|
'Overhang perimeter': 1,
|
||||||
|
'Perimeter': 2,
|
||||||
|
'Internal infill': 3,
|
||||||
|
'Solid infill': 3,
|
||||||
|
'Top solid infill': 3,
|
||||||
|
'Bridge infill': 3,
|
||||||
|
'Support material': 5,
|
||||||
|
'Skirt/Brim': 7,
|
||||||
|
'Support material interface': 8
|
||||||
|
};
|
||||||
|
|
||||||
|
// Merge aliases into TYPE_INDEX
|
||||||
|
Object.assign(TYPE_INDEX, TYPE_INDEX_ALIASES);
|
||||||
|
|
||||||
let layers = [];
|
let layers = [];
|
||||||
let scene, camera, renderer, controls;
|
let scene, camera, renderer, controls;
|
||||||
let group = new THREE.Group();
|
let group = new THREE.Group();
|
||||||
@@ -160,6 +194,21 @@ document.addEventListener('DOMContentLoaded', async function() {
|
|||||||
'TRAVEL': 'uShowTravel'
|
'TRAVEL': 'uShowTravel'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const uniformMapAliases = {
|
||||||
|
'External perimeter': 'uShowOuter',
|
||||||
|
'Overhang perimeter': 'uShowOuter',
|
||||||
|
'Perimeter': 'uShowInner',
|
||||||
|
'Internal infill': 'uShowInfill',
|
||||||
|
'Solid infill': 'uShowInfill',
|
||||||
|
'Top solid infill': 'uShowInfill',
|
||||||
|
'Bridge infill': 'uShowInfill',
|
||||||
|
'Support material': 'uShowSupport',
|
||||||
|
'Skirt/Brim': 'uShowSkirt',
|
||||||
|
'Support material interface': 'uShowSupportInterface'
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.assign(uniformMap, uniformMapAliases);
|
||||||
|
|
||||||
document.querySelectorAll('.legend-item').forEach(el => {
|
document.querySelectorAll('.legend-item').forEach(el => {
|
||||||
el.addEventListener('click', function() {
|
el.addEventListener('click', function() {
|
||||||
const t = this.dataset.type;
|
const t = this.dataset.type;
|
||||||
@@ -292,16 +341,29 @@ document.addEventListener('DOMContentLoaded', async function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < lines.length; i++) {
|
for (let i = 0; i < lines.length; i++) {
|
||||||
let chunk = lines[i].trim().toUpperCase();
|
let chunk = lines[i].trim();
|
||||||
if (!chunk) continue;
|
if (!chunk) continue;
|
||||||
|
let upperChunk = chunk.toUpperCase();
|
||||||
|
|
||||||
if (chunk.startsWith(';LAYER:')) {
|
if (upperChunk.startsWith(';LAYER:')) {
|
||||||
flushLayer();
|
flushLayer();
|
||||||
} else if (chunk.startsWith(';TYPE:')) {
|
} else if (upperChunk.startsWith(';TYPE:')) {
|
||||||
currentTypeStr = chunk.substring(6).trim();
|
currentTypeStr = chunk.substring(6).trim();
|
||||||
} else if (chunk.startsWith('G0') || chunk.startsWith('G1')) {
|
} else if (upperChunk.startsWith(';') && chunk.includes(' perimeter')) {
|
||||||
|
// Heuristics for Prusa/Slic3r specific comments like `; External perimeter`
|
||||||
|
currentTypeStr = chunk.substring(1).trim();
|
||||||
|
} else if (upperChunk.startsWith(';') && chunk.includes(' infill')) {
|
||||||
|
// Heuristics for Prusa/Slic3r specific comments like `; Internal infill`
|
||||||
|
currentTypeStr = chunk.substring(1).trim();
|
||||||
|
} else if (upperChunk.startsWith(';') && chunk.includes(' material')) {
|
||||||
|
// Support material
|
||||||
|
currentTypeStr = chunk.substring(1).trim();
|
||||||
|
} else if (upperChunk.startsWith(';') && chunk.includes('Skirt/Brim')) {
|
||||||
|
// Skirt/Brim
|
||||||
|
currentTypeStr = 'Skirt/Brim';
|
||||||
|
} else if (upperChunk.startsWith('G0') || upperChunk.startsWith('G1')) {
|
||||||
let next = { x: current.x, y: current.y, z: current.z, e: current.e };
|
let next = { x: current.x, y: current.y, z: current.z, e: current.e };
|
||||||
let parts = chunk.split(/\s+/);
|
let parts = upperChunk.split(/\s+/);
|
||||||
let hasMove = false;
|
let hasMove = false;
|
||||||
|
|
||||||
for (let p of parts) {
|
for (let p of parts) {
|
||||||
@@ -314,11 +376,17 @@ document.addEventListener('DOMContentLoaded', async function() {
|
|||||||
if (hasMove && !isNaN(next.x) && !isNaN(next.y) && !isNaN(next.z)) {
|
if (hasMove && !isNaN(next.x) && !isNaN(next.y) && !isNaN(next.z)) {
|
||||||
let isExtrude = (next.e > current.e);
|
let isExtrude = (next.e > current.e);
|
||||||
// Cura uses G0 for travel generally
|
// Cura uses G0 for travel generally
|
||||||
if (chunk.startsWith('G0') && !chunk.includes('E')) isExtrude = false;
|
if (upperChunk.startsWith('G0') && !upperChunk.includes('E')) isExtrude = false;
|
||||||
|
|
||||||
let activeType = isExtrude ? currentTypeStr : 'TRAVEL';
|
let activeType = isExtrude ? currentTypeStr : 'TRAVEL';
|
||||||
let col = COLORS[activeType] || COLORS['DEFAULT'];
|
// Special case for default aliases like "; External perimeter" which we stored in currentTypeStr
|
||||||
let tIdx = TYPE_INDEX[activeType] !== undefined ? TYPE_INDEX[activeType] : TYPE_INDEX['DEFAULT'];
|
let resolvedType = activeType;
|
||||||
|
if (isExtrude && Object.keys(COLOR_ALIASES).includes(activeType)) {
|
||||||
|
resolvedType = activeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
let col = COLORS[resolvedType] || COLORS['DEFAULT'];
|
||||||
|
let tIdx = TYPE_INDEX[resolvedType] !== undefined ? TYPE_INDEX[resolvedType] : TYPE_INDEX['DEFAULT'];
|
||||||
|
|
||||||
if (isExtrude) {
|
if (isExtrude) {
|
||||||
let dx = next.x - current.x;
|
let dx = next.x - current.x;
|
||||||
|
|||||||
@@ -101,6 +101,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="card shadow-sm flex-shrink-0 mb-3">
|
||||||
|
<div class="card-header bg-light fw-bold text-secondary d-flex justify-content-between align-items-center collapsed" style="cursor: pointer;" data-bs-toggle="collapse" data-bs-target="#collapseMaterial" aria-expanded="false">
|
||||||
|
<span><i class="bi bi-box me-2"></i>{{ _('Material Profile') }}</span>
|
||||||
|
<i class="bi bi-chevron-bar-contract"></i>
|
||||||
|
</div>
|
||||||
|
<div id="collapseMaterial" class="collapse" data-bs-parent="#platerSidebarAccordion">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="mb-3">
|
||||||
|
<select class="form-select bg-light" id="material" data-selected="{{ last_material }}"></select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card shadow-sm flex-shrink-0 mb-3">
|
<div class="card shadow-sm flex-shrink-0 mb-3">
|
||||||
<div class="card-header bg-light fw-bold text-secondary d-flex justify-content-between align-items-center collapsed" style="cursor: pointer;" data-bs-toggle="collapse" data-bs-target="#collapseQuality" aria-expanded="false">
|
<div class="card-header bg-light fw-bold text-secondary d-flex justify-content-between align-items-center collapsed" style="cursor: pointer;" data-bs-toggle="collapse" data-bs-target="#collapseQuality" aria-expanded="false">
|
||||||
<span><i class="bi bi-gear-wide-connected me-2"></i>{{ _('Quality Profile') }}</span>
|
<span><i class="bi bi-gear-wide-connected me-2"></i>{{ _('Quality Profile') }}</span>
|
||||||
@@ -679,6 +693,11 @@ function addModelToPlate(btnElement, fileId, url, name, status) {
|
|||||||
qSelect.setAttribute('data-selected', data.settings.quality);
|
qSelect.setAttribute('data-selected', data.settings.quality);
|
||||||
qSelect.value = data.settings.quality;
|
qSelect.value = data.settings.quality;
|
||||||
}
|
}
|
||||||
|
if (data.settings.material) {
|
||||||
|
const mSelect = document.getElementById('material');
|
||||||
|
mSelect.setAttribute('data-selected', data.settings.material);
|
||||||
|
mSelect.value = data.settings.material;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
@@ -882,6 +901,7 @@ function mergeAndSlice() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const quality = document.getElementById('quality').value;
|
const quality = document.getElementById('quality').value;
|
||||||
|
const material = document.getElementById('material').value;
|
||||||
const infill = document.getElementById('infill-density').value;
|
const infill = document.getElementById('infill-density').value;
|
||||||
const support = document.getElementById('support-type').value;
|
const support = document.getElementById('support-type').value;
|
||||||
const supportPattern = document.getElementById('support-pattern').value;
|
const supportPattern = document.getElementById('support-pattern').value;
|
||||||
@@ -900,7 +920,7 @@ function mergeAndSlice() {
|
|||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ pieces: pieces, quality: quality, infill: infill, support: support, support_pattern: supportPattern, is_edit: isEdit, target_file_id: targetFileId })
|
body: JSON.stringify({ pieces: pieces, quality: quality, material: material, infill: infill, support: support, support_pattern: supportPattern, is_edit: isEdit, target_file_id: targetFileId })
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
@@ -959,6 +979,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
const engine = "{{ configs.get('slicer_engine', 'cura') }}";
|
const engine = "{{ configs.get('slicer_engine', 'cura') }}";
|
||||||
const qualitySelect = document.getElementById('quality');
|
const qualitySelect = document.getElementById('quality');
|
||||||
const patternSelect = document.getElementById('support-pattern');
|
const patternSelect = document.getElementById('support-pattern');
|
||||||
|
const materialSelect = document.getElementById('material');
|
||||||
|
|
||||||
fetch(`/api/engine_options/${engine}`)
|
fetch(`/api/engine_options/${engine}`)
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
@@ -972,6 +993,20 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
});
|
});
|
||||||
if(selQ) qualitySelect.value = selQ;
|
if(selQ) qualitySelect.value = selQ;
|
||||||
|
|
||||||
|
const selM = materialSelect.getAttribute('data-selected');
|
||||||
|
materialSelect.innerHTML = '';
|
||||||
|
const emptyOpt = document.createElement('option');
|
||||||
|
emptyOpt.value = ''; emptyOpt.textContent = "{{ _('Auto / Default') }}";
|
||||||
|
materialSelect.appendChild(emptyOpt);
|
||||||
|
if(data.materials) {
|
||||||
|
data.materials.forEach(p => {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = p.id; opt.textContent = p.name;
|
||||||
|
materialSelect.appendChild(opt);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if(selM) materialSelect.value = selM;
|
||||||
|
|
||||||
const selP = patternSelect.getAttribute('data-selected');
|
const selP = patternSelect.getAttribute('data-selected');
|
||||||
patternSelect.innerHTML = '';
|
patternSelect.innerHTML = '';
|
||||||
data.support_patterns.forEach(p => {
|
data.support_patterns.forEach(p => {
|
||||||
|
|||||||
@@ -68,12 +68,17 @@ class CuraEngine:
|
|||||||
preset_path = os.path.join(presets_path, 'creality', 'presets', quality_preset)
|
preset_path = os.path.join(presets_path, 'creality', 'presets', quality_preset)
|
||||||
if os.path.exists(preset_path):
|
if os.path.exists(preset_path):
|
||||||
config.read(preset_path)
|
config.read(preset_path)
|
||||||
material_type = config.get('metadata', 'material', fallback=None)
|
material_type_from_preset = config.get('metadata', 'material', fallback=None)
|
||||||
variant_type = config.get('metadata', 'variant', fallback=None)
|
variant_type = config.get('metadata', 'variant', fallback=None)
|
||||||
quality_type = config.get('metadata', 'quality_type', fallback=None)
|
quality_type = config.get('metadata', 'quality_type', fallback=None)
|
||||||
|
|
||||||
|
# Use explicit material if provided, otherwise fallback to preset's material
|
||||||
|
material_type = kwargs.get('material_preset') or material_type_from_preset
|
||||||
|
|
||||||
if material_type:
|
if material_type:
|
||||||
m_path = os.path.join(materials_path, f"{material_type}.inst.cfg")
|
m_path = os.path.join(materials_path, f"{material_type}.inst.cfg")
|
||||||
|
if not os.path.exists(m_path) and kwargs.get('material_preset'):
|
||||||
|
m_path = os.path.join(materials_path, f"{kwargs.get('material_preset')}")
|
||||||
if os.path.exists(m_path): inst_files_list.append(m_path)
|
if os.path.exists(m_path): inst_files_list.append(m_path)
|
||||||
if variant_type:
|
if variant_type:
|
||||||
variant_d = variant_type.split("mm")[0]
|
variant_d = variant_type.split("mm")[0]
|
||||||
@@ -200,7 +205,7 @@ class CuraEngine:
|
|||||||
except:
|
except:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def get_support_patterns(self):
|
def get_support_patterns(self, app):
|
||||||
return [
|
return [
|
||||||
{'id': 'tree', 'name': 'Tree'},
|
{'id': 'tree', 'name': 'Tree'},
|
||||||
{'id': 'lines', 'name': 'Lines'},
|
{'id': 'lines', 'name': 'Lines'},
|
||||||
@@ -213,3 +218,16 @@ class CuraEngine:
|
|||||||
{'id': 'honeycomb', 'name': 'Honeycomb'},
|
{'id': 'honeycomb', 'name': 'Honeycomb'},
|
||||||
{'id': 'octagon', 'name': 'Octagon'}
|
{'id': 'octagon', 'name': 'Octagon'}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def get_materials(self, app):
|
||||||
|
try:
|
||||||
|
path = os.path.join(app.root_path, '..', 'print_config', 'cura_engine', 'materials')
|
||||||
|
if not os.path.exists(path): return []
|
||||||
|
files = [f for f in os.listdir(path) if f.endswith('.inst.cfg')]
|
||||||
|
materials = []
|
||||||
|
for f in files:
|
||||||
|
materials.append({'id': f, 'name': f.replace('.inst.cfg', '').replace('generic_', 'Generic ').replace('_', ' ').title()})
|
||||||
|
materials.sort(key=lambda x: x['name'])
|
||||||
|
return materials
|
||||||
|
except:
|
||||||
|
return []
|
||||||
|
|||||||
@@ -30,10 +30,21 @@ class PrusaSlicerEngine:
|
|||||||
# Map quality, infill, supports to PrusaSlicer CLI arguments.
|
# Map quality, infill, supports to PrusaSlicer CLI arguments.
|
||||||
# Example defaults, normally these would load from an .ini or be dynamically matched.
|
# Example defaults, normally these would load from an .ini or be dynamically matched.
|
||||||
quality_preset = kwargs.get('quality_preset')
|
quality_preset = kwargs.get('quality_preset')
|
||||||
|
material_preset = kwargs.get('material_preset')
|
||||||
infill_density = kwargs.get('infill_density')
|
infill_density = kwargs.get('infill_density')
|
||||||
support_enable = kwargs.get('support_enable')
|
support_enable = kwargs.get('support_enable')
|
||||||
support_pattern = kwargs.get('support_pattern')
|
support_pattern = kwargs.get('support_pattern')
|
||||||
|
|
||||||
|
if quality_preset:
|
||||||
|
q_ini = os.path.join(app.root_path, '..', 'print_config', 'prusa_slicer', 'quality', f"{quality_preset}.ini")
|
||||||
|
if os.path.exists(q_ini):
|
||||||
|
command.extend(['--load', q_ini])
|
||||||
|
|
||||||
|
if material_preset:
|
||||||
|
m_ini = os.path.join(app.root_path, '..', 'print_config', 'prusa_slicer', 'materials', f"{material_preset}.ini")
|
||||||
|
if os.path.exists(m_ini):
|
||||||
|
command.extend(['--load', m_ini])
|
||||||
|
|
||||||
if infill_density is not None:
|
if infill_density is not None:
|
||||||
command.extend(["--fill-density", f"{infill_density}%"])
|
command.extend(["--fill-density", f"{infill_density}%"])
|
||||||
|
|
||||||
@@ -80,10 +91,29 @@ class PrusaSlicerEngine:
|
|||||||
})
|
})
|
||||||
return quality_presets
|
return quality_presets
|
||||||
|
|
||||||
def get_support_patterns(self):
|
def get_support_patterns(self, app):
|
||||||
return [
|
all_files = [f for f in os.listdir(os.path.join(app.root_path, '..', 'print_config', 'prusa_slicer',"supports")) if f.endswith('.ini')]
|
||||||
{'id': 'rectilinear', 'name': 'Rectilinear'},
|
support_presets = []
|
||||||
{'id': 'grid', 'name': 'Grid'},
|
for file in all_files:
|
||||||
{'id': 'organic', 'name': 'Organic (Tree)'},
|
with open(os.path.join(app.root_path, '..', 'print_config', 'prusa_slicer', "supports", file), 'r') as f:
|
||||||
{'id': 'snug', 'name': 'Snug'}
|
config = configparser.ConfigParser()
|
||||||
]
|
config.read_file(f)
|
||||||
|
if 'metadata' in config:
|
||||||
|
support_presets.append({
|
||||||
|
'id': file.replace('.ini', ''),
|
||||||
|
'name': config['metadata'].get('show_name', file.replace('.ini', '').replace('_', ' '))
|
||||||
|
})
|
||||||
|
return support_presets
|
||||||
|
|
||||||
|
def get_materials(self, app):
|
||||||
|
try:
|
||||||
|
path = os.path.join(app.root_path, '..', 'print_config', 'prusa_slicer', 'materials')
|
||||||
|
if not os.path.exists(path): return []
|
||||||
|
files = [f for f in os.listdir(path) if f.endswith('.ini')]
|
||||||
|
materials = []
|
||||||
|
for f in files:
|
||||||
|
materials.append({'id': f.replace('.ini', ''), 'name': f.replace('.ini', '').replace('_', ' ')})
|
||||||
|
materials.sort(key=lambda x: x['name'])
|
||||||
|
return materials
|
||||||
|
except:
|
||||||
|
return []
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ def get_gcode_dir(app):
|
|||||||
|
|
||||||
|
|
||||||
@huey.task()
|
@huey.task()
|
||||||
def slice_stl_task(file_id, stl_filepath, quality_preset=None, infill_density=None, support_enable=None, support_pattern=None, delete_stl=False):
|
def slice_stl_task(file_id, stl_filepath, quality_preset=None, material_preset=None, infill_density=None, support_enable=None, support_pattern=None, delete_stl=False):
|
||||||
# This is run by the Huey worker
|
# This is run by the Huey worker
|
||||||
# We need to create an app context to interact with the database
|
# We need to create an app context to interact with the database
|
||||||
from app import create_app
|
from app import create_app
|
||||||
@@ -61,6 +61,7 @@ def slice_stl_task(file_id, stl_filepath, quality_preset=None, infill_density=No
|
|||||||
stl_filepath=stl_filepath,
|
stl_filepath=stl_filepath,
|
||||||
gcode_filepath=gcode_filepath,
|
gcode_filepath=gcode_filepath,
|
||||||
quality_preset=quality_preset,
|
quality_preset=quality_preset,
|
||||||
|
material_preset=material_preset,
|
||||||
infill_density=infill_density,
|
infill_density=infill_density,
|
||||||
support_enable=support_enable,
|
support_enable=support_enable,
|
||||||
support_pattern=support_pattern
|
support_pattern=support_pattern
|
||||||
@@ -95,7 +96,7 @@ def slice_stl_task(file_id, stl_filepath, quality_preset=None, infill_density=No
|
|||||||
|
|
||||||
|
|
||||||
@huey.task()
|
@huey.task()
|
||||||
def merge_and_slice_task(file_id, inputs, merged_filepath, quality_preset=None, infill_density=None, support_enable=None, support_pattern=None, delete_stl=False):
|
def merge_and_slice_task(file_id, inputs, merged_filepath, quality_preset=None, material_preset=None, infill_density=None, support_enable=None, support_pattern=None, delete_stl=False):
|
||||||
from app import create_app
|
from app import create_app
|
||||||
app = create_app()
|
app = create_app()
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
@@ -112,7 +113,7 @@ def merge_and_slice_task(file_id, inputs, merged_filepath, quality_preset=None,
|
|||||||
|
|
||||||
# Now trigger the regular slicing task
|
# Now trigger the regular slicing task
|
||||||
# We can just call the slicing logic or enqueue it
|
# We can just call the slicing logic or enqueue it
|
||||||
slice_stl_task(file_id, merged_filepath, quality_preset, infill_density, support_enable, support_pattern, delete_stl=delete_stl)
|
slice_stl_task(file_id, merged_filepath, quality_preset, material_preset, infill_density, support_enable, support_pattern, delete_stl=delete_stl)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print_file = PrintFile.query.get(file_id)
|
print_file = PrintFile.query.get(file_id)
|
||||||
if print_file:
|
if print_file:
|
||||||
|
|||||||
50
print_config/prusa_slicer/supports/grid_support.ini
Normal file
50
print_config/prusa_slicer/supports/grid_support.ini
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
[metadata]
|
||||||
|
show_name = Grid Support
|
||||||
|
|
||||||
|
|
||||||
|
[settings]
|
||||||
|
enable_support = 1
|
||||||
|
support_filament = 0
|
||||||
|
support_line_width = 0.4
|
||||||
|
support_interface_filament = 0
|
||||||
|
support_on_build_plate_only = 0
|
||||||
|
support_top_z_distance = 0.2
|
||||||
|
support_interface_loop_pattern = 0
|
||||||
|
support_interface_top_layers = 2
|
||||||
|
support_interface_spacing = 0.5
|
||||||
|
support_interface_speed = 100%
|
||||||
|
support_base_pattern = rectilinear
|
||||||
|
support_base_pattern_spacing = 2.5
|
||||||
|
support_speed = 50
|
||||||
|
support_threshold_angle = 30
|
||||||
|
support_object_xy_distance = 0.35
|
||||||
|
|
||||||
|
support_type = normal(auto)
|
||||||
|
support_style = Grid
|
||||||
|
support_interface_bottom_layers = 2
|
||||||
|
tree_support_branch_angle = 45
|
||||||
|
tree_support_wall_count = 0
|
||||||
|
|
||||||
|
support_angle = 0
|
||||||
|
support_bottom_interface_spacing = 0.5
|
||||||
|
support_bottom_z_distance = 0.2
|
||||||
|
support_critical_regions_only = 0
|
||||||
|
support_expansion = 0
|
||||||
|
support_interface_not_for_body = 1
|
||||||
|
support_interface_pattern = auto
|
||||||
|
support_remove_small_overhang = 1
|
||||||
|
support_xy_overrides_z = xy_overrides_z
|
||||||
|
|
||||||
|
tree_support_adaptive_layer_height = 1
|
||||||
|
tree_support_angle_slow = 25
|
||||||
|
tree_support_auto_brim = 1
|
||||||
|
tree_support_branch_angle_organic = 40
|
||||||
|
tree_support_branch_diameter = 2
|
||||||
|
tree_support_branch_diameter_angle = 5
|
||||||
|
tree_support_branch_diameter_double_wall = 3
|
||||||
|
tree_support_branch_diameter_organic = 2
|
||||||
|
tree_support_branch_distance = 5
|
||||||
|
tree_support_branch_distance_organic = 1
|
||||||
|
tree_support_brim_width = 3
|
||||||
|
tree_support_tip_diameter = 0.8
|
||||||
|
tree_support_top_rate = 30%
|
||||||
50
print_config/prusa_slicer/supports/snug_support.ini
Normal file
50
print_config/prusa_slicer/supports/snug_support.ini
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
[metadata]
|
||||||
|
show_name = Snug Support
|
||||||
|
|
||||||
|
|
||||||
|
[settings]
|
||||||
|
enable_support = 1
|
||||||
|
support_filament = 0
|
||||||
|
support_line_width = 0.4
|
||||||
|
support_interface_filament = 0
|
||||||
|
support_on_build_plate_only = 0
|
||||||
|
support_top_z_distance = 0.2
|
||||||
|
support_interface_loop_pattern = 0
|
||||||
|
support_interface_top_layers = 2
|
||||||
|
support_interface_spacing = 0.5
|
||||||
|
support_interface_speed = 100%
|
||||||
|
support_base_pattern = rectilinear
|
||||||
|
support_base_pattern_spacing = 2.5
|
||||||
|
support_speed = 50
|
||||||
|
support_threshold_angle = 30
|
||||||
|
support_object_xy_distance = 0.35
|
||||||
|
|
||||||
|
support_type = normal(auto)
|
||||||
|
support_style = Snug
|
||||||
|
support_interface_bottom_layers = 2
|
||||||
|
tree_support_branch_angle = 45
|
||||||
|
tree_support_wall_count = 0
|
||||||
|
|
||||||
|
support_angle = 0
|
||||||
|
support_bottom_interface_spacing = 0.5
|
||||||
|
support_bottom_z_distance = 0.2
|
||||||
|
support_critical_regions_only = 0
|
||||||
|
support_expansion = 0
|
||||||
|
support_interface_not_for_body = 1
|
||||||
|
support_interface_pattern = auto
|
||||||
|
support_remove_small_overhang = 1
|
||||||
|
support_xy_overrides_z = xy_overrides_z
|
||||||
|
|
||||||
|
tree_support_adaptive_layer_height = 1
|
||||||
|
tree_support_angle_slow = 25
|
||||||
|
tree_support_auto_brim = 1
|
||||||
|
tree_support_branch_angle_organic = 40
|
||||||
|
tree_support_branch_diameter = 2
|
||||||
|
tree_support_branch_diameter_angle = 5
|
||||||
|
tree_support_branch_diameter_double_wall = 3
|
||||||
|
tree_support_branch_diameter_organic = 2
|
||||||
|
tree_support_branch_distance = 5
|
||||||
|
tree_support_branch_distance_organic = 1
|
||||||
|
tree_support_brim_width = 3
|
||||||
|
tree_support_tip_diameter = 0.8
|
||||||
|
tree_support_top_rate = 30%
|
||||||
50
print_config/prusa_slicer/supports/tree_support.ini
Normal file
50
print_config/prusa_slicer/supports/tree_support.ini
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
[metadata]
|
||||||
|
show_name = Tree Support
|
||||||
|
|
||||||
|
|
||||||
|
[settings]
|
||||||
|
enable_support = 1
|
||||||
|
support_filament = 0
|
||||||
|
support_line_width = 0.4
|
||||||
|
support_interface_filament = 0
|
||||||
|
support_on_build_plate_only = 0
|
||||||
|
support_top_z_distance = 0.2
|
||||||
|
support_interface_loop_pattern = 0
|
||||||
|
support_interface_top_layers = 2
|
||||||
|
support_interface_spacing = 0.5
|
||||||
|
support_interface_speed = 100%
|
||||||
|
support_base_pattern = rectilinear
|
||||||
|
support_base_pattern_spacing = 2.5
|
||||||
|
support_speed = 50
|
||||||
|
support_threshold_angle = 30
|
||||||
|
support_object_xy_distance = 0.35
|
||||||
|
|
||||||
|
support_type = normal(auto)
|
||||||
|
support_style = Organic
|
||||||
|
support_interface_bottom_layers = 2
|
||||||
|
tree_support_branch_angle = 45
|
||||||
|
tree_support_wall_count = 0
|
||||||
|
|
||||||
|
support_angle = 0
|
||||||
|
support_bottom_interface_spacing = 0.5
|
||||||
|
support_bottom_z_distance = 0.2
|
||||||
|
support_critical_regions_only = 0
|
||||||
|
support_expansion = 0
|
||||||
|
support_interface_not_for_body = 1
|
||||||
|
support_interface_pattern = auto
|
||||||
|
support_remove_small_overhang = 1
|
||||||
|
support_xy_overrides_z = xy_overrides_z
|
||||||
|
|
||||||
|
tree_support_adaptive_layer_height = 1
|
||||||
|
tree_support_angle_slow = 25
|
||||||
|
tree_support_auto_brim = 1
|
||||||
|
tree_support_branch_angle_organic = 40
|
||||||
|
tree_support_branch_diameter = 2
|
||||||
|
tree_support_branch_diameter_angle = 5
|
||||||
|
tree_support_branch_diameter_double_wall = 3
|
||||||
|
tree_support_branch_diameter_organic = 2
|
||||||
|
tree_support_branch_distance = 5
|
||||||
|
tree_support_branch_distance_organic = 1
|
||||||
|
tree_support_brim_width = 3
|
||||||
|
tree_support_tip_diameter = 0.8
|
||||||
|
tree_support_top_rate = 30%
|
||||||
Reference in New Issue
Block a user