Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b2ae48e4a | ||
|
|
8095904bc2 | ||
|
|
b7c86befe1 | ||
|
|
526a91d323 | ||
|
|
493896260e | ||
|
|
ca83497bb6 | ||
|
|
6a985744c4 |
@@ -1,139 +0,0 @@
|
|||||||
name: Daily OFL OTA Update
|
|
||||||
|
|
||||||
# This workflow is intended for creating and publishing the OrcaFilamentLibrary (OFL) OPC package to
|
|
||||||
# https://github.com/OrcaSlicer/orcaslicer-profiles, which generates an OTA update.
|
|
||||||
# This cronjob runs daily at 00:00 UTC every day and scans main plus every release/vX.Y.Z branch for
|
|
||||||
# changes to resources/profiles/OrcaFilamentLibrary since that branch's own last successful run. Any
|
|
||||||
# branch with no changes is skipped; each changed branch gets its own post_merge_profiles.yml dispatch.
|
|
||||||
#
|
|
||||||
# OFL has no dedicated FOLDER_MERGERS grant (it isn't merged through the PR merge-bot delegation
|
|
||||||
# scheme), so post_merge_profiles.yml is dispatched with an explicit `vendor` input, which that
|
|
||||||
# workflow trusts and uses to bypass the FOLDER_MERGERS check for this trigger. That same explicit-
|
|
||||||
# vendor-dispatch path is also what makes post_merge_profiles.yml call the OTA auto-publish API after
|
|
||||||
# uploading - see post_merge_profiles.yml for both sides of that contract.
|
|
||||||
#
|
|
||||||
# At the start of each run, the pending-publish table is cleared up to a captured
|
|
||||||
# timestamp (POST /api/v1/ota/ofl/pending/clear?timestamp=...). Changes merged after
|
|
||||||
# that timestamp remain pending for the next run.
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "0 0 * * *"
|
|
||||||
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
actions: write # list this workflow's past runs and dispatch post_merge_profiles.yml
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
env:
|
|
||||||
VENDOR: OrcaFilamentLibrary
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
daily-job:
|
|
||||||
if: ${{ github.repository == 'OrcaSlicer/OrcaSlicer' }}
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
steps:
|
|
||||||
- name: Capture start timestamp and clear OFL pending queue
|
|
||||||
id: start
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
OTA_API_BASE_URL: ${{ vars.OTA_API_BASE_URL }}
|
|
||||||
OTA_API_KEY: ${{ secrets.OFL_OTA_PUBLISH_KEY }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
[ -n "$OTA_API_BASE_URL" ] || { echo "::error::vars.OTA_API_BASE_URL is not set"; exit 1; }
|
|
||||||
[ -n "$OTA_API_KEY" ] || { echo "::error::secrets.OFL_OTA_PUBLISH_KEY is not set"; exit 1; }
|
|
||||||
|
|
||||||
timestamp="$(date -u +%s)"
|
|
||||||
echo "timestamp=$timestamp" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
resp_file="$RUNNER_TEMP/ota-pending-clear-response.json"
|
|
||||||
status="$(curl -sS -o "$resp_file" -w '%{http_code}' -X POST \
|
|
||||||
"${OTA_API_BASE_URL%/}/api/v1/ota/ofl/pending/clear?timestamp=$timestamp" \
|
|
||||||
-H "Authorization: Bearer $OTA_API_KEY")"
|
|
||||||
body="$(cat "$resp_file")"
|
|
||||||
echo "$body"
|
|
||||||
|
|
||||||
if [ "$status" != "200" ]; then
|
|
||||||
echo "::error::OTA pending-clear call failed with HTTP $status"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v7
|
|
||||||
with:
|
|
||||||
# Full history: the per-branch "since last successful run" check below
|
|
||||||
# needs to look arbitrarily far back if a prior run failed or was skipped.
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Fetch all branches
|
|
||||||
shell: bash
|
|
||||||
run: git fetch origin '+refs/heads/*:refs/remotes/origin/*'
|
|
||||||
|
|
||||||
- name: Scan branches and publish changed OFL profiles
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
SCAN_UNTIL: ${{ steps.start.outputs.timestamp }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
mapfile -t branches < <(
|
|
||||||
gh api "repos/${{ github.repository }}/branches" --paginate --jq '.[].name' \
|
|
||||||
| grep -E '^(main|release/v[0-9]+\.[0-9]+\.[0-9]+)$' | sort -u
|
|
||||||
)
|
|
||||||
|
|
||||||
for branch in "${branches[@]}"; do
|
|
||||||
echo "::group::$branch"
|
|
||||||
|
|
||||||
# post_merge_profiles.yml's own run history, not this workflow's: this
|
|
||||||
# workflow only ever runs against main (schedule, or workflow_dispatch
|
|
||||||
# --ref main), so its head branch never varies - filtering ITS history
|
|
||||||
# by $branch would never match anything except main. post_merge_profiles.yml
|
|
||||||
# genuinely runs per-branch (this dispatch below sets --ref "$branch"),
|
|
||||||
# so its history is the real per-branch checkpoint. It also means a
|
|
||||||
# failed publish naturally gets retried tomorrow: the checkpoint only
|
|
||||||
# advances on a run that actually succeeded.
|
|
||||||
# --method GET is required, not cosmetic: gh api defaults to POST
|
|
||||||
# whenever -f fields are present unless a method is given
|
|
||||||
# explicitly, and POST on this list-runs endpoint 404s - confirmed
|
|
||||||
# on real Actions infrastructure, not just reasoned about.
|
|
||||||
since="$(gh api --method GET "repos/${{ github.repository }}/actions/workflows/post_merge_profiles.yml/runs" \
|
|
||||||
-f status=success -f branch="$branch" -f per_page=1 \
|
|
||||||
--jq '.workflow_runs[0].run_started_at // empty')"
|
|
||||||
|
|
||||||
if [ -z "$since" ]; then
|
|
||||||
echo "No prior successful run for $branch; checking OFL changes up to $SCAN_UNTIL."
|
|
||||||
changed_files="$(git log --until="$SCAN_UNTIL" --name-only --pretty=format: "origin/$branch" -- \
|
|
||||||
resources/profiles/OrcaFilamentLibrary resources/profiles/OrcaFilamentLibrary.json \
|
|
||||||
| sed '/^$/d')"
|
|
||||||
else
|
|
||||||
changed_files="$(git log --since="$since" --until="$SCAN_UNTIL" --name-only --pretty=format: "origin/$branch" -- \
|
|
||||||
resources/profiles/OrcaFilamentLibrary resources/profiles/OrcaFilamentLibrary.json \
|
|
||||||
| sed '/^$/d')"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$changed_files" ]; then
|
|
||||||
echo "OFL changed on $branch from ${since:-the beginning} through $SCAN_UNTIL:"
|
|
||||||
echo "$changed_files"
|
|
||||||
changed=true
|
|
||||||
else
|
|
||||||
echo "No OFL changes on $branch through $SCAN_UNTIL."
|
|
||||||
changed=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$changed" = true ]; then
|
|
||||||
# Tolerate a per-branch failure (e.g. a pre-existing release branch
|
|
||||||
# whose post_merge_profiles.yml predates the vendor/auto_publish
|
|
||||||
# inputs) rather than aborting the whole scan under set -e.
|
|
||||||
if ! gh workflow run post_merge_profiles.yml \
|
|
||||||
--repo "${{ github.repository }}" \
|
|
||||||
--ref "$branch" \
|
|
||||||
-f vendor="$VENDOR" -f auto_publish=true; then
|
|
||||||
echo "::warning::failed to dispatch post_merge_profiles.yml for $branch - its post_merge_profiles.yml at this ref may predate the vendor/auto_publish inputs"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "::endgroup::"
|
|
||||||
done
|
|
||||||
@@ -5,9 +5,8 @@
|
|||||||
# re-sliced on its own to see whether it changes the G-code
|
# re-sliced on its own to see whether it changes the G-code
|
||||||
# harness - the GUI-vs-CLI parity harness (metrics only, never fails)
|
# harness - the GUI-vs-CLI parity harness (metrics only, never fails)
|
||||||
# Both test the latest successful build_all.yml Linux AppImage from main, with
|
# Both test the latest successful build_all.yml Linux AppImage from main, with
|
||||||
# sources checked out at the commit that build was made from; a manual run can
|
# sources checked out at the commit that build was made from. Nothing here
|
||||||
# name another branch, or pin one build by its run id. Nothing here gates a
|
# gates a build or a PR.
|
||||||
# build or a PR.
|
|
||||||
name: Parity Nightly
|
name: Parity Nightly
|
||||||
|
|
||||||
on:
|
on:
|
||||||
@@ -21,13 +20,9 @@ on:
|
|||||||
required: false
|
required: false
|
||||||
default: "main"
|
default: "main"
|
||||||
build_branch:
|
build_branch:
|
||||||
description: "branch whose newest successful build_all artifact to test (a PR build is the PR merged into its base; sources are checked out at the PR head)"
|
description: "branch whose latest successful build_all artifact to test"
|
||||||
required: false
|
required: false
|
||||||
default: "main"
|
default: "main"
|
||||||
build_run_id:
|
|
||||||
description: "build_all run id to test instead of build_branch's newest (same PR caveat)"
|
|
||||||
required: false
|
|
||||||
default: ""
|
|
||||||
fixtures:
|
fixtures:
|
||||||
description: "harness fixture ids, space-separated (empty = all)"
|
description: "harness fixture ids, space-separated (empty = all)"
|
||||||
required: false
|
required: false
|
||||||
@@ -55,53 +50,14 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
GH_REPO: ${{ github.repository }}
|
GH_REPO: ${{ github.repository }}
|
||||||
BRANCH: ${{ inputs.build_branch || 'main' }}
|
|
||||||
RUN_ID: ${{ inputs.build_run_id }}
|
|
||||||
SCHEDULED: ${{ github.event_name == 'schedule' }}
|
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
if [ -n "$RUN_ID" ]; then
|
gh run list --workflow build_all.yml \
|
||||||
[[ $RUN_ID =~ ^[0-9]+$ ]] || { echo "build_run_id must be a numeric run id, got '$RUN_ID'" >&2; exit 1; }
|
--branch "${{ inputs.build_branch || 'main' }}" \
|
||||||
# a pinned build is read directly, not through a search; it must come
|
--status success --limit 1 --json databaseId,headSha \
|
||||||
# from this repository, because the later jobs check out its commit here
|
--jq '"run_id=\(.[0].databaseId)\nhead_sha=\(.[0].headSha)"' \
|
||||||
found=$(gh api "repos/$GH_REPO/actions/runs/$RUN_ID" --jq \
|
>> "$GITHUB_OUTPUT"
|
||||||
'select(.path == ".github/workflows/build_all.yml" and .conclusion == "success"
|
|
||||||
and .head_repository.full_name == env.GH_REPO)
|
|
||||||
| "\(.id) \(.head_sha) \(.created_at)"')
|
|
||||||
[ -n "$found" ] || { echo "run $RUN_ID is not a successful build_all run of $GH_REPO" >&2; exit 1; }
|
|
||||||
else
|
|
||||||
# GitHub serves filtered run listings (branch=, status=, head_sha=, ...)
|
|
||||||
# from a search index that has returned weeks-old results, while the
|
|
||||||
# unfiltered listing stays current, so list unfiltered and filter here.
|
|
||||||
# The repository check keeps out fork PRs whose branch has the same
|
|
||||||
# name. A feature branch is normally built only for its PR, and a PR
|
|
||||||
# build compiles the PR merged into its base rather than head_sha, so
|
|
||||||
# a build of the branch itself (push or dispatch) is preferred when
|
|
||||||
# the same page has one.
|
|
||||||
pick='([.workflow_runs[] | select(.head_branch == env.BRANCH and .conclusion == "success"
|
|
||||||
and .head_repository.full_name == env.GH_REPO)]
|
|
||||||
| map(select(.event != "pull_request"))[0] // .[0])
|
|
||||||
| select(.) | "\(.id) \(.head_sha) \(.created_at)"'
|
|
||||||
# a page of 100 runs spans about a day and a half; a manual run may
|
|
||||||
# target a branch that last built weeks ago
|
|
||||||
pages=3
|
|
||||||
if [ "$SCHEDULED" != true ]; then pages=20; fi
|
|
||||||
found=""
|
|
||||||
for page in $(seq "$pages"); do
|
|
||||||
found=$(gh api "repos/$GH_REPO/actions/workflows/build_all.yml/runs?per_page=100&page=$page" --jq "$pick")
|
|
||||||
if [ -n "$found" ]; then break; fi
|
|
||||||
done
|
|
||||||
[ -n "$found" ] || { echo "no successful $BRANCH build among the last $((pages * 100)) build_all runs; pass build_run_id to test an older one" >&2; exit 1; }
|
|
||||||
fi
|
|
||||||
read -r run_id head_sha created <<< "$found"
|
|
||||||
# the nightly fails rather than report on a stale build
|
|
||||||
if [ "$SCHEDULED" = true ] && [ $(( $(date +%s) - $(date -d "$created" +%s) )) -gt 172800 ]; then
|
|
||||||
echo "newest $BRANCH build $run_id is from $created, over 48 hours old" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
printf 'run_id=%s\nhead_sha=%s\n' "$run_id" "$head_sha" >> "$GITHUB_OUTPUT"
|
|
||||||
cat "$GITHUB_OUTPUT"
|
cat "$GITHUB_OUTPUT"
|
||||||
echo "Testing build [$run_id](https://github.com/$GH_REPO/actions/runs/$run_id) of \`$head_sha\`, built $created" >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
|
|
||||||
effect:
|
effect:
|
||||||
name: Override sweep effect stage (shard ${{ matrix.shard }})
|
name: Override sweep effect stage (shard ${{ matrix.shard }})
|
||||||
|
|||||||
@@ -8,19 +8,6 @@ name: Post-merge profiles
|
|||||||
# only then does it become a live OTA update - this workflow does none of that
|
# only then does it become a live OTA update - this workflow does none of that
|
||||||
# last part (no changelog, no R2, no webhook).
|
# last part (no changelog, no R2, no webhook).
|
||||||
#
|
#
|
||||||
# A workflow_dispatch carrying a `vendor` input (e.g. the daily OFL cron - OFL has
|
|
||||||
# no FOLDER_MERGERS grant, since it isn't merged through the PR merge-bot delegation
|
|
||||||
# scheme) publishes that vendor directly and skips the FOLDER_MERGERS check below.
|
|
||||||
# workflow_dispatch is already a trusted, explicit trigger, unlike the automatic
|
|
||||||
# push-diff path the FOLDER_MERGERS check exists to gate.
|
|
||||||
#
|
|
||||||
# Separately, an ordinary push whose diff touches an OrcaFilamentLibrary company
|
|
||||||
# folder (resources/profiles/OrcaFilamentLibrary/filament/<Company>/**) records
|
|
||||||
# that PR as pending via POST /api/v1/ota/ofl/pending, regardless of whether
|
|
||||||
# OrcaFilamentLibrary as a whole is authorized to publish in this same run - a
|
|
||||||
# partner's OTA Manager dashboard should see a merged PR immediately, well
|
|
||||||
# before the daily cron actually builds and publishes it.
|
|
||||||
#
|
|
||||||
# Asset contract expected by OrcaCloud's release scanner:
|
# Asset contract expected by OrcaCloud's release scanner:
|
||||||
# ^(\d+\.\d+\.\d+)_([^_]+)_(\d+(?:\.\d+){3})_(\d{12})\.zip$
|
# ^(\d+\.\d+\.\d+)_([^_]+)_(\d+(?:\.\d+){3})_(\d{12})\.zip$
|
||||||
# <orca_ver>_<vendor>_<profile_version>_<UTC yyyymmddHHMM>.zip (zip root: <vendor>.opc)
|
# <orca_ver>_<vendor>_<profile_version>_<UTC yyyymmddHHMM>.zip (zip root: <vendor>.opc)
|
||||||
@@ -30,39 +17,16 @@ name: Post-merge profiles
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
# once v2.5.0 stable is released, this will be removed, so nightly won't receive OTA updates.
|
|
||||||
- main
|
- main
|
||||||
# release/vX.Y.Z point-release branches only, not the release/vX.Y working
|
- release/*
|
||||||
# branch profile PRs land on first - "v*.*.*" requires two literal dots,
|
|
||||||
# which release/vX.Y (one dot) doesn't have.
|
|
||||||
- release/v*.*.*
|
|
||||||
paths:
|
paths:
|
||||||
- 'resources/profiles/**'
|
- 'resources/profiles/**'
|
||||||
- '.github/workflows/post_merge_profiles.yml'
|
- '.github/workflows/post_merge_profiles.yml'
|
||||||
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
|
||||||
vendor:
|
|
||||||
description: >-
|
|
||||||
Publish only this vendor, bypassing the FOLDER_MERGERS grant check.
|
|
||||||
For trusted explicit dispatches only (e.g. the OFL nightly cron).
|
|
||||||
Leave empty to fall back to diffing the triggering commit.
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
auto_publish:
|
|
||||||
description: >-
|
|
||||||
After publishing, also call the OTA auto-publish API to go live
|
|
||||||
immediately, skipping the human changelog/Publish step. Separate
|
|
||||||
from `vendor` on purpose: a maintainer can dispatch with just
|
|
||||||
`vendor` set to rebuild/republish an asset without it going live.
|
|
||||||
Only the OFL nightly cron should set this to true.
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: false
|
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
pull-requests: read # commits/{sha}/pulls lookup in the OFL-pending step
|
|
||||||
|
|
||||||
# One run per branch; let a run finish rather than cancel it, since it publishes.
|
# One run per branch; let a run finish rather than cancel it, since it publishes.
|
||||||
concurrency:
|
concurrency:
|
||||||
@@ -102,38 +66,8 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
FOLDER_MERGERS: ${{ vars.FOLDER_MERGERS }}
|
FOLDER_MERGERS: ${{ vars.FOLDER_MERGERS }}
|
||||||
DISPATCH_VENDOR: ${{ github.event_name == 'workflow_dispatch' && inputs.vendor || '' }}
|
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# A vendor has a manifest plus either a preset directory or a version
|
|
||||||
# field; this drops non-vendor files such as blacklist.json. Shared by
|
|
||||||
# both the explicit-dispatch path below and the push-diff path further
|
|
||||||
# down, so the definition of "valid vendor" can't drift between them.
|
|
||||||
is_valid_vendor() {
|
|
||||||
local v="$1"
|
|
||||||
local json="resources/profiles/$v.json"
|
|
||||||
[ -f "$json" ] && { [ -d "resources/profiles/$v" ] || jq -e '.version' "$json" >/dev/null 2>&1; }
|
|
||||||
}
|
|
||||||
|
|
||||||
# Explicit vendor dispatch (e.g. the OFL cron): trust the caller and
|
|
||||||
# skip both the git-diff detection and the FOLDER_MERGERS check below.
|
|
||||||
if [ -n "$DISPATCH_VENDOR" ]; then
|
|
||||||
v="$DISPATCH_VENDOR"
|
|
||||||
# Becomes part of the release asset filename and the OTA API's
|
|
||||||
# payload; keep it to the same charset every real vendor name uses.
|
|
||||||
if ! [[ "$v" =~ ^[A-Za-z0-9]+$ ]]; then
|
|
||||||
echo "::error::vendor '$v' must be alphanumeric"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if ! is_valid_vendor "$v"; then
|
|
||||||
echo "::error::vendor '$v' has no resources/profiles/$v.json with a profile directory or version field"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "vendors=$v" >> "$GITHUB_OUTPUT"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
base='${{ github.event.before }}'
|
base='${{ github.event.before }}'
|
||||||
head='${{ github.sha }}'
|
head='${{ github.sha }}'
|
||||||
# Zero SHA (branch created / force push) or manual dispatch: fall back
|
# Zero SHA (branch created / force push) or manual dispatch: fall back
|
||||||
@@ -141,10 +75,6 @@ jobs:
|
|||||||
if [ -z "$base" ] || [ "$base" = "0000000000000000000000000000000000000000" ] || ! git cat-file -e "$base^{commit}" 2>/dev/null; then
|
if [ -z "$base" ] || [ "$base" = "0000000000000000000000000000000000000000" ] || ! git cat-file -e "$base^{commit}" 2>/dev/null; then
|
||||||
base="$head^"
|
base="$head^"
|
||||||
fi
|
fi
|
||||||
# Exposed so the OFL-pending step below can reuse this exact diff
|
|
||||||
# range instead of re-deriving it (and drifting from this logic).
|
|
||||||
echo "base=$base" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "head=$head" >> "$GITHUB_OUTPUT"
|
|
||||||
mapfile -t candidates < <(
|
mapfile -t candidates < <(
|
||||||
git diff --name-only "$base" "$head" -- resources/profiles \
|
git diff --name-only "$base" "$head" -- resources/profiles \
|
||||||
| sed -nE 's#^resources/profiles/([^/]+)/.*#\1#p; s#^resources/profiles/([^/]+)\.json$#\1#p' \
|
| sed -nE 's#^resources/profiles/([^/]+)/.*#\1#p; s#^resources/profiles/([^/]+)\.json$#\1#p' \
|
||||||
@@ -154,7 +84,10 @@ jobs:
|
|||||||
vendors=()
|
vendors=()
|
||||||
for v in "${candidates[@]:-}"; do
|
for v in "${candidates[@]:-}"; do
|
||||||
[ -n "$v" ] || continue
|
[ -n "$v" ] || continue
|
||||||
if is_valid_vendor "$v"; then
|
json="resources/profiles/$v.json"
|
||||||
|
# A vendor has a manifest plus either a preset directory or a version
|
||||||
|
# field; this drops non-vendor files such as blacklist.json.
|
||||||
|
if [ -f "$json" ] && { [ -d "resources/profiles/$v" ] || jq -e '.version' "$json" >/dev/null 2>&1; }; then
|
||||||
vendors+=("$v")
|
vendors+=("$v")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -168,9 +101,6 @@ jobs:
|
|||||||
# sibling bundle JSON are covered by at least one FOLDER_MERGERS
|
# sibling bundle JSON are covered by at least one FOLDER_MERGERS
|
||||||
# grant. The account part is intentionally ignored here: this is a
|
# grant. The account part is intentionally ignored here: this is a
|
||||||
# post-merge safety check, not an authorization check for a command.
|
# post-merge safety check, not an authorization check for a command.
|
||||||
# An ineligible vendor (e.g. OrcaFilamentLibrary, which has no grant)
|
|
||||||
# is dropped on its own - it never blocks other vendors in the same
|
|
||||||
# push from publishing.
|
|
||||||
grants=()
|
grants=()
|
||||||
while IFS= read -r raw_line; do
|
while IFS= read -r raw_line; do
|
||||||
line="${raw_line#"${raw_line%%[![:space:]]*}"}"
|
line="${raw_line#"${raw_line%%[![:space:]]*}"}"
|
||||||
@@ -197,29 +127,23 @@ jobs:
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
authorized=()
|
|
||||||
unauthorized=()
|
unauthorized=()
|
||||||
for v in "${vendors[@]}"; do
|
for v in "${vendors[@]}"; do
|
||||||
if is_granted "resources/profiles/$v" && is_granted "resources/profiles/$v.json"; then
|
if ! is_granted "resources/profiles/$v" || ! is_granted "resources/profiles/$v.json"; then
|
||||||
authorized+=("$v")
|
|
||||||
else
|
|
||||||
unauthorized+=("$v")
|
unauthorized+=("$v")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ "${#unauthorized[@]}" -ne 0 ]; then
|
if [ "${#unauthorized[@]}" -ne 0 ]; then
|
||||||
echo "::warning::skipping vendor(s) with no FOLDER_MERGERS grant (no asset built or published for them this run): ${unauthorized[*]}"
|
echo "vendors=" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "vendors=${authorized[*]}" >> "$GITHUB_OUTPUT"
|
echo "vendors=${vendors[*]}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Resolve Orca version
|
- name: Resolve Orca version
|
||||||
id: orca
|
id: orca
|
||||||
# Unconditional: needed both by the vendor-publish pipeline below (only
|
if: steps.vendors.outputs.vendors != ''
|
||||||
# when vendors is non-empty) and by the OFL-pending step at the end
|
|
||||||
# (which runs whenever OFL itself changed, even if vendors ends up
|
|
||||||
# empty because OFL has no FOLDER_MERGERS grant). Cheap and harmless
|
|
||||||
# to always resolve - version.inc is present on every commit.
|
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
@@ -318,132 +242,3 @@ jobs:
|
|||||||
echo "### Published to \`$repo\` release \`$RELEASE_TAG\`"
|
echo "### Published to \`$repo\` release \`$RELEASE_TAG\`"
|
||||||
for f in "$ASSET_DIR"/*.zip; do echo "- \`$(basename "$f")\`"; done
|
for f in "$ASSET_DIR"/*.zip; do echo "- \`$(basename "$f")\`"; done
|
||||||
} >> "$GITHUB_STEP_SUMMARY"
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
|
||||||
- name: Notify OTA auto-publish
|
|
||||||
# Gated on auto_publish specifically, not just "vendor was dispatched":
|
|
||||||
# a maintainer manually dispatching with vendor=OrcaFilamentLibrary (e.g.
|
|
||||||
# to rebuild/republish an asset while debugging) must not silently go
|
|
||||||
# live. Only a caller that explicitly opts in with auto_publish=true
|
|
||||||
# (the OFL nightly cron) skips the human changelog/Publish step.
|
|
||||||
if: >-
|
|
||||||
steps.vendors.outputs.vendors != '' && github.event_name == 'workflow_dispatch'
|
|
||||||
&& (inputs.auto_publish == true || inputs.auto_publish == 'true')
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
OTA_API_BASE_URL: ${{ vars.OTA_API_BASE_URL }}
|
|
||||||
OTA_API_KEY: ${{ secrets.OFL_OTA_PUBLISH_KEY }}
|
|
||||||
ASSET_DIR: ${{ steps.pkg.outputs.dir }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
[ -n "$OTA_API_BASE_URL" ] || { echo "::error::vars.OTA_API_BASE_URL is not set"; exit 1; }
|
|
||||||
[ -n "$OTA_API_KEY" ] || { echo "::error::secrets.OFL_OTA_PUBLISH_KEY is not set"; exit 1; }
|
|
||||||
|
|
||||||
mapfile -t zip_files < <(cd "$ASSET_DIR" && ls -1 *.zip)
|
|
||||||
filenames_json="$(printf '%s\n' "${zip_files[@]}" | jq -R . | jq -s .)"
|
|
||||||
payload="$(jq -n --argjson filenames "$filenames_json" '{filenames: $filenames}')"
|
|
||||||
|
|
||||||
resp_file="$RUNNER_TEMP/ota-auto-publish-response.json"
|
|
||||||
status="$(curl -sS -o "$resp_file" -w '%{http_code}' -X POST \
|
|
||||||
"${OTA_API_BASE_URL%/}/api/v1/ota/auto-publish" \
|
|
||||||
-H "Authorization: Bearer $OTA_API_KEY" \
|
|
||||||
-H 'Content-Type: application/json' \
|
|
||||||
-d "$payload")"
|
|
||||||
body="$(cat "$resp_file")"
|
|
||||||
echo "$body"
|
|
||||||
|
|
||||||
if [ "$status" != "200" ]; then
|
|
||||||
echo "::error::OTA auto-publish call failed with HTTP $status"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# A 200 can still carry per-file "error" results (e.g. NOT_FOUND); the
|
|
||||||
# asset is already safely published to the profiles release above, but
|
|
||||||
# it never went live, so treat that as a failure worth surfacing loudly.
|
|
||||||
error_count="$(jq '[.results[] | select(.status == "error")] | length' <<< "$body")"
|
|
||||||
if [ "$error_count" != "0" ]; then
|
|
||||||
jq -r '.results[] | select(.status == "error") | "::error::\(.filename): \(.code) - \(.message)"' <<< "$body"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Record OFL pending changes
|
|
||||||
# A real merge, never the cron's explicit-vendor dispatch (that's
|
|
||||||
# automation publishing, not a new merge to report). This covers two
|
|
||||||
# trigger shapes: an ordinary push, and a vendor-less workflow_dispatch
|
|
||||||
# - the latter is exactly what pr-merge-bot.yml's re-dispatch after a
|
|
||||||
# successful /bot merge looks like (a GITHUB_TOKEN-authored merge fires
|
|
||||||
# no push event at all, which is why that re-dispatch exists). Both
|
|
||||||
# land in the same diff-fallback path in "Resolve changed vendors", so
|
|
||||||
# base/head/orca_ver are already correctly populated either way - only
|
|
||||||
# this condition needs widening.
|
|
||||||
# Placed last in the job on purpose: a failure here must never block
|
|
||||||
# the vendor-publish pipeline above, which a step failing earlier in
|
|
||||||
# the job would do (subsequent steps without always() get skipped).
|
|
||||||
if: >-
|
|
||||||
github.event_name == 'push' ||
|
|
||||||
(github.event_name == 'workflow_dispatch' && !inputs.vendor)
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
OTA_API_BASE_URL: ${{ vars.OTA_API_BASE_URL }}
|
|
||||||
OTA_API_KEY: ${{ secrets.OFL_OTA_PUBLISH_KEY }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
base='${{ steps.vendors.outputs.base }}'
|
|
||||||
head='${{ steps.vendors.outputs.head }}'
|
|
||||||
orca_ver='${{ steps.orca.outputs.orca_ver }}'
|
|
||||||
|
|
||||||
# Only real vendor subdirectories under filament/, e.g.
|
|
||||||
# .../filament/Qidi/x.json -> "Qidi". This naturally excludes loose
|
|
||||||
# top-level files (.../filament/Generic PLA @System.json - no further
|
|
||||||
# slash to match) and is further filtered below to drop "base", the
|
|
||||||
# shared @base/@System inheritance folder, not a partner company.
|
|
||||||
mapfile -t ofl_companies < <(
|
|
||||||
git diff --name-only "$base" "$head" -- resources/profiles/OrcaFilamentLibrary/filament \
|
|
||||||
| sed -nE 's#^resources/profiles/OrcaFilamentLibrary/filament/([^/]+)/.*#\1#p' \
|
|
||||||
| grep -vx 'base' \
|
|
||||||
| sort -u
|
|
||||||
)
|
|
||||||
|
|
||||||
if [ "${#ofl_companies[@]}" -eq 0 ]; then
|
|
||||||
echo "No OFL company folders changed in this push."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
[ -n "$OTA_API_BASE_URL" ] || { echo "::error::vars.OTA_API_BASE_URL is not set"; exit 1; }
|
|
||||||
[ -n "$OTA_API_KEY" ] || { echo "::error::secrets.OFL_OTA_PUBLISH_KEY is not set"; exit 1; }
|
|
||||||
|
|
||||||
# The head commit's own merged PR, not a per-commit walk: this
|
|
||||||
# assumes the ordinary one-PR-per-push shape every other merge path
|
|
||||||
# in this repo already assumes (pr-merge-bot.yml's re-dispatch logic
|
|
||||||
# does the same). A merge commit's parents don't matter here - this
|
|
||||||
# API call works the same regardless of merge strategy.
|
|
||||||
pr_json="$(gh api "repos/${{ github.repository }}/commits/$head/pulls" \
|
|
||||||
--jq '[.[] | select(.merged_at != null)] | sort_by(.merged_at) | last // empty')"
|
|
||||||
|
|
||||||
if [ -z "$pr_json" ]; then
|
|
||||||
echo "::warning::push $head touches OFL compan(y/ies) (${ofl_companies[*]}) but has no associated merged PR; skipping pending record(s)"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
pr_number="$(jq -r '.number' <<< "$pr_json")"
|
|
||||||
pr_url="$(jq -r '.html_url' <<< "$pr_json")"
|
|
||||||
pr_title="$(jq -r '.title' <<< "$pr_json")"
|
|
||||||
|
|
||||||
for company in "${ofl_companies[@]}"; do
|
|
||||||
payload="$(jq -n --arg vendor "$company" --arg ver "$orca_ver" --argjson pr "$pr_number" \
|
|
||||||
--arg url "$pr_url" --arg title "$pr_title" \
|
|
||||||
'{vendor: $vendor, orcaSlicerVersion: $ver, prNumber: $pr, prUrl: $url, prTitle: $title}')"
|
|
||||||
|
|
||||||
resp_file="$RUNNER_TEMP/ofl-pending-$company.json"
|
|
||||||
status="$(curl -sS -o "$resp_file" -w '%{http_code}' -X POST \
|
|
||||||
"${OTA_API_BASE_URL%/}/api/v1/ota/ofl/pending" \
|
|
||||||
-H "Authorization: Bearer $OTA_API_KEY" \
|
|
||||||
-H 'Content-Type: application/json' \
|
|
||||||
-d "$payload")"
|
|
||||||
body="$(cat "$resp_file")"
|
|
||||||
echo "$body"
|
|
||||||
|
|
||||||
if [ "$status" != "200" ]; then
|
|
||||||
echo "::error::OFL pending record failed for vendor=$company (PR #$pr_number): HTTP $status"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|||||||
@@ -56,9 +56,9 @@ You can do this in Environment Variables settings.
|
|||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
# if CMAKE_OSX_DEPLOYMENT_TARGET is not set, set it to 12.0 (the lowest Xcode 27 accepts)
|
# if CMAKE_OSX_DEPLOYMENT_TARGET is not set, set it to 11.3
|
||||||
if (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
|
if (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0" CACHE STRING "Minimum OS X deployment version" FORCE)
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "11.3" CACHE STRING "Minimum OS X deployment version" FORCE)
|
||||||
endif ()
|
endif ()
|
||||||
message(STATUS "CMAKE_OSX_DEPLOYMENT_TARGET: ${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
message(STATUS "CMAKE_OSX_DEPLOYMENT_TARGET: ${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||||
endif ()
|
endif ()
|
||||||
@@ -70,9 +70,6 @@ if (POLICY CMP0092)
|
|||||||
cmake_policy(SET CMP0092 NEW)
|
cmake_policy(SET CMP0092 NEW)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# project() reads this, so set it first.
|
|
||||||
set(CMAKE_USER_MAKE_RULES_OVERRIDE "${CMAKE_CURRENT_LIST_DIR}/cmake/modules/ClangClShowIncludes.cmake")
|
|
||||||
|
|
||||||
project(OrcaSlicer)
|
project(OrcaSlicer)
|
||||||
|
|
||||||
# Backward compatibility for old CMake versions
|
# Backward compatibility for old CMake versions
|
||||||
@@ -279,11 +276,6 @@ if (APPLE)
|
|||||||
endif()
|
endif()
|
||||||
SET(CMAKE_XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.orcaslicer.OrcaSlicer")
|
SET(CMAKE_XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.orcaslicer.OrcaSlicer")
|
||||||
|
|
||||||
# The macOS CI jobs build with Ninja (build_release_macos.sh -x), so the Xcode generator
|
|
||||||
# is not covered. Xcode adds -Wshorten-64-to-32 by default ("Implicit Conversion to 32 Bit
|
|
||||||
# Type"); Ninja/-Wall does not, and under -Werror it fails Xcode builds on code CI accepts.
|
|
||||||
set(CMAKE_XCODE_ATTRIBUTE_GCC_WARN_64_TO_32_BIT_CONVERSION "NO")
|
|
||||||
|
|
||||||
message(STATUS "Orca: IS_CROSS_COMPILE: ${IS_CROSS_COMPILE}")
|
message(STATUS "Orca: IS_CROSS_COMPILE: ${IS_CROSS_COMPILE}")
|
||||||
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
set(CMAKE_INSTALL_RPATH "$ORIGIN")
|
set(CMAKE_INSTALL_RPATH "$ORIGIN")
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ while getopts ":dpa:snt:xbc:i:j:Tuh" opt; do
|
|||||||
echo " -s: Build slicer only"
|
echo " -s: Build slicer only"
|
||||||
echo " -u: Build universal app only (requires existing arm64 and x86_64 app bundles)"
|
echo " -u: Build universal app only (requires existing arm64 and x86_64 app bundles)"
|
||||||
echo " -n: Nightly build"
|
echo " -n: Nightly build"
|
||||||
echo " -t: Specify minimum version of the target platform, default is 12.0"
|
echo " -t: Specify minimum version of the target platform, default is 11.3"
|
||||||
echo " -x: Use Ninja Multi-Config CMake generator, default is Xcode"
|
echo " -x: Use Ninja Multi-Config CMake generator, default is Xcode"
|
||||||
echo " -b: Build without reconfiguring CMake"
|
echo " -b: Build without reconfiguring CMake"
|
||||||
echo " -c: Set CMake build configuration, default is Release"
|
echo " -c: Set CMake build configuration, default is Release"
|
||||||
@@ -95,7 +95,7 @@ if [ -z "$DEPS_CMAKE_GENERATOR" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$OSX_DEPLOYMENT_TARGET" ]; then
|
if [ -z "$OSX_DEPLOYMENT_TARGET" ]; then
|
||||||
export OSX_DEPLOYMENT_TARGET="12.0"
|
export OSX_DEPLOYMENT_TARGET="11.3"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$CMAKE_IGNORE_PREFIX_PATH" ]; then
|
if [ -z "$CMAKE_IGNORE_PREFIX_PATH" ]; then
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
# ccache does not parse the -clang: arguments CMake uses for clang-cl's gcc-style
|
|
||||||
# depfile, so a cache hit writes the object and no depfile, and Ninja then records
|
|
||||||
# no headers for that object. ccache reproduces /showIncludes output on a hit.
|
|
||||||
foreach (_lang C CXX)
|
|
||||||
if (CMAKE_${_lang}_COMPILER_ID STREQUAL "Clang" AND
|
|
||||||
CMAKE_${_lang}_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
|
||||||
set(CMAKE_DEPFILE_FLAGS_${_lang} "/showIncludes")
|
|
||||||
set(CMAKE_${_lang}_DEPFILE_FORMAT msvc)
|
|
||||||
endif ()
|
|
||||||
endforeach ()
|
|
||||||
@@ -26,9 +26,9 @@ endif()
|
|||||||
|
|
||||||
cmake_minimum_required(VERSION 3.2)
|
cmake_minimum_required(VERSION 3.2)
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
# if CMAKE_OSX_DEPLOYMENT_TARGET is not set, set it to 12.0 (the lowest Xcode 27 accepts)
|
# if CMAKE_OSX_DEPLOYMENT_TARGET is not set, set it to 11.3
|
||||||
if (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
|
if (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0" CACHE STRING "Minimum OS X deployment version" FORCE)
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "11.3" CACHE STRING "Minimum OS X deployment version" FORCE)
|
||||||
endif ()
|
endif ()
|
||||||
message(STATUS "CMAKE_OSX_DEPLOYMENT_TARGET: ${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
message(STATUS "CMAKE_OSX_DEPLOYMENT_TARGET: ${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||||
|
|
||||||
@@ -38,14 +38,6 @@ if(POLICY CMP0135) # DOWNLOAD_EXTRACT_TIMESTAMP
|
|||||||
cmake_policy(SET CMP0135 NEW)
|
cmake_policy(SET CMP0135 NEW)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# project() reads this, so set it first. scripts/flatpak/make_deps_tar.sh packs deps/
|
|
||||||
# without cmake/, so the file is missing in a Flatpak build.
|
|
||||||
set(_rules_override "${CMAKE_CURRENT_LIST_DIR}/../cmake/modules/ClangClShowIncludes.cmake")
|
|
||||||
if (EXISTS "${_rules_override}")
|
|
||||||
set(CMAKE_USER_MAKE_RULES_OVERRIDE "${_rules_override}")
|
|
||||||
endif ()
|
|
||||||
unset(_rules_override)
|
|
||||||
|
|
||||||
project(OrcaSlicer-deps)
|
project(OrcaSlicer-deps)
|
||||||
|
|
||||||
# Backward compatibility for old CMake versions
|
# Backward compatibility for old CMake versions
|
||||||
@@ -228,7 +220,6 @@ if (NOT IS_CROSS_COMPILE OR NOT APPLE)
|
|||||||
-DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
|
-DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER:STRING=${CMAKE_C_COMPILER_LAUNCHER}
|
-DCMAKE_C_COMPILER_LAUNCHER:STRING=${CMAKE_C_COMPILER_LAUNCHER}
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER:STRING=${CMAKE_CXX_COMPILER_LAUNCHER}
|
-DCMAKE_CXX_COMPILER_LAUNCHER:STRING=${CMAKE_CXX_COMPILER_LAUNCHER}
|
||||||
-DCMAKE_USER_MAKE_RULES_OVERRIDE:STRING=${CMAKE_USER_MAKE_RULES_OVERRIDE}
|
|
||||||
-DCMAKE_TOOLCHAIN_FILE:STRING=${CMAKE_TOOLCHAIN_FILE}
|
-DCMAKE_TOOLCHAIN_FILE:STRING=${CMAKE_TOOLCHAIN_FILE}
|
||||||
-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS}
|
-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS}
|
||||||
-DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS}
|
-DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS}
|
||||||
@@ -276,7 +267,6 @@ else()
|
|||||||
-DCMAKE_IGNORE_PREFIX_PATH:STRING=${CMAKE_IGNORE_PREFIX_PATH}
|
-DCMAKE_IGNORE_PREFIX_PATH:STRING=${CMAKE_IGNORE_PREFIX_PATH}
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER:STRING=${CMAKE_C_COMPILER_LAUNCHER}
|
-DCMAKE_C_COMPILER_LAUNCHER:STRING=${CMAKE_C_COMPILER_LAUNCHER}
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER:STRING=${CMAKE_CXX_COMPILER_LAUNCHER}
|
-DCMAKE_CXX_COMPILER_LAUNCHER:STRING=${CMAKE_CXX_COMPILER_LAUNCHER}
|
||||||
-DCMAKE_USER_MAKE_RULES_OVERRIDE:STRING=${CMAKE_USER_MAKE_RULES_OVERRIDE}
|
|
||||||
-DBUILD_SHARED_LIBS:BOOL=OFF
|
-DBUILD_SHARED_LIBS:BOOL=OFF
|
||||||
${_cmake_osx_arch}
|
${_cmake_osx_arch}
|
||||||
"${_configs_line}"
|
"${_configs_line}"
|
||||||
|
|||||||
@@ -1,137 +0,0 @@
|
|||||||
# Deferred Page Construction: High Level Design
|
|
||||||
|
|
||||||
## Why it exists
|
|
||||||
|
|
||||||
The main window is a notebook of tabs, and only one of them is on screen when the first
|
|
||||||
frame appears. Others are opened later in the session, some never, and some only exist
|
|
||||||
for certain printers. Building every tab before the first frame makes each startup pay for
|
|
||||||
tabs the user may never open.
|
|
||||||
|
|
||||||
This subsystem builds a tab the first time it is shown, and builds the rest in small units
|
|
||||||
while the user is idle after startup. Startup pays only for what the first frame shows,
|
|
||||||
the other tabs are usually ready before anyone opens them, and a click that lands in the
|
|
||||||
middle of the idle build waits for one unit at most. Work that is not a tab, such as a
|
|
||||||
dialog or the 3D view's GL resources, uses the same machinery.
|
|
||||||
|
|
||||||
## The parts
|
|
||||||
|
|
||||||
The parts are independent. A holder can hold anything a factory makes, a placeholder page
|
|
||||||
is a holder with a widget, a staged object can live outside a holder, and the scheduler
|
|
||||||
knows none of them; it runs tasks, which the main window makes from the holders.
|
|
||||||
|
|
||||||
### The holder: `Lazy<T>`
|
|
||||||
|
|
||||||
A holder keeps one object and the factory that makes it. The rest of the app reads the
|
|
||||||
object if it exists, makes sure it exists now when about to show or navigate to it, or runs
|
|
||||||
something once it exists. A type with one instance in the app gets these as statics
|
|
||||||
through `LazyInstance<T>`, so callers need no reference to the main window, and all of them
|
|
||||||
are harmless while no holder exists.
|
|
||||||
|
|
||||||
The holder guarantees that callers see the object only once it is completely built. A
|
|
||||||
build cannot re-enter itself, so a nested request finds nothing yet, and a factory that
|
|
||||||
returns null or a unit that throws leaves the holder and the scheduler able to carry on.
|
|
||||||
The holder does not own the object; its wx parent does, as for any window. The holder has
|
|
||||||
no wx dependency and is unit-tested.
|
|
||||||
|
|
||||||
### The placeholder page: `LazyPage<Panel>`
|
|
||||||
|
|
||||||
The notebook needs a page object for a tab to exist and for tabs to be inserted and
|
|
||||||
removed by pointer, and the placeholder is that object. It builds the real panel inside
|
|
||||||
itself the first time it is shown and forwards showing and hiding afterwards, so a panel's
|
|
||||||
own show handling stays its activation hook. Nothing builds while the main window is
|
|
||||||
hidden; the window's first show builds the start page. A page that is out of the book is
|
|
||||||
not prebuilt. A panel built while its page is hidden stays hidden, and gets the theming
|
|
||||||
the window applied before the panel existed.
|
|
||||||
|
|
||||||
### Staged construction: `StagedBuild`
|
|
||||||
|
|
||||||
A constructor too big to be one unit builds a skeleton and queues the rest as steps, which
|
|
||||||
run one per unit. A child panel's steps can be forwarded to its parent, and the parent is
|
|
||||||
complete only once the child is. Nothing may use what a step builds before the last step
|
|
||||||
has run, so staged panels follow these constraints:
|
|
||||||
|
|
||||||
- members created in steps start out null, so a partly built panel can be destroyed;
|
|
||||||
- timers, event handlers and destructors that touch step content check that the panel is
|
|
||||||
complete first;
|
|
||||||
- nothing takes focus while off screen, since a unit may run while the user is typing
|
|
||||||
elsewhere;
|
|
||||||
- a widget added by a step keeps its place in the sizer through an empty slot the skeleton
|
|
||||||
creates.
|
|
||||||
|
|
||||||
### The scheduler: `IdleScheduler` and `PrebuildQueue`
|
|
||||||
|
|
||||||
The queue holds tasks in order, and a slice runs units of the first pending task until
|
|
||||||
the task finishes, the time budget is spent, or input arrives. It has no wx dependency and
|
|
||||||
is unit-tested with a fake clock. A task whose work goes away, such as a tab removed from
|
|
||||||
the book, is skipped, and becomes pending again if the work comes back.
|
|
||||||
|
|
||||||
A slice runs only once the user has been idle for a short quiet time, and each slice is its
|
|
||||||
own timer message, so paint, timers and input queued in between are handled before the
|
|
||||||
next slice. Posting slices as pending events would not do that, because wx drains every
|
|
||||||
pending event before the next native message. On GTK a timer that is always due starves
|
|
||||||
the lower-priority sources that repaint and deliver posted events, so slices are a few
|
|
||||||
milliseconds apart. On Windows a slice also waits while the native queue holds input,
|
|
||||||
not counting mouse moves, which Windows synthesizes whenever a window appears under the
|
|
||||||
cursor. A slice never runs inside a `wxYield()`, where it would build pages in the middle of
|
|
||||||
the code that yielded. A unit cannot be interrupted, so the largest unit bounds how long a
|
|
||||||
click can wait.
|
|
||||||
When nothing is pending the timer stops and the subsystem costs nothing.
|
|
||||||
|
|
||||||
The main window owns the scheduler because it owns what the tasks build, and clearing the
|
|
||||||
queue with the window keeps a task from outliving its object. Each owner provides its own
|
|
||||||
tasks, such as a tab, a dialog, the Prepare tab's settings page one option group at a
|
|
||||||
time, the Prepare page's layout at the size the book gives its pages, or the 3D view's GL
|
|
||||||
resources.
|
|
||||||
|
|
||||||
### The 3D view's GL resources
|
|
||||||
|
|
||||||
OpenGL is loaded on the Prepare tab's canvas. When the start page is not Prepare, loading
|
|
||||||
it is an idle task that makes the context current on the hidden canvas, so the start page
|
|
||||||
paints first and Prepare never appears. Loading it on a shown canvas under `Freeze()` holds
|
|
||||||
back the start page's paint, and on GTK `Freeze()` cannot hide the canvas, which is a
|
|
||||||
native child window or a Wayland subsurface drawn outside GTK. A hidden Windows child
|
|
||||||
window keeps its device context, macOS attaches the context to a hidden view, and GTK
|
|
||||||
creates the canvas's surface when the widget is realized, so on GTK the task realizes the
|
|
||||||
canvas first. If the context cannot be made current, the canvas's first render loads the
|
|
||||||
resources.
|
|
||||||
|
|
||||||
## Rules
|
|
||||||
|
|
||||||
**Before the first frame.** Only the start page and the Prepare tab's plater are built
|
|
||||||
before the first frame. Everything else goes through a holder.
|
|
||||||
|
|
||||||
**Reaching a lazy object.** Callers use the type's statics. Reading it if built is for
|
|
||||||
things the object can live without, such as a rescale, a color change or a status refresh.
|
|
||||||
Making sure it exists is for navigating to it or showing it. Running something once it is
|
|
||||||
built is for state it would not fetch for itself on construction. A panel that pulls its
|
|
||||||
state when constructed only ever needs to be read if built.
|
|
||||||
|
|
||||||
**Unit size.** A unit should fit in one slice on a fast machine. A constructor over that is
|
|
||||||
staged, and a single widget over it is accepted unless the widget itself can be split.
|
|
||||||
|
|
||||||
**Order.** Tasks run cheapest and most likely to be opened first. Each holder's order is
|
|
||||||
given where it is created, with gaps so a new task fits between its neighbors. A negative
|
|
||||||
order is never prebuilt, for something few sessions open that costs more to build unasked
|
|
||||||
than it saves.
|
|
||||||
|
|
||||||
## Adopting it
|
|
||||||
|
|
||||||
A lazy tab needs a panel type deriving from `LazyInstance`, a placeholder page the main
|
|
||||||
window creates once with its order and registers for the idle build, and every use of the
|
|
||||||
panel outside the main window going through the statics. Its constructor has to cope with
|
|
||||||
the main window already existing and the user being busy elsewhere, so it takes no focus
|
|
||||||
while off screen, and it does all of its own setup, since the main window does nothing to a
|
|
||||||
panel after creating it.
|
|
||||||
|
|
||||||
To stage a heavy constructor, keep the skeleton in the constructor, move the rest into
|
|
||||||
steps in its original order, and follow the staged-construction constraints. Measure the
|
|
||||||
units; a step that is still one big widget is split inside the widget or accepted.
|
|
||||||
|
|
||||||
## Verifying
|
|
||||||
|
|
||||||
The log lists the queue when it is registered, reports each completed task at info level
|
|
||||||
and each slice and unit at debug level, and reports every on-demand build with its units
|
|
||||||
and time. A task's completion line counts only the slice it finished in. A run from the
|
|
||||||
configured start page should show every registered task complete in order, with no unit
|
|
||||||
longer than intended. A click on a tab during the idle build should show an on-demand
|
|
||||||
build for what was left, with the slices resuming once the user is idle again.
|
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
# G-code preview while dragging
|
||||||
|
|
||||||
|
The sliced preview draws every toolpath segment of the plate as an instanced box. On a large
|
||||||
|
plate that is tens of millions of segments, and the frame is GPU-bound: the cost is the number of
|
||||||
|
instances drawn, not anything the CPU does per frame. Dragging the camera over such a plate cannot
|
||||||
|
keep up. The `preview_reduced_detail_mode` preference (*Graphics > G-code Preview*, off by
|
||||||
|
default) lets the preview draw less while the user drags and put the full toolpaths back when they
|
||||||
|
let go.
|
||||||
|
|
||||||
|
| Preference | Values | Effect |
|
||||||
|
|---|---|---|
|
||||||
|
| `preview_reduced_detail_mode` | `off`, `solid`, `layers`, `outer_walls`, `shell` | what is drawn while dragging |
|
||||||
|
| `preview_reduced_detail_layer_stride` | 1–20 | one layer in every N is kept by the toolpath modes |
|
||||||
|
|
||||||
|
libvgcode (`src/libvgcode`) builds and binds the reduced toolpath set, `GCodeViewer` maps the
|
||||||
|
preferences onto it and draws the solid model, and `GLCanvas3D` decides when the user is dragging.
|
||||||
|
The OpenGL ES path keeps a single set and ignores the preference.
|
||||||
|
|
||||||
|
## Two sets, one walk
|
||||||
|
|
||||||
|
`ViewerImpl::update_enabled_entities()` walks the visible vertex range once and fills two segment
|
||||||
|
index buffers side by side: the **full** set and the **reduced** set (segments and options).
|
||||||
|
Building them together is what makes switching free: starting or ending a drag is a buffer
|
||||||
|
binding, never a rebuild. A change of mode or stride does rebuild. Nothing is built while the mode
|
||||||
|
is off, and the reduced buffers are then uploaded empty so that the last set does not stay
|
||||||
|
allocated.
|
||||||
|
|
||||||
|
Whatever the mode leaves out, the bottom and top layers of the visible range are kept whole: they
|
||||||
|
are the faces the range cuts open, and the top is what the user is looking at.
|
||||||
|
|
||||||
|
### Modes
|
||||||
|
|
||||||
|
- `EndLayersOnly` (`solid` in the preference) keeps only the two end layers. `GCodeViewer` then
|
||||||
|
draws the sliced objects and the prime tower as opaque solids, see below.
|
||||||
|
- `LayersOnly` (`layers`) keeps every role of one layer in every stride.
|
||||||
|
- `OuterWallsOnly` (`outer_walls`) keeps the outer and overhang perimeters of one layer in every
|
||||||
|
stride. The prime tower and supports have other roles and are left out.
|
||||||
|
- `ShellOnly` (`shell`) keeps what the shell extraction below marks as visible surface, of one
|
||||||
|
layer in every stride, plus whatever a view from above or below sees of the skipped layers, so
|
||||||
|
that a step does not vanish. It is the only mode that knows the prime tower's outside from its
|
||||||
|
inside.
|
||||||
|
|
||||||
|
## The solid model
|
||||||
|
|
||||||
|
The preview already loads the sliced objects as shells for its translucent ghost.
|
||||||
|
`GCodeViewer::render_solid_model()` draws those shells opaque, in their filament colors, with the
|
||||||
|
`gouraud` shader, whose z range cuts them to the visible layer range. The two toolpath layers of
|
||||||
|
the reduced set are drawn afterwards and cap the cut with what was really printed there. The
|
||||||
|
shells hold only the objects, so while this mode is on the prime tower is added from its sliced
|
||||||
|
mesh, positioned as the print placed it. It is added or removed on its own when the mode changes,
|
||||||
|
without reloading the objects, keeps its opaque color so that it never appears among the
|
||||||
|
translucent shells, and stays out of their bounding box. Supports have no mesh and are not shown,
|
||||||
|
and `load_shells()` drops every non-model-part volume, so a negative volume is not cut out.
|
||||||
|
|
||||||
|
A plate whose shells are not loaded keeps drawing toolpaths, since the solid model would leave
|
||||||
|
only the end layers.
|
||||||
|
|
||||||
|
## Shell extraction
|
||||||
|
|
||||||
|
`ViewerImpl::update_shell_bitset()` classifies every extrusion segment once per load, on demand
|
||||||
|
the first time the shell mode needs it, and records the result in four bit sets. It is purely
|
||||||
|
geometric so that the wipe tower, whose every segment shares one role, works as well as the
|
||||||
|
objects.
|
||||||
|
|
||||||
|
Each layer is rasterized into a coarse 2D **occupancy grid** over the print's footprint: cells
|
||||||
|
are 0.5 mm, or coarser so that the grid is at most 1024 cells across. The footprint is then
|
||||||
|
**closed** with a radius of 2.5 mm so that sparse infill and support read as the solid area they
|
||||||
|
belong to, while holes wider than 5 mm stay open. The closing dilates each 8-connected component
|
||||||
|
separately and leaves a cell that two components both reach empty, so the gap between two objects
|
||||||
|
standing close together is never bridged and both of their facing walls stay on the shell;
|
||||||
|
fragments under eight cells do not spread and are absorbed by whatever reaches them. A separable
|
||||||
|
erosion shrinks the result back, and the raw cells are OR-ed in again so that a closing never
|
||||||
|
loses one.
|
||||||
|
|
||||||
|
A cell is a **shell cell** when it is filled and any of its six neighbours, four in the layer,
|
||||||
|
one below, one above, is not. A segment is on the shell when at least half of the cells it
|
||||||
|
crosses are shell cells: walls run along the shell, infill only touches it at the ends. The
|
||||||
|
interior infill roles and gap fill are excluded regardless, since short infill segments hugging a
|
||||||
|
wall would otherwise pass by the thousand.
|
||||||
|
|
||||||
|
Two refinements keep sloped surfaces closed:
|
||||||
|
|
||||||
|
- **Near-wall segments.** The step between one layer's outer wall and the next is often
|
||||||
|
narrower than a cell. An inner wall (`Perimeter`) segment whose midpoint lies within a line and
|
||||||
|
a half of an outer or overhang perimeter of the same layer is kept as well. So is any segment,
|
||||||
|
whatever its role, whose midpoint lies within that reach, or a cell if larger, of an outer wall
|
||||||
|
of the layer above or below: that strip is the exposed band of the step, which the cell tests
|
||||||
|
cannot see when it is narrower than a cell.
|
||||||
|
- **Top and bottom visibility.** The same pass records the highest and lowest layer occupying
|
||||||
|
each cell over the whole print. A segment whose layer is the topmost occupant of any cell it
|
||||||
|
crosses is visible from above, and likewise from below with the lowest. These segments are kept
|
||||||
|
even when their layer is skipped by the stride.
|
||||||
|
|
||||||
|
The layer range is split across up to eight `std::async` workers, each owning its grids. An
|
||||||
|
allocation failure on a huge print falls back to marking every segment as shell, which leaves out
|
||||||
|
only the hidden infill roles.
|
||||||
|
|
||||||
|
## Deciding that the user is dragging
|
||||||
|
|
||||||
|
`GLCanvas3D::_update_preview_interaction()` runs at the top of every preview frame, before the
|
||||||
|
canvas decides whether to reuse its cached scene, so that the switch lands in that frame. Dragging
|
||||||
|
is `GLCanvas3D::is_user_interacting()`, the same answer the scene cache reads: the camera, the
|
||||||
|
navigator, a gizmo, the rectangle selection or either slider being held. A slider reports this from
|
||||||
|
ImGui's active id rather than its dirty flag, which is raised and consumed inside one frame. A
|
||||||
|
wheel step has no duration, so it holds the reduced set for a 150 ms settle time instead, and the
|
||||||
|
frame that restores the toolpaths is scheduled for when that time runs out, since the render timer
|
||||||
|
only wakes the idle loop. A drag cut short by focus or capture loss is ended explicitly, and a
|
||||||
|
button release wakes the idle loop, because on some platforms nothing else would until the next
|
||||||
|
input.
|
||||||
|
|
||||||
|
## Reused scene frames
|
||||||
|
|
||||||
|
`GLCanvas3D` keeps its last scene pass for frames that only rebuild the overlay (`SceneCache`). Its
|
||||||
|
key covers the canvas size, the camera and hover state, not what the toolpath sets draw, so a frame
|
||||||
|
that reuses the scene must never be one on which the set is switched.
|
||||||
|
`_update_preview_interaction()` therefore reports whether the bound set changed, and a frame on
|
||||||
|
which it did redraws the scene. The canvas neither captures nor reuses the scene while the user
|
||||||
|
drags, so no reduced frame outlives a drag, and the frame that ends a wheel's settle time is
|
||||||
|
requested as a full frame.
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
# Multiline infill — High Level Design
|
|
||||||
|
|
||||||
## Purpose and scope
|
|
||||||
|
|
||||||
`fill_multiline` prints every sparse infill wall as N adjacent lines instead of
|
|
||||||
one, so a wall is `d1 = N * spacing` thick. Only internal sparse infill uses it.
|
|
||||||
Each pattern first builds its single-line centerlines at N times the usual line
|
|
||||||
spacing (so the density holds), and `multiline_fill()` then replaces each
|
|
||||||
centerline by the lines of that wall: the centerline itself when N is odd, and
|
|
||||||
closed outlines around it at every `spacing` out to `d1 / 2`. The outlines are
|
|
||||||
clipped to the fill region contracted by half a line width, then connected like
|
|
||||||
any other infill.
|
|
||||||
|
|
||||||
Outlines of centerlines that cross each other overlap at every crossing, which
|
|
||||||
over-extrudes the wall intersections. The line-crossing patterns Grid,
|
|
||||||
Triangles, Tri-hexagon and Cubic therefore build centerlines that never cross
|
|
||||||
(`FillRectilinear::fill_surface_trapezoidal()`), and so do Adaptive Cubic and
|
|
||||||
Support Cubic (`FillAdaptive`); the other patterns outline their usual
|
|
||||||
centerlines.
|
|
||||||
|
|
||||||
## Non-crossing centerlines
|
|
||||||
|
|
||||||
The crossing lines are resolved into x-monotone paths, the levels of the line
|
|
||||||
arrangement: walking along x, the k-th path is always the k-th line from the
|
|
||||||
bottom. At every crossing, the two paths bounce off each other instead of
|
|
||||||
passing through. Adjacent paths meet only at crossings, so their outlines touch
|
|
||||||
there and nowhere overlap.
|
|
||||||
|
|
||||||
Where two paths meet, each is cut short by a line perpendicular to the bisector
|
|
||||||
of its bend, `d1 / 2` from the crossing. The two cut segments are parallel and
|
|
||||||
`d1` apart, so the outermost lines of the two walls sit exactly `spacing` apart,
|
|
||||||
like the lines inside a wall. Where three lines meet at one point, the middle
|
|
||||||
path runs straight through and the outer two are cut `d1` from it.
|
|
||||||
|
|
||||||
Each pattern builds its rows along x in a rotated frame. Grid lines run at ±45°
|
|
||||||
there, and its rows are trapezoid waves that transpose on alternate layers. The three families of Triangles, Tri-hexagon and
|
|
||||||
Cubic run at 0°, 60° and 120°. Those rows rotate by 120° every layer about a
|
|
||||||
3-fold center of the arrangement, so each family takes every role in turn.
|
|
||||||
The pattern is phased on fixed positions, so it lines up across layers and
|
|
||||||
across the regions of one layer. Rounding the corners with
|
|
||||||
`sparse_infill_smooth_factor` happens before `multiline_fill()`.
|
|
||||||
|
|
||||||
## Cubic
|
|
||||||
|
|
||||||
Single-line Cubic draws the three families at the same spacing `h` and shifts
|
|
||||||
them with z: by `+dx`, `-dx` and `+dx`, `dx = z / sqrt(2)`. The multiline paths
|
|
||||||
follow the same lines. In the frame where one family is horizontal, the other two
|
|
||||||
cross in rows `h` apart, alternating by half a period, at height
|
|
||||||
`tau = -3 * dx (mod h)` above the horizontal line below them. The crossings split
|
|
||||||
every band between horizontal lines into up-pointing triangles of height `tau`,
|
|
||||||
down-pointing triangles of height `h - tau`, and hexagons. At `tau = 0` (and `h`)
|
|
||||||
all three families meet at common points, as in Triangles. At `tau = h / 2` the
|
|
||||||
triangles are equal, as in Tri-hexagon. The origin of that frame is always a
|
|
||||||
3-fold center, whatever z is, so the per-layer rotation keeps the lines in place.
|
|
||||||
|
|
||||||
Each band holds two paths that touch at its crossings: the upper one takes the
|
|
||||||
V below the crossing and runs along the top horizontal line, and the lower one
|
|
||||||
takes the inverted V above it and runs along the bottom line. Both are the same function
|
|
||||||
of `tau`, the lower one mirrored with `h - tau`. `cubic_upper_level()` builds one
|
|
||||||
period of the upper path as the lower envelope of five lines, clipped from below:
|
|
||||||
|
|
||||||
- the two slanted lines through the crossings,
|
|
||||||
- the horizontal line, lowered when the triangle above it is less than `1.5 * d1` high,
|
|
||||||
- the two chamfers where the path turns onto and off the horizontal line, `d1 / 2`
|
|
||||||
from those crossings,
|
|
||||||
- the flat cut into the V at the crossing.
|
|
||||||
|
|
||||||
The cut height `clamp(tau - d1 / 2, 0, h - d1) + d1` is what makes the pattern
|
|
||||||
continuous in z. While both triangles are at least `1.5 * d1` high, every
|
|
||||||
crossing is a pair of bends `d1 / 2` from it, as in Tri-hexagon. When a triangle
|
|
||||||
is thinner, its three paths stack like a triple crossing. The path through it
|
|
||||||
flattens toward its base line and lies on it once the triangle is under `d1 / 2`
|
|
||||||
high, and the paths beside it are pushed `d1` away. The layout thus reaches the
|
|
||||||
Triangles one where the families meet. Adjacent paths stay at least `d1` apart
|
|
||||||
at every `tau` and at every density up to 100%.
|
|
||||||
|
|
||||||
## Adaptive Cubic
|
|
||||||
|
|
||||||
Adaptive Cubic and Support Cubic take their lines from an octree of cubes
|
|
||||||
standing on a corner. On each layer every cube cuts its three mid-planes into
|
|
||||||
segments of the same three 60° families as Cubic, but the pattern is not
|
|
||||||
periodic. Smaller cubes near the surface add finer lines, and a finer line ends
|
|
||||||
where it meets the wall of its coarser cube, so the lines form crossings and
|
|
||||||
T-junctions. `FillAdaptive::multiline_paths()` builds the paths from these
|
|
||||||
segments directly, for each fill region and within `4 * d1` of it.
|
|
||||||
|
|
||||||
At a crossing the two paths bounce as in Cubic. At a T-junction the through line
|
|
||||||
runs straight on and the path of the ending line stops there. Every path still
|
|
||||||
runs left to right in the frame where one family is horizontal, and that family
|
|
||||||
rotates with the layer.
|
|
||||||
|
|
||||||
Every line of every cube size lies on one fine lattice, so crossings closer than
|
|
||||||
a few `d1` are the corners of one small triangle of that lattice, as in Cubic.
|
|
||||||
The cuts follow the Cubic rules without a closed formula:
|
|
||||||
|
|
||||||
- The two bends of a crossing are cut `d1` apart, `d1 / 2` each, perpendicular
|
|
||||||
to their bisector, so their walls touch. A cut goes no further than the path
|
|
||||||
end, and the other bend takes the rest of `d1`.
|
|
||||||
- At the tip of a small triangle, between the two slanted families, a cut also
|
|
||||||
goes no further than the neighbouring bend turning the other way, and the
|
|
||||||
path beyond that bend is kept a wall away from it. The bends onto the
|
|
||||||
horizontal family are not limited this way: pushing their paths apart would
|
|
||||||
open gaps between walls that should touch.
|
|
||||||
- A cut moves the path only where the cut line lies beyond it, near its bend.
|
|
||||||
The sharp bends between the two slanted families are cut after the bends onto
|
|
||||||
the horizontal family, so the tip of a small triangle wins, as in Cubic.
|
|
||||||
- A path stopping at a T-junction is trimmed until it is `d1` less half a line
|
|
||||||
spacing from every other path, so that its end overlaps the wall it stops on
|
|
||||||
by half a line and bonds to it. The paths are trimmed one at a time against
|
|
||||||
the others as already trimmed, so two ends facing each other meet instead of
|
|
||||||
both backing off. A path stopping on the line of another is trimmed before
|
|
||||||
that one, so it gives way and the other still reaches the line it stops on. A
|
|
||||||
second round trims every path again from its full length, so an end grows
|
|
||||||
back where the ends it gave way to were trimmed later, and a last round only
|
|
||||||
shortens them, keeping them that far apart. Paths shorter than `d1` are left
|
|
||||||
out.
|
|
||||||
- A line that ends on another less than `2 * d1` past a crossing stops at that
|
|
||||||
crossing instead, the shorter one where both do. The path along such a stub
|
|
||||||
would be trimmed away, leaving a hole between the walls that were cut to
|
|
||||||
touch it.
|
|
||||||
|
|
||||||
Short paths enclosed by coarser lines still print as closed outlines, but most
|
|
||||||
paths run on across several cells.
|
|
||||||
@@ -76,10 +76,9 @@ and the count of errors the original parse hit.
|
|||||||
|
|
||||||
Each entry is one preset **in source form**: what its JSON sub-file states and nothing
|
Each entry is one preset **in source form**: what its JSON sub-file states and nothing
|
||||||
that resolving it derives — the preset's own config diff, the name of the preset it
|
that resolving it derives — the preset's own config diff, the name of the preset it
|
||||||
inherits, the names of the presets it includes, and the parse metadata (name, sub-path,
|
inherits, and the parse metadata (name, sub-path, description, instantiation, setting
|
||||||
description, instantiation, setting and filament ids, renames). Non-instantiated base
|
and filament ids, renames). Non-instantiated base presets are stored too; the children
|
||||||
presets are stored too; the children that inherit from or include them cannot resolve
|
that inherit from them cannot resolve without them.
|
||||||
without them.
|
|
||||||
|
|
||||||
**The payload names its own keys.** The dictionary holds the distinct `opt_key`s the
|
**The payload names its own keys.** The dictionary holds the distinct `opt_key`s the
|
||||||
file uses, the `ConfigOptionType` each was written as, and the distinct enum *value
|
file uses, the `ConfigOptionType` each was written as, and the distinct enum *value
|
||||||
@@ -162,9 +161,9 @@ cache nothing can invalidate is worse than no cache.
|
|||||||
|
|
||||||
Vendors load in a fixed order, because filament inheritance crosses exactly one
|
Vendors load in a fixed order, because filament inheritance crosses exactly one
|
||||||
boundary: any vendor's filament may inherit from the shared Orca filament library,
|
boundary: any vendor's filament may inherit from the shared Orca filament library,
|
||||||
and nothing else reaches across vendors — an `include` is always vendor-local. The
|
and nothing else reaches across vendors. The library therefore goes first, alone;
|
||||||
library therefore goes first, alone; every other vendor follows in parallel, resolving
|
every other vendor follows in parallel, resolving against it; and the results are
|
||||||
against it; and the results are merged in a stable order:
|
merged in a stable order:
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart LR
|
flowchart LR
|
||||||
@@ -212,16 +211,13 @@ and its cache was never written back.
|
|||||||
|
|
||||||
Serving from a cache is not a memory-image restore. The entries are deserialized and
|
Serving from a cache is not a memory-image restore. The entries are deserialized and
|
||||||
then installed one by one — inheritance resolved against the presets installed before
|
then installed one by one — inheritance resolved against the presets installed before
|
||||||
them and the currently loaded filament library, includes layered in, configs flattened
|
them and the currently loaded filament library, configs flattened onto the collection
|
||||||
onto the collection defaults, validated and registered — by the same function the JSON
|
defaults, validated and registered — by the same function the JSON path calls straight
|
||||||
path calls straight after parsing a sub-file. An `include` layers what the included
|
after parsing a sub-file. The two paths share everything below the parse, which is what
|
||||||
base states, between the parent and the preset's own keys: the base's diff against the
|
makes a cache-loaded bundle indistinguishable from a JSON-loaded one by construction
|
||||||
default, taken when the base itself was installed and before the per-variant padding
|
rather than by test coverage. Installation also rebuilds each preset's file path from
|
||||||
`inherits` sees, so only what a template sets reaches the presets including it. The two
|
the local data directory, so a shipped cache never carries the generating machine's
|
||||||
paths share everything below the parse, which is what makes a cache-loaded bundle
|
paths.
|
||||||
indistinguishable from a JSON-loaded one by construction rather than by test coverage.
|
|
||||||
Installation also rebuilds each preset's file path from the local data directory, so a
|
|
||||||
shipped cache never carries the generating machine's paths.
|
|
||||||
|
|
||||||
App upgrades work because a cache normally survives one. Only a deliberate
|
App upgrades work because a cache normally survives one. Only a deliberate
|
||||||
`CACHE_VERSION` bump makes an installed cache unreadable, and that is handled at
|
`CACHE_VERSION` bump makes an installed cache unreadable, and that is handled at
|
||||||
|
|||||||
@@ -1,197 +0,0 @@
|
|||||||
# Prime tower sparse layers — High Level Design
|
|
||||||
|
|
||||||
## Purpose and scope
|
|
||||||
|
|
||||||
A prime tower exists to absorb filament changes, but it is planned on every
|
|
||||||
object layer below the topmost change, not only on the layers that purge. The
|
|
||||||
layers in between carry no filament change and print nothing but a block of the
|
|
||||||
tower's own footprint to keep its top level. They are called sparse layers, and
|
|
||||||
on a print with few changes they are most of the tower: they cost time, filament
|
|
||||||
and a travel to the tower on every layer.
|
|
||||||
|
|
||||||
Two settings trade that cost against something else. `wipe_tower_no_sparse_layers`
|
|
||||||
drops them, which sinks the tower below the model. `wipe_tower_sparse_layers_combination`
|
|
||||||
merges runs of them into fewer, thicker layers, which keeps the tower level with
|
|
||||||
the model. Both are off by default, and with both off the tower prints one layer
|
|
||||||
per object layer as it always has.
|
|
||||||
|
|
||||||
The decisions belong to tower planning and G-code emission. They do not change
|
|
||||||
sliced object geometry, but they do change the emitted G-code, the filament and
|
|
||||||
time estimates, and — for the compacted case — whether a plate is printable at
|
|
||||||
all. Changing either setting invalidates the tower step.
|
|
||||||
|
|
||||||
## What a sparse layer is
|
|
||||||
|
|
||||||
`ToolOrdering::fill_wipe_tower_partitions` counts the filament changes per layer
|
|
||||||
and propagates that count downwards, so every layer below the topmost change is
|
|
||||||
marked as carrying a tower. It then fills any gap between two tower layers, so
|
|
||||||
the tower is continuous from the bed to its last purge. `wipe_tower_layer_height`
|
|
||||||
is the distance from the previous tower layer, which is the object's layer height
|
|
||||||
whenever the tower prints on every layer.
|
|
||||||
|
|
||||||
`Print::_make_wipe_tower` plans one tower layer per such object layer. A layer
|
|
||||||
whose only call keeps the current filament leaves no toolchange in the plan, and
|
|
||||||
the layer it generates is a single result whose initial and new tool are equal.
|
|
||||||
That is what `wipe_tower_layer_is_sparse` recognises, and it is the unit both
|
|
||||||
settings work on.
|
|
||||||
|
|
||||||
The plan stays one entry per tower layer in every case. The G-code emitter walks
|
|
||||||
`WipeTowerData::tool_changes` by layer index, advancing once per object layer
|
|
||||||
that carries a tower, so a planner that removed entries would silently shift
|
|
||||||
every later layer onto the wrong tower geometry. Layers that print nothing are
|
|
||||||
therefore still planned and still generated; they are marked, and the emitter
|
|
||||||
drops them.
|
|
||||||
|
|
||||||
## Shared rules
|
|
||||||
|
|
||||||
Tower planning, G-code emission and the plate validation all have to agree about
|
|
||||||
which layers print and where. They ask one set of free functions, declared beside
|
|
||||||
the tower classes, rather than each re-deriving the answer from the raw options:
|
|
||||||
|
|
||||||
- `wipe_tower_sparse_layers_skipped` — whether sparse layers are really dropped.
|
|
||||||
Smooth timelapse and clumping detection park the nozzle on the tower every
|
|
||||||
layer, so with either of them on no layer is ever dropped and the option reads
|
|
||||||
as off everywhere.
|
|
||||||
- `wipe_tower_sparse_layers_combined` — whether runs are really merged. The same
|
|
||||||
two rule it out, and so does `wipe_tower_no_sparse_layers`: dropping the layers
|
|
||||||
outright is the stronger answer to the same problem, so the two settings are
|
|
||||||
exclusive and the GUI greys out the second while the first is on.
|
|
||||||
- `wipe_tower_layer_is_sparse`, `wipe_tower_layer_is_combined_away` — per-layer
|
|
||||||
questions the emitter asks about generated results.
|
|
||||||
- `compute_compacted_wipe_tower_z` — the tower's print z per planned layer when
|
|
||||||
it is compacted.
|
|
||||||
- `combine_sparse_wipe_tower_layers` and its `combine_sparse_wipe_tower_plan`
|
|
||||||
wrapper — the merge rule, applied to either generator's plan.
|
|
||||||
|
|
||||||
Both tower generators are driven through these. `WipeTower` (Type 1, the block
|
|
||||||
tower) and `WipeTower2` (Type 2, the default) keep separate plans with the same
|
|
||||||
per-layer shape — print z, layer height, toolchanges, and a `combined_away` flag
|
|
||||||
— so one template covers both.
|
|
||||||
|
|
||||||
## Dropping sparse layers
|
|
||||||
|
|
||||||
With `wipe_tower_no_sparse_layers`, the tower only grows on layers that carry a
|
|
||||||
real change. It therefore falls one layer height behind the object for every
|
|
||||||
sparse layer, and by the top of a tall print it can sit far below the model. The
|
|
||||||
nozzle has to reach down to it at each purge.
|
|
||||||
|
|
||||||
`compute_compacted_wipe_tower_z` derives that z once, from the generated results,
|
|
||||||
so the emitter and the validator cannot disagree. Emission descends to it, but
|
|
||||||
only once the nozzle is parked over the tower: descending while still over the
|
|
||||||
model would drive the nozzle into the print, so a descent that would do that is
|
|
||||||
deferred until after the travel to the tower. Extrusions emitted without an
|
|
||||||
explicit z — the nozzle-change wipe in particular — are pulled down to the
|
|
||||||
compacted z for the same reason.
|
|
||||||
|
|
||||||
Reaching down is only safe if nothing tall stands near the tower. `Print.hpp`
|
|
||||||
carries the clearance rule: a keep-out zone grown from the tower's footprint by
|
|
||||||
the spiral z-hop envelope, and a per-object limit on how high an object may rise
|
|
||||||
near it, tiered by the nozzle cone, the head body, the rod and the lid. The same
|
|
||||||
rule serves the precise check on real extrusions, the pre-slice estimate that
|
|
||||||
feeds the plater, and the outlines the plater draws while an object is dragged,
|
|
||||||
so that the ring the user sees touches the object's outline exactly when the
|
|
||||||
check trips.
|
|
||||||
|
|
||||||
## Merging sparse layers
|
|
||||||
|
|
||||||
With `wipe_tower_sparse_layers_combination`, no layer is dropped and nothing is
|
|
||||||
compacted: the tower keeps following the object, and the nozzle never descends.
|
|
||||||
Instead a run of consecutive sparse layers prints once, on the run's last layer,
|
|
||||||
at the accumulated height of everything it covers — the same way infill
|
|
||||||
combination merges sparse infill. The layers below it in the run print nothing.
|
|
||||||
|
|
||||||
`combine_sparse_wipe_tower_plan` runs before the tower's depths are planned,
|
|
||||||
because the heights it rewrites feed the extrusion flow of every later pass. It
|
|
||||||
raises `height` in place on the layer that prints a run and sets `combined_away`
|
|
||||||
on the rest; generation then proceeds unchanged, and the flag is copied onto the
|
|
||||||
results so the emitter can drop them.
|
|
||||||
|
|
||||||
Four constraints shape the rule:
|
|
||||||
|
|
||||||
- **Whole layers only.** A tower layer is entered at the object's z, so a merged
|
|
||||||
layer has to end on an object layer boundary. The merged height is therefore a
|
|
||||||
sum of whole layer heights, never a clamped value.
|
|
||||||
- **The nozzle's maximum layer height.** A run stops growing as soon as one more
|
|
||||||
layer would pass `max_layer_height` for the nozzle printing it — three quarters
|
|
||||||
of the nozzle diameter when that is left at 0, as elsewhere in slicing. The cap
|
|
||||||
is read through the filament-to-nozzle map, since `max_layer_height` is per
|
|
||||||
nozzle while the tower indexes filaments. This is what makes the setting inert
|
|
||||||
at common layer heights: two 0.2 mm layers are 0.4 mm and do not fit under a
|
|
||||||
0.3 mm maximum, so nothing merges until the layer height is 0.15 mm or below,
|
|
||||||
or the maximum is raised.
|
|
||||||
- **A filament change purges at its own z.** A layer with a real change can
|
|
||||||
neither be merged away nor absorb the run below it, so a run always ends on its
|
|
||||||
own last sparse layer and the change above it is untouched.
|
|
||||||
- **The first layer stays on the bed.** It carries the brim and is never merged.
|
|
||||||
|
|
||||||
A run holds one filament throughout — that is what makes it sparse — so the cap
|
|
||||||
is uniform across it, and the tower reserves depth only for the purges above a
|
|
||||||
layer, so a run has one footprint and the merged layer covers exactly the area
|
|
||||||
the layers it replaces would have.
|
|
||||||
|
|
||||||
## Emission and accounting
|
|
||||||
|
|
||||||
`WipeTowerIntegration` drops a layer whose results are marked, for both settings,
|
|
||||||
through the same `ignore_sparse` path in `tool_change` and
|
|
||||||
`is_empty_wipe_tower_gcode`. A dropped layer emits no travel to the tower and no
|
|
||||||
extrusion.
|
|
||||||
|
|
||||||
Filament used is accumulated by the generators while they write, so a layer that
|
|
||||||
will be dropped must not be charged. Type 1 asks `layer_is_printed` at each of
|
|
||||||
its accumulation points; Type 2 guards the equivalent block in `finish_layer`,
|
|
||||||
which also stops a merged-away layer from adding height of its own — the layer
|
|
||||||
that prints the run carries all of it.
|
|
||||||
|
|
||||||
A merged layer is the only case where the tower's layer height differs from the
|
|
||||||
object layer it sits on, and therefore the only case where the height the
|
|
||||||
exporter already emitted for that layer is wrong for the tower. Both generators
|
|
||||||
do declare a height, but each hardcodes a tag dialect — the block tower forces
|
|
||||||
the BBL tag, the other writes the compatible one — while the G-code processor
|
|
||||||
reads only the tag its printer uses. On a non-BBL printer with a Type 1 tower the
|
|
||||||
declaration is dropped, and the merged layer is drawn and costed as a thin one.
|
|
||||||
`WipeTowerIntegration::tower_height_tag` therefore declares it at export time,
|
|
||||||
where the printer is known, and only when the tower's own G-code does not already
|
|
||||||
carry the tag that will be read. The object's height returns on the next object
|
|
||||||
path, because emission forces the processor role to the tower on any layer that
|
|
||||||
carries one.
|
|
||||||
|
|
||||||
## Constraints
|
|
||||||
|
|
||||||
A layer that prints nothing prints nothing at all, including any interface work
|
|
||||||
the tower planner scheduled there. The Type 1 block planner marks a layer as a
|
|
||||||
contact layer when a filament category stops or starts being used relative to the
|
|
||||||
layer below, and a sparse layer immediately above a change qualifies. Merging a
|
|
||||||
run, like dropping its layers, replaces that interface with the run's single
|
|
||||||
layer. Both settings are off by default for this among other reasons.
|
|
||||||
|
|
||||||
Neither setting changes what the tower is for. A plate that needs a tower on
|
|
||||||
every layer — smooth timelapse, clumping detection — gets one, and the settings
|
|
||||||
read as off rather than compacting or merging in one place and not another.
|
|
||||||
|
|
||||||
## Implementation and verification
|
|
||||||
|
|
||||||
- [WipeTower.hpp](../../src/libslic3r/GCode/WipeTower.hpp) declares the shared
|
|
||||||
rules and the plan-merging template;
|
|
||||||
[WipeTower.cpp](../../src/libslic3r/GCode/WipeTower.cpp) implements them and
|
|
||||||
the Type 1 tower, [WipeTower2.cpp](../../src/libslic3r/GCode/WipeTower2.cpp)
|
|
||||||
the Type 2 tower.
|
|
||||||
- [ToolOrdering.cpp](../../src/libslic3r/GCode/ToolOrdering.cpp) decides which
|
|
||||||
layers carry a tower at all, and
|
|
||||||
[Print.cpp](../../src/libslic3r/Print.cpp) plans it and runs the clearance
|
|
||||||
check whose rule lives in [Print.hpp](../../src/libslic3r/Print.hpp).
|
|
||||||
- [GCode.cpp](../../src/libslic3r/GCode.cpp) emits the tower, drops the layers
|
|
||||||
that print nothing, and declares a merged layer's height;
|
|
||||||
[PrintConfig.cpp](../../src/libslic3r/PrintConfig.cpp) defines the settings and
|
|
||||||
[ConfigManipulation.cpp](../../src/slic3r/GUI/ConfigManipulation.cpp) their
|
|
||||||
mutual exclusion.
|
|
||||||
- [GLCanvas3D.cpp](../../src/slic3r/GUI/GLCanvas3D.cpp) and
|
|
||||||
[PartPlate.cpp](../../src/slic3r/GUI/PartPlate.cpp) draw the compacted tower's
|
|
||||||
keep-out outlines live while the user drags.
|
|
||||||
- [Rule tests](../../tests/libslic3r/test_wipe_tower.cpp) cover the gating of
|
|
||||||
both settings, the per-layer predicates, the compacted z, the merge rule's run
|
|
||||||
flushing, height conservation, the nozzle cap and the first-layer exemption,
|
|
||||||
and the clearance geometry the plater draws.
|
|
||||||
- [Slicing tests](../../tests/fff_print/test_wipe_tower.cpp) slice a real print
|
|
||||||
and check that a run folds, that the tower still covers the object exactly
|
|
||||||
once, that a run too thin for the cap is left alone, and that a merged layer
|
|
||||||
declares its height in the tag the printer's processor reads.
|
|
||||||
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 18 KiB |
@@ -3,7 +3,7 @@
|
|||||||
"name": "AliZ PA-CF @P1-X1",
|
"name": "AliZ PA-CF @P1-X1",
|
||||||
"inherits": "AliZ PA-CF @base",
|
"inherits": "AliZ PA-CF @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "cN0uesF0mZf3KSkj",
|
"setting_id": "AliZ003_00",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"1"
|
"1"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "AliZ PETG @P1-X1",
|
"name": "AliZ PETG @P1-X1",
|
||||||
"inherits": "AliZ PETG @base",
|
"inherits": "AliZ PETG @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "cZp23cC4ong9q6dn",
|
"setting_id": "AliZ001_00",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"1"
|
"1"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "AliZ PETG-CF @P1-X1",
|
"name": "AliZ PETG-CF @P1-X1",
|
||||||
"inherits": "AliZ PETG-CF @base",
|
"inherits": "AliZ PETG-CF @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "HWW5mejsB0SfEfWw",
|
"setting_id": "AZ01-1_00",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"1"
|
"1"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "AliZ PETG-Metal @P1-X1",
|
"name": "AliZ PETG-Metal @P1-X1",
|
||||||
"inherits": "AliZ PETG-Metal @base",
|
"inherits": "AliZ PETG-Metal @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "JqD0blE4fxaNfXqB",
|
"setting_id": "AZ01-2_00",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"1"
|
"1"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "AliZ PLA @P1-X1",
|
"name": "AliZ PLA @P1-X1",
|
||||||
"inherits": "AliZ PLA @base",
|
"inherits": "AliZ PLA @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "fRELapY8YiP4qrBW",
|
"setting_id": "AliZ002_00",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"1"
|
"1"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA ABS @BBL A1",
|
"name": "BETA ABS @BBL A1",
|
||||||
"inherits": "BETA ABS @base",
|
"inherits": "BETA ABS @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "dUGRrmxU89pRaJ2Z",
|
"setting_id": "BABB00_07",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"20"
|
"20"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA ABS @BBL H2D",
|
"name": "BETA ABS @BBL H2D",
|
||||||
"inherits": "BETA ABS @base",
|
"inherits": "BETA ABS @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "oxZKTEMd8TpyoH39",
|
"setting_id": "BABB00_11",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"chamber_temperatures": [
|
"chamber_temperatures": [
|
||||||
"65"
|
"65"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA ABS @BBL P1P",
|
"name": "BETA ABS @BBL P1P",
|
||||||
"inherits": "BETA ABS @base",
|
"inherits": "BETA ABS @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "MPYyfCKMsJZy8GaY",
|
"setting_id": "BABB00_03",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"20"
|
"20"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA ABS @BBL X1C",
|
"name": "BETA ABS @BBL X1C",
|
||||||
"inherits": "BETA ABS @base",
|
"inherits": "BETA ABS @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "vMA7EhgNDT4MwMRr",
|
"setting_id": "BABB00",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"60"
|
"60"
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"type": "filament",
|
||||||
|
"name": "BETA ABS @base",
|
||||||
|
"inherits": "fdm_filament_abs",
|
||||||
|
"from": "system",
|
||||||
|
"filament_id": "OFjUXn67",
|
||||||
|
"instantiation": "false",
|
||||||
|
"description": "When printing this filament, there's a risk of warping and low layer adhesion strength. To get better results, please refer to this wiki: Printing Tips for High Temp / Engineering materials.",
|
||||||
|
"filament_cost": [
|
||||||
|
"24.99"
|
||||||
|
],
|
||||||
|
"filament_flow_ratio": [
|
||||||
|
"0.95"
|
||||||
|
],
|
||||||
|
"filament_vendor": [
|
||||||
|
"BETA"
|
||||||
|
],
|
||||||
|
"impact_strength_z": [
|
||||||
|
"7.4"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA ASA @BBL A1 0.4 nozzle",
|
"name": "BETA ASA @BBL A1 0.4 nozzle",
|
||||||
"inherits": "BETA ASA @base",
|
"inherits": "BETA ASA @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "LevRG7t9mTlEseaB",
|
"setting_id": "BASB00_09",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"chamber_temperatures": [
|
"chamber_temperatures": [
|
||||||
"60"
|
"60"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA ASA @BBL H2D 0.4 nozzle",
|
"name": "BETA ASA @BBL H2D 0.4 nozzle",
|
||||||
"inherits": "BETA ASA @base",
|
"inherits": "BETA ASA @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "3NBkWTXmqi8eRUhi",
|
"setting_id": "BASB00_13",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"chamber_temperatures": [
|
"chamber_temperatures": [
|
||||||
"65"
|
"65"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA ASA @BBL X1C 0.4 nozzle",
|
"name": "BETA ASA @BBL X1C 0.4 nozzle",
|
||||||
"inherits": "BETA ASA @base",
|
"inherits": "BETA ASA @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "0nWTEZkH7NKXgCib",
|
"setting_id": "BASB00_02",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"chamber_temperatures": [
|
"chamber_temperatures": [
|
||||||
"60"
|
"60"
|
||||||
@@ -53,53 +53,5 @@
|
|||||||
],
|
],
|
||||||
"textured_plate_temp_initial_layer": [
|
"textured_plate_temp_initial_layer": [
|
||||||
"100"
|
"100"
|
||||||
],
|
|
||||||
"activate_air_filtration": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"close_additional_fan_first_x_layers": [
|
|
||||||
"3"
|
|
||||||
],
|
|
||||||
"retraction_distances_when_ec": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"slow_down_min_speed": [
|
|
||||||
"20"
|
|
||||||
],
|
|
||||||
"temperature_vitrification": [
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"filament_start_gcode": [
|
|
||||||
"; Filament gcode\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
|
||||||
],
|
|
||||||
"filament_end_gcode": [
|
|
||||||
"; filament end gcode \n\n"
|
|
||||||
],
|
|
||||||
"volumetric_speed_coefficients": [
|
|
||||||
"0 0 0 0 0 0"
|
|
||||||
],
|
|
||||||
"filament_adhesiveness_category": [
|
|
||||||
"200"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_time": [
|
|
||||||
"12",
|
|
||||||
"8.0",
|
|
||||||
"12",
|
|
||||||
"8.0"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_cooling_temperature": [
|
|
||||||
"85"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_temperature": [
|
|
||||||
"65",
|
|
||||||
"80",
|
|
||||||
"65",
|
|
||||||
"80"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_softening_temperature": [
|
|
||||||
"85"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA HIPS @BBL H2D",
|
"name": "BETA HIPS @BBL H2D",
|
||||||
"inherits": "BETA HIPS @base",
|
"inherits": "BETA HIPS @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "9nN2uWxlYH1c507A",
|
"setting_id": "BHIB00_06",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_deretraction_speed": [
|
"filament_deretraction_speed": [
|
||||||
"nil",
|
"nil",
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA HIPS @BBL X1C",
|
"name": "BETA HIPS @BBL X1C",
|
||||||
"inherits": "BETA HIPS @base",
|
"inherits": "BETA HIPS @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "mTcT8sCciWyX5enc",
|
"setting_id": "BHIB00_00",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_max_volumetric_speed": [
|
"filament_max_volumetric_speed": [
|
||||||
"8",
|
"8",
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"type": "filament",
|
||||||
|
"name": "BETA HIPS @base",
|
||||||
|
"inherits": "fdm_filament_hips",
|
||||||
|
"from": "system",
|
||||||
|
"filament_id": "OFlmxlDG",
|
||||||
|
"instantiation": "false",
|
||||||
|
"filament_is_support": [
|
||||||
|
"1"
|
||||||
|
],
|
||||||
|
"filament_vendor": [
|
||||||
|
"BETA"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PAHT-CF @BBL H2D",
|
"name": "BETA PAHT-CF @BBL H2D",
|
||||||
"inherits": "BETA PAHT-CF @base",
|
"inherits": "BETA PAHT-CF @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "YbYCVQd5IR0sQR8S",
|
"setting_id": "BPAB00_01",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"chamber_temperatures": [
|
"chamber_temperatures": [
|
||||||
"60"
|
"60"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PAHT-CF @BBL P1P",
|
"name": "BETA PAHT-CF @BBL P1P",
|
||||||
"inherits": "BETA PAHT-CF @base",
|
"inherits": "BETA PAHT-CF @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "5O5fzmFrT3O1k1H0",
|
"setting_id": "BPAB00_10",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_flow_ratio": [
|
"filament_flow_ratio": [
|
||||||
"0.96",
|
"0.96",
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PAHT-CF @BBL X1C",
|
"name": "BETA PAHT-CF @BBL X1C",
|
||||||
"inherits": "BETA PAHT-CF @base",
|
"inherits": "BETA PAHT-CF @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "gB5HLYTDCooFy2W5",
|
"setting_id": "BPAB00",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"chamber_temperatures": [
|
"chamber_temperatures": [
|
||||||
"60"
|
"60"
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"type": "filament",
|
||||||
|
"name": "BETA PAHT-CF @base",
|
||||||
|
"inherits": "fdm_filament_pa",
|
||||||
|
"from": "system",
|
||||||
|
"filament_id": "OF6qw3Wb",
|
||||||
|
"instantiation": "false",
|
||||||
|
"description": "When printing this filament, there's a risk of nozzle clogging, oozing, warping and low layer adhesion strength. To get better results, please refer to this wiki: Printing Tips for High Temp / Engineering materials.",
|
||||||
|
"fan_cooling_layer_time": [
|
||||||
|
"5"
|
||||||
|
],
|
||||||
|
"fan_max_speed": [
|
||||||
|
"30"
|
||||||
|
],
|
||||||
|
"fan_min_speed": [
|
||||||
|
"10"
|
||||||
|
],
|
||||||
|
"filament_cost": [
|
||||||
|
"94.99"
|
||||||
|
],
|
||||||
|
"filament_density": [
|
||||||
|
"1.06"
|
||||||
|
],
|
||||||
|
"filament_flow_ratio": [
|
||||||
|
"0.96"
|
||||||
|
],
|
||||||
|
"filament_type": [
|
||||||
|
"PA-CF"
|
||||||
|
],
|
||||||
|
"filament_vendor": [
|
||||||
|
"BETA"
|
||||||
|
],
|
||||||
|
"full_fan_speed_layer": [
|
||||||
|
"2"
|
||||||
|
],
|
||||||
|
"impact_strength_z": [
|
||||||
|
"13.3"
|
||||||
|
],
|
||||||
|
"overhang_fan_speed": [
|
||||||
|
"40"
|
||||||
|
],
|
||||||
|
"overhang_fan_threshold": [
|
||||||
|
"0%"
|
||||||
|
],
|
||||||
|
"temperature_vitrification": [
|
||||||
|
"180"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PEBA 90A @BBL A1",
|
"name": "BETA PEBA 90A @BBL A1",
|
||||||
"inherits": "BETA PEBA 90A @base",
|
"inherits": "BETA PEBA 90A @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "A57Sbar56Ah1NiU7",
|
"setting_id": "BPBB00_04",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_density": [
|
"filament_density": [
|
||||||
"1.22"
|
"1.22"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PEBA 90A @BBL A1M",
|
"name": "BETA PEBA 90A @BBL A1M",
|
||||||
"inherits": "BETA PEBA 90A @base",
|
"inherits": "BETA PEBA 90A @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "OoLkWS147R0AasZc",
|
"setting_id": "BPBB00_05",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_density": [
|
"filament_density": [
|
||||||
"1.22"
|
"1.22"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PEBA 90A @BBL H2D",
|
"name": "BETA PEBA 90A @BBL H2D",
|
||||||
"inherits": "BETA PEBA 90A @base",
|
"inherits": "BETA PEBA 90A @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "91b8WTzvOky9wAVK",
|
"setting_id": "BPBB00_02",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"additional_cooling_fan_speed": [
|
"additional_cooling_fan_speed": [
|
||||||
"100"
|
"100"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PEBA 90A @BBL P1P",
|
"name": "BETA PEBA 90A @BBL P1P",
|
||||||
"inherits": "BETA PEBA 90A @base",
|
"inherits": "BETA PEBA 90A @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "ydudEBLRmj1WSXqB",
|
"setting_id": "BPBB00_01",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_max_volumetric_speed": [
|
"filament_max_volumetric_speed": [
|
||||||
"2.8",
|
"2.8",
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PEBA 90A @BBL X1C",
|
"name": "BETA PEBA 90A @BBL X1C",
|
||||||
"inherits": "BETA PEBA 90A @base",
|
"inherits": "BETA PEBA 90A @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "F1hTal3M92tBjv2N",
|
"setting_id": "BPBB00_00",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_max_volumetric_speed": [
|
"filament_max_volumetric_speed": [
|
||||||
"2.8",
|
"2.8",
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"type": "filament",
|
||||||
|
"name": "BETA PEBA 90A @base",
|
||||||
|
"inherits": "fdm_filament_tpu",
|
||||||
|
"from": "system",
|
||||||
|
"filament_id": "OFI2MKy7",
|
||||||
|
"instantiation": "false",
|
||||||
|
"description": "This filament is too soft and not compatible with the AMS. Printing it is of many requirements, and to get better printing quality, please refer to this wiki: TPU printing guide.",
|
||||||
|
"filament_cost": [
|
||||||
|
"59.99"
|
||||||
|
],
|
||||||
|
"filament_max_volumetric_speed": [
|
||||||
|
"2.8"
|
||||||
|
],
|
||||||
|
"filament_vendor": [
|
||||||
|
"BETA"
|
||||||
|
],
|
||||||
|
"impact_strength_z": [
|
||||||
|
"87.3"
|
||||||
|
],
|
||||||
|
"nozzle_temperature": [
|
||||||
|
"225"
|
||||||
|
],
|
||||||
|
"nozzle_temperature_initial_layer": [
|
||||||
|
"225"
|
||||||
|
],
|
||||||
|
"nozzle_temperature_range_high": [
|
||||||
|
"240"
|
||||||
|
],
|
||||||
|
"slow_down_layer_time": [
|
||||||
|
"14"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG @BBL A1",
|
"name": "BETA PETG @BBL A1",
|
||||||
"inherits": "BETA PETG @base",
|
"inherits": "BETA PETG @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "EpYzxZwVHvLaseku",
|
"setting_id": "BPGB00_06",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"50"
|
"50"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG @BBL A1M 0.4 nozzle",
|
"name": "BETA PETG @BBL A1M 0.4 nozzle",
|
||||||
"inherits": "BETA PETG @base",
|
"inherits": "BETA PETG @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "5V0hyhzFoDU8Tfwm",
|
"setting_id": "BPGB00_03",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"50"
|
"50"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG @BBL H2D 0.4 nozzle",
|
"name": "BETA PETG @BBL H2D 0.4 nozzle",
|
||||||
"inherits": "BETA PETG @base",
|
"inherits": "BETA PETG @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "KnKvUsD4rSpQU413",
|
"setting_id": "BPGB00_09",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"30"
|
"30"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG @BBL X1C",
|
"name": "BETA PETG @BBL X1C",
|
||||||
"inherits": "BETA PETG @base",
|
"inherits": "BETA PETG @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "uM6wHdt0N5ftZRge",
|
"setting_id": "BPGB00_01",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_min_speed": [
|
"fan_min_speed": [
|
||||||
"20"
|
"20"
|
||||||
@@ -92,48 +92,5 @@
|
|||||||
],
|
],
|
||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
"; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
||||||
],
|
|
||||||
"close_additional_fan_first_x_layers": [
|
|
||||||
"3"
|
|
||||||
],
|
|
||||||
"retraction_distances_when_ec": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"filament_end_gcode": [
|
|
||||||
"; filament end gcode \n\n"
|
|
||||||
],
|
|
||||||
"volumetric_speed_coefficients": [
|
|
||||||
"0 0 0 0 0 0"
|
|
||||||
],
|
|
||||||
"filament_adhesiveness_category": [
|
|
||||||
"300"
|
|
||||||
],
|
|
||||||
"filament_dev_chamber_drying_bed_temperature": [
|
|
||||||
"80"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_time": [
|
|
||||||
"12",
|
|
||||||
"12",
|
|
||||||
"12",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_ams_limitations": [
|
|
||||||
"1",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_cooling_temperature": [
|
|
||||||
"55"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_temperature": [
|
|
||||||
"65",
|
|
||||||
"65",
|
|
||||||
"55",
|
|
||||||
"55"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_softening_temperature": [
|
|
||||||
"60"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Fluorescence @BBL A1",
|
"name": "BETA PETG Fluorescence @BBL A1",
|
||||||
"inherits": "BETA PETG Fluorescence @base",
|
"inherits": "BETA PETG Fluorescence @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "ZtyTtAWsZnLGsM0O",
|
"setting_id": "BPGB02_06",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"50"
|
"50"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Fluorescence @BBL A1M 0.4 nozzle",
|
"name": "BETA PETG Fluorescence @BBL A1M 0.4 nozzle",
|
||||||
"inherits": "BETA PETG Fluorescence @base",
|
"inherits": "BETA PETG Fluorescence @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "VUSunTT0OJa7iOSd",
|
"setting_id": "BPGB02_03",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"50"
|
"50"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Fluorescence @BBL H2D 0.4 nozzle",
|
"name": "BETA PETG Fluorescence @BBL H2D 0.4 nozzle",
|
||||||
"inherits": "BETA PETG Fluorescence @base",
|
"inherits": "BETA PETG Fluorescence @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "JHg4y0pxAOtoJSuw",
|
"setting_id": "BPGB02_09",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"30"
|
"30"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Fluorescence @BBL X1C",
|
"name": "BETA PETG Fluorescence @BBL X1C",
|
||||||
"inherits": "BETA PETG Fluorescence @base",
|
"inherits": "BETA PETG Fluorescence @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "pCetfFvyLLw3vS2j",
|
"setting_id": "BPGB02_01",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_min_speed": [
|
"fan_min_speed": [
|
||||||
"20"
|
"20"
|
||||||
@@ -92,48 +92,5 @@
|
|||||||
],
|
],
|
||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
"; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
||||||
],
|
|
||||||
"close_additional_fan_first_x_layers": [
|
|
||||||
"3"
|
|
||||||
],
|
|
||||||
"retraction_distances_when_ec": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"filament_end_gcode": [
|
|
||||||
"; filament end gcode \n\n"
|
|
||||||
],
|
|
||||||
"volumetric_speed_coefficients": [
|
|
||||||
"0 0 0 0 0 0"
|
|
||||||
],
|
|
||||||
"filament_adhesiveness_category": [
|
|
||||||
"300"
|
|
||||||
],
|
|
||||||
"filament_dev_chamber_drying_bed_temperature": [
|
|
||||||
"80"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_time": [
|
|
||||||
"12",
|
|
||||||
"12",
|
|
||||||
"12",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_ams_limitations": [
|
|
||||||
"1",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_cooling_temperature": [
|
|
||||||
"55"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_temperature": [
|
|
||||||
"65",
|
|
||||||
"65",
|
|
||||||
"55",
|
|
||||||
"55"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_softening_temperature": [
|
|
||||||
"60"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Glitter @BBL A1",
|
"name": "BETA PETG Glitter @BBL A1",
|
||||||
"inherits": "BETA PETG Glitter @base",
|
"inherits": "BETA PETG Glitter @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "cz5dC7OrXDlX1Ctj",
|
"setting_id": "BPGB03_06",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"50"
|
"50"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Glitter @BBL A1M 0.4 nozzle",
|
"name": "BETA PETG Glitter @BBL A1M 0.4 nozzle",
|
||||||
"inherits": "BETA PETG Glitter @base",
|
"inherits": "BETA PETG Glitter @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "PozWnOfZ2l7HqTpx",
|
"setting_id": "BPGB03_03",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"50"
|
"50"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Glitter @BBL H2D 0.4 nozzle",
|
"name": "BETA PETG Glitter @BBL H2D 0.4 nozzle",
|
||||||
"inherits": "BETA PETG Glitter @base",
|
"inherits": "BETA PETG Glitter @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "ijW4zvNAQ3DIK984",
|
"setting_id": "BPGB03_09",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"30"
|
"30"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Glitter @BBL X1C",
|
"name": "BETA PETG Glitter @BBL X1C",
|
||||||
"inherits": "BETA PETG Glitter @base",
|
"inherits": "BETA PETG Glitter @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "UI220qldPoLY8VZN",
|
"setting_id": "BPGB03_01",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_min_speed": [
|
"fan_min_speed": [
|
||||||
"20"
|
"20"
|
||||||
@@ -92,48 +92,5 @@
|
|||||||
],
|
],
|
||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
"; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
||||||
],
|
|
||||||
"close_additional_fan_first_x_layers": [
|
|
||||||
"3"
|
|
||||||
],
|
|
||||||
"retraction_distances_when_ec": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"filament_end_gcode": [
|
|
||||||
"; filament end gcode \n\n"
|
|
||||||
],
|
|
||||||
"volumetric_speed_coefficients": [
|
|
||||||
"0 0 0 0 0 0"
|
|
||||||
],
|
|
||||||
"filament_adhesiveness_category": [
|
|
||||||
"300"
|
|
||||||
],
|
|
||||||
"filament_dev_chamber_drying_bed_temperature": [
|
|
||||||
"80"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_time": [
|
|
||||||
"12",
|
|
||||||
"12",
|
|
||||||
"12",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_ams_limitations": [
|
|
||||||
"1",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_cooling_temperature": [
|
|
||||||
"55"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_temperature": [
|
|
||||||
"65",
|
|
||||||
"65",
|
|
||||||
"55",
|
|
||||||
"55"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_softening_temperature": [
|
|
||||||
"60"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Glow @BBL A1",
|
"name": "BETA PETG Glow @BBL A1",
|
||||||
"inherits": "BETA PETG Glow @base",
|
"inherits": "BETA PETG Glow @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "LudMQeiSJOLw0Aoy",
|
"setting_id": "BPGB04_06",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"50"
|
"50"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Glow @BBL A1M 0.4 nozzle",
|
"name": "BETA PETG Glow @BBL A1M 0.4 nozzle",
|
||||||
"inherits": "BETA PETG Glow @base",
|
"inherits": "BETA PETG Glow @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "cl1Rl9hgrahhhSd3",
|
"setting_id": "BPGB04_03",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"50"
|
"50"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Glow @BBL H2D 0.4 nozzle",
|
"name": "BETA PETG Glow @BBL H2D 0.4 nozzle",
|
||||||
"inherits": "BETA PETG Glow @base",
|
"inherits": "BETA PETG Glow @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "3s9w3mH6M4OdbrUV",
|
"setting_id": "BPGB04_09",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"30"
|
"30"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Glow @BBL X1C",
|
"name": "BETA PETG Glow @BBL X1C",
|
||||||
"inherits": "BETA PETG Glow @base",
|
"inherits": "BETA PETG Glow @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "wv5FRKdnsHaIFA7L",
|
"setting_id": "BPGB04_01",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_min_speed": [
|
"fan_min_speed": [
|
||||||
"20"
|
"20"
|
||||||
@@ -92,48 +92,5 @@
|
|||||||
],
|
],
|
||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
"; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
||||||
],
|
|
||||||
"close_additional_fan_first_x_layers": [
|
|
||||||
"3"
|
|
||||||
],
|
|
||||||
"retraction_distances_when_ec": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"filament_end_gcode": [
|
|
||||||
"; filament end gcode \n\n"
|
|
||||||
],
|
|
||||||
"volumetric_speed_coefficients": [
|
|
||||||
"0 0 0 0 0 0"
|
|
||||||
],
|
|
||||||
"filament_adhesiveness_category": [
|
|
||||||
"300"
|
|
||||||
],
|
|
||||||
"filament_dev_chamber_drying_bed_temperature": [
|
|
||||||
"80"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_time": [
|
|
||||||
"12",
|
|
||||||
"12",
|
|
||||||
"12",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_ams_limitations": [
|
|
||||||
"1",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_cooling_temperature": [
|
|
||||||
"55"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_temperature": [
|
|
||||||
"65",
|
|
||||||
"65",
|
|
||||||
"55",
|
|
||||||
"55"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_softening_temperature": [
|
|
||||||
"60"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Gradient @BBL A1",
|
"name": "BETA PETG Gradient @BBL A1",
|
||||||
"inherits": "BETA PETG Gradient @base",
|
"inherits": "BETA PETG Gradient @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "L3hZggzEZUgUv0Qv",
|
"setting_id": "BPGB05_06",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"50"
|
"50"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Gradient @BBL A1M 0.4 nozzle",
|
"name": "BETA PETG Gradient @BBL A1M 0.4 nozzle",
|
||||||
"inherits": "BETA PETG Gradient @base",
|
"inherits": "BETA PETG Gradient @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "zsITnsNFRG7IE6sR",
|
"setting_id": "BPGB05_03",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"50"
|
"50"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Gradient @BBL H2D 0.4 nozzle",
|
"name": "BETA PETG Gradient @BBL H2D 0.4 nozzle",
|
||||||
"inherits": "BETA PETG Gradient @base",
|
"inherits": "BETA PETG Gradient @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "GqmCuPg6baUxeoYS",
|
"setting_id": "BPGB05_09",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"30"
|
"30"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Gradient @BBL X1C",
|
"name": "BETA PETG Gradient @BBL X1C",
|
||||||
"inherits": "BETA PETG Gradient @base",
|
"inherits": "BETA PETG Gradient @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "oYJjUiaCI4UBZ0ur",
|
"setting_id": "BPGB05_01",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_min_speed": [
|
"fan_min_speed": [
|
||||||
"20"
|
"20"
|
||||||
@@ -92,48 +92,5 @@
|
|||||||
],
|
],
|
||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
"; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
||||||
],
|
|
||||||
"close_additional_fan_first_x_layers": [
|
|
||||||
"3"
|
|
||||||
],
|
|
||||||
"retraction_distances_when_ec": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"filament_end_gcode": [
|
|
||||||
"; filament end gcode \n\n"
|
|
||||||
],
|
|
||||||
"volumetric_speed_coefficients": [
|
|
||||||
"0 0 0 0 0 0"
|
|
||||||
],
|
|
||||||
"filament_adhesiveness_category": [
|
|
||||||
"300"
|
|
||||||
],
|
|
||||||
"filament_dev_chamber_drying_bed_temperature": [
|
|
||||||
"80"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_time": [
|
|
||||||
"12",
|
|
||||||
"12",
|
|
||||||
"12",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_ams_limitations": [
|
|
||||||
"1",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_cooling_temperature": [
|
|
||||||
"55"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_temperature": [
|
|
||||||
"65",
|
|
||||||
"65",
|
|
||||||
"55",
|
|
||||||
"55"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_softening_temperature": [
|
|
||||||
"60"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG HF @BBL A1",
|
"name": "BETA PETG HF @BBL A1",
|
||||||
"inherits": "BETA PETG HF @base",
|
"inherits": "BETA PETG HF @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "T2Ea25pM2u9BM7Oa",
|
"setting_id": "BPGB06_03",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_cooling_layer_time": [
|
"fan_cooling_layer_time": [
|
||||||
"15"
|
"15"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG HF @BBL A1M",
|
"name": "BETA PETG HF @BBL A1M",
|
||||||
"inherits": "BETA PETG HF @base",
|
"inherits": "BETA PETG HF @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "nO5R86dkDle1m5Pq",
|
"setting_id": "BPGB06_06",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_cooling_layer_time": [
|
"fan_cooling_layer_time": [
|
||||||
"15"
|
"15"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG HF @BBL H2D 0.4 nozzle",
|
"name": "BETA PETG HF @BBL H2D 0.4 nozzle",
|
||||||
"inherits": "BETA PETG HF @base",
|
"inherits": "BETA PETG HF @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "YOBguayM9PiwkpfT",
|
"setting_id": "BPGB06_09",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"counter_coef_2": [
|
"counter_coef_2": [
|
||||||
"0.007"
|
"0.007"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG HF @BBL X1C",
|
"name": "BETA PETG HF @BBL X1C",
|
||||||
"inherits": "BETA PETG HF @base",
|
"inherits": "BETA PETG HF @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "EG3h0IHVO1yyVNMs",
|
"setting_id": "BPGB06_00",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_cooling_layer_time": [
|
"fan_cooling_layer_time": [
|
||||||
"20"
|
"20"
|
||||||
@@ -85,48 +85,5 @@
|
|||||||
],
|
],
|
||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
"; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
||||||
],
|
|
||||||
"close_additional_fan_first_x_layers": [
|
|
||||||
"3"
|
|
||||||
],
|
|
||||||
"retraction_distances_when_ec": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"filament_end_gcode": [
|
|
||||||
"; filament end gcode \n\n"
|
|
||||||
],
|
|
||||||
"volumetric_speed_coefficients": [
|
|
||||||
"0 0 0 0 0 0"
|
|
||||||
],
|
|
||||||
"filament_adhesiveness_category": [
|
|
||||||
"300"
|
|
||||||
],
|
|
||||||
"filament_dev_chamber_drying_bed_temperature": [
|
|
||||||
"80"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_time": [
|
|
||||||
"12",
|
|
||||||
"12",
|
|
||||||
"12",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_ams_limitations": [
|
|
||||||
"1",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_cooling_temperature": [
|
|
||||||
"55"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_temperature": [
|
|
||||||
"65",
|
|
||||||
"65",
|
|
||||||
"55",
|
|
||||||
"55"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_softening_temperature": [
|
|
||||||
"60"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Heat Color Change @BBL A1",
|
"name": "BETA PETG Heat Color Change @BBL A1",
|
||||||
"inherits": "BETA PETG Heat Color Change @base",
|
"inherits": "BETA PETG Heat Color Change @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "ZhHASdXFywqbRuBf",
|
"setting_id": "BPGB01_06",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"50"
|
"50"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Heat Color Change @BBL A1M 0.4 nozzle",
|
"name": "BETA PETG Heat Color Change @BBL A1M 0.4 nozzle",
|
||||||
"inherits": "BETA PETG Heat Color Change @base",
|
"inherits": "BETA PETG Heat Color Change @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "YiFgzCJDAOW9YSjZ",
|
"setting_id": "BPGB01_03",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"50"
|
"50"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Heat Color Change @BBL H2D 0.4 nozzle",
|
"name": "BETA PETG Heat Color Change @BBL H2D 0.4 nozzle",
|
||||||
"inherits": "BETA PETG Heat Color Change @base",
|
"inherits": "BETA PETG Heat Color Change @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "DpWgpTiKdm70Xt1i",
|
"setting_id": "BPGB01_09",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"30"
|
"30"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Heat Color Change @BBL X1C",
|
"name": "BETA PETG Heat Color Change @BBL X1C",
|
||||||
"inherits": "BETA PETG Heat Color Change @base",
|
"inherits": "BETA PETG Heat Color Change @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "3lJe6ftSHQDkQZ1S",
|
"setting_id": "BPGB01_01",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_min_speed": [
|
"fan_min_speed": [
|
||||||
"20"
|
"20"
|
||||||
@@ -92,48 +92,5 @@
|
|||||||
],
|
],
|
||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
"; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
||||||
],
|
|
||||||
"close_additional_fan_first_x_layers": [
|
|
||||||
"3"
|
|
||||||
],
|
|
||||||
"retraction_distances_when_ec": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"filament_end_gcode": [
|
|
||||||
"; filament end gcode \n\n"
|
|
||||||
],
|
|
||||||
"volumetric_speed_coefficients": [
|
|
||||||
"0 0 0 0 0 0"
|
|
||||||
],
|
|
||||||
"filament_adhesiveness_category": [
|
|
||||||
"300"
|
|
||||||
],
|
|
||||||
"filament_dev_chamber_drying_bed_temperature": [
|
|
||||||
"80"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_time": [
|
|
||||||
"12",
|
|
||||||
"12",
|
|
||||||
"12",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_ams_limitations": [
|
|
||||||
"1",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_cooling_temperature": [
|
|
||||||
"55"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_temperature": [
|
|
||||||
"65",
|
|
||||||
"65",
|
|
||||||
"55",
|
|
||||||
"55"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_softening_temperature": [
|
|
||||||
"60"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Marble @BBL A1",
|
"name": "BETA PETG Marble @BBL A1",
|
||||||
"inherits": "BETA PETG Marble @base",
|
"inherits": "BETA PETG Marble @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "tSCDuE4dE44PyIwb",
|
"setting_id": "BPGB07_06",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"50"
|
"50"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Marble @BBL A1M 0.4 nozzle",
|
"name": "BETA PETG Marble @BBL A1M 0.4 nozzle",
|
||||||
"inherits": "BETA PETG Marble @base",
|
"inherits": "BETA PETG Marble @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "n6dguOo5ZleD6Ec4",
|
"setting_id": "BPGB07_03",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"50"
|
"50"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Marble @BBL H2D 0.4 nozzle",
|
"name": "BETA PETG Marble @BBL H2D 0.4 nozzle",
|
||||||
"inherits": "BETA PETG Marble @base",
|
"inherits": "BETA PETG Marble @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "RxCTxdvym4iNOB5j",
|
"setting_id": "BPGB07_09",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"30"
|
"30"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Marble @BBL X1C",
|
"name": "BETA PETG Marble @BBL X1C",
|
||||||
"inherits": "BETA PETG Marble @base",
|
"inherits": "BETA PETG Marble @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "3BgsPAgilo1MgtOV",
|
"setting_id": "BPGB07_01",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_min_speed": [
|
"fan_min_speed": [
|
||||||
"20"
|
"20"
|
||||||
@@ -92,48 +92,5 @@
|
|||||||
],
|
],
|
||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
"; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
||||||
],
|
|
||||||
"close_additional_fan_first_x_layers": [
|
|
||||||
"3"
|
|
||||||
],
|
|
||||||
"retraction_distances_when_ec": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"filament_end_gcode": [
|
|
||||||
"; filament end gcode \n\n"
|
|
||||||
],
|
|
||||||
"volumetric_speed_coefficients": [
|
|
||||||
"0 0 0 0 0 0"
|
|
||||||
],
|
|
||||||
"filament_adhesiveness_category": [
|
|
||||||
"300"
|
|
||||||
],
|
|
||||||
"filament_dev_chamber_drying_bed_temperature": [
|
|
||||||
"80"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_time": [
|
|
||||||
"12",
|
|
||||||
"12",
|
|
||||||
"12",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_ams_limitations": [
|
|
||||||
"1",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_cooling_temperature": [
|
|
||||||
"55"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_temperature": [
|
|
||||||
"65",
|
|
||||||
"65",
|
|
||||||
"55",
|
|
||||||
"55"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_softening_temperature": [
|
|
||||||
"60"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Matte @BBL A1",
|
"name": "BETA PETG Matte @BBL A1",
|
||||||
"inherits": "BETA PETG Matte @base",
|
"inherits": "BETA PETG Matte @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "zYkrzQk11C98R31F",
|
"setting_id": "BPGB08_06",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"50"
|
"50"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Matte @BBL A1M 0.4 nozzle",
|
"name": "BETA PETG Matte @BBL A1M 0.4 nozzle",
|
||||||
"inherits": "BETA PETG Matte @base",
|
"inherits": "BETA PETG Matte @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "rzX5oP4037Ex5Chh",
|
"setting_id": "BPGB08_03",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"50"
|
"50"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Matte @BBL H2D 0.4 nozzle",
|
"name": "BETA PETG Matte @BBL H2D 0.4 nozzle",
|
||||||
"inherits": "BETA PETG Matte @base",
|
"inherits": "BETA PETG Matte @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "sqz8Vluq7GMd3siv",
|
"setting_id": "BPGB08_09",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"30"
|
"30"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Matte @BBL X1C",
|
"name": "BETA PETG Matte @BBL X1C",
|
||||||
"inherits": "BETA PETG Matte @base",
|
"inherits": "BETA PETG Matte @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "NXgqYCqHeVCgFF3I",
|
"setting_id": "BPGB08_01",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_min_speed": [
|
"fan_min_speed": [
|
||||||
"20"
|
"20"
|
||||||
@@ -92,48 +92,5 @@
|
|||||||
],
|
],
|
||||||
"filament_start_gcode": [
|
"filament_start_gcode": [
|
||||||
"; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
"; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
||||||
],
|
|
||||||
"close_additional_fan_first_x_layers": [
|
|
||||||
"3"
|
|
||||||
],
|
|
||||||
"retraction_distances_when_ec": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"filament_end_gcode": [
|
|
||||||
"; filament end gcode \n\n"
|
|
||||||
],
|
|
||||||
"volumetric_speed_coefficients": [
|
|
||||||
"0 0 0 0 0 0"
|
|
||||||
],
|
|
||||||
"filament_adhesiveness_category": [
|
|
||||||
"300"
|
|
||||||
],
|
|
||||||
"filament_dev_chamber_drying_bed_temperature": [
|
|
||||||
"80"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_time": [
|
|
||||||
"12",
|
|
||||||
"12",
|
|
||||||
"12",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_ams_limitations": [
|
|
||||||
"1",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_cooling_temperature": [
|
|
||||||
"55"
|
|
||||||
],
|
|
||||||
"filament_dev_ams_drying_temperature": [
|
|
||||||
"65",
|
|
||||||
"65",
|
|
||||||
"55",
|
|
||||||
"55"
|
|
||||||
],
|
|
||||||
"filament_dev_drying_softening_temperature": [
|
|
||||||
"60"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Metallic @BBL A1",
|
"name": "BETA PETG Metallic @BBL A1",
|
||||||
"inherits": "BETA PETG Metallic @base",
|
"inherits": "BETA PETG Metallic @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "1baUIJ3P8n6DcyRc",
|
"setting_id": "BPGB09_06",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"50"
|
"50"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"name": "BETA PETG Metallic @BBL A1M 0.4 nozzle",
|
"name": "BETA PETG Metallic @BBL A1M 0.4 nozzle",
|
||||||
"inherits": "BETA PETG Metallic @base",
|
"inherits": "BETA PETG Metallic @base",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "LMsVDqsChBksLNqL",
|
"setting_id": "BPGB09_03",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"50"
|
"50"
|
||||||